1 #include <petsc/private/drawimpl.h> /*I "petscdraw.h" I*/ 2 3 #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20 4 PetscClassId PETSC_DRAWAXIS_CLASSID = 0; 5 6 /*@ 7 PetscDrawAxisCreate - Generate the axis data structure. 8 9 Collective 10 11 Input Parameter: 12 . draw - `PetscDraw` object where axis to be made 13 14 Output Parameter: 15 . axis - the axis datastructure 16 17 Note: 18 The MPI communicator that owns the underlying draw object owns the `PetscDrawAxis` object, but calls to set `PetscDrawAxis` options are 19 ignored by all processes except the first MPI rank in the communicator 20 21 Level: advanced 22 23 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawLGGetAxis()`, `PetscDrawSPGetAxis()`, 24 `PetscDrawHGGetAxis()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisDestroy()`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetHoldLimits()`, 25 `PetscDrawAxisDraw()` 26 @*/ 27 PetscErrorCode PetscDrawAxisCreate(PetscDraw draw, PetscDrawAxis *axis) 28 { 29 PetscDrawAxis ad; 30 31 PetscFunctionBegin; 32 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 33 PetscAssertPointer(axis, 2); 34 35 PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL)); 36 PetscCall(PetscObjectReference((PetscObject)draw)); 37 ad->win = draw; 38 ad->xticks = PetscADefTicks; 39 ad->yticks = PetscADefTicks; 40 ad->xlabelstr = PetscADefLabel; 41 ad->ylabelstr = PetscADefLabel; 42 ad->ac = PETSC_DRAW_BLACK; 43 ad->tc = PETSC_DRAW_BLACK; 44 ad->cc = PETSC_DRAW_BLACK; 45 ad->xlabel = NULL; 46 ad->ylabel = NULL; 47 ad->toplabel = NULL; 48 *axis = ad; 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 52 /*@ 53 PetscDrawAxisDestroy - Frees the space used by an axis structure. 54 55 Collective 56 57 Input Parameter: 58 . axis - the axis context 59 60 Level: advanced 61 62 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis` 63 @*/ 64 PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis) 65 { 66 PetscFunctionBegin; 67 if (!*axis) PetscFunctionReturn(PETSC_SUCCESS); 68 PetscValidHeaderSpecific(*axis, PETSC_DRAWAXIS_CLASSID, 1); 69 if (--((PetscObject)*axis)->refct > 0) { 70 *axis = NULL; 71 PetscFunctionReturn(PETSC_SUCCESS); 72 } 73 74 PetscCall(PetscFree((*axis)->toplabel)); 75 PetscCall(PetscFree((*axis)->xlabel)); 76 PetscCall(PetscFree((*axis)->ylabel)); 77 PetscCall(PetscDrawDestroy(&(*axis)->win)); 78 PetscCall(PetscHeaderDestroy(axis)); 79 PetscFunctionReturn(PETSC_SUCCESS); 80 } 81 82 /*@ 83 PetscDrawAxisSetColors - Sets the colors to be used for the axis, 84 tickmarks, and text. 85 86 Logically Collective 87 88 Input Parameters: 89 + axis - the axis 90 . ac - the color of the axis lines 91 . tc - the color of the tick marks 92 - cc - the color of the text strings 93 94 Level: advanced 95 96 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()` 97 @*/ 98 PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc) 99 { 100 PetscFunctionBegin; 101 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 102 PetscValidLogicalCollectiveInt(axis, ac, 2); 103 PetscValidLogicalCollectiveInt(axis, tc, 3); 104 PetscValidLogicalCollectiveInt(axis, cc, 4); 105 axis->ac = ac; 106 axis->tc = tc; 107 axis->cc = cc; 108 PetscFunctionReturn(PETSC_SUCCESS); 109 } 110 111 /*@ 112 PetscDrawAxisSetLabels - Sets the x and y axis labels. 113 114 Logically Collective 115 116 Input Parameters: 117 + axis - the axis 118 . top - the label at the top of the image 119 . xlabel - the x axis label 120 - ylabel - the y axis label 121 122 Level: advanced 123 124 Notes: 125 Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()` 126 127 There should be no newlines in the arguments 128 129 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()` 130 @*/ 131 PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[]) 132 { 133 PetscFunctionBegin; 134 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 135 PetscCall(PetscFree(axis->xlabel)); 136 PetscCall(PetscFree(axis->ylabel)); 137 PetscCall(PetscFree(axis->toplabel)); 138 PetscCall(PetscStrallocpy(xlabel, &axis->xlabel)); 139 PetscCall(PetscStrallocpy(ylabel, &axis->ylabel)); 140 PetscCall(PetscStrallocpy(top, &axis->toplabel)); 141 PetscFunctionReturn(PETSC_SUCCESS); 142 } 143 144 /*@ 145 PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis 146 147 Logically Collective 148 149 Input Parameters: 150 + axis - the axis 151 . xmin - the lower x limit 152 . xmax - the upper x limit 153 . ymin - the lower y limit 154 - ymax - the upper y limit 155 156 Options Database Key: 157 . -drawaxis_hold - hold the initial set of axis limits for future plotting 158 159 Level: advanced 160 161 .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 162 @*/ 163 PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax) 164 { 165 PetscFunctionBegin; 166 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 167 if (axis->hold) PetscFunctionReturn(PETSC_SUCCESS); 168 axis->xlow = xmin; 169 axis->xhigh = xmax; 170 axis->ylow = ymin; 171 axis->yhigh = ymax; 172 PetscCall(PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold)); 173 PetscFunctionReturn(PETSC_SUCCESS); 174 } 175 176 /*@ 177 PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis 178 179 Not Collective 180 181 Input Parameters: 182 + axis - the axis 183 . xmin - the lower x limit 184 . xmax - the upper x limit 185 . ymin - the lower y limit 186 - ymax - the upper y limit 187 188 Level: advanced 189 190 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 191 @*/ 192 PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax) 193 { 194 PetscFunctionBegin; 195 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 196 if (xmin) *xmin = axis->xlow; 197 if (xmax) *xmax = axis->xhigh; 198 if (ymin) *ymin = axis->ylow; 199 if (ymax) *ymax = axis->yhigh; 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 /*@ 204 PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called 205 again 206 207 Logically Collective 208 209 Input Parameters: 210 + axis - the axis 211 - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed 212 213 Level: advanced 214 215 Note: 216 Once this has been called with `PETSC_TRUE` the limits will not change if you call 217 `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE` 218 219 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 220 @*/ 221 PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold) 222 { 223 PetscFunctionBegin; 224 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 225 PetscValidLogicalCollectiveBool(axis, hold, 2); 226 axis->hold = hold; 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 /*@ 231 PetscDrawAxisDraw - draws an axis. 232 233 Collective 234 235 Input Parameter: 236 . axis - `PetscDrawAxis` structure 237 238 Level: advanced 239 240 Note: 241 This draws the actual axis. The limits etc have already been set. 242 By picking special routines for the ticks and labels, special 243 effects may be generated. These routines are part of the Axis 244 structure (axis). 245 246 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 247 @*/ 248 PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis) 249 { 250 int i, ntick, numx, numy, ac, tc, cc; 251 PetscMPIInt rank; 252 size_t len, ytlen = 0; 253 PetscReal coors[4] = {0, 0, 0, 0}, tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th; 254 PetscReal xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0; 255 char *p; 256 PetscDraw draw; 257 PetscBool isnull; 258 259 PetscFunctionBegin; 260 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 261 PetscCall(PetscDrawIsNull(axis->win, &isnull)); 262 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 263 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank)); 264 265 draw = axis->win; 266 267 ac = axis->ac; 268 tc = axis->tc; 269 cc = axis->cc; 270 if (axis->xlow == axis->xhigh) { 271 axis->xlow -= .5; 272 axis->xhigh += .5; 273 } 274 if (axis->ylow == axis->yhigh) { 275 axis->ylow -= .5; 276 axis->yhigh += .5; 277 } 278 279 PetscDrawCollectiveBegin(draw); 280 if (rank) goto finally; 281 282 /* get canonical string size */ 283 PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1)); 284 PetscCall(PetscDrawStringGetSize(draw, &tw, &th)); 285 /* lower spacing */ 286 if (axis->xlabelstr) dyl += 1.5 * th; 287 if (axis->xlabel) dyl += 1.5 * th; 288 /* left spacing */ 289 if (axis->ylabelstr) dxl += 7.5 * tw; 290 if (axis->ylabel) dxl += 2.0 * tw; 291 /* right and top spacing */ 292 if (axis->xlabelstr) dxr = 2.5 * tw; 293 if (axis->ylabelstr) dyr = 0.5 * th; 294 if (axis->toplabel) dyr = 1.5 * th; 295 /* extra spacing */ 296 dxl += 0.7 * tw; 297 dxr += 0.5 * tw; 298 dyl += 0.2 * th; 299 dyr += 0.2 * th; 300 /* determine coordinates */ 301 xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1); 302 xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1); 303 yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1); 304 yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1); 305 PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr)); 306 PetscCall(PetscDrawStringGetSize(draw, &tw, &th)); 307 308 /* PetscDraw the axis lines */ 309 PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac)); 310 PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac)); 311 PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac)); 312 PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac)); 313 314 /* PetscDraw the top label */ 315 if (axis->toplabel) { 316 PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th; 317 318 PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel)); 319 } 320 321 /* PetscDraw the X ticks and labels */ 322 if (axis->xticks) { 323 numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw); 324 numx = PetscClipInterval(numx, 2, 6); 325 PetscCall((*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS)); 326 /* PetscDraw in tick marks */ 327 for (i = 0; i < ntick; i++) { 328 PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc)); 329 PetscCall(PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc)); 330 } 331 /* label ticks */ 332 if (axis->xlabelstr) { 333 for (i = 0; i < ntick; i++) { 334 if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i]; 335 else if (i > 0) sep = tickloc[i] - tickloc[i - 1]; 336 else sep = 0.0; 337 PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p)); 338 PetscCall(PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p)); 339 } 340 } 341 } 342 if (axis->xlabel) { 343 PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th; 344 345 if (axis->xlabelstr) y -= 1.5 * th; 346 PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel)); 347 } 348 349 /* PetscDraw the Y ticks and labels */ 350 if (axis->yticks) { 351 numy = (int)(.50 * (axis->yhigh - axis->ylow) / th); 352 numy = PetscClipInterval(numy, 2, 6); 353 PetscCall((*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS)); 354 /* PetscDraw in tick marks */ 355 for (i = 0; i < ntick; i++) { 356 PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc)); 357 PetscCall(PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc)); 358 } 359 /* label ticks */ 360 if (axis->ylabelstr) { 361 for (i = 0; i < ntick; i++) { 362 if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i]; 363 else if (i > 0) sep = tickloc[i] - tickloc[i - 1]; 364 else sep = 0.0; 365 PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p)); 366 PetscCall(PetscStrlen(p, &len)); 367 ytlen = PetscMax(ytlen, len); 368 PetscCall(PetscDrawString(draw, axis->xlow - ((PetscReal)len + .5) * tw, tickloc[i] - .5 * th, cc, p)); 369 } 370 } 371 } 372 if (axis->ylabel) { 373 PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2; 374 375 if (axis->ylabelstr) x -= ((PetscReal)ytlen + .5) * tw; 376 PetscCall(PetscStrlen(axis->ylabel, &len)); 377 PetscCall(PetscDrawStringVertical(draw, x, y + ((PetscReal)len) * th / 2, cc, axis->ylabel)); 378 } 379 380 PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3])); 381 finally: 382 PetscDrawCollectiveEnd(draw); 383 PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw))); 384 PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3])); 385 PetscFunctionReturn(PETSC_SUCCESS); 386 } 387 388 /* 389 Removes all zeros but one from .0000 390 */ 391 PetscErrorCode PetscStripe0(char *buf) 392 { 393 size_t n; 394 PetscBool flg; 395 char *str = NULL; 396 397 PetscFunctionBegin; 398 PetscCall(PetscStrlen(buf, &n)); 399 PetscCall(PetscStrendswith(buf, "e00", &flg)); 400 if (flg) buf[n - 3] = 0; 401 PetscCall(PetscStrstr(buf, "e0", &str)); 402 if (str) { 403 buf[n - 2] = buf[n - 1]; 404 buf[n - 1] = 0; 405 } 406 PetscCall(PetscStrstr(buf, "e-0", &str)); 407 if (str) { 408 buf[n - 2] = buf[n - 1]; 409 buf[n - 1] = 0; 410 } 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 /* 415 Removes all zeros but one from .0000 416 */ 417 PetscErrorCode PetscStripAllZeros(char *buf) 418 { 419 size_t i, n; 420 421 PetscFunctionBegin; 422 PetscCall(PetscStrlen(buf, &n)); 423 if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS); 424 for (i = 1; i < n; i++) { 425 if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS); 426 } 427 buf[0] = '0'; 428 buf[1] = 0; 429 PetscFunctionReturn(PETSC_SUCCESS); 430 } 431 432 /* 433 Removes trailing zeros 434 */ 435 #if (PETSC_SIZEOF_SIZE_T == 8) 436 #define MAX_SIZE_T PETSC_INT64_MAX 437 #else 438 #define MAX_SIZE_T INT_MAX 439 #endif 440 PetscErrorCode PetscStripTrailingZeros(char *buf) 441 { 442 char *found = NULL; 443 size_t i, n, m = MAX_SIZE_T; 444 445 PetscFunctionBegin; 446 /* if there is an e in string DO NOT strip trailing zeros */ 447 PetscCall(PetscStrchr(buf, 'e', &found)); 448 if (found) PetscFunctionReturn(PETSC_SUCCESS); 449 450 PetscCall(PetscStrlen(buf, &n)); 451 /* locate decimal point */ 452 for (i = 0; i < n; i++) { 453 if (buf[i] == '.') { 454 m = i; 455 break; 456 } 457 } 458 /* if not decimal point then no zeros to remove */ 459 if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS); 460 /* start at right end of string removing 0s */ 461 for (i = n - 1; i > m; i++) { 462 if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS); 463 buf[i] = 0; 464 } 465 PetscFunctionReturn(PETSC_SUCCESS); 466 } 467 468 /* 469 Removes leading 0 from 0.22 or -0.22 470 */ 471 PetscErrorCode PetscStripInitialZero(char *buf) 472 { 473 size_t i, n; 474 475 PetscFunctionBegin; 476 PetscCall(PetscStrlen(buf, &n)); 477 if (buf[0] == '0') { 478 for (i = 0; i < n; i++) buf[i] = buf[i + 1]; 479 } else if (buf[0] == '-' && buf[1] == '0') { 480 for (i = 1; i < n; i++) buf[i] = buf[i + 1]; 481 } 482 PetscFunctionReturn(PETSC_SUCCESS); 483 } 484 485 /* 486 Removes the extraneous zeros in numbers like 1.10000e6 487 */ 488 PetscErrorCode PetscStripZeros(char *buf) 489 { 490 size_t i, j, n; 491 492 PetscFunctionBegin; 493 PetscCall(PetscStrlen(buf, &n)); 494 if (n < 5) PetscFunctionReturn(PETSC_SUCCESS); 495 for (i = 1; i < n - 1; i++) { 496 if (buf[i] == 'e' && buf[i - 1] == '0') { 497 for (j = i; j < n + 1; j++) buf[j - 1] = buf[j]; 498 PetscCall(PetscStripZeros(buf)); 499 PetscFunctionReturn(PETSC_SUCCESS); 500 } 501 } 502 PetscFunctionReturn(PETSC_SUCCESS); 503 } 504 505 /* 506 Removes the plus in something like 1.1e+2 or 1.1e+02 507 */ 508 PetscErrorCode PetscStripZerosPlus(char *buf) 509 { 510 size_t i, j, n; 511 512 PetscFunctionBegin; 513 PetscCall(PetscStrlen(buf, &n)); 514 if (n < 5) PetscFunctionReturn(PETSC_SUCCESS); 515 for (i = 1; i < n - 2; i++) { 516 if (buf[i] == '+') { 517 if (buf[i + 1] == '0') { 518 for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1]; 519 PetscFunctionReturn(PETSC_SUCCESS); 520 } else { 521 for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j]; 522 PetscFunctionReturn(PETSC_SUCCESS); 523 } 524 } else if (buf[i] == '-') { 525 if (buf[i + 1] == '0') { 526 for (j = i + 1; j < n; j++) buf[j] = buf[j + 1]; 527 PetscFunctionReturn(PETSC_SUCCESS); 528 } 529 } 530 } 531 PetscFunctionReturn(PETSC_SUCCESS); 532 } 533