mirror of
https://github.com/OpenEmu/picodrive.git
synced 2025-11-01 11:08:35 +00:00
OpenEmu port (32X only)
Note that commit 0c720b9144 has caused
choppy audio in some games (Virtua Fighter)
This commit is contained in:
Binary file not shown.
+42
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.openemu.${PRODUCT_NAME:identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.81</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>OEGameCoreController</string>
|
||||
<key>OEGameCoreClass</key>
|
||||
<string>PicodriveGameCore</string>
|
||||
<key>OEGameCorePlayerCount</key>
|
||||
<string>2</string>
|
||||
<key>OEProjectURL</key>
|
||||
<string>https://github.com/notaz/picodrive</string>
|
||||
<key>OESystemIdentifiers</key>
|
||||
<array>
|
||||
<string>openemu.system.32x</string>
|
||||
</array>
|
||||
<key>SUEnableAutomaticChecks</key>
|
||||
<string>1</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>http://openemu.org/updater/picodrive_appcast.xml</string>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
<string>dsa_pub.pem</string>
|
||||
</dict>
|
||||
</plist>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2013, OpenEmu Team
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the OpenEmu Team nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenEmuBase/OEGameCore.h>
|
||||
|
||||
@class OERingBuffer;
|
||||
|
||||
OE_EXPORTED_CLASS
|
||||
@interface PicodriveGameCore : OEGameCore
|
||||
@end
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
Copyright (c) 2013, OpenEmu Team
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the OpenEmu Team nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "PicodriveGameCore.h"
|
||||
#import <OpenEmuBase/OERingBuffer.h>
|
||||
#import "OESega32XSystemResponderClient.h"
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
#include "libretro.h"
|
||||
|
||||
@interface PicodriveGameCore () <OESega32XSystemResponderClient>
|
||||
{
|
||||
uint16_t *videoBuffer;
|
||||
int videoWidth, videoHeight;
|
||||
int16_t pad[2][12];
|
||||
NSString *romName;
|
||||
double sampleRate;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NSUInteger Sega32XEmulatorValues[] = { RETRO_DEVICE_ID_JOYPAD_UP, RETRO_DEVICE_ID_JOYPAD_DOWN, RETRO_DEVICE_ID_JOYPAD_LEFT, RETRO_DEVICE_ID_JOYPAD_RIGHT, RETRO_DEVICE_ID_JOYPAD_Y, RETRO_DEVICE_ID_JOYPAD_B, RETRO_DEVICE_ID_JOYPAD_A, RETRO_DEVICE_ID_JOYPAD_L, RETRO_DEVICE_ID_JOYPAD_X, RETRO_DEVICE_ID_JOYPAD_R, RETRO_DEVICE_ID_JOYPAD_START, RETRO_DEVICE_ID_JOYPAD_SELECT };
|
||||
|
||||
PicodriveGameCore *current;
|
||||
@implementation PicodriveGameCore
|
||||
|
||||
static void audio_callback(int16_t left, int16_t right)
|
||||
{
|
||||
[[current ringBufferAtIndex:0] write:&left maxLength:2];
|
||||
[[current ringBufferAtIndex:0] write:&right maxLength:2];
|
||||
}
|
||||
|
||||
static size_t audio_batch_callback(const int16_t *data, size_t frames){
|
||||
[[current ringBufferAtIndex:0] write:data maxLength:frames << 2];
|
||||
return frames;
|
||||
}
|
||||
|
||||
static void video_callback(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
current->videoWidth = width;
|
||||
current->videoHeight = height;
|
||||
|
||||
dispatch_queue_t the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
|
||||
dispatch_apply(height, the_queue, ^(size_t y){
|
||||
const uint16_t *src = (uint16_t*)data + y * (pitch >> 1); //pitch is in bytes not pixels
|
||||
uint16_t *dst = current->videoBuffer + y * 320;
|
||||
|
||||
memcpy(dst, src, sizeof(uint16_t)*width);
|
||||
});
|
||||
}
|
||||
|
||||
static void input_poll_callback(void)
|
||||
{
|
||||
//NSLog(@"poll callback");
|
||||
}
|
||||
|
||||
static int16_t input_state_callback(unsigned port, unsigned device, unsigned index, unsigned _id)
|
||||
{
|
||||
//NSLog(@"polled input: port: %d device: %d id: %d", port, device, id);
|
||||
|
||||
if (port == 0 & device == RETRO_DEVICE_JOYPAD) {
|
||||
return current->pad[0][_id];
|
||||
}
|
||||
else if(port == 1 & device == RETRO_DEVICE_JOYPAD) {
|
||||
return current->pad[1][_id];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool environment_callback(unsigned cmd, void *data)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE :
|
||||
{
|
||||
break;
|
||||
}
|
||||
case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT :
|
||||
{
|
||||
enum retro_pixel_format pix_fmt = *(const enum retro_pixel_format*)data;
|
||||
switch (pix_fmt)
|
||||
{
|
||||
case RETRO_PIXEL_FORMAT_0RGB1555:
|
||||
NSLog(@"Environ SET_PIXEL_FORMAT: 0RGB1555");
|
||||
break;
|
||||
|
||||
case RETRO_PIXEL_FORMAT_RGB565:
|
||||
NSLog(@"Environ SET_PIXEL_FORMAT: RGB565");
|
||||
break;
|
||||
|
||||
case RETRO_PIXEL_FORMAT_XRGB8888:
|
||||
NSLog(@"Environ SET_PIXEL_FORMAT: XRGB8888");
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
//currentPixFmt = pix_fmt;
|
||||
break;
|
||||
}
|
||||
case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY :
|
||||
{
|
||||
// FIXME: Build a path in a more appropriate place
|
||||
NSString *appSupportPath = [NSString pathWithComponents:@[
|
||||
[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject],
|
||||
@"OpenEmu", @"BIOS"]];
|
||||
|
||||
*(const char **)data = [appSupportPath UTF8String];
|
||||
NSLog(@"Environ SYSTEM_DIRECTORY: \"%@\".\n", appSupportPath);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
NSLog(@"Environ UNSUPPORTED (#%u).\n", cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void loadSaveFile(const char* path, int type)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
file = fopen(path, "rb");
|
||||
if ( !file )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = retro_get_memory_size(type);
|
||||
void *data = retro_get_memory_data(type);
|
||||
|
||||
if (size == 0 || !data)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = fread(data, sizeof(uint8_t), size, file);
|
||||
if ( rc != size )
|
||||
{
|
||||
NSLog(@"Couldn't load save file.");
|
||||
}
|
||||
|
||||
NSLog(@"Loaded save file: %s", path);
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
static void writeSaveFile(const char* path, int type)
|
||||
{
|
||||
size_t size = retro_get_memory_size(type);
|
||||
void *data = retro_get_memory_data(type);
|
||||
|
||||
if ( data && size > 0 )
|
||||
{
|
||||
FILE *file = fopen(path, "wb");
|
||||
if ( file != NULL )
|
||||
{
|
||||
NSLog(@"Saving state %s. Size: %d bytes.", path, (int)size);
|
||||
retro_serialize(data, size);
|
||||
if ( fwrite(data, sizeof(uint8_t), size, file) != size )
|
||||
NSLog(@"Did not save state properly.");
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(BOOL)rendersToOpenGL;
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (oneway void)didPushSega32XButton:(OESega32XButton)button forPlayer:(NSUInteger)player;
|
||||
{
|
||||
pad[player-1][Sega32XEmulatorValues[button]] = 1;
|
||||
}
|
||||
|
||||
- (oneway void)didReleaseSega32XButton:(OESega32XButton)button forPlayer:(NSUInteger)player;
|
||||
{
|
||||
pad[player-1][Sega32XEmulatorValues[button]] = 0;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if((self = [super init]))
|
||||
{
|
||||
videoBuffer = (uint16_t*)malloc(320 * 240 * 2);
|
||||
}
|
||||
|
||||
current = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Exectuion
|
||||
|
||||
- (void)executeFrame
|
||||
{
|
||||
[self executeFrameSkippingFrame:NO];
|
||||
}
|
||||
|
||||
- (void)executeFrameSkippingFrame: (BOOL) skip
|
||||
{
|
||||
retro_run();
|
||||
}
|
||||
|
||||
- (BOOL)loadFileAtPath: (NSString*) path
|
||||
{
|
||||
memset(pad, 0, sizeof(int16_t) * 10);
|
||||
|
||||
const void *data;
|
||||
size_t size;
|
||||
romName = [path copy];
|
||||
|
||||
//load cart, read bytes, get length
|
||||
NSData* dataObj = [NSData dataWithContentsOfFile:[romName stringByStandardizingPath]];
|
||||
if(dataObj == nil) return false;
|
||||
size = [dataObj length];
|
||||
data = (uint8_t*)[dataObj bytes];
|
||||
const char *meta = NULL;
|
||||
|
||||
retro_set_environment(environment_callback);
|
||||
retro_init();
|
||||
|
||||
retro_set_audio_sample(audio_callback);
|
||||
retro_set_audio_sample_batch(audio_batch_callback);
|
||||
retro_set_video_refresh(video_callback);
|
||||
retro_set_input_poll(input_poll_callback);
|
||||
retro_set_input_state(input_state_callback);
|
||||
|
||||
|
||||
const char *fullPath = [path UTF8String];
|
||||
|
||||
struct retro_game_info info = {NULL};
|
||||
info.path = fullPath;
|
||||
info.data = data;
|
||||
info.size = size;
|
||||
info.meta = meta;
|
||||
|
||||
if(retro_load_game(&info))
|
||||
{
|
||||
NSString *path = romName;
|
||||
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
|
||||
|
||||
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
|
||||
|
||||
if([batterySavesDirectory length] != 0)
|
||||
{
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
|
||||
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
|
||||
|
||||
loadSaveFile([filePath UTF8String], RETRO_MEMORY_SAVE_RAM);
|
||||
}
|
||||
|
||||
struct retro_system_av_info info;
|
||||
retro_get_system_av_info(&info);
|
||||
|
||||
current->frameInterval = info.timing.fps;
|
||||
current->sampleRate = info.timing.sample_rate;
|
||||
|
||||
//retro_set_controller_port_device(SNES_PORT_1, RETRO_DEVICE_JOYPAD);
|
||||
|
||||
retro_get_region();
|
||||
|
||||
retro_run();
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark Video
|
||||
- (const void *)videoBuffer
|
||||
{
|
||||
return videoBuffer;
|
||||
}
|
||||
|
||||
- (OEIntRect)screenRect
|
||||
{
|
||||
return OEIntRectMake(0, 0, current->videoWidth, current->videoHeight);
|
||||
}
|
||||
|
||||
- (OEIntSize)bufferSize
|
||||
{
|
||||
return OEIntSizeMake(320, 240);
|
||||
//return OEIntSizeMake(current->videoWidth, current->videoHeight);
|
||||
}
|
||||
|
||||
- (void)setupEmulation
|
||||
{
|
||||
}
|
||||
|
||||
- (void)resetEmulation
|
||||
{
|
||||
retro_reset();
|
||||
}
|
||||
|
||||
- (void)stopEmulation
|
||||
{
|
||||
NSString *path = romName;
|
||||
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
|
||||
|
||||
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
|
||||
|
||||
if([batterySavesDirectory length] != 0)
|
||||
{
|
||||
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
|
||||
NSLog(@"Trying to save SRAM");
|
||||
|
||||
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
|
||||
|
||||
writeSaveFile([filePath UTF8String], RETRO_MEMORY_SAVE_RAM);
|
||||
}
|
||||
|
||||
NSLog(@"retro term");
|
||||
retro_unload_game();
|
||||
retro_deinit();
|
||||
[super stopEmulation];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(videoBuffer);
|
||||
}
|
||||
|
||||
- (GLenum)pixelFormat
|
||||
{
|
||||
return GL_RGB;
|
||||
}
|
||||
|
||||
- (GLenum)pixelType
|
||||
{
|
||||
return GL_UNSIGNED_SHORT_5_6_5;
|
||||
}
|
||||
|
||||
- (GLenum)internalPixelFormat
|
||||
{
|
||||
return GL_RGB5;
|
||||
}
|
||||
|
||||
- (double)audioSampleRate
|
||||
{
|
||||
return sampleRate ? sampleRate : 44100;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)frameInterval
|
||||
{
|
||||
return frameInterval ? frameInterval : 60;
|
||||
}
|
||||
|
||||
- (NSUInteger)channelCount
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (BOOL)saveStateToFileAtPath:(NSString *)fileName
|
||||
{
|
||||
// int serial_size = retro_serialize_size();
|
||||
// uint8_t *serial_data = (uint8_t *) malloc(serial_size);
|
||||
//
|
||||
// retro_serialize(serial_data, serial_size);
|
||||
//
|
||||
// FILE *state_file = fopen([fileName UTF8String], "wb");
|
||||
// long bytes_written = fwrite(serial_data, sizeof(uint8_t), serial_size, state_file);
|
||||
//
|
||||
// free(serial_data);
|
||||
//
|
||||
// if( bytes_written != serial_size )
|
||||
// {
|
||||
// NSLog(@"Couldn't write state");
|
||||
// return NO;
|
||||
// }
|
||||
// fclose( state_file );
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)loadStateFromFileAtPath:(NSString *)fileName
|
||||
{
|
||||
// FILE *state_file = fopen([fileName UTF8String], "rb");
|
||||
// if( !state_file )
|
||||
// {
|
||||
// NSLog(@"Could not open state file");
|
||||
// return NO;
|
||||
// }
|
||||
//
|
||||
// int serial_size = retro_serialize_size();
|
||||
// uint8_t *serial_data = (uint8_t *) malloc(serial_size);
|
||||
//
|
||||
// if(!fread(serial_data, sizeof(uint8_t), serial_size, state_file))
|
||||
// {
|
||||
// NSLog(@"Couldn't read file");
|
||||
// return NO;
|
||||
// }
|
||||
// fclose(state_file);
|
||||
//
|
||||
// if(!retro_unserialize(serial_data, serial_size))
|
||||
// {
|
||||
// NSLog(@"Couldn't unpack state");
|
||||
// return NO;
|
||||
// }
|
||||
//
|
||||
// free(serial_data);
|
||||
//
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIDOjCCAi0GByqGSM44BAEwggIgAoIBAQD/nSuLzikeU6MrymSPr34AiU2RDJz6
|
||||
0pm/3PPs27f6QTtbUAvGC13q6XWrE3HJU8Gz7RM0EJZGpiwb86LgqOJhjfQ7WKse
|
||||
uaGdbHnvJEFsGqpKX7rnUWaWO3HAsKzDx4HzJqKupFEbTbzXl/GT3JMm+a3PXA3S
|
||||
kyATydRPrX583Ih8iHO1zQs1pwp2AnUvaQXvp4QOLFWheH5napkDZBjc9B7H38dg
|
||||
f4c0QqEXJw0lJbG26FxhpOWMiXwpWpOHSfb+XtmzpeTDIHxKPLMEdf2wc+xNC/M9
|
||||
GdVBfM7+hCEhl1JGqNWPpT7ZzciX8Cxg+5/MIfx+BQ7xQ4wo1SN7y1bZAhUAuBcT
|
||||
+ZsHbLXlR3uGHLIMg8boUKcCggEAGKgD56/tB6siFr5zEY+RTozPLmbBEcvhz5/p
|
||||
hAQo7z7ODimZAA1MN1J7Hv7o1S5D9dpZuOnGhiXaN3Z50WdePb9LVH7twrB8v3Xn
|
||||
ZOEHpumYNcYhvXrIx8LbhnMZmU27xSnrOQF9UfokRxGnXkNmlIwjT0NWqZCqQZwM
|
||||
wVj1Bgld3YV7CpGTF3aGM6a0pk9LBB71PoczXAx0Cum87ouXXy3c8F/82RF9tgXE
|
||||
ZBQ+7K2QXYPv9smbYDB+ZlsQ4VTOi3AReG5AeHTVWha3uaSFxY5vKpfau31iMRuT
|
||||
b1VQ2HVynBpemwhAw4FFvj5dm94aN0Rrvq9BKM09DL4zoOlLogOCAQUAAoIBAE8B
|
||||
I8z38GdbtswSoSV5JZ9z9cBMj/7x/sHi5ED9v1M8MD6AcxJSbo2cbK98xA3A9U22
|
||||
6XFHthGReVLa0dyN3Ov+GhBdf8b4CBuebAAS4z8du2EvUFtwDUHorLIo2Qtq2SYR
|
||||
wpznpB9+3g+z+8GZbzZkdm2mFBKa6GItj82qfEHwxB40aEBx7uQXzM3TH0rV8sMq
|
||||
u91aAVUQuoiG2/IYWc5O34kKMlHUTt6+uuJiSG0ax8ysWE5XltCfSh/VJcGrzKU6
|
||||
ZjGBzh8j5+KSXgoe9TuKlsnN5HDCZKaFTCvrxq889HJj0/ks4UrIF+meEyJvDt4P
|
||||
O4HHoKRtUdLEBMcY0JA=
|
||||
-----END PUBLIC KEY-----
|
||||
Reference in New Issue
Block a user