diff --git a/Compile.md b/Compile.md index d8763e858..1ee6e6c9d 100644 --- a/Compile.md +++ b/Compile.md @@ -16,19 +16,11 @@ Open a terminal and run: ```sh git clone https://git.743378673.xyz/MeloNX/MeloNX.git -cd MeloNX -./compile.sh -``` -You may need to run this command if compilation fails, then run the `./compile.sh` command again (You will need to put in your user password. Your password will not be shown at all.) -``` -sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer ``` - -However, if you only need to update MeloNX, make sure you have cd into the directory then run this then skip to step 5 +However, if you only need to update MeloNX, make sure you have cd into the directory then run this ``` git pull -./compile.sh ``` ### 2. Open the Xcode Project @@ -66,7 +58,7 @@ Ensure your **iPhone/iPad** is **connected** and **selected** (Next to MeloNX wi - You will be need to press GET and wait for it to finish downloading and installing - Then you will be able to select your device and Build and Run. -Make Sure you do **NOT** select the Simulator. (Which is the Generic names and the ones with the non-coloured icons, e.g. "iPhone 16 Pro") +### Make Sure you do **NOT** select the Simulator. (Which is the Generic names and the ones with the non-coloured icons, e.g. "iPhone 16 Pro") ### 6. Build and Run @@ -77,5 +69,4 @@ Click the **Run (▶️) button** in Xcode to compile and launch MeloNX. --- -Now you're all set! 🚀 If you encounter issues, please join the discord at https://melonx.org -``` \ No newline at end of file +Now you're all set! 🚀 If you encounter issues, please join the discord at https://melonx.org \ No newline at end of file diff --git a/compile.sh b/distribution/ios/compile.sh similarity index 99% rename from compile.sh rename to distribution/ios/compile.sh index 74c158b82..658f6210b 100755 --- a/compile.sh +++ b/distribution/ios/compile.sh @@ -1,6 +1,5 @@ #!/bin/bash - # Define the destination directory (hardcoded) DESTINATION_DIR="src/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib" diff --git a/distribution/ios/get_dotnet.sh b/distribution/ios/get_dotnet.sh new file mode 100755 index 000000000..a600eb398 --- /dev/null +++ b/distribution/ios/get_dotnet.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig" + +# Define the common paths to search for dotnet, including user-specific directories +SEARCH_PATHS=( + "/usr/local/share/dotnet" + "/usr/local/bin" + "/usr/bin" + "/bin" + "/opt" + "/Library/Frameworks" + "$HOME/.dotnet" + "$HOME/Developer" +) + +# Initialize DOTNET_PATH as empty +DOTNET_PATH="" + +# Search in the defined paths +for path in "${SEARCH_PATHS[@]}"; do + if [ -d "$path" ]; then + DOTNET_PATH=$(find "$path" -name dotnet -type f -print -quit 2>/dev/null) + if [ -n "$DOTNET_PATH" ]; then + break + fi + fi +done + +# Check if the path was found +if [ -z "$DOTNET_PATH" ]; then + echo "Error: dotnet path not found." + exit 1 +fi + +echo "dotnet path: $DOTNET_PATH" + +# Escape the path for sed +ESCAPED_PATH=$(echo "$DOTNET_PATH" | sed 's/\//\\\//g') + +# Update the xcconfig file +sed -i '' "s/^DOTNET = .*/DOTNET = $ESCAPED_PATH/g" "$XCCONFIG_FILE" + +echo "Updated MeloNX.xcconfig with DOTNET path: $DOTNET_PATH" diff --git a/distribution/ios/set_current_version.sh b/distribution/ios/set_current_version.sh new file mode 100644 index 000000000..c9b713e15 --- /dev/null +++ b/distribution/ios/set_current_version.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +GITEA_URL="https://git.743378673.xyz/" +REPO="MeloNX" +XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig" + +INCREMENT_PATCH=false + +# Check for --patch argument +if [[ "$1" == "--patch" ]]; then + INCREMENT_PATCH=true +fi + +# Fetch latest tag from Gitea +LATEST_VERSION=$(curl -s "${GITEA_URL}/api/v1/repos/${REPO}/${REPO}/tags" | jq -r '.[].name' | sort -V | tail -n1) + +if [ -z "$LATEST_VERSION" ]; then + echo "Error: Could not fetch latest tag from Gitea" + exit 1 +fi + +echo "Latest version: $LATEST_VERSION" + +# Split version into major, minor, and patch +IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION" + +# Increment version based on argument +if $INCREMENT_PATCH; then + NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))" +else + NEW_VERSION="$MAJOR.$((MINOR + 1)).0" +fi + +echo "New version: $NEW_VERSION" + +sed -i '' "s/^VERSION = $LATEST_VERSION$/VERSION = $NEW_VERSION/g" "$XCCONFIG_FILE" + +echo "Updated MeloNX.xcconfig with version $NEW_VERSION" diff --git a/src/MeloNX/MeloNX.xcconfig b/src/MeloNX/MeloNX.xcconfig new file mode 100644 index 000000000..486226384 --- /dev/null +++ b/src/MeloNX/MeloNX.xcconfig @@ -0,0 +1,13 @@ +// +// MeloNX.xcconfig +// MeloNX +// +// Created by Stossy11 on 06/03/2025. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +VERSION = 1.5.0 + +DOTNET = /usr/local/share/dotnet/dotnet diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj index 485f34a3a..ce9b31ccd 100644 --- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj +++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj @@ -25,12 +25,20 @@ /* Begin PBXBuildFile section */ 4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */ = {isa = PBXBuildFile; productRef = 4E0DED332D05695D00FEF007 /* SwiftUIJoystick */; }; + 4E12B23C2D797CFA00FB2271 /* MeloNX.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; }; 4E8A80772D5FDD2D0041B48F /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; }; 4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */ = {isa = PBXBuildFile; productRef = 4EA5AE812D16807500AD0B9F /* SwiftSVG */; }; CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 4E12B3A12D798BD100FB2271 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4E80A9852CD6F54500029585 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BD43C6212D1B248D003BBC42; + remoteInfo = com.Stossy11.MeloNX.RyujinxAg; + }; 4E80A99E2CD6F54700029585 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4E80A9852CD6F54500029585 /* Project object */; @@ -78,12 +86,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = MeloNX.xcconfig; sourceTree = ""; }; 4E7023A52D5A98E2002C7183 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 4E80A98D2CD6F54500029585 /* MeloNX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeloNX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4E80A99D2CD6F54700029585 /* MeloNXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 4E80A9A72CD6F54700029585 /* MeloNXUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 4E80AA622CD7122800029585 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; - 5650564A2D2A758600C8BB1E /* dotnet.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = dotnet.xcconfig; sourceTree = ""; }; BD43C6282D1B2514003BBC42 /* Ryujinx.Headless.SDL2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = Ryujinx.Headless.SDL2.dylib; path = "MeloNX/Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -222,7 +230,7 @@ 4E80A9842CD6F54500029585 = { isa = PBXGroup; children = ( - 5650564A2D2A758600C8BB1E /* dotnet.xcconfig */, + 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */, BD43C6282D1B2514003BBC42 /* Ryujinx.Headless.SDL2.dylib */, 4E80A98F2CD6F54500029585 /* MeloNX */, 4E80A9A02CD6F54700029585 /* MeloNXTests */, @@ -260,7 +268,7 @@ buildConfigurationList = BD43C61E2D1B23AB003BBC42 /* Build configuration list for PBXLegacyTarget "Ryujinx" */; buildPhases = ( ); - buildToolPath = /usr/local/share/dotnet/dotnet; + buildToolPath = "$(DOTNET)"; buildWorkingDirectory = "$(SRCROOT)/../.."; dependencies = ( ); @@ -286,6 +294,7 @@ buildRules = ( ); dependencies = ( + 4E12B3A22D798BD100FB2271 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 4E80A98F2CD6F54500029585 /* MeloNX */, @@ -406,6 +415,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4E12B23C2D797CFA00FB2271 /* MeloNX.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -472,6 +482,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 4E12B3A22D798BD100FB2271 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BD43C6212D1B248D003BBC42 /* com.Stossy11.MeloNX.RyujinxAg */; + targetProxy = 4E12B3A12D798BD100FB2271 /* PBXContainerItemProxy */; + }; 4E80A99F2CD6F54700029585 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4E80A98C2CD6F54500029585 /* MeloNX */; @@ -492,6 +507,7 @@ /* Begin XCBuildConfiguration section */ 4E80A9AF2CD6F54700029585 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -561,6 +577,7 @@ }; 4E80A9B02CD6F54700029585 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -626,6 +643,7 @@ }; 4E80A9B22CD6F54700029585 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -680,6 +698,12 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -779,8 +803,20 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); - MARKETING_VERSION = 1.4.0; + MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -792,6 +828,7 @@ }; 4E80A9B32CD6F54700029585 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -846,6 +883,12 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -945,8 +988,20 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); - MARKETING_VERSION = 1.4.0; + MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -958,6 +1013,7 @@ }; 4E80A9B52CD6F54700029585 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -977,6 +1033,7 @@ }; 4E80A9B62CD6F54700029585 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -996,6 +1053,7 @@ }; 4E80A9B82CD6F54700029585 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -1013,6 +1071,7 @@ }; 4E80A9B92CD6F54700029585 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -1030,7 +1089,9 @@ }; BD43C61F2D1B23AB003BBC42 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; CODE_SIGN_STYLE = Automatic; DEBUGGING_SYMBOLS = YES; DEBUG_INFORMATION_FORMAT = dwarf; @@ -1046,7 +1107,9 @@ }; BD43C6202D1B23AB003BBC42 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 95J8WZ4TN8; @@ -1058,6 +1121,7 @@ }; BD43C6232D1B248D003BBC42 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 95J8WZ4TN8; @@ -1067,6 +1131,7 @@ }; BD43C6242D1B248D003BBC42 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4E12B23B2D797CFA00FB2271 /* MeloNX.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 95J8WZ4TN8; diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index f990ba9d5..90507c9d7 100644 Binary files a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme index b48bf4f6f..9f2439a96 100644 --- a/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme +++ b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme @@ -100,5 +100,15 @@ + + + + + + diff --git a/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/Ryujinx.xcscheme b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/Ryujinx.xcscheme new file mode 100644 index 000000000..eb2c0a6a5 --- /dev/null +++ b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/Ryujinx.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +