Scippy

    SCIP

    Solving Constraint Integer Programs

    scip_datatree.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file scip_datatree.c
    26 * @ingroup OTHER_CFILES
    27 * @brief public methods for managing data trees
    28 * @author Mohammed Ghannam
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/scip_datatree.h"
    34#include "scip/scip_mem.h"
    35#include "scip/scip_message.h"
    36#include "scip/pub_message.h"
    37#include "scip/set.h"
    38#include "scip/datatree.h"
    39#include "scip/pub_datatree.h"
    40#include "scip/struct_mem.h"
    41#include "scip/struct_scip.h"
    43
    44
    45/** creates a new SCIP_DATATREE */
    47 SCIP* scip, /**< SCIP data structure */
    48 SCIP_DATATREE** datatree, /**< buffer to store created data tree */
    49 int capacity /**< desired capacity, or -1 for default */
    50 )
    51{
    52 assert(scip != NULL);
    53 assert(datatree != NULL);
    54
    55 SCIP_CALL( SCIPdatatreeCreate(datatree, scip->mem->setmem, capacity) );
    56
    57 return SCIP_OKAY;
    58}
    59
    60/** creates a new SCIP_DATATREE and inserts it into a SCIP_DATATREE object */
    62 SCIP* scip, /**< SCIP data structure */
    63 SCIP_DATATREE* datatree, /**< data tree where to insert new tree */
    64 SCIP_DATATREE** newtree, /**< buffer to store pointer to created data tree */
    65 const char* name, /**< name of entry to add */
    66 int capacity /**< capacity of new tree, or -1 for default */
    67 )
    68{
    69 assert(scip != NULL);
    70 assert(scip->mem != NULL);
    71 assert(newtree != NULL);
    72 assert(name != NULL);
    73
    74 SCIP_CALL( SCIPdatatreeCreate(newtree, scip->mem->setmem, capacity) );
    75
    76 SCIP_CALL( SCIPdatatreeInsertTree(datatree, scip->set, scip->mem->setmem, name, *newtree) );
    77
    78 return SCIP_OKAY;
    79}
    80
    81/** inserts a bool value into a SCIP_DATATREE object */
    83 SCIP* scip, /**< SCIP data structure */
    84 SCIP_DATATREE* datatree, /**< data tree */
    85 const char* name, /**< name of entry to add */
    86 SCIP_Bool value /**< value to add */
    87 )
    88{
    89 assert(scip != NULL);
    90 assert(scip->mem != NULL);
    91 assert(name != NULL);
    92
    93 SCIP_CALL( SCIPdatatreeInsertBool(datatree, scip->set, scip->mem->setmem, name, value) );
    94
    95 return SCIP_OKAY;
    96}
    97
    98/** inserts an int value into a SCIP_DATATREE object
    99 *
    100 * The value will be stored as SCIP_Longint.
    101 */
    103 SCIP* scip, /**< SCIP data structure */
    104 SCIP_DATATREE* datatree, /**< data tree */
    105 const char* name, /**< name of entry to add */
    106 int value /**< value to add */
    107 )
    108{
    109 assert(scip != NULL);
    110 assert(scip->mem != NULL);
    111 assert(name != NULL);
    112
    113 SCIP_CALL( SCIPdatatreeInsertLong(datatree, scip->set, scip->mem->setmem, name, (SCIP_Longint)value) );
    114
    115 return SCIP_OKAY;
    116}
    117
    118/** inserts a long value into a SCIP_DATATREE object */
    120 SCIP* scip, /**< SCIP data structure */
    121 SCIP_DATATREE* datatree, /**< data tree */
    122 const char* name, /**< name of entry to add */
    123 SCIP_Longint value /**< value to add */
    124 )
    125{
    126 assert(scip != NULL);
    127 assert(scip->mem != NULL);
    128 assert(name != NULL);
    129
    130 SCIP_CALL( SCIPdatatreeInsertLong(datatree, scip->set, scip->mem->setmem, name, value) );
    131
    132 return SCIP_OKAY;
    133}
    134
    135/** inserts a SCIP_Real value into a SCIP_DATATREE object */
    137 SCIP* scip, /**< SCIP data structure */
    138 SCIP_DATATREE* datatree, /**< data tree */
    139 const char* name, /**< name of entry to add */
    140 SCIP_Real value /**< value to add */
    141 )
    142{
    143 assert(scip != NULL);
    144 assert(scip->mem != NULL);
    145 assert(name != NULL);
    146
    147 SCIP_CALL( SCIPdatatreeInsertReal(datatree, scip->set, scip->mem->setmem, name, value) );
    148
    149 return SCIP_OKAY;
    150}
    151
    152/** inserts a string value into a SCIP_DATATREE object
    153 *
    154 * The string value will be copied.
    155 */
    157 SCIP* scip, /**< SCIP data structure */
    158 SCIP_DATATREE* datatree, /**< data tree */
    159 const char* name, /**< name of entry to add */
    160 const char* value /**< value to add */
    161 )
    162{
    163 assert(scip != NULL);
    164 assert(scip->mem != NULL);
    165 assert(name != NULL);
    166 assert(value != NULL);
    167
    168 SCIP_CALL( SCIPdatatreeInsertString(datatree, scip->set, scip->mem->setmem, name, value) );
    169
    170 return SCIP_OKAY;
    171}
    172
    173/** inserts a SCIP_Bool array into a SCIP_DATATREE object */
    175 SCIP* scip, /**< SCIP data structure */
    176 SCIP_DATATREE* datatree, /**< data tree */
    177 const char* name, /**< name of entry to add */
    178 const SCIP_Bool* values, /**< values of entry */
    179 int nvalues /**< number of values */
    180 )
    181{
    182 assert(scip != NULL);
    183 assert(scip->mem != NULL);
    184 assert(name != NULL);
    185 assert(values != NULL);
    186 assert(nvalues >= 0);
    187
    188 SCIP_CALL( SCIPdatatreeInsertBoolArray(datatree, scip->set, scip->mem->setmem, name, values, nvalues) );
    189
    190 return SCIP_OKAY;
    191}
    192
    193/** inserts an int array into a SCIP_DATATREE object
    194 *
    195 * The value will be stored as array of SCIP_Longint.
    196 */
    198 SCIP* scip, /**< SCIP data structure */
    199 SCIP_DATATREE* datatree, /**< data tree */
    200 const char* name, /**< name of entry to add */
    201 const int* values, /**< values of entry */
    202 int nvalues /**< number of values */
    203 )
    204{
    205 SCIP_Longint* longvalues = NULL;
    206
    207 assert(scip != NULL);
    208 assert(scip->mem != NULL);
    209 assert(name != NULL);
    210 assert(values != NULL);
    211 assert(nvalues >= 0);
    212
    213 /* turn int array into long array */
    214 SCIP_CALL( SCIPallocBufferArray(scip, &longvalues, nvalues) );
    215 for( int i = 0; i < nvalues; i++ )
    216 longvalues[i] = (SCIP_Longint)values[i];
    217
    218 SCIP_CALL( SCIPdatatreeInsertLongArray(datatree, scip->set, scip->mem->setmem, name, longvalues, nvalues) );
    219
    220 SCIPfreeBufferArray(scip, &longvalues);
    221
    222 return SCIP_OKAY;
    223}
    224
    225/** inserts a SCIP_Real array into a SCIP_DATATREE object */
    227 SCIP* scip, /**< SCIP data structure */
    228 SCIP_DATATREE* datatree, /**< data tree */
    229 const char* name, /**< name of entry to add */
    230 const SCIP_Real* values, /**< values of entry */
    231 int nvalues /**< number of values */
    232 )
    233{
    234 assert(scip != NULL);
    235 assert(scip->mem != NULL);
    236 assert(name != NULL);
    237 assert(values != NULL);
    238 assert(nvalues >= 0);
    239
    240 SCIP_CALL( SCIPdatatreeInsertRealArray(datatree, scip->set, scip->mem->setmem, name, values, nvalues) );
    241
    242 return SCIP_OKAY;
    243}
    244
    245/** inserts a SCIP_Longint array into a SCIP_DATATREE object */
    247 SCIP* scip, /**< SCIP data structure */
    248 SCIP_DATATREE* datatree, /**< data tree */
    249 const char* name, /**< name of entry to add */
    250 const SCIP_Longint* values, /**< values of entry */
    251 int nvalues /**< number of values */
    252 )
    253{
    254 assert(scip != NULL);
    255 assert(scip->mem != NULL);
    256 assert(name != NULL);
    257 assert(values != NULL);
    258 assert(nvalues >= 0);
    259
    260 SCIP_CALL( SCIPdatatreeInsertLongArray(datatree, scip->set, scip->mem->setmem, name, values, nvalues) );
    261
    262 return SCIP_OKAY;
    263}
    264
    265/** inserts a string array into a SCIP_DATATREE object */
    267 SCIP* scip, /**< SCIP data structure */
    268 SCIP_DATATREE* datatree, /**< data tree */
    269 const char* name, /**< name of entry to add */
    270 const char* const* values, /**< values of entry */
    271 int nvalues /**< number of values */
    272 )
    273{
    274 assert(scip != NULL);
    275 assert(scip->mem != NULL);
    276 assert(name != NULL);
    277 assert(values != NULL);
    278 assert(nvalues >= 0);
    279
    280 SCIP_CALL( SCIPdatatreeInsertStringArray(datatree, scip->set, scip->mem->setmem, name, values, nvalues) );
    281
    282 return SCIP_OKAY;
    283}
    284
    285/** inserts a data tree value into a SCIP_DATATREE object
    286 *
    287 * The data tree assumes ownership of value.
    288 */
    290 SCIP* scip, /**< SCIP data structure */
    291 SCIP_DATATREE* datatree, /**< data tree */
    292 const char* name, /**< name of entry to add */
    293 SCIP_DATATREE* value /**< value to add */
    294 )
    295{
    296 assert(scip != NULL);
    297 assert(scip->mem != NULL);
    298 assert(name != NULL);
    299 assert(value != NULL);
    300
    301 SCIP_CALL( SCIPdatatreeInsertTree( datatree, scip->set, scip->mem->setmem, name, value ) );
    302
    303 return SCIP_OKAY;
    304}
    305
    306/** frees a SCIP_DATATREE object */
    308 SCIP* scip, /**< SCIP data structure */
    309 SCIP_DATATREE** datatree /**< pointer to data tree to free */
    310 )
    311{
    312 assert(scip != NULL);
    313 assert(scip->mem != NULL);
    314
    315 SCIPdatatreeFree(datatree, scip->mem->setmem);
    316}
    317
    318/** writes a SCIP_DATATREE object as JSON to a file */
    320 SCIP* scip, /**< SCIP data structure */
    321 FILE* file, /**< file to write to, or NULL for stdout */
    322 SCIP_DATATREE* datatree /**< data tree to write */
    323 )
    324{
    325 assert(scip != NULL);
    326
    327 SCIP_CALL( SCIPdatatreeWriteJson(datatree, scip->messagehdlr, file) );
    328
    329 return SCIP_OKAY;
    330}
    331
    332/** prints a generic table from a data tree */
    334 SCIP* scip, /**< SCIP data structure */
    335 SCIP_DATATREE* datatree, /**< data tree */
    336 FILE* file, /**< output file */
    337 const char* sectionname, /**< section name to process, e.g., "plugins" */
    338 const char* tablename /**< table name to process, e.g., "heuristics" */
    339 )
    340{
    341 SCIP_DATATREE* section;
    342 SCIP_DATATREE* firstsectionitem = NULL;
    343
    344 assert(scip != NULL);
    345 assert(datatree != NULL);
    346
    347 /* Get the section name */
    348 SCIP_CALL( SCIPdatatreeGetTree( datatree, sectionname, &section ) );
    349
    350 /* Print the table header */
    351 SCIPinfoMessage(scip, file, "%-19s:", tablename);
    352
    353 if( section->nitems == 0 )
    354 {
    355 SCIPinfoMessage(scip, file, "No data available in section '%s'\n", sectionname);
    356 return SCIP_OKAY;
    357 }
    358
    359 SCIP_CALL( SCIPdatatreeGetTree( section, section->items[0].name, &firstsectionitem ) );
    360
    361 /* Dynamically determine all keys from the first item */
    362 for( int i = 0; i < firstsectionitem->nitems; ++i )
    363 {
    364 size_t len = strlen(firstsectionitem->items[i].name);
    365 if( len > 14 )
    366 {
    367 SCIPinfoMessage(scip, file, " %-15.14s", firstsectionitem->items[i].name);
    368 }
    369 else
    370 {
    371 SCIPinfoMessage(scip, file, " %-15s", firstsectionitem->items[i].name);
    372 }
    373 }
    374 SCIPinfoMessage(scip, file, "\n");
    375
    376 /* Print each item's data */
    377 for( int i = 0; i < section->nitems; ++i )
    378 {
    379 SCIP_DATATREE* sectionitem = NULL;
    380 SCIPinfoMessage(scip, file, "%-19s:", section->items[i].name);
    381
    382 SCIP_CALL( SCIPdatatreeGetTree(section, section->items[i].name, &sectionitem) );
    383 assert(sectionitem != NULL);
    384 assert(sectionitem->nitems == firstsectionitem->nitems);
    385
    386 /* Print the values of all keys for this item */
    387 for( int j = 0; j < sectionitem->nitems; ++j )
    388 {
    389 SCIP_DATATREEITEM* item = &sectionitem->items[j];
    390
    391 assert(strcmp(item->name, firstsectionitem->items[j].name) == 0);
    392
    393 switch( item->value.type )
    394 {
    396 {
    397 SCIP_Bool boolval;
    398 SCIP_CALL( SCIPdatatreeGetBool(sectionitem, item->name, &boolval) );
    399 SCIPinfoMessage(scip, file, " %-15s", boolval ? "true" : "false");
    400 break;
    401 }
    403 {
    404 SCIP_Longint longval;
    405 SCIP_CALL( SCIPdatatreeGetLong(sectionitem, item->name, &longval) );
    406 SCIPinfoMessage(scip, file, " %-15" SCIP_LONGINT_FORMAT, longval);
    407 break;
    408 }
    410 {
    411 SCIP_Real realval;
    412 SCIP_CALL( SCIPdatatreeGetReal(sectionitem, item->name, &realval) );
    413 SCIPinfoMessage(scip, file, " %-15.2f", realval);
    414 break;
    415 }
    417 {
    418 const char* stringval;
    419 SCIP_CALL( SCIPdatatreeGetString(sectionitem, item->name, &stringval) );
    420 size_t len = strlen(stringval);
    421 if( len > 14 )
    422 {
    423 SCIPinfoMessage(scip, file, " %-15.14s", stringval);
    424 }
    425 else
    426 {
    427 SCIPinfoMessage(scip, file, " %-15s", stringval);
    428 }
    429 break;
    430 }
    432 SCIPwarningMessage(scip, "Table value type not supported in SCIPprintDatatreeAsTable\n");
    433 break;
    438 SCIPwarningMessage(scip, "Table array value type not supported in SCIPprintDatatreeAsTable\n");
    439 break;
    440 default:
    441 SCIPinfoMessage(scip, file, " %-15s", "N/A");
    442 break;
    443 }
    444 }
    445 SCIPinfoMessage(scip, file, "\n");
    446 }
    447
    448 return SCIP_OKAY;
    449}
    SCIP_RETCODE SCIPdatatreeInsertBoolArray(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, const SCIP_Bool *values, int nvalues)
    Definition: datatree.c:316
    SCIP_RETCODE SCIPdatatreeInsertTree(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, SCIP_DATATREE *value)
    Definition: datatree.c:461
    SCIP_RETCODE SCIPdatatreeInsertStringArray(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, const char *const *values, int nvalues)
    Definition: datatree.c:421
    SCIP_RETCODE SCIPdatatreeInsertLongArray(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, const SCIP_Longint *values, int nvalues)
    Definition: datatree.c:351
    SCIP_RETCODE SCIPdatatreeCreate(SCIP_DATATREE **datatree, BMS_BLKMEM *blkmem, int capacity)
    Definition: datatree.c:112
    void SCIPdatatreeFree(SCIP_DATATREE **datatree, BMS_BLKMEM *blkmem)
    Definition: datatree.c:135
    SCIP_RETCODE SCIPdatatreeInsertLong(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, SCIP_Longint value)
    Definition: datatree.c:223
    SCIP_RETCODE SCIPdatatreeWriteJson(SCIP_DATATREE *datatree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
    Definition: datatree.c:492
    SCIP_RETCODE SCIPdatatreeInsertString(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, const char *value)
    Definition: datatree.c:285
    SCIP_RETCODE SCIPdatatreeInsertRealArray(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, const SCIP_Real *values, int nvalues)
    Definition: datatree.c:386
    SCIP_RETCODE SCIPdatatreeInsertBool(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, SCIP_Bool value)
    Definition: datatree.c:192
    SCIP_RETCODE SCIPdatatreeInsertReal(SCIP_DATATREE *datatree, SCIP_SET *set, BMS_BLKMEM *blkmem, const char *name, SCIP_Real value)
    Definition: datatree.c:254
    internal methods for handling data trees
    #define NULL
    Definition: def.h:248
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_RETCODE SCIPinsertDatatreeStringArray(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const char *const *values, int nvalues)
    SCIP_RETCODE SCIPprintDatatreeAsTable(SCIP *scip, SCIP_DATATREE *datatree, FILE *file, const char *sectionname, const char *tablename)
    SCIP_RETCODE SCIPinsertDatatreeLongArray(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const SCIP_Longint *values, int nvalues)
    SCIP_RETCODE SCIPinsertDatatreeRealArray(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const SCIP_Real *values, int nvalues)
    SCIP_RETCODE SCIPinsertDatatreeBoolArray(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const SCIP_Bool *values, int nvalues)
    void SCIPfreeDatatree(SCIP *scip, SCIP_DATATREE **datatree)
    SCIP_RETCODE SCIPdatatreeGetLong(SCIP_DATATREE *datatree, const char *name, SCIP_Longint *value)
    Definition: datatree.c:629
    SCIP_RETCODE SCIPinsertDatatreeTree(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_DATATREE *value)
    SCIP_RETCODE SCIPdatatreeGetTree(SCIP_DATATREE *datatree, const char *name, SCIP_DATATREE **value)
    Definition: datatree.c:861
    SCIP_RETCODE SCIPdatatreeGetReal(SCIP_DATATREE *datatree, const char *name, SCIP_Real *value)
    Definition: datatree.c:658
    SCIP_RETCODE SCIPcreateDatatreeInTree(SCIP *scip, SCIP_DATATREE *datatree, SCIP_DATATREE **newtree, const char *name, int capacity)
    Definition: scip_datatree.c:61
    SCIP_RETCODE SCIPdatatreeGetString(SCIP_DATATREE *datatree, const char *name, const char **value)
    Definition: datatree.c:687
    SCIP_RETCODE SCIPinsertDatatreeString(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const char *value)
    SCIP_RETCODE SCIPinsertDatatreeBool(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Bool value)
    Definition: scip_datatree.c:82
    SCIP_RETCODE SCIPcreateDatatree(SCIP *scip, SCIP_DATATREE **datatree, int capacity)
    Definition: scip_datatree.c:46
    SCIP_RETCODE SCIPinsertDatatreeInt(SCIP *scip, SCIP_DATATREE *datatree, const char *name, int value)
    SCIP_RETCODE SCIPdatatreeGetBool(SCIP_DATATREE *datatree, const char *name, SCIP_Bool *value)
    Definition: datatree.c:600
    SCIP_RETCODE SCIPinsertDatatreeIntArray(SCIP *scip, SCIP_DATATREE *datatree, const char *name, const int *values, int nvalues)
    SCIP_RETCODE SCIPinsertDatatreeLong(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Longint value)
    SCIP_RETCODE SCIPwriteDatatreeJson(SCIP *scip, FILE *file, SCIP_DATATREE *datatree)
    SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    public methods for managing data trees
    public methods for message output
    public methods for data tree structure
    public methods for memory management
    public methods for message handling
    internal methods for global SCIP settings
    SCIP_DATATREEVALUE value
    SCIP_DATATREE_VALUETYPE type
    SCIP_DATATREEITEM * items
    data structures for data trees
    datastructures for block memory pools and memory buffers
    SCIP main data structure.
    @ SCIP_DATATREE_REALARRAY
    Definition: type_datatree.h:49
    @ SCIP_DATATREE_LONGARRAY
    Definition: type_datatree.h:48
    @ SCIP_DATATREE_BOOLARRAY
    Definition: type_datatree.h:47
    @ SCIP_DATATREE_LONG
    Definition: type_datatree.h:44
    @ SCIP_DATATREE_REAL
    Definition: type_datatree.h:45
    @ SCIP_DATATREE_DATATREE
    Definition: type_datatree.h:51
    @ SCIP_DATATREE_STRING
    Definition: type_datatree.h:46
    @ SCIP_DATATREE_BOOL
    Definition: type_datatree.h:43
    @ SCIP_DATATREE_STRINGARRAY
    Definition: type_datatree.h:50
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63