00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <string>
00029 #include <vector>
00030 #include <list>
00031
00032 #include "lo-mappers.h"
00033
00034 #include "oct-map.h"
00035 #include "defun-dld.h"
00036 #include "parse.h"
00037 #include "variables.h"
00038 #include "ov-colon.h"
00039 #include "unwind-prot.h"
00040 #include "ov-fcn-handle.h"
00041
00042
00043 enum bsxfun_builtin_op
00044 {
00045 bsxfun_builtin_plus = 0,
00046 bsxfun_builtin_minus,
00047 bsxfun_builtin_times,
00048 bsxfun_builtin_divide,
00049 bsxfun_builtin_max,
00050 bsxfun_builtin_min,
00051 bsxfun_builtin_eq,
00052 bsxfun_builtin_ne,
00053 bsxfun_builtin_lt,
00054 bsxfun_builtin_le,
00055 bsxfun_builtin_gt,
00056 bsxfun_builtin_ge,
00057 bsxfun_builtin_and,
00058 bsxfun_builtin_or,
00059 bsxfun_builtin_power,
00060 bsxfun_builtin_unknown,
00061 bsxfun_num_builtin_ops = bsxfun_builtin_unknown
00062 };
00063
00064 const char *bsxfun_builtin_names[] =
00065 {
00066 "plus",
00067 "minus",
00068 "times",
00069 "rdivide",
00070 "max",
00071 "min",
00072 "eq",
00073 "ne",
00074 "lt",
00075 "le",
00076 "gt",
00077 "ge",
00078 "and",
00079 "or",
00080 "power"
00081 };
00082
00083 static bsxfun_builtin_op
00084 bsxfun_builtin_lookup (const std::string& name)
00085 {
00086 for (int i = 0; i < bsxfun_num_builtin_ops; i++)
00087 if (name == bsxfun_builtin_names[i])
00088 return static_cast<bsxfun_builtin_op> (i);
00089 return bsxfun_builtin_unknown;
00090 }
00091
00092 typedef octave_value (*bsxfun_handler) (const octave_value&, const octave_value&);
00093
00094
00095 bsxfun_handler bsxfun_handler_table[bsxfun_num_builtin_ops][btyp_num_types];
00096
00097 template <class NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
00098 static octave_value
00099 bsxfun_forward_op (const octave_value& x, const octave_value& y)
00100 {
00101 NDA xa = octave_value_extract<NDA> (x);
00102 NDA ya = octave_value_extract<NDA> (y);
00103 return octave_value (bsxfun_op (xa, ya));
00104 }
00105
00106 template <class NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
00107 static octave_value
00108 bsxfun_forward_rel (const octave_value& x, const octave_value& y)
00109 {
00110 NDA xa = octave_value_extract<NDA> (x);
00111 NDA ya = octave_value_extract<NDA> (y);
00112 return octave_value (bsxfun_rel (xa, ya));
00113 }
00114
00115
00116 template <class NDA, class CNDA>
00117 static octave_value
00118 do_bsxfun_real_pow (const octave_value& x, const octave_value& y)
00119 {
00120 NDA xa = octave_value_extract<NDA> (x);
00121 NDA ya = octave_value_extract<NDA> (y);
00122 if (! ya.all_integers () && xa.any_element_is_negative ())
00123 return octave_value (bsxfun_pow (CNDA (xa), ya));
00124 else
00125 return octave_value (bsxfun_pow (xa, ya));
00126 }
00127
00128 static void maybe_fill_table (void)
00129 {
00130 static bool filled = false;
00131 if (filled)
00132 return;
00133
00134 #define REGISTER_OP_HANDLER(OP, BTYP, NDA, FUNOP) \
00135 bsxfun_handler_table[OP][BTYP] = bsxfun_forward_op<NDA, FUNOP>
00136 #define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL) \
00137 bsxfun_handler_table[REL][BTYP] = bsxfun_forward_rel<NDA, FUNREL>
00138 #define REGISTER_STD_HANDLERS(BTYP, NDA) \
00139 REGISTER_OP_HANDLER (bsxfun_builtin_plus, BTYP, NDA, bsxfun_add); \
00140 REGISTER_OP_HANDLER (bsxfun_builtin_minus, BTYP, NDA, bsxfun_sub); \
00141 REGISTER_OP_HANDLER (bsxfun_builtin_times, BTYP, NDA, bsxfun_mul); \
00142 REGISTER_OP_HANDLER (bsxfun_builtin_divide, BTYP, NDA, bsxfun_div); \
00143 REGISTER_OP_HANDLER (bsxfun_builtin_max, BTYP, NDA, bsxfun_max); \
00144 REGISTER_OP_HANDLER (bsxfun_builtin_min, BTYP, NDA, bsxfun_min); \
00145 REGISTER_REL_HANDLER (bsxfun_builtin_eq, BTYP, NDA, bsxfun_eq); \
00146 REGISTER_REL_HANDLER (bsxfun_builtin_ne, BTYP, NDA, bsxfun_ne); \
00147 REGISTER_REL_HANDLER (bsxfun_builtin_lt, BTYP, NDA, bsxfun_lt); \
00148 REGISTER_REL_HANDLER (bsxfun_builtin_le, BTYP, NDA, bsxfun_le); \
00149 REGISTER_REL_HANDLER (bsxfun_builtin_gt, BTYP, NDA, bsxfun_gt); \
00150 REGISTER_REL_HANDLER (bsxfun_builtin_ge, BTYP, NDA, bsxfun_ge)
00151
00152 REGISTER_STD_HANDLERS (btyp_double, NDArray);
00153 REGISTER_STD_HANDLERS (btyp_float, FloatNDArray);
00154 REGISTER_STD_HANDLERS (btyp_complex, ComplexNDArray);
00155 REGISTER_STD_HANDLERS (btyp_float_complex, FloatComplexNDArray);
00156 REGISTER_STD_HANDLERS (btyp_int8, int8NDArray);
00157 REGISTER_STD_HANDLERS (btyp_int16, int16NDArray);
00158 REGISTER_STD_HANDLERS (btyp_int32, int32NDArray);
00159 REGISTER_STD_HANDLERS (btyp_int64, int64NDArray);
00160 REGISTER_STD_HANDLERS (btyp_uint8, uint8NDArray);
00161 REGISTER_STD_HANDLERS (btyp_uint16, uint16NDArray);
00162 REGISTER_STD_HANDLERS (btyp_uint32, uint32NDArray);
00163 REGISTER_STD_HANDLERS (btyp_uint64, uint64NDArray);
00164
00165
00166 REGISTER_OP_HANDLER (bsxfun_builtin_and, btyp_bool, boolNDArray, bsxfun_and);
00167 REGISTER_OP_HANDLER (bsxfun_builtin_or, btyp_bool, boolNDArray, bsxfun_or);
00168
00169
00170 bsxfun_handler_table[bsxfun_builtin_power][btyp_double] =
00171 do_bsxfun_real_pow<NDArray, ComplexNDArray>;
00172 bsxfun_handler_table[bsxfun_builtin_power][btyp_float] =
00173 do_bsxfun_real_pow<FloatNDArray, FloatComplexNDArray>;
00174
00175 REGISTER_OP_HANDLER (bsxfun_builtin_power, btyp_complex, ComplexNDArray, bsxfun_pow);
00176 REGISTER_OP_HANDLER (bsxfun_builtin_power, btyp_float_complex, FloatComplexNDArray, bsxfun_pow);
00177
00178
00179 REGISTER_REL_HANDLER (bsxfun_builtin_eq, btyp_char, charNDArray, bsxfun_eq);
00180 REGISTER_REL_HANDLER (bsxfun_builtin_ne, btyp_char, charNDArray, bsxfun_ne);
00181 REGISTER_REL_HANDLER (bsxfun_builtin_lt, btyp_char, charNDArray, bsxfun_lt);
00182 REGISTER_REL_HANDLER (bsxfun_builtin_le, btyp_char, charNDArray, bsxfun_le);
00183 REGISTER_REL_HANDLER (bsxfun_builtin_gt, btyp_char, charNDArray, bsxfun_gt);
00184 REGISTER_REL_HANDLER (bsxfun_builtin_ge, btyp_char, charNDArray, bsxfun_ge);
00185
00186 filled = true;
00187 }
00188
00189 static octave_value
00190 maybe_optimized_builtin (const std::string& name,
00191 const octave_value& a, const octave_value& b)
00192 {
00193 octave_value retval;
00194
00195 maybe_fill_table ();
00196
00197 bsxfun_builtin_op op = bsxfun_builtin_lookup (name);
00198 if (op != bsxfun_builtin_unknown)
00199 {
00200 builtin_type_t btyp_a = a.builtin_type (), btyp_b = b.builtin_type ();
00201
00202
00203 if (btyp_a == btyp_float && btyp_b == btyp_double)
00204 btyp_b = btyp_float;
00205 else if (btyp_a == btyp_double && btyp_b == btyp_float)
00206 btyp_a = btyp_float;
00207 else if (btyp_a == btyp_float_complex && btyp_b == btyp_complex)
00208 btyp_b = btyp_float_complex;
00209 else if (btyp_a == btyp_complex && btyp_b == btyp_float_complex)
00210 btyp_a = btyp_float_complex;
00211
00212 if (btyp_a == btyp_b && btyp_a != btyp_unknown)
00213 {
00214 bsxfun_handler handler = bsxfun_handler_table[op][btyp_a];
00215 if (handler)
00216 retval = handler (a, b);
00217 }
00218 }
00219
00220 return retval;
00221 }
00222
00223 static bool
00224 maybe_update_column (octave_value& Ac, const octave_value& A,
00225 const dim_vector& dva, const dim_vector& dvc,
00226 octave_idx_type i, octave_value_list &idx)
00227 {
00228 octave_idx_type nd = dva.length ();
00229
00230 if (i == 0)
00231 {
00232 idx(0) = octave_value (':');
00233 for (octave_idx_type j = 1; j < nd; j++)
00234 {
00235 if (dva (j) == 1)
00236 idx (j) = octave_value (1);
00237 else
00238 idx (j) = octave_value ((i % dvc(j)) + 1);
00239
00240 i = i / dvc (j);
00241 }
00242
00243 Ac = A;
00244 Ac = Ac.single_subsref ("(", idx);
00245 return true;
00246 }
00247 else
00248 {
00249 bool is_changed = false;
00250 octave_idx_type k = i;
00251 octave_idx_type k1 = i - 1;
00252 for (octave_idx_type j = 1; j < nd; j++)
00253 {
00254 if (dva(j) != 1 && k % dvc (j) != k1 % dvc (j))
00255 {
00256 idx (j) = octave_value ((k % dvc(j)) + 1);
00257 is_changed = true;
00258 }
00259
00260 k = k / dvc (j);
00261 k1 = k1 / dvc (j);
00262 }
00263
00264 if (is_changed)
00265 {
00266 Ac = A;
00267 Ac = Ac.single_subsref ("(", idx);
00268 return true;
00269 }
00270 else
00271 return false;
00272 }
00273 }
00274
00275 #if 0
00276
00277 static void
00278 update_index (octave_value_list& idx, const dim_vector& dv, octave_idx_type i)
00279 {
00280 octave_idx_type nd = dv.length ();
00281
00282 if (i == 0)
00283 {
00284 for (octave_idx_type j = nd - 1; j > 0; j--)
00285 idx(j) = octave_value (static_cast<double>(1));
00286 idx(0) = octave_value (':');
00287 }
00288 else
00289 {
00290 for (octave_idx_type j = 1; j < nd; j++)
00291 {
00292 idx (j) = octave_value (i % dv (j) + 1);
00293 i = i / dv (j);
00294 }
00295 }
00296 }
00297 #endif
00298
00299 static void
00300 update_index (Array<int>& idx, const dim_vector& dv, octave_idx_type i)
00301 {
00302 octave_idx_type nd = dv.length ();
00303
00304 idx(0) = 0;
00305 for (octave_idx_type j = 1; j < nd; j++)
00306 {
00307 idx (j) = i % dv (j);
00308 i = i / dv (j);
00309 }
00310 }
00311
00312 DEFUN_DLD (bsxfun, args, ,
00313 "-*- texinfo -*-\n\
00314 @deftypefn {Loadable Function} {} bsxfun (@var{f}, @var{A}, @var{B})\n\
00315 The binary singleton expansion function applier performs broadcasting,\n\
00316 that is, applies a binary function @var{f} element-by-element to two\n\
00317 array arguments @var{A} and @var{B}, and expands as necessary\n\
00318 singleton dimensions in either input argument. @var{f} is a function\n\
00319 handle, inline function, or string containing the name of the function\n\
00320 to evaluate. The function @var{f} must be capable of accepting two\n\
00321 column-vector arguments of equal length, or one column vector argument\n\
00322 and a scalar.\n\
00323 \n\
00324 The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\
00325 singleton dimensions of the arrays will be expanded to the same\n\
00326 dimensionality as the other array.\n\
00327 @seealso{arrayfun, cellfun}\n\
00328 @end deftypefn")
00329 {
00330 int nargin = args.length ();
00331 octave_value_list retval;
00332
00333 if (nargin != 3)
00334 print_usage ();
00335 else
00336 {
00337 octave_value func = args(0);
00338
00339 if (func.is_string ())
00340 {
00341 std::string name = func.string_value ();
00342 func = symbol_table::find_function (name);
00343 if (func.is_undefined ())
00344 error ("bsxfun: invalid function name: %s", name.c_str ());
00345 }
00346 else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
00347 error ("bsxfun: F must be a string or function handle");
00348
00349 const octave_value A = args (1);
00350 const octave_value B = args (2);
00351
00352 if (func.is_builtin_function ()
00353 || (func.is_function_handle () && ! A.is_object () && ! B.is_object ()))
00354 {
00355
00356
00357
00358
00359 octave_function *fcn_val = func.function_value ();
00360 if (fcn_val)
00361 {
00362 octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
00363 if (tmp.is_defined ())
00364 retval(0) = tmp;
00365 }
00366 }
00367
00368 if (! error_state && retval.empty ())
00369 {
00370 dim_vector dva = A.dims ();
00371 octave_idx_type nda = dva.length ();
00372 dim_vector dvb = B.dims ();
00373 octave_idx_type ndb = dvb.length ();
00374 octave_idx_type nd = nda;
00375
00376 if (nda > ndb)
00377 dvb.resize (nda, 1);
00378 else if (nda < ndb)
00379 {
00380 dva.resize (ndb, 1);
00381 nd = ndb;
00382 }
00383
00384 for (octave_idx_type i = 0; i < nd; i++)
00385 if (dva (i) != dvb (i) && dva (i) != 1 && dvb (i) != 1)
00386 {
00387 error ("bsxfun: dimensions of A and B must match");
00388 break;
00389 }
00390
00391 if (!error_state)
00392 {
00393
00394 dim_vector dvc;
00395 dvc.resize (nd);
00396
00397 for (octave_idx_type i = 0; i < nd; i++)
00398 dvc (i) = (dva (i) < 1 ? dva (i) : (dvb (i) < 1 ? dvb (i) :
00399 (dva (i) > dvb (i) ? dva (i) : dvb (i))));
00400
00401 if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
00402 {
00403 octave_value_list inputs;
00404 inputs (0) = A;
00405 inputs (1) = B;
00406 retval = func.do_multi_index_op (1, inputs);
00407 }
00408 else if (dvc.numel () < 1)
00409 {
00410 octave_value_list inputs;
00411 inputs (0) = A.resize (dvc);
00412 inputs (1) = B.resize (dvc);
00413 retval = func.do_multi_index_op (1, inputs);
00414 }
00415 else
00416 {
00417 octave_idx_type ncount = 1;
00418 for (octave_idx_type i = 1; i < nd; i++)
00419 ncount *= dvc (i);
00420
00421 #define BSXDEF(T) \
00422 T result_ ## T; \
00423 bool have_ ## T = false;
00424
00425 BSXDEF(NDArray);
00426 BSXDEF(ComplexNDArray);
00427 BSXDEF(FloatNDArray);
00428 BSXDEF(FloatComplexNDArray);
00429 BSXDEF(boolNDArray);
00430 BSXDEF(int8NDArray);
00431 BSXDEF(int16NDArray);
00432 BSXDEF(int32NDArray);
00433 BSXDEF(int64NDArray);
00434 BSXDEF(uint8NDArray);
00435 BSXDEF(uint16NDArray);
00436 BSXDEF(uint32NDArray);
00437 BSXDEF(uint64NDArray);
00438
00439 octave_value Ac ;
00440 octave_value_list idxA;
00441 octave_value Bc;
00442 octave_value_list idxB;
00443 octave_value C;
00444 octave_value_list inputs;
00445 Array<int> ra_idx (dim_vector (dvc.length(), 1), 0);
00446
00447
00448 for (octave_idx_type i = 0; i < ncount; i++)
00449 {
00450 if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
00451 inputs (0) = Ac;
00452
00453 if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
00454 inputs (1) = Bc;
00455
00456 octave_value_list tmp = func.do_multi_index_op (1, inputs);
00457
00458 if (error_state)
00459 break;
00460
00461 #define BSXINIT(T, CLS, EXTRACTOR) \
00462 (result_type == CLS) \
00463 { \
00464 have_ ## T = true; \
00465 result_ ## T = \
00466 tmp (0). EXTRACTOR ## _array_value (); \
00467 result_ ## T .resize (dvc); \
00468 }
00469
00470 if (i == 0)
00471 {
00472 if (! tmp(0).is_sparse_type ())
00473 {
00474 std::string result_type = tmp(0).class_name ();
00475 if (result_type == "double")
00476 {
00477 if (tmp(0).is_real_type ())
00478 {
00479 have_NDArray = true;
00480 result_NDArray = tmp(0).array_value ();
00481 result_NDArray.resize (dvc);
00482 }
00483 else
00484 {
00485 have_ComplexNDArray = true;
00486 result_ComplexNDArray =
00487 tmp(0).complex_array_value ();
00488 result_ComplexNDArray.resize (dvc);
00489 }
00490 }
00491 else if (result_type == "single")
00492 {
00493 if (tmp(0).is_real_type ())
00494 {
00495 have_FloatNDArray = true;
00496 result_FloatNDArray = tmp(0).float_array_value ();
00497 result_FloatNDArray.resize (dvc);
00498 }
00499 else
00500 {
00501 have_ComplexNDArray = true;
00502 result_ComplexNDArray =
00503 tmp(0).complex_array_value ();
00504 result_ComplexNDArray.resize (dvc);
00505 }
00506 }
00507 else if BSXINIT(boolNDArray, "logical", bool)
00508 else if BSXINIT(int8NDArray, "int8", int8)
00509 else if BSXINIT(int16NDArray, "int16", int16)
00510 else if BSXINIT(int32NDArray, "int32", int32)
00511 else if BSXINIT(int64NDArray, "int64", int64)
00512 else if BSXINIT(uint8NDArray, "uint8", uint8)
00513 else if BSXINIT(uint16NDArray, "uint16", uint16)
00514 else if BSXINIT(uint32NDArray, "uint32", uint32)
00515 else if BSXINIT(uint64NDArray, "uint64", uint64)
00516 else
00517 {
00518 C = tmp (0);
00519 C = C.resize (dvc);
00520 }
00521 }
00522 }
00523 else
00524 {
00525 update_index (ra_idx, dvc, i);
00526
00527 if (have_FloatNDArray ||
00528 have_FloatComplexNDArray)
00529 {
00530 if (! tmp(0).is_float_type ())
00531 {
00532 if (have_FloatNDArray)
00533 {
00534 have_FloatNDArray = false;
00535 C = result_FloatNDArray;
00536 }
00537 else
00538 {
00539 have_FloatComplexNDArray = false;
00540 C = result_FloatComplexNDArray;
00541 }
00542 C = do_cat_op (C, tmp(0), ra_idx);
00543 }
00544 else if (tmp(0).is_double_type ())
00545 {
00546 if (tmp(0).is_complex_type () &&
00547 have_FloatNDArray)
00548 {
00549 result_ComplexNDArray =
00550 ComplexNDArray (result_FloatNDArray);
00551 result_ComplexNDArray.insert
00552 (tmp(0).complex_array_value(), ra_idx);
00553 have_FloatComplexNDArray = false;
00554 have_ComplexNDArray = true;
00555 }
00556 else
00557 {
00558 result_NDArray =
00559 NDArray (result_FloatNDArray);
00560 result_NDArray.insert
00561 (tmp(0).array_value(), ra_idx);
00562 have_FloatNDArray = false;
00563 have_NDArray = true;
00564 }
00565 }
00566 else if (tmp(0).is_real_type ())
00567 result_FloatNDArray.insert
00568 (tmp(0).float_array_value(), ra_idx);
00569 else
00570 {
00571 result_FloatComplexNDArray =
00572 FloatComplexNDArray (result_FloatNDArray);
00573 result_FloatComplexNDArray.insert
00574 (tmp(0).float_complex_array_value(), ra_idx);
00575 have_FloatNDArray = false;
00576 have_FloatComplexNDArray = true;
00577 }
00578 }
00579 else if (have_NDArray)
00580 {
00581 if (! tmp(0).is_float_type ())
00582 {
00583 have_NDArray = false;
00584 C = result_NDArray;
00585 C = do_cat_op (C, tmp(0), ra_idx);
00586 }
00587 else if (tmp(0).is_real_type ())
00588 result_NDArray.insert (tmp(0).array_value(),
00589 ra_idx);
00590 else
00591 {
00592 result_ComplexNDArray =
00593 ComplexNDArray (result_NDArray);
00594 result_ComplexNDArray.insert
00595 (tmp(0).complex_array_value(), ra_idx);
00596 have_NDArray = false;
00597 have_ComplexNDArray = true;
00598 }
00599 }
00600
00601 #define BSXLOOP(T, CLS, EXTRACTOR) \
00602 (have_ ## T) \
00603 { \
00604 if (tmp (0).class_name () != CLS) \
00605 { \
00606 have_ ## T = false; \
00607 C = result_ ## T; \
00608 C = do_cat_op (C, tmp (0), ra_idx); \
00609 } \
00610 else \
00611 result_ ## T .insert \
00612 (tmp(0). EXTRACTOR ## _array_value (), \
00613 ra_idx); \
00614 }
00615
00616 else if BSXLOOP(ComplexNDArray, "double", complex)
00617 else if BSXLOOP(boolNDArray, "logical", bool)
00618 else if BSXLOOP(int8NDArray, "int8", int8)
00619 else if BSXLOOP(int16NDArray, "int16", int16)
00620 else if BSXLOOP(int32NDArray, "int32", int32)
00621 else if BSXLOOP(int64NDArray, "int64", int64)
00622 else if BSXLOOP(uint8NDArray, "uint8", uint8)
00623 else if BSXLOOP(uint16NDArray, "uint16", uint16)
00624 else if BSXLOOP(uint32NDArray, "uint32", uint32)
00625 else if BSXLOOP(uint64NDArray, "uint64", uint64)
00626 else
00627 C = do_cat_op (C, tmp(0), ra_idx);
00628 }
00629 }
00630
00631 #define BSXEND(T) \
00632 (have_ ## T) \
00633 retval (0) = result_ ## T;
00634
00635 if BSXEND(NDArray)
00636 else if BSXEND(ComplexNDArray)
00637 else if BSXEND(FloatNDArray)
00638 else if BSXEND(FloatComplexNDArray)
00639 else if BSXEND(boolNDArray)
00640 else if BSXEND(int8NDArray)
00641 else if BSXEND(int16NDArray)
00642 else if BSXEND(int32NDArray)
00643 else if BSXEND(int64NDArray)
00644 else if BSXEND(uint8NDArray)
00645 else if BSXEND(uint16NDArray)
00646 else if BSXEND(uint32NDArray)
00647 else if BSXEND(uint64NDArray)
00648 else
00649 retval(0) = C;
00650 }
00651 }
00652 }
00653 }
00654
00655 return retval;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813