Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.api / src / main / java / org / gvsig / fmap / dal / feature / FeatureStore.java @ 40435

History | View | Annotate | Download (24.8 KB)

1
package org.gvsig.fmap.dal.feature;
2

    
3
import java.util.Iterator;
4
import java.util.List;
5

    
6
import org.cresques.cts.IProjection;
7

    
8
import org.gvsig.fmap.dal.DataServerExplorer;
9
import org.gvsig.fmap.dal.DataStore;
10
import org.gvsig.fmap.dal.DataStoreParameters;
11
import org.gvsig.fmap.dal.exception.DataException;
12
import org.gvsig.fmap.dal.exception.ReadException;
13
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
14
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
15
import org.gvsig.fmap.geom.Geometry;
16
import org.gvsig.fmap.geom.primitive.Envelope;
17
import org.gvsig.tools.dispose.DisposableIterator;
18
import org.gvsig.tools.dynobject.DynObject;
19
import org.gvsig.tools.lang.Cloneable;
20
import org.gvsig.tools.observer.Observer;
21
import org.gvsig.tools.undo.UndoRedoStack;
22

    
23
/**
24
 * <p>
25
 * A FeatureStore is a type of store whose data consists on sets of
26
 * {@link Feature}(s). {@link Feature}(s) from the same FeatureStore can be of
27
 * different {@link FeatureType}(s) (as in GML format for instance).
28
 * </p>
29
 * 
30
 * <p>
31
 * FeatureStore allows:
32
 * </p>
33
 * <ul>
34
 * <li>Obtaining the default {@link FeatureType}. A FeatureStore always has one
35
 * and only one default FeatureType.
36
 * <li>Obtaining the list of {@link FeatureType}(s) defined in the FeatureStore.
37
 * <li>Obtaining, filtering and sorting subsets of data ({@link FeatureSet})
38
 * through {@link FeatureQuery}, as well as background loading.
39
 * <li>Obtaining the total {@link Envelope} (AKA bounding box or extent) of the
40
 * store.
41
 * <li>Support for editing {@link FeatureType}(s).
42
 * <li>Obtaining information about contained {@link Geometry} types.
43
 * <li>Exporting to another store.
44
 * <li>Indexing.
45
 * <li>Selection.
46
 * <li>Locks management.
47
 * </ul>
48
 * 
49
 */
50
public interface FeatureStore extends DataStore, UndoRedoStack, Cloneable {
51

    
52
    public static final String METADATA_DEFINITION_NAME = "FeatureStore";
53

    
54
    /** Indicates that this store is in query mode */
55
    final static int MODE_QUERY = 0;
56

    
57
    /** Indicates that this store is in full edit mode */
58
    final static int MODE_FULLEDIT = 1;
59

    
60
    /** Indicates that this store is in append mode */
61
    final static int MODE_APPEND = 2;
62

    
63
    /*
64
     * =============================================================
65
     * 
66
     * information related services
67
     */
68

    
69
    /**
70
     * Indicates whether this store allows writing.
71
     * 
72
     * @return
73
     *         true if this store can be written, false if not.
74
     */
75
    public boolean allowWrite();
76

    
77
    /**
78
     * Returns this store's default {@link FeatureType}.
79
     * 
80
     * @return
81
     *         this store's default {@link FeatureType}.
82
     * 
83
     * @throws DataException
84
     */
85
    public FeatureType getDefaultFeatureType() throws DataException;
86

    
87
    /**
88
     * Returns this store's featureType {@link FeatureType} matches with
89
     * featureTypeId.
90
     * 
91
     * @param featureTypeId
92
     * 
93
     * @return this store's default {@link FeatureType}.
94
     * 
95
     * @throws DataException
96
     */
97
    public FeatureType getFeatureType(String featureTypeId)
98
        throws DataException;
99

    
100
    /**
101
     * Returns this store's {@link FeatureType}(s).
102
     * 
103
     * @return a list with this store's {@link FeatureType}(s).
104
     * 
105
     * @throws DataException
106
     */
107
    public List getFeatureTypes() throws DataException;
108

    
109
    /**
110
     * Returns this store's parameters.
111
     * 
112
     * @return
113
     *         {@link DataStoreParameters} containing this store's parameters
114
     */
115
    public DataStoreParameters getParameters();
116

    
117
    /**
118
     *@throws DataException
119
     * @deprecated Mirar de cambiarlo a metadatos
120
     */
121
    public boolean canWriteGeometry(int gvSIGgeometryType) throws DataException;
122

    
123
    /**
124
     * Returns this store's total envelope (extent).
125
     * 
126
     * @return this store's total envelope (extent) or <code>null</code> if
127
     *         store not have geometry information
128
     */
129
    public Envelope getEnvelope() throws DataException;
130

    
131
    /**
132
     * 
133
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
134
     * @return
135
     * @throws DataException
136
     */
137
    public IProjection getSRSDefaultGeometry() throws DataException;
138

    
139
    /**
140
     * Exports this store to another store.
141
     * 
142
     * @param explorer
143
     *            {@link DataServerExplorer} target
144
     * @param params
145
     *            New parameters of this store that will be used on the target
146
     *            explorer
147
     * 
148
     * @throws DataException
149
     * 
150
     * @Deprecated this method is unstable
151
     */
152
    public void export(DataServerExplorer explorer, String provider,
153
        NewFeatureStoreParameters params) throws DataException;
154

    
155
    /*
156
     * =============================================================
157
     * 
158
     * Query related services
159
     */
160

    
161
    /**
162
     * Returns all available features in the store.
163
     * <p>
164
     * <em>
165
     * <strong>NOTE:</strong> if you use this method to get a 
166
     * {@link FeatureSet}, you  must get sure it is disposed 
167
     * (@see {@link DisposableIterator#dispose()}) in any case, even if an 
168
     * error occurs while getting the data. It is recommended to use the 
169
     * <code>accept</code> methods instead, which handle everything for you. 
170
     * Take into account the accept methods may use a fast iterator to 
171
     * get the features.
172
     * </em>
173
     * </p>
174
     * 
175
     * @see #accept(org.gvsig.tools.visitor.Visitor)
176
     * 
177
     * @return a collection of features
178
     * @throws ReadException
179
     *             if there is any error while reading the features
180
     */
181
    FeatureSet getFeatureSet() throws DataException;
182

    
183
    /**
184
     * Returns a subset of features taking into account the properties and
185
     * restrictions of the FeatureQuery.
186
     * <p>
187
     * <em>
188
     * <strong>NOTE:</strong> if you use this method to get a 
189
     * {@link FeatureSet}, you  must get sure it is disposed 
190
     * (@see {@link DisposableIterator#dispose()}) in any case, even if an 
191
     * error occurs while getting the data. It is recommended to use the 
192
     * <code>accept</code> methods instead, which handle everything for you. 
193
     * Take into account the accept methods may use a fast iterator to 
194
     * get the features.
195
     * </em>
196
     * </p>
197
     * 
198
     * @see #accept(org.gvsig.tools.visitor.Visitor,
199
     *      org.gvsig.fmap.dal.DataQuery)
200
     * 
201
     * @param featureQuery
202
     *            defines the characteristics of the features to return
203
     * @return a collection of features
204
     * @throws ReadException
205
     *             if there is any error while reading the features
206
     */
207
    FeatureSet getFeatureSet(FeatureQuery featureQuery) throws DataException;
208

    
209
    /**
210
     * Loads a subset of features taking into account the properties and
211
     * restrictions of the FeatureQuery. Feature loading is performed by calling
212
     * the Observer, once each loaded Feature.
213
     * 
214
     * @param featureQuery
215
     *            defines the characteristics of the features to return
216
     * @param observer
217
     *            to be notified of each loaded Feature
218
     * @throws DataException
219
     *             if there is any error while loading the features
220
     */
221
    void getFeatureSet(FeatureQuery featureQuery, Observer observer)
222
        throws DataException;
223

    
224
    /**
225
     * Loads all available feature in the store. The loading of Features is
226
     * performed by calling the Observer, once each loaded Feature.
227
     * 
228
     * @param observer
229
     *            to be notified of each loaded Feature
230
     * @throws DataException
231
     *             if there is any error while loading the features
232
     */
233
    void getFeatureSet(Observer observer) throws DataException;
234

    
235
    /**
236
     * Returns the feature given its reference.
237
     * 
238
     * @param reference
239
     *            a unique FeatureReference
240
     * @return
241
     *         The Feature
242
     * 
243
     * @throws DataException
244
     * 
245
     */
246
    public Feature getFeatureByReference(FeatureReference reference)
247
        throws DataException;
248

    
249
    /**
250
     * Returns the feature given its reference and feature type.
251
     * 
252
     * @param reference
253
     *            a unique FeatureReference
254
     * 
255
     * @param featureType
256
     *            FeatureType to which the requested Feature belongs
257
     * 
258
     * @return
259
     *         The Feature
260
     * 
261
     * @throws DataException
262
     * 
263
     */
264
    public Feature getFeatureByReference(FeatureReference reference,
265
        FeatureType featureType) throws DataException;
266

    
267
    /*
268
     * =============================================================
269
     * 
270
     * Editing related services
271
     */
272

    
273
    /**
274
     * Enters editing state.
275
     */
276
    public void edit() throws DataException;
277

    
278
    /**
279
     * Enters editing state specifying the editing mode.
280
     * 
281
     * @param mode
282
     * 
283
     * @throws DataException
284
     */
285
    public void edit(int mode) throws DataException;
286

    
287
    /**
288
     * Cancels all editing since the last edit().
289
     * 
290
     * @throws DataException
291
     */
292
    public void cancelEditing() throws DataException;
293

    
294
    /**
295
     * Exits editing state.
296
     * 
297
     * @throws DataException
298
     */
299
    public void finishEditing() throws DataException;
300

    
301
    /**
302
     * Save changes in the provider without leaving the edit mode.
303
     * Do not call observers to communicate a change of ediding mode.
304
     * The operation's history is eliminated to prevent inconsistencies
305
     * in the data.
306
     *
307
     * @throws DataException
308
     */
309
    public void commitChanges() throws DataException ;
310

    
311
    /**
312
     *
313
     * Returns true if you can call CommitChanges method.
314
     * If not in editing or changes have been made in the structure
315
     * return false.
316
     *  
317
     * @return true if can call commitChanges
318
     * @throws DataException 
319
     */
320
    public boolean canCommitChanges() throws DataException;
321

    
322
    
323
    /**
324
     * Indicates whether this store is in editing state.
325
     * 
326
     * @return
327
     *         true if this store is in editing state, false if not.
328
     */
329
    public boolean isEditing();
330

    
331
    /**
332
     * Indicates whether this store is in appending state. In this state the new
333
     * features are automatically inserted at the end of the {@link FeatureSet}.
334
     * 
335
     * @return true if this store is in appending state.
336
     */
337
    public boolean isAppending();
338

    
339
    /**
340
     * Updates a {@link FeatureType} in the store with the changes in the
341
     * {@link EditableFeatureType}.<br>
342
     * 
343
     * Any {@link FeatureSet} from this store that are used will be invalidated.
344
     * 
345
     * @param featureType
346
     *            an {@link EditableFeatureType} with the changes.
347
     * 
348
     * @throws DataException
349
     */
350
    public void update(EditableFeatureType featureType) throws DataException;
351

    
352
    /**
353
     * Updates a {@link Feature} in the store with the changes in the
354
     * {@link EditableFeature}.<br>
355
     * 
356
     * Any {@link FeatureSet} from this store that was still in use will be
357
     * invalidated. You can override this using
358
     * {@link FeatureSet#update(EditableFeature)}.
359
     * 
360
     * @param feature
361
     *            the feature to be updated
362
     * 
363
     * @throws DataException
364
     */
365
    public void update(EditableFeature feature) throws DataException;
366

    
367
    /**
368
     * Deletes a {@link Feature} from the store.<br>
369
     * 
370
     * Any {@link FeatureSet} from this store that was still in use will be
371
     * invalidated. You can override this using {@link Iterator#remove()} from
372
     * {@link FeatureSet}.
373
     * 
374
     * @param feature
375
     *            The feature to be deleted.
376
     * 
377
     * @throws DataException
378
     */
379
    public void delete(Feature feature) throws DataException;
380

    
381
    /**
382
     * Inserts a {@link Feature} in the store.<br>
383
     * 
384
     * Any {@link FeatureSet} from this store that was still in use will be
385
     * invalidated. You can override this using
386
     * {@link FeatureSet#insert(EditableFeature)}.
387
     * 
388
     * @param feature
389
     *            The feature to be inserted
390
     * 
391
     * @throws DataException
392
     */
393
    public void insert(EditableFeature feature) throws DataException;
394

    
395
    /**
396
     * Creates a new feature using the default feature type and returns it as an
397
     * {@link EditableFeature}
398
     * 
399
     * @return a new feature in editable state
400
     * 
401
     * @throws DataException
402
     */
403
    public EditableFeature createNewFeature() throws DataException;
404

    
405
    /**
406
     * Creates a new feature of the given {@link FeatureType} and uses the given
407
     * {@link Feature} as default values to initialize it.
408
     * 
409
     * @param type
410
     *            the new feature's feature type
411
     * 
412
     * @param defaultValues
413
     *            a feature whose values are used as default values for the new
414
     *            feature.
415
     * 
416
     * @return the new feature.
417
     * 
418
     * @throws DataException
419
     */
420
    public EditableFeature createNewFeature(FeatureType type,
421
        Feature defaultValues) throws DataException;
422

    
423
    /**
424
     * Creates a new feature of the given {@link FeatureType}. The flag
425
     * defaultValues is used to indicate whether the new feature should be
426
     * initialized with default values or not.
427
     * 
428
     * @param type
429
     *            the new feature's feature type
430
     * 
431
     * @param defaultValues
432
     *            if true the new feature is initialized with each attribute's
433
     *            default value.
434
     * 
435
     * @return
436
     *         the new feature
437
     * 
438
     * @throws DataException
439
     */
440
    public EditableFeature createNewFeature(FeatureType type,
441
        boolean defaultValues) throws DataException;
442

    
443
    /**
444
     * Creates a new feature of default {@link FeatureType}. The flag
445
     * defaultValues is used to indicate whether the new feature should be
446
     * initialized with default values or not.
447
     * 
448
     * @param defaultValues
449
     *            if true the new feature is initialized with each attribute's
450
     *            default value.
451
     * 
452
     * @return
453
     *         the new feature
454
     * 
455
     * @throws DataException
456
     */
457
    public EditableFeature createNewFeature(boolean defaultValues)
458
        throws DataException;
459

    
460
    /**
461
     * Applies the validation rules associated to the given mode to the active
462
     * {@link FeatureSet}.
463
     * 
464
     * @param mode
465
     *            can be one of {MODE_QUERY, MODE_FULLEDIT, MODE_APPEND}
466
     * 
467
     * @throws DataException
468
     */
469
    public void validateFeatures(int mode) throws DataException;
470

    
471
    /**
472
     * Indicates whether this store supports append mode.
473
     * 
474
     * @return
475
     *         true if this store supports append mode.
476
     */
477
    public boolean isAppendModeSupported();
478

    
479
    /**
480
     * Initiates an editing group. This is typically used to group series of
481
     * store editing operations.
482
     * 
483
     * @param description
484
     *            Description of the editing group.
485
     * 
486
     * @throws NeedEditingModeException
487
     */
488
    public void beginEditingGroup(String description)
489
        throws NeedEditingModeException;
490

    
491
    /**
492
     * Finishes an editing group.
493
     * 
494
     * @throws NeedEditingModeException
495
     */
496
    public void endEditingGroup() throws NeedEditingModeException;
497

    
498
    /*
499
     * =============================================================
500
     * 
501
     * Index related services
502
     */
503

    
504
    /**
505
     * Creates an index which will be applied to the features of the given type,
506
     * by using the data of the given attribute.
507
     * 
508
     * @param featureType
509
     *            The FeatureType to which the indexed attribute belongs.
510
     * 
511
     * @param attributeName
512
     *            The name of the attributed to be indexed
513
     * 
514
     * @param indexName
515
     *            The index name
516
     * 
517
     * @return the resulting {@link FeatureIndex}
518
     * 
519
     * 
520
     * @throws FeatureIndexException
521
     *             if there is an error creating the index
522
     */
523
    public FeatureIndex createIndex(FeatureType featureType,
524
        String attributeName, String indexName) throws DataException;
525

    
526
    /**
527
     * Creates an index which will be applied to the features of the given type,
528
     * by using the data of the given attribute.
529
     * 
530
     * @param indexTypeName
531
     *            the type of the index to be created. That name is
532
     *            related to one of the registered index providers
533
     * @param featureType
534
     *            The FeatureType to which the indexed attribute belongs.
535
     * 
536
     * @param attributeName
537
     *            The name of the attributed to be indexed
538
     * 
539
     * @param indexName
540
     *            The index name
541
     * 
542
     * @return the resulting {@link FeatureIndex}
543
     * 
544
     * 
545
     * @throws FeatureIndexException
546
     *             if there is an error creating the index
547
     */
548
    public FeatureIndex createIndex(String indexTypeName,
549
        FeatureType featureType, String attributeName, String indexName)
550
        throws DataException;
551

    
552
    /**
553
     * Creates an index which will be applied to the features of the given type,
554
     * by using the data of the given attribute. This method will return without
555
     * waiting for the index to be filled, as that will be performed in
556
     * background. An optional {@link Observer} parameter is provided to be
557
     * notified ( {@link FeatureStoreNotification#INDEX_FILLING_SUCCESS} )
558
     * when the index has finished filling with data and is available to be
559
     * used.
560
     * 
561
     * @param featureType
562
     *            The FeatureType to which the indexed attribute belongs.
563
     * 
564
     * @param attributeName
565
     *            The name of the attributed to be indexed
566
     * 
567
     * @param indexName
568
     *            The index name
569
     * 
570
     * @param observer
571
     *            to notify to when the created index has finished filling
572
     *            with data and is available to be used. The observer will
573
     *            receive then a
574
     *            {@link FeatureStoreNotification#INDEX_FILLING_SUCCESS}
575
     *            notification, with the index object if it has finished
576
     *            successfully, or a
577
     *            {@link FeatureStoreNotification#INDEX_FILLING_ERROR}
578
     *            notification with the exception object if there has been
579
     *            any error in the process. Optional.
580
     * 
581
     * @return the resulting {@link FeatureIndex}
582
     * 
583
     * @see FeatureStoreNotification#INDEX_FILLING_STARTED
584
     * @see FeatureStoreNotification#INDEX_FILLING_SUCCESS
585
     * @see FeatureStoreNotification#INDEX_FILLING_CANCELLED
586
     * @see FeatureStoreNotification#INDEX_FILLING_ERROR
587
     * 
588
     * @throws FeatureIndexException
589
     *             if there is an error creating the index
590
     */
591
    public FeatureIndex createIndex(FeatureType featureType,
592
        String attributeName, String indexName, Observer observer)
593
        throws DataException;
594

    
595
    /**
596
     * Creates an index which will be applied to the features of the given type,
597
     * by using the data of the given attribute. This method will return without
598
     * waiting for the index to be filled, as that will be performed in
599
     * background. An optional {@link Observer} parameter is provided to be
600
     * notified ( {@link FeatureStoreNotification#INDEX_FILLING_SUCCESS} )
601
     * when the index has finished filling with data and is available to be
602
     * used.
603
     * 
604
     * @param indexTypeName
605
     *            the type of the index to be created. That name is
606
     *            related to one of the registered index providers
607
     * @param featureType
608
     *            The FeatureType to which the indexed attribute belongs.
609
     * 
610
     * @param attributeName
611
     *            The name of the attributed to be indexed
612
     * 
613
     * @param indexName
614
     *            The index name
615
     * 
616
     * @param observer
617
     *            to notify to when the created index has finished filling
618
     *            with data and is available to be used. The observer will
619
     *            receive then a
620
     *            {@link FeatureStoreNotification#INDEX_FILLING_SUCCESS}
621
     *            notification, with the index object if it has finished
622
     *            successfully, or a
623
     *            {@link FeatureStoreNotification#INDEX_FILLING_ERROR}
624
     *            notification with the exception object if there has been
625
     *            any error in the process. Optional.
626
     * 
627
     * @return the resulting {@link FeatureIndex}
628
     * 
629
     * @see FeatureStoreNotification#INDEX_FILLING_STARTED
630
     * @see FeatureStoreNotification#INDEX_FILLING_SUCCESS
631
     * @see FeatureStoreNotification#INDEX_FILLING_CANCELLED
632
     * @see FeatureStoreNotification#INDEX_FILLING_ERROR
633
     * 
634
     * @throws FeatureIndexException
635
     *             if there is an error creating the index
636
     */
637
    public FeatureIndex createIndex(String indexTypeName,
638
        FeatureType featureType, String attributeName, String indexName,
639
        Observer observer) throws DataException;
640

    
641
    /**
642
     * Returns a FeatureIndexes structure containing all available indexes in
643
     * the store.
644
     * 
645
     * @return
646
     */
647
    public FeatureIndexes getIndexes();
648

    
649
    /*
650
     * =============================================================
651
     * 
652
     * Selection related services
653
     */
654

    
655
    /**
656
     * Sets the selection to the passed {@link FeatureSet}
657
     * 
658
     * @param selection
659
     *            A {@link FeatureSet} with the requested selection
660
     */
661
    public void setSelection(FeatureSet selection) throws DataException;
662

    
663
    /**
664
     * Creates a {@link FeatureSelection}
665
     * 
666
     * @return
667
     *         a {@link FeatureSelection}
668
     * 
669
     * @throws DataException
670
     */
671
    public FeatureSelection createFeatureSelection() throws DataException;
672

    
673
    /**
674
     * Returns the current {@link FeatureSelection}.
675
     * Create a empty selection if not exits.
676
     * 
677
     * @return
678
     *         current {@link FeatureSelection}.
679
     * 
680
     * @throws DataException
681
     */
682
    public FeatureSelection getFeatureSelection() throws DataException;
683

    
684
    /*
685
     * =============================================================
686
     * 
687
     * Lock related services
688
     */
689

    
690
    /**
691
     * Indicates whether this store supports locks.
692
     * 
693
     * @return
694
     *         true if this store supports locks, false if not.
695
     */
696
    public boolean isLocksSupported();
697

    
698
    /**
699
     * Returns the set of locked features
700
     * 
701
     * @return
702
     *         set of locked features
703
     * 
704
     * @throws DataException
705
     */
706
    public FeatureLocks getLocks() throws DataException;
707

    
708
    /*
709
     * =============================================================
710
     * Transforms related services
711
     * =============================================================
712
     */
713

    
714
    /**
715
     * Returns this store transforms
716
     * 
717
     * @return
718
     *         this store transforms
719
     */
720
    public FeatureStoreTransforms getTransforms();
721

    
722
    /**
723
     * Returns a new {@link FeatureQuery} associated to this store.
724
     * 
725
     * @return
726
     *         a new {@link FeatureQuery} associated to this store.
727
     */
728
    public FeatureQuery createFeatureQuery();
729

    
730
    /**
731
     * Returns featue count of this store.
732
     * 
733
     * @return
734
     * @throws DataException
735
     */
736
    public long getFeatureCount() throws DataException;
737

    
738
    /**
739
     * Creates a vectorial cache that is used to save and retrieve data.
740
     * 
741
     * @param name
742
     *            the cache name.
743
     * @param parameters
744
     *            parameters to create the stores used to save data.
745
     * @throws DataException
746
     */
747
    public void createCache(String name, DynObject parameters)
748
        throws DataException;
749

    
750
    /**
751
     * @return the vectorial cache
752
     */
753
    public FeatureCache getCache();
754

    
755
    /**
756
     * Return if the provider knows the real envelope of a layer. If not,
757
     * the {@link FeatureStoreProvider#getEnvelope()} method doesn't return
758
     * the full envelope.
759
     * 
760
     * @return
761
     *         <true> if it knows the real envelope.
762
     */
763
    public boolean isKnownEnvelope();
764

    
765
    /**
766
     * Return if the maximum number of features provided by the
767
     * provider are limited.
768
     * 
769
     * @return
770
     *         <true> if there is a limit of features.
771
     */
772
    public boolean hasRetrievedFeaturesLimit();
773

    
774
    /**
775
     * If the {@link FeatureStoreProvider#hasRetrievedFeaturesLimit()} returns
776
     * true,
777
     * it returns the limit of features retrieved from the provider.
778
     * 
779
     * @return
780
     *         The limit of the retrieved features.
781
     */
782
    public int getRetrievedFeaturesLimit();
783
}