Index: trunk/i386/boot2/gui.c =================================================================== --- trunk/i386/boot2/gui.c (revision 1989) +++ trunk/i386/boot2/gui.c (revision 1990) @@ -15,7 +15,7 @@ #define IMG_REQUIRED -1 #define THEME_NAME_DEFAULT "Default" -static const char *theme_name = THEME_NAME_DEFAULT; +static const char *theme_name = THEME_NAME_DEFAULT; #ifdef CONFIG_EMBED_THEME #include "art.h" @@ -43,23 +43,27 @@ iDeviceGeneric_o, iDeviceHFS, iDeviceHFS_o, - iDeviceHFS_Lion, + iDeviceHFS_ML, + iDeviceHFS_ML_o, + iDeviceHFS_Lion, iDeviceHFS_Lion_o, - iDeviceHFS_SL, + iDeviceHFS_SL, iDeviceHFS_SL_o, - iDeviceHFS_Leo, + iDeviceHFS_Leo, iDeviceHFS_Leo_o, - iDeviceHFS_Tiger, + iDeviceHFS_Tiger, iDeviceHFS_Tiger_o, iDeviceHFSRAID, iDeviceHFSRAID_o, - iDeviceHFSRAID_Lion, + iDeviceHFSRAID_ML, + iDeviceHFSRAID_ML_o, + iDeviceHFSRAID_Lion, iDeviceHFSRAID_Lion_o, - iDeviceHFSRAID_SL, + iDeviceHFSRAID_SL, iDeviceHFSRAID_SL_o, - iDeviceHFSRAID_Leo, + iDeviceHFSRAID_Leo, iDeviceHFSRAID_Leo_o, - iDeviceHFSRAID_Tiger, + iDeviceHFSRAID_Tiger, iDeviceHFSRAID_Tiger_o, iDeviceEXT3, iDeviceEXT3_o, @@ -113,26 +117,30 @@ {.name = "device_generic", .image = NULL}, {.name = "device_generic_o", .image = NULL}, {.name = "device_hfsplus", .image = NULL}, - {.name = "device_hfsplus_o", .image = NULL}, - {.name = "device_hfsplus_lion", .image = NULL}, - {.name = "device_hfsplus_lion_o", .image = NULL}, - {.name = "device_hfsplus_sl", .image = NULL}, - {.name = "device_hfsplus_sl_o", .image = NULL}, - {.name = "device_hfsplus_leo", .image = NULL}, - {.name = "device_hfsplus_leo_o", .image = NULL}, - {.name = "device_hfsplus_tiger", .image = NULL}, - {.name = "device_hfsplus_tiger_o", .image = NULL}, - + {.name = "device_hfsplus_o", .image = NULL}, + {.name = "device_hfsplus_ml", .image = NULL}, + {.name = "device_hfsplus_ml_o", .image = NULL}, + {.name = "device_hfsplus_lion", .image = NULL}, + {.name = "device_hfsplus_lion_o", .image = NULL}, + {.name = "device_hfsplus_sl", .image = NULL}, + {.name = "device_hfsplus_sl_o", .image = NULL}, + {.name = "device_hfsplus_leo", .image = NULL}, + {.name = "device_hfsplus_leo_o", .image = NULL}, + {.name = "device_hfsplus_tiger", .image = NULL}, + {.name = "device_hfsplus_tiger_o", .image = NULL}, + {.name = "device_hfsraid", .image = NULL}, {.name = "device_hfsraid_o", .image = NULL}, - {.name = "device_hfsraid_lion", .image = NULL}, - {.name = "device_hfsraid_lion_o", .image = NULL}, - {.name = "device_hfsraid_sl", .image = NULL}, - {.name = "device_hfsraid_sl_o", .image = NULL}, - {.name = "device_hfsraid_leo", .image = NULL}, - {.name = "device_hfsraid_leo_o", .image = NULL}, - {.name = "device_hfsraid_tiger", .image = NULL}, - {.name = "device_hfsraid_tiger_o", .image = NULL}, + {.name = "device_hfsraid_ml", .image = NULL}, + {.name = "device_hfsraid_ml_o", .image = NULL}, + {.name = "device_hfsraid_lion", .image = NULL}, + {.name = "device_hfsraid_lion_o", .image = NULL}, + {.name = "device_hfsraid_sl", .image = NULL}, + {.name = "device_hfsraid_sl_o", .image = NULL}, + {.name = "device_hfsraid_leo", .image = NULL}, + {.name = "device_hfsraid_leo_o", .image = NULL}, + {.name = "device_hfsraid_tiger", .image = NULL}, + {.name = "device_hfsraid_tiger_o", .image = NULL}, {.name = "device_ext3", .image = NULL}, {.name = "device_ext3_o", .image = NULL}, {.name = "device_freebsd", .image = NULL}, /* FreeBSD/OpenBSD detection,nawcom's code by valv, Icon credits to blackosx */ @@ -189,7 +197,7 @@ extern char gBootArgs[BOOT_STRING_LEN]; char prompt_text[] = "boot: "; - + menuitem_t infoMenuItems[] = { { .text = "Boot" }, @@ -306,7 +314,7 @@ unsigned int embed_size; embed_data = embeddedImages[e].pngdata; embed_size = *embeddedImages[e].length; - + if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) == 0) { images[i].image->width = width; @@ -330,9 +338,9 @@ images[i].image->pixels = images[alt_image].image->pixels; } else { - + // Unable to load or to find the image, this image not vital anyway, reseting and returning success !! - + free(images[i].image); images[i].image = NULL; } @@ -348,9 +356,9 @@ free(images[i].image); images[i].image = NULL; return 1; - + } - + } return 1; } @@ -364,6 +372,8 @@ LOADPNG(device_generic_o, iDeviceGeneric); LOADPNG(device_hfsplus, iDeviceGeneric); LOADPNG(device_hfsplus_o, iDeviceHFS); + LOADPNG(device_hfsplus_ml, iDeviceHFS_ML); + LOADPNG(device_hfsplus_ml_o, iDeviceHFS_ML_o); LOADPNG(device_hfsplus_lion, iDeviceHFS_Lion); LOADPNG(device_hfsplus_lion_o, iDeviceHFS_Lion_o); LOADPNG(device_hfsplus_sl, iDeviceHFS_SL); @@ -372,17 +382,19 @@ LOADPNG(device_hfsplus_leo_o, iDeviceHFS_Leo_o); LOADPNG(device_hfsplus_tiger, iDeviceHFS_Tiger); LOADPNG(device_hfsplus_tiger_o, iDeviceHFS_Tiger_o); - + LOADPNG(device_hfsraid, iDeviceGeneric); LOADPNG(device_hfsraid_o, iDeviceHFSRAID); - LOADPNG(device_hfsraid_lion, iDeviceHFSRAID_Lion); - LOADPNG(device_hfsraid_lion_o, iDeviceHFSRAID_Lion_o); - LOADPNG(device_hfsraid_sl, iDeviceHFSRAID_SL); - LOADPNG(device_hfsraid_sl_o, iDeviceHFSRAID_SL_o); - LOADPNG(device_hfsraid_leo, iDeviceHFSRAID_Leo); - LOADPNG(device_hfsraid_leo_o, iDeviceHFSRAID_Leo_o); - LOADPNG(device_hfsraid_tiger, iDeviceHFSRAID_Tiger); - LOADPNG(device_hfsraid_tiger_o, iDeviceHFSRAID_Tiger_o); + LOADPNG(device_hfsraid_ml, iDeviceHFSRAID_ML); + LOADPNG(device_hfsraid_ml_o, iDeviceHFSRAID_ML_o); + LOADPNG(device_hfsraid_lion, iDeviceHFSRAID_Lion); + LOADPNG(device_hfsraid_lion_o, iDeviceHFSRAID_Lion_o); + LOADPNG(device_hfsraid_sl, iDeviceHFSRAID_SL); + LOADPNG(device_hfsraid_sl_o, iDeviceHFSRAID_SL_o); + LOADPNG(device_hfsraid_leo, iDeviceHFSRAID_Leo); + LOADPNG(device_hfsraid_leo_o, iDeviceHFSRAID_Leo_o); + LOADPNG(device_hfsraid_tiger, iDeviceHFSRAID_Tiger); + LOADPNG(device_hfsraid_tiger_o, iDeviceHFSRAID_Tiger_o); LOADPNG(device_ext3, iDeviceGeneric); LOADPNG(device_ext3_o, iDeviceEXT3); LOADPNG(device_freebsd, iDeviceGeneric); /* FreeBSD/OpenBSD detection,nawcom's code by valv, Icon credits to blackosx */ @@ -432,14 +444,13 @@ return 0; } - + static int unloadGraphics(void) { int i; destroyFont(&font_console); destroyFont(&font_small); - for (i = 0; i < sizeof(images) / sizeof(images[0]); i++) { if (images[i].image) @@ -452,6 +463,19 @@ return 0; } +int freeBackBuffer( window_t *window ) +{ + if (gui.backbuffer && gui.backbuffer->pixels) + { + free(gui.backbuffer->pixels); + free(gui.backbuffer); + gui.backbuffer = 0; + return 0; + } + + return 1; +} + pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height ) { @@ -482,8 +506,9 @@ { gui.backbuffer = malloc(sizeof(pixmap_t)); if(!gui.backbuffer) + { return 1; - + } gui.backbuffer->pixels = malloc( window->width * window->height * 4 ); if(!gui.backbuffer->pixels) { @@ -494,28 +519,17 @@ gui.backbuffer->width = gui.screen.width; gui.backbuffer->height = gui.screen.height; - + return 0; } -int freeBackBuffer( window_t *window ) -{ - if (gui.backbuffer && gui.backbuffer->pixels) - { - free(gui.backbuffer->pixels); - free(gui.backbuffer); - gui.backbuffer = 0; - return 0; - } - - return 1; -} - int createWindowBuffer( window_t *window ) { window->pixmap = malloc(sizeof(pixmap_t)); if(!window->pixmap) + { return 1; + } window->pixmap->pixels = malloc( window->width * window->height * 4 ); if(!window->pixmap->pixels) @@ -527,7 +541,7 @@ window->pixmap->width = window->width; window->pixmap->height = window->height; - + return 0; } @@ -539,7 +553,7 @@ free(window->pixmap); return 0; } - + return 1; } @@ -606,7 +620,7 @@ if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) ) gui.devicelist.pos.y = pixel; break; - + case HorizontalLayout: default: gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, gDeviceCount) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing); @@ -790,7 +804,7 @@ if(getColorForKey("font_console_color", &color, theme)) gui.screen.font_console_color = (color & 0x00FFFFFF); } - + int initGUI(void) { int val; @@ -859,14 +873,16 @@ } } } - // not available memory, freeing resources - freeWindowBuffer(&gui.menu); - freeWindowBuffer(&gui.infobox); - freeWindowBuffer(&gui.bootprompt); - freeWindowBuffer(&gui.devicelist); - freeWindowBuffer(&gui.screen); - freeBackBuffer(&gui.screen); - unloadGraphics(); + + // not available memory, freeing resources + freeWindowBuffer(&gui.menu); + freeWindowBuffer(&gui.infobox); + freeWindowBuffer(&gui.bootprompt); + freeWindowBuffer(&gui.devicelist); + freeWindowBuffer(&gui.screen); + freeBackBuffer(&gui.screen); + unloadGraphics(); + return 1; } @@ -889,9 +905,13 @@ { // Use HFS or HFSRAID icon depending on bvr flags. - if (device->flags & kBVFlagBooter) { + if (device->flags & kBVFlagBooter) + { switch (device->OSVersion[3]) { + case '8': + devicetype = is_image_loaded(iDeviceHFSRAID_ML) ? iDeviceHFSRAID_ML : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric; + break; case '7': devicetype = is_image_loaded(iDeviceHFSRAID_Lion) ? iDeviceHFSRAID_Lion : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric; break; @@ -909,11 +929,12 @@ break; } - } - else - { - + } else { + switch (device->OSVersion[3]) { + case '8': + devicetype = is_image_loaded(iDeviceHFS_ML) ? iDeviceHFS_ML : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric; + break; case '7': devicetype = is_image_loaded(iDeviceHFS_Lion) ? iDeviceHFS_Lion : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric; break; @@ -939,31 +960,31 @@ case kPartitionTypeHPFS: devicetype = is_image_loaded(iDeviceNTFS) ? iDeviceNTFS : iDeviceGeneric; // Use HPFS / NTFS icon break; - + case kPartitionTypeFAT16: devicetype = is_image_loaded(iDeviceFAT16) ? iDeviceFAT16 : iDeviceGeneric; // Use FAT16 icon break; - + case kPartitionTypeFAT32: devicetype = is_image_loaded(iDeviceFAT32) ? iDeviceFAT32 : iDeviceGeneric; // Use FAT32 icon break; - + case kPartitionTypeEXT3: devicetype = is_image_loaded(iDeviceEXT3) ? iDeviceEXT3 : iDeviceGeneric; // Use EXT2/3 icon break; - - case kPartitionTypeFreeBSD: + + case kPartitionTypeFreeBSD: /* FreeBSD/OpenBSD detection,nawcom's code by valv, Icon credits to blackosx */ devicetype = is_image_loaded(iDeviceFreeBSD) ? iDeviceFreeBSD : iDeviceGeneric; // Use FreeBSD icon break; - - case kPartitionTypeOpenBSD: + + case kPartitionTypeOpenBSD: /* FreeBSD/OpenBSD detection,nawcom's code by valv, Icon credits to blackosx */ devicetype = is_image_loaded(iDeviceOpenBSD) ? iDeviceOpenBSD : iDeviceGeneric; // Use OpenBSD icon break; - - case kPartitionTypeBEFS: /* Haiku detection and Icon credits to scorpius */ + + case kPartitionTypeBEFS: /* Haiku detection and Icon credits to scorpius */ devicetype = is_image_loaded(iDeviceBEFS) ? iDeviceBEFS : iDeviceGeneric;// Use BEFS / Haiku icon break; - + default: devicetype = iDeviceGeneric; // Use Generic icon break; @@ -974,7 +995,7 @@ if (isSelected) { blend(images[iSelection].image, buffer, centeredAt(images[iSelection].image, p)); - devicetype++; + devicetype++; // selec override image } // draw icon @@ -995,7 +1016,7 @@ position_t p, p_prev, p_next; //uint8_t maxDevices = MIN( gui.maxdevices, menucount ); - + fillPixmapWithColor( gui.devicelist.pixmap, gui.devicelist.bgcolor); makeRoundedCorners( gui.devicelist.pixmap); @@ -1045,7 +1066,7 @@ if(infoMenuSelection >= INFOMENU_NATIVEBOOT_START && infoMenuSelection <= INFOMENU_NATIVEBOOT_END) infoMenuSelection = 0; } - + if (gui.menu.draw) drawInfoMenuItems(); @@ -1098,7 +1119,7 @@ updateVRAM(); } - + void clearGraphicBootPrompt() { // clear text buffer @@ -1172,7 +1193,7 @@ // break; case 15: *(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xf8)<<2) | ((r&0xf8)<<7); - break; + break; } } } @@ -1187,14 +1208,14 @@ if (gui.bootprompt.draw) blend( gui.bootprompt.pixmap, gui.backbuffer, gui.bootprompt.pos ); - + if (gui.menu.draw) blend( gui.menu.pixmap, gui.backbuffer, gui.menu.pos ); if (gui.infobox.draw) blend( gui.infobox.pixmap, gui.backbuffer, gui.infobox.pos ); } - + vramwrite ( gui.backbuffer->pixels, gui.backbuffer->width, gui.backbuffer->height ); if (gui.redraw) @@ -1251,15 +1272,15 @@ bounds.y = ( window->height - window->vborder ); cursor = origin; - + font_t *font = &font_console; - + for( i=0; i< strlen(formattedtext); i++ ) { character = formattedtext[i]; character -= 32; - + // newline ? if( formattedtext[i] == '\n' ) { @@ -1271,7 +1292,7 @@ continue; } - + // tab ? if( formattedtext[i] == '\t' ) cursor.x += ( font->chars[0]->width * 5 ); @@ -1414,7 +1435,7 @@ bounds.x = ( window->width - ( window->hborder * 2 ) ); bounds.y = ( window->height - ( window->vborder * 2 ) ); cursor = origin; - + for( i=0; i< strlen(formattedtext); i++ ) { character = formattedtext[i]; @@ -1449,7 +1470,7 @@ cursor.x = origin.x; cursor.y += font->height; } - + // check y pos and reset to origin.y if ( cursor.y > ( bounds.y + font->chars[0]->height) ) { @@ -1548,6 +1569,21 @@ drawStr(text, font, blendInto, p); } +int destroyFont(font_t *font) +{ + int i; + for (i = 0; i < CHARACTERS_COUNT; i++) + { + if (font->chars[i]) + { + if (font->chars[i]->pixels) free (font->chars[i]->pixels); + free (font->chars[i]); + font->chars[i] = 0; + } + } + return 0; +} + int initFont(font_t *font, image_t *data) { unsigned int x = 0, y = 0, x2 = 0, x3 = 0; @@ -1561,7 +1597,7 @@ for( x = 0; x < data->image->width && count < CHARACTERS_COUNT; x++) { start = end; - + // if the pixel is red we've reached the end of the char if( pixel( data->image, x, 0 ).value == 0xFFFF0000) { @@ -1587,7 +1623,7 @@ // check if font is monospaced if( ( count > 0 ) && ( font->width != font->chars[count]->width ) ) monospaced = true; - + font->width = font->chars[count]->width; count++; @@ -1607,21 +1643,6 @@ return 0; } -int destroyFont(font_t *font) -{ - int i; - for (i = 0; i < CHARACTERS_COUNT; i++) - { - if (font->chars[i]) - { - if (font->chars[i]->pixels) free (font->chars[i]->pixels); - free (font->chars[i]); - font->chars[i] = 0; - } - } - return 0; -} - void colorFont(font_t *font, uint32_t color) { if( !color ) @@ -1759,11 +1780,11 @@ break; } } - + fillPixmapWithColor( gui.infobox.pixmap, gui.infobox.bgcolor); makeRoundedCorners( gui.infobox.pixmap); - + // print the title if present if( title ) drawStr(title, &font_console, gui.infobox.pixmap, pos_title); @@ -1813,7 +1834,7 @@ updateVRAM(); break; } - + if(key == ' ') // spacebar = next page { if( lines > ( currentline + visiblelines ) ) @@ -1885,7 +1906,7 @@ for(x=todraw, x2 = 0; x < width - 1; x++, x2++) { if(x2 == (buffBG->width -2 )) x2 = 0; - pixel(&progressbar, x,y).value = pixel(buffBG, x2,y).value; + pixel(&progressbar, x,y).value = pixel(buffBG, x2,y).value; } if(progress < 100) pixel(&progressbar, width - 1, y).value = pixel(buffBG, buffBG->width - 1, y).value; @@ -1893,7 +1914,7 @@ pixel(&progressbar, 0, y).value = pixel(buffBG, buffBG->width - 1, y).value; x2=0; } - + blend(&progressbar, blendInto, p); animateProgressBar(); free(progressbar.pixels); @@ -1920,15 +1941,21 @@ for ( i = 0, n = iMenuBoot; i < infoMenuItemsCount; i++, n++) { if (i == infoMenuSelection) + { blend(selection, gui.menu.pixmap, position); + } pbuff = images[n].image; if (offset && i >= INFOMENU_NATIVEBOOT_START && i <= INFOMENU_NATIVEBOOT_END) + { blend( images[n + (iMenuHelp - iMenuBoot)].image , gui.menu.pixmap, pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2))); + } else + { blend( pbuff, gui.menu.pixmap, pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2))); + } drawStr(infoMenuItems[i].text, &font_console, gui.menu.pixmap, pos(position.x + (pbuff->width + gui.menu.hborder), @@ -1957,58 +1984,63 @@ { case KEY_UP: // up arrow - if (infoMenuSelection > 0) + if (infoMenuSelection > 0) + { + if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_END + 1) { - if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_END + 1) - infoMenuSelection -= 4; - - else - infoMenuSelection--; - drawInfoMenuItems(); - updateVRAM(); - - } else { - - gui.menu.draw = false; - gui.redraw = true; - - updateVRAM(); - - return CLOSE_INFO_MENU; + infoMenuSelection -= 4; } - break; - - case KEY_DOWN: // down arrow - if (infoMenuSelection < infoMenuItemsCount - 1) + else { - if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_START - 1) - infoMenuSelection += 4; - else - infoMenuSelection++; - drawInfoMenuItems(); - updateVRAM(); + infoMenuSelection--; } - break; + drawInfoMenuItems(); + updateVRAM(); + } + else + { + + gui.menu.draw = false; + gui.redraw = true; + + updateVRAM(); + + return CLOSE_INFO_MENU; + } + break; + + case KEY_DOWN: // down arrow + if (infoMenuSelection < infoMenuItemsCount - 1) + { + if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_START - 1) + infoMenuSelection += 4; + else + infoMenuSelection++; + drawInfoMenuItems(); + updateVRAM(); + } + break; + case KEY_ENTER: - key = 0; - if( infoMenuSelection == MENU_SHOW_MEMORY_INFO ) - showInfoBox( "Memory Info. Press q to quit.\n", getMemoryInfoString()); + key = 0; + if( infoMenuSelection == MENU_SHOW_MEMORY_INFO ) + showInfoBox( "Memory Info. Press q to quit.\n", getMemoryInfoString()); - else if( infoMenuSelection == MENU_SHOW_VIDEO_INFO ) - showInfoBox( getVBEInfoString(), getVBEModeInfoString() ); + else if( infoMenuSelection == MENU_SHOW_VIDEO_INFO ) + showInfoBox( getVBEInfoString(), getVBEModeInfoString() ); - else if( infoMenuSelection == MENU_SHOW_HELP ) - showHelp(); - - else - { - int buff = infoMenuSelection; - infoMenuSelection = 0; - return buff; - } - break; - } + else if( infoMenuSelection == MENU_SHOW_HELP ) + showHelp(); + + else + { + int buff = infoMenuSelection; + infoMenuSelection = 0; + return buff; + } + break; + } return DO_NOT_BOOT; } Index: trunk/i386/boot2/gui.h =================================================================== --- trunk/i386/boot2/gui.h (revision 1989) +++ trunk/i386/boot2/gui.h (revision 1990) @@ -17,25 +17,25 @@ #include "graphic_utils.h" #include "picopng.h" -#define CHARACTERS_COUNT 223 +#define CHARACTERS_COUNT 223 #define BOOT_NORMAL 0 -#define BOOT_VERBOSE 1 -#define BOOT_IGNORECACHE 2 -#define BOOT_SINGLEUSER 3 +#define BOOT_VERBOSE 1 +#define BOOT_IGNORECACHE 2 +#define BOOT_SINGLEUSER 3 #define DO_NOT_BOOT 4 -#define CLOSE_INFO_MENU 5 +#define CLOSE_INFO_MENU 5 #define INFOMENU_NATIVEBOOT_START 1 #define INFOMENU_NATIVEBOOT_END 3 #define MENU_SHOW_MEMORY_INFO 4 #define MENU_SHOW_VIDEO_INFO 5 -#define MENU_SHOW_HELP 6 +#define MENU_SHOW_HELP 6 enum { HorizontalLayout = 0, - VerticalLayout = 1 + VerticalLayout = 1, }; /*