1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 /* 25 * Conversion parameters: 26 * inFile = GDrive.html 27 * outPack = gio 28 * outFile = DriveT 29 * strct = GDrive 30 * realStrct= 31 * ctorStrct= 32 * clss = DriveT 33 * interf = DriveIF 34 * class Code: No 35 * interface Code: No 36 * template for: 37 * - TStruct 38 * extend = 39 * implements: 40 * prefixes: 41 * - g_drive_ 42 * omit structs: 43 * omit prefixes: 44 * omit code: 45 * omit signals: 46 * imports: 47 * - glib.Str 48 * - glib.ErrorG 49 * - glib.GException 50 * - glib.ListG 51 * - gobject.Signals 52 * - gio.AsyncResultIF 53 * - gio.Cancellable 54 * - gio.Icon 55 * - gio.IconIF 56 * - gio.MountOperation 57 * structWrap: 58 * - GAsyncResult* -> AsyncResultIF 59 * - GCancellable* -> Cancellable 60 * - GIcon* -> IconIF 61 * - GList* -> ListG 62 * - GMountOperation* -> MountOperation 63 * module aliases: 64 * local aliases: 65 * overrides: 66 */ 67 68 module gio.DriveT; 69 70 public import gtkc.giotypes; 71 72 public import gtkc.gio; 73 public import glib.ConstructionException; 74 public import gobject.ObjectG; 75 76 public import gobject.Signals; 77 public import gtkc.gdktypes; 78 79 public import glib.Str; 80 public import glib.ErrorG; 81 public import glib.GException; 82 public import glib.ListG; 83 public import gobject.Signals; 84 public import gio.AsyncResultIF; 85 public import gio.Cancellable; 86 public import gio.Icon; 87 public import gio.IconIF; 88 public import gio.MountOperation; 89 90 91 92 93 /** 94 * GDrive - this represent a piece of hardware connected to the machine. 95 * It's generally only created for removable hardware or hardware with 96 * removable media. 97 * 98 * GDrive is a container class for GVolume objects that stem from 99 * the same piece of media. As such, GDrive abstracts a drive with 100 * (or without) removable media and provides operations for querying 101 * whether media is available, determining whether media change is 102 * automatically detected and ejecting the media. 103 * 104 * If the GDrive reports that media isn't automatically detected, one 105 * can poll for media; typically one should not do this periodically 106 * as a poll for media operation is potententially expensive and may 107 * spin up the drive creating noise. 108 * 109 * GDrive supports starting and stopping drives with authentication 110 * support for the former. This can be used to support a diverse set 111 * of use cases including connecting/disconnecting iSCSI devices, 112 * powering down external disk enclosures and starting/stopping 113 * multi-disk devices such as RAID devices. Note that the actual 114 * semantics and side-effects of starting/stopping a GDrive may vary 115 * according to implementation. To choose the correct verbs in e.g. a 116 * file manager, use g_drive_get_start_stop_type(). 117 * 118 * For porting from GnomeVFS note that there is no equivalent of 119 * GDrive in that API. 120 */ 121 public template DriveT(TStruct) 122 { 123 124 /** the main Gtk struct */ 125 protected GDrive* gDrive; 126 127 128 public GDrive* getDriveTStruct() 129 { 130 return cast(GDrive*)getStruct(); 131 } 132 133 134 /** 135 */ 136 int[string] connectedSignals; 137 138 void delegate(DriveIF)[] _onChangedListeners; 139 @property void delegate(DriveIF)[] onChangedListeners() 140 { 141 return _onChangedListeners; 142 } 143 /** 144 * Emitted when the drive's state has changed. 145 */ 146 void addOnChanged(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 147 { 148 if ( !("changed" in connectedSignals) ) 149 { 150 Signals.connectData( 151 getStruct(), 152 "changed", 153 cast(GCallback)&callBackChanged, 154 cast(void*)cast(DriveIF)this, 155 null, 156 connectFlags); 157 connectedSignals["changed"] = 1; 158 } 159 _onChangedListeners ~= dlg; 160 } 161 extern(C) static void callBackChanged(GDrive* driveStruct, DriveIF _driveIF) 162 { 163 foreach ( void delegate(DriveIF) dlg ; _driveIF.onChangedListeners ) 164 { 165 dlg(_driveIF); 166 } 167 } 168 169 void delegate(DriveIF)[] _onDisconnectedListeners; 170 @property void delegate(DriveIF)[] onDisconnectedListeners() 171 { 172 return _onDisconnectedListeners; 173 } 174 /** 175 * This signal is emitted when the GDrive have been 176 * disconnected. If the recipient is holding references to the 177 * object they should release them so the object can be 178 * finalized. 179 */ 180 void addOnDisconnected(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 181 { 182 if ( !("disconnected" in connectedSignals) ) 183 { 184 Signals.connectData( 185 getStruct(), 186 "disconnected", 187 cast(GCallback)&callBackDisconnected, 188 cast(void*)cast(DriveIF)this, 189 null, 190 connectFlags); 191 connectedSignals["disconnected"] = 1; 192 } 193 _onDisconnectedListeners ~= dlg; 194 } 195 extern(C) static void callBackDisconnected(GDrive* driveStruct, DriveIF _driveIF) 196 { 197 foreach ( void delegate(DriveIF) dlg ; _driveIF.onDisconnectedListeners ) 198 { 199 dlg(_driveIF); 200 } 201 } 202 203 void delegate(DriveIF)[] _onEjectButtonListeners; 204 @property void delegate(DriveIF)[] onEjectButtonListeners() 205 { 206 return _onEjectButtonListeners; 207 } 208 /** 209 * Emitted when the physical eject button (if any) of a drive has 210 * been pressed. 211 */ 212 void addOnEjectButton(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 213 { 214 if ( !("eject-button" in connectedSignals) ) 215 { 216 Signals.connectData( 217 getStruct(), 218 "eject-button", 219 cast(GCallback)&callBackEjectButton, 220 cast(void*)cast(DriveIF)this, 221 null, 222 connectFlags); 223 connectedSignals["eject-button"] = 1; 224 } 225 _onEjectButtonListeners ~= dlg; 226 } 227 extern(C) static void callBackEjectButton(GDrive* driveStruct, DriveIF _driveIF) 228 { 229 foreach ( void delegate(DriveIF) dlg ; _driveIF.onEjectButtonListeners ) 230 { 231 dlg(_driveIF); 232 } 233 } 234 235 void delegate(DriveIF)[] _onStopButtonListeners; 236 @property void delegate(DriveIF)[] onStopButtonListeners() 237 { 238 return _onStopButtonListeners; 239 } 240 /** 241 * Emitted when the physical stop button (if any) of a drive has 242 * been pressed. 243 * Since 2.22 244 */ 245 void addOnStopButton(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 246 { 247 if ( !("stop-button" in connectedSignals) ) 248 { 249 Signals.connectData( 250 getStruct(), 251 "stop-button", 252 cast(GCallback)&callBackStopButton, 253 cast(void*)cast(DriveIF)this, 254 null, 255 connectFlags); 256 connectedSignals["stop-button"] = 1; 257 } 258 _onStopButtonListeners ~= dlg; 259 } 260 extern(C) static void callBackStopButton(GDrive* driveStruct, DriveIF _driveIF) 261 { 262 foreach ( void delegate(DriveIF) dlg ; _driveIF.onStopButtonListeners ) 263 { 264 dlg(_driveIF); 265 } 266 } 267 268 269 /** 270 * Gets the name of drive. 271 * Returns: a string containing drive's name. The returned string should be freed when no longer needed. 272 */ 273 public string getName() 274 { 275 // char * g_drive_get_name (GDrive *drive); 276 return Str.toString(g_drive_get_name(getDriveTStruct())); 277 } 278 279 /** 280 * Gets the icon for drive. 281 * Returns: GIcon for the drive. Free the returned object with g_object_unref(). [transfer full] 282 */ 283 public IconIF getIcon() 284 { 285 // GIcon * g_drive_get_icon (GDrive *drive); 286 auto p = g_drive_get_icon(getDriveTStruct()); 287 288 if(p is null) 289 { 290 return null; 291 } 292 293 return ObjectG.getDObject!(Icon, IconIF)(cast(GIcon*) p); 294 } 295 296 /** 297 * Gets the icon for drive. 298 * Since 2.34 299 * Returns: symbolic GIcon for the drive. Free the returned object with g_object_unref(). [transfer full] 300 */ 301 public IconIF getSymbolicIcon() 302 { 303 // GIcon * g_drive_get_symbolic_icon (GDrive *drive); 304 auto p = g_drive_get_symbolic_icon(getDriveTStruct()); 305 306 if(p is null) 307 { 308 return null; 309 } 310 311 return ObjectG.getDObject!(Icon, IconIF)(cast(GIcon*) p); 312 } 313 314 /** 315 * Check if drive has any mountable volumes. 316 * Returns: TRUE if the drive contains volumes, FALSE otherwise. 317 */ 318 public int hasVolumes() 319 { 320 // gboolean g_drive_has_volumes (GDrive *drive); 321 return g_drive_has_volumes(getDriveTStruct()); 322 } 323 324 /** 325 * Get a list of mountable volumes for drive. 326 * The returned list should be freed with g_list_free(), after 327 * its elements have been unreffed with g_object_unref(). 328 * Returns: GList containing any GVolume objects on the given drive. [element-type GVolume][transfer full] 329 */ 330 public ListG getVolumes() 331 { 332 // GList * g_drive_get_volumes (GDrive *drive); 333 auto p = g_drive_get_volumes(getDriveTStruct()); 334 335 if(p is null) 336 { 337 return null; 338 } 339 340 return ObjectG.getDObject!(ListG)(cast(GList*) p); 341 } 342 343 /** 344 * Checks if a drive can be ejected. 345 * Returns: TRUE if the drive can be ejected, FALSE otherwise. 346 */ 347 public int canEject() 348 { 349 // gboolean g_drive_can_eject (GDrive *drive); 350 return g_drive_can_eject(getDriveTStruct()); 351 } 352 353 /** 354 * Gets a hint about how a drive can be started/stopped. 355 * Since 2.22 356 * Returns: A value from the GDriveStartStopType enumeration. 357 */ 358 public GDriveStartStopType getStartStopType() 359 { 360 // GDriveStartStopType g_drive_get_start_stop_type (GDrive *drive); 361 return g_drive_get_start_stop_type(getDriveTStruct()); 362 } 363 364 /** 365 * Checks if a drive can be started. 366 * Since 2.22 367 * Returns: TRUE if the drive can be started, FALSE otherwise. 368 */ 369 public int canStart() 370 { 371 // gboolean g_drive_can_start (GDrive *drive); 372 return g_drive_can_start(getDriveTStruct()); 373 } 374 375 /** 376 * Checks if a drive can be started degraded. 377 * Since 2.22 378 * Returns: TRUE if the drive can be started degraded, FALSE otherwise. 379 */ 380 public int canStartDegraded() 381 { 382 // gboolean g_drive_can_start_degraded (GDrive *drive); 383 return g_drive_can_start_degraded(getDriveTStruct()); 384 } 385 386 /** 387 * Checks if a drive can be stopped. 388 * Since 2.22 389 * Returns: TRUE if the drive can be stopped, FALSE otherwise. 390 */ 391 public int canStop() 392 { 393 // gboolean g_drive_can_stop (GDrive *drive); 394 return g_drive_can_stop(getDriveTStruct()); 395 } 396 397 /** 398 * Checks if a drive can be polled for media changes. 399 * Returns: TRUE if the drive can be polled for media changes, FALSE otherwise. 400 */ 401 public int canPollForMedia() 402 { 403 // gboolean g_drive_can_poll_for_media (GDrive *drive); 404 return g_drive_can_poll_for_media(getDriveTStruct()); 405 } 406 407 /** 408 * Asynchronously polls drive to see if media has been inserted or removed. 409 * When the operation is finished, callback will be called. 410 * You can then call g_drive_poll_for_media_finish() to obtain the 411 * result of the operation. 412 * Params: 413 * cancellable = optional GCancellable object, NULL to ignore. [allow-none] 414 * callback = a GAsyncReadyCallback, or NULL. [allow-none] 415 * userData = user data to pass to callback 416 */ 417 public void pollForMedia(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 418 { 419 // void g_drive_poll_for_media (GDrive *drive, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); 420 g_drive_poll_for_media(getDriveTStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 421 } 422 423 /** 424 * Finishes an operation started with g_drive_poll_for_media() on a drive. 425 * Params: 426 * result = a GAsyncResult. 427 * Returns: TRUE if the drive has been poll_for_mediaed successfully, FALSE otherwise. 428 * Throws: GException on failure. 429 */ 430 public int pollForMediaFinish(AsyncResultIF result) 431 { 432 // gboolean g_drive_poll_for_media_finish (GDrive *drive, GAsyncResult *result, GError **error); 433 GError* err = null; 434 435 auto p = g_drive_poll_for_media_finish(getDriveTStruct(), (result is null) ? null : result.getAsyncResultTStruct(), &err); 436 437 if (err !is null) 438 { 439 throw new GException( new ErrorG(err) ); 440 } 441 442 return p; 443 } 444 445 /** 446 * Checks if the drive has media. Note that the OS may not be polling 447 * the drive for media changes; see g_drive_is_media_check_automatic() 448 * for more details. 449 * Returns: TRUE if drive has media, FALSE otherwise. 450 */ 451 public int hasMedia() 452 { 453 // gboolean g_drive_has_media (GDrive *drive); 454 return g_drive_has_media(getDriveTStruct()); 455 } 456 457 /** 458 * Checks if drive is capabable of automatically detecting media changes. 459 * Returns: TRUE if the drive is capabable of automatically detecting media changes, FALSE otherwise. 460 */ 461 public int isMediaCheckAutomatic() 462 { 463 // gboolean g_drive_is_media_check_automatic (GDrive *drive); 464 return g_drive_is_media_check_automatic(getDriveTStruct()); 465 } 466 467 /** 468 * Checks if the drive supports removable media. 469 * Returns: TRUE if drive supports removable media, FALSE otherwise. 470 */ 471 public int isMediaRemovable() 472 { 473 // gboolean g_drive_is_media_removable (GDrive *drive); 474 return g_drive_is_media_removable(getDriveTStruct()); 475 } 476 477 /** 478 * Warning 479 * g_drive_eject has been deprecated since version 2.22 and should not be used in newly-written code. Use g_drive_eject_with_operation() instead. 480 * Asynchronously ejects a drive. 481 * When the operation is finished, callback will be called. 482 * You can then call g_drive_eject_finish() to obtain the 483 * result of the operation. 484 * Params: 485 * flags = flags affecting the unmount if required for eject 486 * cancellable = optional GCancellable object, NULL to ignore. [allow-none] 487 * callback = a GAsyncReadyCallback, or NULL. [allow-none] 488 * userData = user data to pass to callback 489 */ 490 public void eject(GMountUnmountFlags flags, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 491 { 492 // void g_drive_eject (GDrive *drive, GMountUnmountFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); 493 g_drive_eject(getDriveTStruct(), flags, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 494 } 495 496 /** 497 * Warning 498 * g_drive_eject_finish has been deprecated since version 2.22 and should not be used in newly-written code. Use g_drive_eject_with_operation_finish() instead. 499 * Finishes ejecting a drive. 500 * Params: 501 * result = a GAsyncResult. 502 * Returns: TRUE if the drive has been ejected successfully, FALSE otherwise. 503 * Throws: GException on failure. 504 */ 505 public int ejectFinish(AsyncResultIF result) 506 { 507 // gboolean g_drive_eject_finish (GDrive *drive, GAsyncResult *result, GError **error); 508 GError* err = null; 509 510 auto p = g_drive_eject_finish(getDriveTStruct(), (result is null) ? null : result.getAsyncResultTStruct(), &err); 511 512 if (err !is null) 513 { 514 throw new GException( new ErrorG(err) ); 515 } 516 517 return p; 518 } 519 520 /** 521 * Ejects a drive. This is an asynchronous operation, and is 522 * finished by calling g_drive_eject_with_operation_finish() with the drive 523 * and GAsyncResult data returned in the callback. 524 * Since 2.22 525 * Params: 526 * flags = flags affecting the unmount if required for eject 527 * mountOperation = a GMountOperation or NULL to avoid 528 * user interaction. [allow-none] 529 * cancellable = optional GCancellable object, NULL to ignore. [allow-none] 530 * callback = a GAsyncReadyCallback, or NULL. [allow-none] 531 * userData = user data passed to callback. 532 */ 533 public void ejectWithOperation(GMountUnmountFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 534 { 535 // void g_drive_eject_with_operation (GDrive *drive, GMountUnmountFlags flags, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); 536 g_drive_eject_with_operation(getDriveTStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 537 } 538 539 /** 540 * Finishes ejecting a drive. If any errors occurred during the operation, 541 * error will be set to contain the errors and FALSE will be returned. 542 * Since 2.22 543 * Params: 544 * result = a GAsyncResult. 545 * Returns: TRUE if the drive was successfully ejected. FALSE otherwise. 546 * Throws: GException on failure. 547 */ 548 public int ejectWithOperationFinish(AsyncResultIF result) 549 { 550 // gboolean g_drive_eject_with_operation_finish (GDrive *drive, GAsyncResult *result, GError **error); 551 GError* err = null; 552 553 auto p = g_drive_eject_with_operation_finish(getDriveTStruct(), (result is null) ? null : result.getAsyncResultTStruct(), &err); 554 555 if (err !is null) 556 { 557 throw new GException( new ErrorG(err) ); 558 } 559 560 return p; 561 } 562 563 /** 564 * Asynchronously starts a drive. 565 * When the operation is finished, callback will be called. 566 * You can then call g_drive_start_finish() to obtain the 567 * result of the operation. 568 * Since 2.22 569 * Params: 570 * flags = flags affecting the start operation. 571 * mountOperation = a GMountOperation or NULL to avoid 572 * user interaction. [allow-none] 573 * cancellable = optional GCancellable object, NULL to ignore. [allow-none] 574 * callback = a GAsyncReadyCallback, or NULL. [allow-none] 575 * userData = user data to pass to callback 576 */ 577 public void start(GDriveStartFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 578 { 579 // void g_drive_start (GDrive *drive, GDriveStartFlags flags, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); 580 g_drive_start(getDriveTStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 581 } 582 583 /** 584 * Finishes starting a drive. 585 * Since 2.22 586 * Params: 587 * result = a GAsyncResult. 588 * Returns: TRUE if the drive has been started successfully, FALSE otherwise. 589 * Throws: GException on failure. 590 */ 591 public int startFinish(AsyncResultIF result) 592 { 593 // gboolean g_drive_start_finish (GDrive *drive, GAsyncResult *result, GError **error); 594 GError* err = null; 595 596 auto p = g_drive_start_finish(getDriveTStruct(), (result is null) ? null : result.getAsyncResultTStruct(), &err); 597 598 if (err !is null) 599 { 600 throw new GException( new ErrorG(err) ); 601 } 602 603 return p; 604 } 605 606 /** 607 * Asynchronously stops a drive. 608 * When the operation is finished, callback will be called. 609 * You can then call g_drive_stop_finish() to obtain the 610 * result of the operation. 611 * Since 2.22 612 * Params: 613 * flags = flags affecting the unmount if required for stopping. 614 * mountOperation = a GMountOperation or NULL to avoid 615 * user interaction. [allow-none] 616 * cancellable = optional GCancellable object, NULL to ignore. [allow-none] 617 * callback = a GAsyncReadyCallback, or NULL. [allow-none] 618 * userData = user data to pass to callback 619 */ 620 public void stop(GMountUnmountFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 621 { 622 // void g_drive_stop (GDrive *drive, GMountUnmountFlags flags, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); 623 g_drive_stop(getDriveTStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 624 } 625 626 /** 627 * Finishes stopping a drive. 628 * Since 2.22 629 * Params: 630 * result = a GAsyncResult. 631 * Returns: TRUE if the drive has been stopped successfully, FALSE otherwise. 632 * Throws: GException on failure. 633 */ 634 public int stopFinish(AsyncResultIF result) 635 { 636 // gboolean g_drive_stop_finish (GDrive *drive, GAsyncResult *result, GError **error); 637 GError* err = null; 638 639 auto p = g_drive_stop_finish(getDriveTStruct(), (result is null) ? null : result.getAsyncResultTStruct(), &err); 640 641 if (err !is null) 642 { 643 throw new GException( new ErrorG(err) ); 644 } 645 646 return p; 647 } 648 649 /** 650 * Gets the kinds of identifiers that drive has. 651 * Use g_drive_get_identifier() to obtain the identifiers 652 * themselves. 653 * Returns: a NULL-terminated array of strings containing kinds of identifiers. Use g_strfreev() to free. [transfer full][array zero-terminated=1] 654 */ 655 public string[] enumerateIdentifiers() 656 { 657 // char ** g_drive_enumerate_identifiers (GDrive *drive); 658 return Str.toStringArray(g_drive_enumerate_identifiers(getDriveTStruct())); 659 } 660 661 /** 662 * Gets the identifier of the given kind for drive. 663 * Params: 664 * kind = the kind of identifier to return 665 * Returns: a newly allocated string containing the requested identfier, or NULL if the GDrive doesn't have this kind of identifier. 666 */ 667 public string getIdentifier(string kind) 668 { 669 // char * g_drive_get_identifier (GDrive *drive, const char *kind); 670 return Str.toString(g_drive_get_identifier(getDriveTStruct(), Str.toStringz(kind))); 671 } 672 673 /** 674 * Gets the sort key for drive, if any. 675 * Since 2.32 676 * Signal Details 677 * The "changed" signal 678 * void user_function (GDrive *drive, 679 * gpointer user_data) : Run Last 680 * Emitted when the drive's state has changed. 681 * Returns: Sorting key for drive or NULL if no such key is available. 682 */ 683 public string getSortKey() 684 { 685 // const gchar * g_drive_get_sort_key (GDrive *drive); 686 return Str.toString(g_drive_get_sort_key(getDriveTStruct())); 687 } 688 }