00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 namespace Gecode { namespace Int { namespace Linear {
00039
00040
00041
00042
00043
00044 forceinline
00045 ScaleBoolArray::ScaleBoolArray(void) {}
00046 forceinline
00047 ScaleBoolArray::ScaleBoolArray(Space& home, int n) {
00048 if (n > 0) {
00049 _fst = home.alloc<ScaleBool>(n);
00050 _lst = _fst+n;
00051 } else {
00052 _fst = _lst = NULL;
00053 }
00054 }
00055 forceinline void
00056 ScaleBoolArray::subscribe(Space& home, Propagator& p) {
00057 for (ScaleBool* f = _fst; f < _lst; f++)
00058 f->x.subscribe(home,p,PC_BOOL_VAL);
00059 }
00060 forceinline void
00061 ScaleBoolArray::cancel(Space& home, Propagator& p) {
00062 for (ScaleBool* f = _fst; f < _lst; f++)
00063 f->x.cancel(home,p,PC_BOOL_VAL);
00064 }
00065 forceinline void
00066 ScaleBoolArray::reschedule(Space& home, Propagator& p) {
00067 for (ScaleBool* f = _fst; f < _lst; f++)
00068 f->x.reschedule(home,p,PC_BOOL_VAL);
00069 }
00070 forceinline void
00071 ScaleBoolArray::update(Space& home, bool share, ScaleBoolArray& sba) {
00072 int n = static_cast<int>(sba._lst - sba._fst);
00073 if (n > 0) {
00074 _fst = home.alloc<ScaleBool>(n);
00075 _lst = _fst+n;
00076 for (int i=n; i--; ) {
00077 _fst[i].a = sba._fst[i].a;
00078 _fst[i].x.update(home,share,sba._fst[i].x);
00079 }
00080 } else {
00081 _fst = _lst = NULL;
00082 }
00083 }
00084 forceinline ScaleBool*
00085 ScaleBoolArray::fst(void) const {
00086 return _fst;
00087 }
00088 forceinline ScaleBool*
00089 ScaleBoolArray::lst(void) const {
00090 return _lst;
00091 }
00092 forceinline void
00093 ScaleBoolArray::fst(ScaleBool* f) {
00094 _fst = f;
00095 }
00096 forceinline void
00097 ScaleBoolArray::lst(ScaleBool* l) {
00098 _lst = l;
00099 }
00100 forceinline bool
00101 ScaleBoolArray::empty(void) const {
00102 return _fst == _lst;
00103 }
00104 forceinline int
00105 ScaleBoolArray::size(void) const {
00106 return static_cast<int>(_lst - _fst);
00107 }
00108 forceinline bool
00109 ScaleBoolArray::ScaleDec::operator ()(const ScaleBool& x,
00110 const ScaleBool& y) {
00111 return x.a > y.a;
00112 }
00113
00114 inline void
00115 ScaleBoolArray::sort(void) {
00116 ScaleDec scale_dec;
00117 Support::quicksort<ScaleBool,ScaleDec>(fst(), size(), scale_dec);
00118 }
00119
00120
00121
00122
00123
00124
00125 forceinline
00126 EmptyScaleBoolArray::EmptyScaleBoolArray(void) {}
00127 forceinline
00128 EmptyScaleBoolArray::EmptyScaleBoolArray(Space&, int) {}
00129 forceinline void
00130 EmptyScaleBoolArray::subscribe(Space&, Propagator&) {}
00131 forceinline void
00132 EmptyScaleBoolArray::cancel(Space&, Propagator&) {}
00133 forceinline void
00134 EmptyScaleBoolArray::reschedule(Space&, Propagator&) {}
00135 forceinline void
00136 EmptyScaleBoolArray::update(Space&, bool, EmptyScaleBoolArray&) {}
00137 forceinline ScaleBool*
00138 EmptyScaleBoolArray::fst(void) const { return NULL; }
00139 forceinline ScaleBool*
00140 EmptyScaleBoolArray::lst(void) const { return NULL; }
00141 forceinline void
00142 EmptyScaleBoolArray::fst(ScaleBool*) {}
00143 forceinline void
00144 EmptyScaleBoolArray::lst(ScaleBool*) {}
00145 forceinline bool
00146 EmptyScaleBoolArray::empty(void) const { return true; }
00147 forceinline int
00148 EmptyScaleBoolArray::size(void) const { return 0; }
00149 forceinline void
00150 EmptyScaleBoolArray::sort(void) {}
00151
00152
00153
00154
00155
00156
00157
00158 template<class SBAP, class SBAN, class VX, PropCond pcx>
00159 forceinline
00160 LinBoolScale<SBAP,SBAN,VX,pcx>::LinBoolScale(Home home,
00161 SBAP& p0, SBAN& n0,
00162 VX x0, int c0)
00163 : Propagator(home), p(p0), n(n0), x(x0), c(c0) {
00164 x.subscribe(home,*this,pcx);
00165 p.subscribe(home,*this);
00166 n.subscribe(home,*this);
00167 }
00168
00169 template<class SBAP, class SBAN, class VX, PropCond pcx>
00170 PropCost
00171 LinBoolScale<SBAP,SBAN,VX,pcx>::cost(const Space&,
00172 const ModEventDelta&) const {
00173 return PropCost::linear(PropCost::LO, p.size() + n.size());
00174 }
00175
00176 template<class SBAP, class SBAN, class VX, PropCond pcx>
00177 void
00178 LinBoolScale<SBAP,SBAN,VX,pcx>::reschedule(Space& home) {
00179 x.reschedule(home,*this,pcx);
00180 p.reschedule(home,*this);
00181 n.reschedule(home,*this);
00182 }
00183
00184 template<class SBAP, class SBAN, class VX, PropCond pcx>
00185 forceinline size_t
00186 LinBoolScale<SBAP,SBAN,VX,pcx>::dispose(Space& home) {
00187 x.cancel(home,*this,pcx);
00188 p.cancel(home,*this);
00189 n.cancel(home,*this);
00190 (void) Propagator::dispose(home);
00191 return sizeof(*this);
00192 }
00193
00194 template<class SBAP, class SBAN, class VX, PropCond pcx>
00195 forceinline
00196 LinBoolScale<SBAP,SBAN,VX,pcx>::LinBoolScale(Space& home, bool share,
00197 Propagator& pr,
00198 SBAP& p0, SBAN& n0,
00199 VX x0, int c0)
00200 : Propagator(home,share,pr), c(c0) {
00201 x.update(home,share,x0);
00202 p.update(home,share,p0);
00203 n.update(home,share,n0);
00204 }
00205
00206
00207
00208
00209
00210
00211 template<class SBAP, class SBAN, class VX>
00212 forceinline
00213 EqBoolScale<SBAP,SBAN,VX>::EqBoolScale(Home home,
00214 SBAP& p, SBAN& n,
00215 VX x, int c)
00216 : LinBoolScale<SBAP,SBAN,VX,PC_INT_BND>(home,p,n,x,c) {}
00217
00218 template<class SBAP, class SBAN, class VX>
00219 forceinline
00220 EqBoolScale<SBAP,SBAN,VX>::EqBoolScale(Space& home, bool share,
00221 Propagator& pr,
00222 SBAP& p, SBAN& n,
00223 VX x, int c)
00224 : LinBoolScale<SBAP,SBAN,VX,PC_INT_BND>(home,share,pr,p,n,x,c) {}
00225
00226 template<class SBAP, class SBAN, class VX>
00227 Actor*
00228 EqBoolScale<SBAP,SBAN,VX>::copy(Space& home, bool share) {
00229 if (p.empty()) {
00230 EmptyScaleBoolArray ep;
00231 if (x.assigned()) {
00232 ZeroIntView z;
00233 return new (home) EqBoolScale<EmptyScaleBoolArray,SBAN,ZeroIntView>
00234 (home,share,*this,ep,n,z,c+x.val());
00235 } else {
00236 return new (home) EqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00237 (home,share,*this,ep,n,x,c);
00238 }
00239 } else if (n.empty()) {
00240 EmptyScaleBoolArray en;
00241 if (x.assigned()) {
00242 ZeroIntView z;
00243 return new (home) EqBoolScale<SBAP,EmptyScaleBoolArray,ZeroIntView>
00244 (home,share,*this,p,en,z,c+x.val());
00245 } else {
00246 return new (home) EqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00247 (home,share,*this,p,en,x,c);
00248 }
00249 } else {
00250 return new (home) EqBoolScale<SBAP,SBAN,VX>(home,share,*this,p,n,x,c);
00251 }
00252 }
00253
00254 template<class SBAP, class SBAN, class VX>
00255 ExecStatus
00256 EqBoolScale<SBAP,SBAN,VX>::propagate(Space& home, const ModEventDelta& med) {
00257 int sl_p = 0;
00258 int su_n = 0;
00259 if (BoolView::me(med) == ME_BOOL_VAL) {
00260
00261 {
00262
00263 ScaleBool* f = p.fst();
00264 ScaleBool* l = p.lst();
00265 while ((f < l) && f->x.none()) {
00266 su_n += f->a; f++;
00267 }
00268
00269 ScaleBool* t = f;
00270 while (f < l) {
00271 if (f->x.one()) {
00272 c -= f->a;
00273 } else if (f->x.none()) {
00274 su_n += f->a; *t = *f; t++;
00275 }
00276 f++;
00277 }
00278 p.lst(t);
00279 }
00280
00281 {
00282
00283 ScaleBool* f = n.fst();
00284 ScaleBool* l = n.lst();
00285 while ((f < l) && f->x.none()) {
00286 sl_p += f->a; f++;
00287 }
00288
00289 ScaleBool* t = f;
00290 while (f < l) {
00291 if (f->x.one()) {
00292 c += f->a;
00293 } else if (f->x.none()) {
00294 sl_p += f->a; *t = *f; t++;
00295 }
00296 f++;
00297 }
00298 n.lst(t);
00299 }
00300 } else {
00301 for (ScaleBool* f=p.fst(); f<p.lst(); f++)
00302 su_n += f->a;
00303 for (ScaleBool* f=n.fst(); f<n.lst(); f++)
00304 sl_p += f->a;
00305 }
00306
00307 if (p.empty() && n.empty()) {
00308 GECODE_ME_CHECK(x.eq(home,-c));
00309 return home.ES_SUBSUMED(*this);
00310 }
00311
00312 sl_p += x.max() + c;
00313 su_n -= x.min() + c;
00314
00315 const int MOD_SL = 1 << 0;
00316 const int MOD_SU = 1 << 1;
00317
00318 int mod = MOD_SL | MOD_SU;
00319
00320 do {
00321 if ((mod & MOD_SL) != 0) {
00322 mod -= MOD_SL;
00323
00324 {
00325 ScaleBool* f=p.fst();
00326 for (ScaleBool* l=p.lst(); (f < l) && (f->a > sl_p); f++) {
00327 GECODE_ME_CHECK(f->x.zero_none(home));
00328 su_n -= f->a;
00329 }
00330 if (f > p.fst()) {
00331 p.fst(f); mod |= MOD_SU;
00332 }
00333 }
00334
00335 {
00336 ScaleBool* f=n.fst();
00337 for (ScaleBool* l=n.lst(); (f < l) && (f->a > sl_p); f++) {
00338 GECODE_ME_CHECK(f->x.one_none(home)); c += f->a;
00339 su_n -= f->a;
00340 }
00341 if (f > n.fst()) {
00342 n.fst(f); mod |= MOD_SU;
00343 }
00344 }
00345
00346 {
00347 const int x_min = x.min();
00348 ModEvent me = x.gq(home,x.max() - sl_p);
00349 if (me_failed(me))
00350 return ES_FAILED;
00351 if (me_modified(me)) {
00352 su_n -= x.min() - x_min;
00353 mod |= MOD_SU;
00354 }
00355 }
00356 }
00357 if ((mod & MOD_SU) != 0) {
00358 mod -= MOD_SU;
00359
00360 {
00361 ScaleBool* f=p.fst();
00362 for (ScaleBool* l=p.lst(); (f < l) && (f->a > su_n); f++) {
00363 GECODE_ME_CHECK(f->x.one_none(home)); c -= f->a;
00364 sl_p -= f->a;
00365 }
00366 if (f > p.fst()) {
00367 p.fst(f); mod |= MOD_SL;;
00368 }
00369 }
00370
00371 {
00372 ScaleBool* f=n.fst();
00373 for (ScaleBool* l=n.lst(); (f < l) && (f->a > su_n); f++) {
00374 GECODE_ME_CHECK(f->x.zero_none(home));
00375 sl_p -= f->a;
00376 }
00377 if (f > n.fst()) {
00378 n.fst(f); mod |= MOD_SL;;
00379 }
00380 }
00381
00382 {
00383 const int x_max = x.max();
00384 ModEvent me = x.lq(home,x.min() + su_n);
00385 if (me_failed(me))
00386 return ES_FAILED;
00387 if (me_modified(me)) {
00388 sl_p += x.max() - x_max;
00389 mod |= MOD_SL;;
00390 }
00391 }
00392 }
00393 } while (mod != 0);
00394
00395 return (sl_p == -su_n) ? home.ES_SUBSUMED(*this) : ES_FIX;
00396 }
00397
00398
00399
00400 template<class SBAP, class SBAN, class VX>
00401 ExecStatus
00402 EqBoolScale<SBAP,SBAN,VX>::post(Home home,
00403 SBAP& p, SBAN& n, VX x, int c) {
00404 p.sort(); n.sort();
00405 if (p.empty()) {
00406 EmptyScaleBoolArray ep;
00407 (void) new (home) EqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00408 (home,ep,n,x,c);
00409 } else if (n.empty()) {
00410 EmptyScaleBoolArray en;
00411 (void) new (home) EqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00412 (home,p,en,x,c);
00413 } else {
00414 (void) new (home) EqBoolScale<SBAP,SBAN,VX>
00415 (home,p,n,x,c);
00416 }
00417 return ES_OK;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426 template<class SBAP, class SBAN, class VX>
00427 forceinline
00428 LqBoolScale<SBAP,SBAN,VX>::LqBoolScale(Home home,
00429 SBAP& p, SBAN& n,
00430 VX x, int c)
00431 : LinBoolScale<SBAP,SBAN,VX,PC_INT_BND>(home,p,n,x,c) {}
00432
00433 template<class SBAP, class SBAN, class VX>
00434 forceinline
00435 LqBoolScale<SBAP,SBAN,VX>::LqBoolScale(Space& home, bool share,
00436 Propagator& pr,
00437 SBAP& p, SBAN& n,
00438 VX x, int c)
00439 : LinBoolScale<SBAP,SBAN,VX,PC_INT_BND>(home,share,pr,p,n,x,c) {}
00440
00441 template<class SBAP, class SBAN, class VX>
00442 Actor*
00443 LqBoolScale<SBAP,SBAN,VX>::copy(Space& home, bool share) {
00444 if (p.empty()) {
00445 EmptyScaleBoolArray ep;
00446 if (x.assigned()) {
00447 ZeroIntView z;
00448 return new (home) LqBoolScale<EmptyScaleBoolArray,SBAN,ZeroIntView>
00449 (home,share,*this,ep,n,z,c+x.val());
00450 } else {
00451 return new (home) LqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00452 (home,share,*this,ep,n,x,c);
00453 }
00454 } else if (n.empty()) {
00455 EmptyScaleBoolArray en;
00456 if (x.assigned()) {
00457 ZeroIntView z;
00458 return new (home) LqBoolScale<SBAP,EmptyScaleBoolArray,ZeroIntView>
00459 (home,share,*this,p,en,z,c+x.val());
00460 } else {
00461 return new (home) LqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00462 (home,share,*this,p,en,x,c);
00463 }
00464 } else {
00465 return new (home) LqBoolScale<SBAP,SBAN,VX>(home,share,*this,p,n,x,c);
00466 }
00467 }
00468
00469 template<class SBAP, class SBAN, class VX>
00470 ExecStatus
00471 LqBoolScale<SBAP,SBAN,VX>::propagate(Space& home, const ModEventDelta& med) {
00472 int sl = 0;
00473 if (BoolView::me(med) == ME_BOOL_VAL) {
00474
00475 {
00476
00477 ScaleBool* f = p.fst();
00478 ScaleBool* l = p.lst();
00479 while ((f < l) && f->x.none())
00480 f++;
00481
00482 ScaleBool* t = f;
00483 while (f < l) {
00484 if (f->x.one()) {
00485 c -= f->a;
00486 } else if (f->x.none()) {
00487 *t = *f; t++;
00488 }
00489 f++;
00490 }
00491 p.lst(t);
00492 }
00493
00494 {
00495
00496 ScaleBool* f = n.fst();
00497 ScaleBool* l = n.lst();
00498 while ((f < l) && f->x.none()) {
00499 sl += f->a; f++;
00500 }
00501
00502 ScaleBool* t = f;
00503 while (f < l) {
00504 if (f->x.one()) {
00505 c += f->a;
00506 } else if (f->x.none()) {
00507 sl += f->a; *t = *f; t++;
00508 }
00509 f++;
00510 }
00511 n.lst(t);
00512 }
00513 } else {
00514 for (ScaleBool* f=n.fst(); f<n.lst(); f++)
00515 sl += f->a;
00516 }
00517
00518 sl += x.max() + c;
00519
00520
00521 {
00522 ScaleBool* f=p.fst();
00523 for (ScaleBool* l=p.lst(); (f < l) && (f->a > sl); f++)
00524 GECODE_ME_CHECK(f->x.zero_none(home));
00525 p.fst(f);
00526 }
00527
00528 {
00529 ScaleBool* f=n.fst();
00530 for (ScaleBool* l=n.lst(); (f < l) && (f->a > sl); f++) {
00531 c += f->a;
00532 GECODE_ME_CHECK(f->x.one_none(home));
00533 }
00534 n.fst(f);
00535 }
00536 ExecStatus es = ES_FIX;
00537
00538 {
00539 const int slx = x.max() - sl;
00540 ModEvent me = x.gq(home,slx);
00541 if (me_failed(me))
00542 return ES_FAILED;
00543 if (me_modified(me) && (slx != x.min()))
00544 es = ES_NOFIX;
00545 }
00546
00547 if (p.empty() && n.empty())
00548 return home.ES_SUBSUMED(*this);
00549
00550 return es;
00551 }
00552
00553
00554
00555 template<class SBAP, class SBAN, class VX>
00556 ExecStatus
00557 LqBoolScale<SBAP,SBAN,VX>::post(Home home,
00558 SBAP& p, SBAN& n, VX x, int c) {
00559 p.sort(); n.sort();
00560 if (p.empty()) {
00561 EmptyScaleBoolArray ep;
00562 (void) new (home) LqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00563 (home,ep,n,x,c);
00564 } else if (n.empty()) {
00565 EmptyScaleBoolArray en;
00566 (void) new (home) LqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00567 (home,p,en,x,c);
00568 } else {
00569 (void) new (home) LqBoolScale<SBAP,SBAN,VX>
00570 (home,p,n,x,c);
00571 }
00572 return ES_OK;
00573 }
00574
00575
00576
00577
00578
00579
00580 template<class SBAP, class SBAN, class VX>
00581 forceinline
00582 NqBoolScale<SBAP,SBAN,VX>::NqBoolScale(Home home,
00583 SBAP& p, SBAN& n,
00584 VX x, int c)
00585 : LinBoolScale<SBAP,SBAN,VX,PC_INT_VAL>(home,p,n,x,c) {}
00586
00587 template<class SBAP, class SBAN, class VX>
00588 forceinline
00589 NqBoolScale<SBAP,SBAN,VX>::NqBoolScale(Space& home, bool share,
00590 Propagator& pr,
00591 SBAP& p, SBAN& n,
00592 VX x, int c)
00593 : LinBoolScale<SBAP,SBAN,VX,PC_INT_VAL>(home,share,pr,p,n,x,c) {}
00594
00595 template<class SBAP, class SBAN, class VX>
00596 Actor*
00597 NqBoolScale<SBAP,SBAN,VX>::copy(Space& home, bool share) {
00598 if (p.empty()) {
00599 EmptyScaleBoolArray ep;
00600 if (x.assigned()) {
00601 ZeroIntView z;
00602 return new (home) NqBoolScale<EmptyScaleBoolArray,SBAN,ZeroIntView>
00603 (home,share,*this,ep,n,z,c+x.val());
00604 } else {
00605 return new (home) NqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00606 (home,share,*this,ep,n,x,c);
00607 }
00608 } else if (n.empty()) {
00609 EmptyScaleBoolArray en;
00610 if (x.assigned()) {
00611 ZeroIntView z;
00612 return new (home) NqBoolScale<SBAP,EmptyScaleBoolArray,ZeroIntView>
00613 (home,share,*this,p,en,z,c+x.val());
00614 } else {
00615 return new (home) NqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00616 (home,share,*this,p,en,x,c);
00617 }
00618 } else {
00619 return new (home) NqBoolScale<SBAP,SBAN,VX>(home,share,*this,p,n,x,c);
00620 }
00621 }
00622
00623 template<class SBAP, class SBAN, class VX>
00624 ExecStatus
00625 NqBoolScale<SBAP,SBAN,VX>::propagate(Space& home, const ModEventDelta& med) {
00626 if (BoolView::me(med) == ME_BOOL_VAL) {
00627
00628 {
00629 ScaleBool* f = p.fst();
00630 ScaleBool* t = f;
00631 ScaleBool* l = p.lst();
00632 while (f < l) {
00633 if (f->x.one()) {
00634 c -= f->a; *f = *(t++);
00635 } else if (f->x.zero()) {
00636 *f = *(t++);
00637 }
00638 f++;
00639 }
00640 p.fst(t);
00641 }
00642
00643 {
00644 ScaleBool* f = n.fst();
00645 ScaleBool* t = f;
00646 ScaleBool* l = n.lst();
00647 while (f < l) {
00648 if (f->x.one()) {
00649 c += f->a; *f = *(t++);
00650 } else if (f->x.zero()) {
00651 *f = *(t++);
00652 }
00653 f++;
00654 }
00655 n.fst(t);
00656 }
00657 }
00658
00659 if (p.empty() && n.empty()) {
00660 GECODE_ME_CHECK(x.nq(home,-c));
00661 return home.ES_SUBSUMED(*this);
00662 }
00663
00664 if (x.assigned()) {
00665 int r = x.val()+c;
00666 if (p.empty() && (n.size() == 1)) {
00667 if (r == -n.fst()->a) {
00668 GECODE_ME_CHECK(n.fst()->x.zero_none(home));
00669 } else if (r == 0) {
00670 GECODE_ME_CHECK(n.fst()->x.one_none(home));
00671 }
00672 return home.ES_SUBSUMED(*this);
00673 }
00674 if ((p.size() == 1) && n.empty()) {
00675 if (r == p.fst()->a) {
00676 GECODE_ME_CHECK(p.fst()->x.zero_none(home));
00677 } else if (r == 0) {
00678 GECODE_ME_CHECK(p.fst()->x.one_none(home));
00679 }
00680 return home.ES_SUBSUMED(*this);
00681 }
00682 }
00683 return ES_FIX;
00684 }
00685
00686
00687
00688 template<class SBAP, class SBAN, class VX>
00689 ExecStatus
00690 NqBoolScale<SBAP,SBAN,VX>::post(Home home,
00691 SBAP& p, SBAN& n, VX x, int c) {
00692 if (p.empty()) {
00693 EmptyScaleBoolArray ep;
00694 (void) new (home) NqBoolScale<EmptyScaleBoolArray,SBAN,VX>
00695 (home,ep,n,x,c);
00696 } else if (n.empty()) {
00697 EmptyScaleBoolArray en;
00698 (void) new (home) NqBoolScale<SBAP,EmptyScaleBoolArray,VX>
00699 (home,p,en,x,c);
00700 } else {
00701 (void) new (home) NqBoolScale<SBAP,SBAN,VX>
00702 (home,p,n,x,c);
00703 }
00704 return ES_OK;
00705 }
00706
00707 }}}
00708
00709
00710