2021-03-08 23:59:02 +00:00
|
|
|
//
|
|
|
|
// Slot.m
|
|
|
|
// Ample
|
|
|
|
//
|
|
|
|
// Created by Kelvin Sherlock on 3/6/2021.
|
|
|
|
// Copyright © 2021 Kelvin Sherlock. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
#import "Slot.h"
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
static NSArray *MapArray(NSArray *src, id(^fn)(id)) {
|
|
|
|
NSMutableArray *rv = [NSMutableArray arrayWithCapacity: [src count]];
|
|
|
|
for (id x in src) {
|
|
|
|
[rv addObject: fn(x)];
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
static NSArray *DeepCopyArray(NSArray *src) {
|
|
|
|
if (!src) return nil;
|
|
|
|
return [[NSArray alloc] initWithArray: src copyItems: YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
@interface Slot () {
|
|
|
|
NSArray<SlotOption *> *_options;
|
|
|
|
//NSArray<NSMenuItem *> *_menuItems;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(SlotOption *)selectedItem;
|
|
|
|
|
|
|
|
-(void)setKeyPath;
|
|
|
|
-(void)setKeyPath: (NSString *)path;
|
|
|
|
//-(NSArray *)buildArgs: (NSMutableArray *)args prefix: (NSString *)prefix;
|
|
|
|
//-(void)buildMedia: (MediaBuilder *)builder;
|
|
|
|
//-(NSArray *)buildSerial: (NSMutableArray *)array;
|
2021-03-10 03:22:24 +00:00
|
|
|
|
|
|
|
-(instancetype)initWithDictionary: (NSDictionary *)dictionary devices: (NSDictionary *)devices;
|
|
|
|
|
2021-03-08 23:59:02 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@interface SlotOption() {
|
2021-03-10 03:58:01 +00:00
|
|
|
//NSArray<Slot *> *_children;
|
2021-03-08 23:59:02 +00:00
|
|
|
//NSDictionary *_media;
|
|
|
|
Media _media;
|
|
|
|
NSString *_keyPath;
|
2021-03-10 03:22:24 +00:00
|
|
|
//NSString *_devName;
|
2021-03-08 23:59:02 +00:00
|
|
|
BOOL _default;
|
|
|
|
}
|
|
|
|
|
2021-03-10 03:58:01 +00:00
|
|
|
@property (readonly) NSArray *children;
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
-(instancetype)initWithDictionary: (NSDictionary *)dictionary devices: (NSDictionary *)devices;
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
-(NSMenuItem *)menuItem;
|
|
|
|
|
|
|
|
-(void)reset;
|
|
|
|
|
|
|
|
-(void)setKeyPath: (NSString *)path;
|
|
|
|
-(void)buildArgs: (NSMutableArray *)args;
|
|
|
|
-(void)buildMedia: (Media *)media;
|
|
|
|
-(void)buildSerial: (NSMutableArray *)array;
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
//-(BOOL)loadDeviceSlots: (NSDictionary *)devices;
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation Slot
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
static NSDictionary *IndexMap = nil;
|
|
|
|
+(void)load {
|
|
|
|
|
|
|
|
IndexMap = @{
|
|
|
|
@"ramsize": @0,
|
|
|
|
@"sl0": @1,
|
|
|
|
@"sl1": @2,
|
|
|
|
@"sl2": @3,
|
|
|
|
@"sl3": @4,
|
|
|
|
@"sl4": @5,
|
|
|
|
@"sl5": @6,
|
|
|
|
@"sl6": @7,
|
|
|
|
@"sl7": @8,
|
|
|
|
@"exp": @9,
|
|
|
|
@"aux": @10,
|
|
|
|
@"rs232": @11,
|
|
|
|
@"gameio": @12,
|
|
|
|
@"modem": @13,
|
|
|
|
@"printer": @14,
|
|
|
|
|
|
|
|
//nubus mac
|
|
|
|
@"nb9": @15,
|
|
|
|
@"nba": @16,
|
|
|
|
@"nbb": @17,
|
|
|
|
@"nbc": @18,
|
|
|
|
@"nbd": @19,
|
|
|
|
@"nbe": @20,
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
-(void)reset {
|
|
|
|
[self setSelectedIndex: _defaultIndex >= 0 ? _defaultIndex : 0];
|
|
|
|
for (SlotOption *s in _options) {
|
|
|
|
[s reset];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)selectValue: (NSString *)value {
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
NSInteger index = 0;
|
|
|
|
for (SlotOption *item in _options) {
|
|
|
|
if ([[item value] isEqualToString: value]) {
|
|
|
|
[self setSelectedIndex: index];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//[self setSelectedIndex: _defaultIndex >= 0 ? _defaultIndex : 0];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(SlotOption *)selectedItem {
|
|
|
|
if (_selectedIndex < 0) return nil;
|
|
|
|
return [_options objectAtIndex: _selectedIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSArray *)args {
|
|
|
|
if (_selectedIndex < 0) return nil;
|
|
|
|
NSMutableArray *rv = [NSMutableArray new];
|
|
|
|
SlotOption *option = [_options objectAtIndex: _selectedIndex];
|
|
|
|
|
|
|
|
[option buildArgs: rv];
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSArray *)serialize {
|
|
|
|
if (_selectedIndex < 0) return nil;
|
|
|
|
|
|
|
|
NSMutableArray *array = [NSMutableArray new];
|
|
|
|
SlotOption *option = [_options objectAtIndex: _selectedIndex];
|
|
|
|
[option buildSerial: array];
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(Media)selectedMedia {
|
|
|
|
|
|
|
|
if (_selectedIndex < 0) return EmptyMedia;
|
|
|
|
|
|
|
|
Media media = { 0 };
|
|
|
|
SlotOption *option = [_options objectAtIndex: _selectedIndex];
|
|
|
|
|
|
|
|
[option buildMedia: &media];
|
|
|
|
return media;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-10 03:58:01 +00:00
|
|
|
-(NSArray *)selectedChildren {
|
|
|
|
if (_selectedIndex < 0) return nil;
|
|
|
|
return [[_options objectAtIndex: _selectedIndex] children];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-08 23:59:02 +00:00
|
|
|
-(id)copyWithZone:(NSZone *)zone {
|
|
|
|
|
|
|
|
Slot *child = [Slot new];
|
|
|
|
child->_index = _index;
|
|
|
|
child->_defaultIndex = _defaultIndex;
|
|
|
|
child->_selectedIndex = _selectedIndex;
|
|
|
|
child->_name = [_name copyWithZone: zone];
|
|
|
|
child->_title = [_title copyWithZone: zone];
|
|
|
|
child->_options = DeepCopyArray(_options);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// menu could still be in use by an off-screen pop up button, so it can't be cached.
|
|
|
|
child->_menuItems = DeepCopyArray(_menuItems);
|
|
|
|
// update represented object.
|
|
|
|
NSInteger index = 0;
|
|
|
|
for (NSMenuItem *item in child->_menuItems) {
|
|
|
|
[item setRepresentedObject: child->_options[index]];
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-(void)setKeyPath {
|
|
|
|
if (![_name length]) return;
|
|
|
|
for (SlotOption *o in _options)
|
|
|
|
[o setKeyPath: _name];
|
|
|
|
}
|
|
|
|
-(void)setKeyPath: (NSString *)path {
|
|
|
|
|
|
|
|
NSString *p = [path stringByAppendingString: _name];
|
|
|
|
for (SlotOption *o in _options) {
|
|
|
|
[o setKeyPath: p];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
-(instancetype)initWithDictionary: (NSDictionary *)data devices: (NSDictionary *)devices {
|
|
|
|
|
|
|
|
BOOL topLevel = NO;
|
|
|
|
_selectedIndex = -1;
|
|
|
|
_defaultIndex = -1;
|
|
|
|
_index = -1;
|
|
|
|
|
|
|
|
_name = [data objectForKey: @"name"];
|
|
|
|
_title = [data objectForKey: @"description"];
|
|
|
|
|
|
|
|
NSNumber *x = [IndexMap objectForKey: _name];
|
|
|
|
if (x) {
|
|
|
|
topLevel = YES;
|
|
|
|
_index = [x integerValue];
|
|
|
|
_name = [@"-" stringByAppendingString: _name];
|
|
|
|
_title = [_title stringByAppendingString: @":"];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSArray *op = [data objectForKey: @"options"];
|
|
|
|
NSMutableArray *options = [NSMutableArray arrayWithCapacity: [op count]];
|
|
|
|
|
|
|
|
|
|
|
|
NSInteger index = 0;
|
|
|
|
for (NSDictionary *d in op) {
|
|
|
|
SlotOption *o = [[SlotOption alloc] initWithDictionary: d devices: devices];
|
|
|
|
if ([o isDefault]) {
|
|
|
|
_defaultIndex = index;
|
|
|
|
}
|
|
|
|
++index;
|
2021-03-10 03:58:01 +00:00
|
|
|
if (topLevel) {
|
|
|
|
[o setKeyPath: _name];
|
|
|
|
NSArray *tmp = [o children];
|
|
|
|
for (Slot *x in tmp) {
|
|
|
|
[x setIndex: _index | 0x10000];
|
|
|
|
}
|
|
|
|
}
|
2021-03-10 03:22:24 +00:00
|
|
|
[options addObject: o];
|
|
|
|
}
|
|
|
|
_options = options;
|
|
|
|
|
|
|
|
_selectedIndex = _defaultIndex;
|
|
|
|
if (_selectedIndex < 0) _selectedIndex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
//if (topLevel) [self setKeyPath];
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
2021-03-08 23:59:02 +00:00
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
#if 0
|
2021-03-08 23:59:02 +00:00
|
|
|
-(instancetype)initWithName: (NSString *)name title: (NSString *)title data: (NSArray *)data {
|
|
|
|
|
|
|
|
_name = [name copy];
|
|
|
|
_title = [title copy];
|
|
|
|
_selectedIndex = -1;
|
|
|
|
_defaultIndex = -1;
|
|
|
|
_index = -1;
|
|
|
|
|
|
|
|
NSMutableArray *options = [NSMutableArray arrayWithCapacity: [data count]];
|
|
|
|
//NSMutableArray *menuItems = [NSMutableArray arrayWithCapacity: [data count]];
|
|
|
|
|
|
|
|
NSInteger index = 0;
|
|
|
|
for (NSDictionary *d in data) {
|
|
|
|
SlotOption *o = [[SlotOption alloc] initWithDictionary: d];
|
|
|
|
if ([o isDefault]) {
|
|
|
|
_defaultIndex = index;
|
|
|
|
}
|
|
|
|
++index;
|
|
|
|
[options addObject: o];
|
|
|
|
}
|
|
|
|
_options = options;
|
|
|
|
//_menuItems = menuItems;
|
|
|
|
|
|
|
|
_selectedIndex = _defaultIndex;
|
|
|
|
if (_selectedIndex < 0) _selectedIndex = 0;
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
2021-03-10 03:22:24 +00:00
|
|
|
#endif
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
-(NSArray *)menuItems {
|
|
|
|
//if (_menuItems) return _menuItems;
|
|
|
|
|
|
|
|
NSMutableArray *menuItems = [NSMutableArray arrayWithCapacity: [_options count]];
|
|
|
|
for (SlotOption *o in _options) {
|
|
|
|
[menuItems addObject: [o menuItem]];
|
|
|
|
}
|
|
|
|
//_menuItems = tmp;
|
|
|
|
return menuItems;
|
|
|
|
}
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
#if 0
|
2021-03-08 23:59:02 +00:00
|
|
|
-(void)loadDeviceSlots: (NSDictionary *)devices {
|
|
|
|
for (SlotOption *s in _options) {
|
|
|
|
[s loadDeviceSlots: devices];
|
|
|
|
}
|
|
|
|
}
|
2021-03-10 03:22:24 +00:00
|
|
|
#endif
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
-(void)prepareView: (SlotTableCellView *)view {
|
|
|
|
|
|
|
|
// can't cache the menu items since they
|
|
|
|
// may still be in use.
|
|
|
|
|
|
|
|
NSPopUpButton *button = [view menuButton];
|
|
|
|
NSTextField *text = [view textField];
|
|
|
|
|
|
|
|
[text setObjectValue: _title];
|
|
|
|
[button unbind: @"selectedIndex"];
|
|
|
|
NSMenu *menu = [button menu];
|
|
|
|
NSArray *menuItems = [self menuItems];
|
|
|
|
|
|
|
|
[menu setItemArray: menuItems];
|
|
|
|
[button bind: @"selectedIndex" toObject: self withKeyPath: @"selectedIndex" options: nil];
|
|
|
|
[button setTag: _index];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation SlotOption
|
|
|
|
|
|
|
|
@synthesize isDefault = _default;
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
#if 0
|
2021-03-08 23:59:02 +00:00
|
|
|
-(instancetype)initWithDictionary: (NSDictionary *)dictionary {
|
|
|
|
|
|
|
|
_default = [(NSNumber *)[dictionary objectForKey: @"default"] boolValue];
|
|
|
|
_disabled = [(NSNumber *)[dictionary objectForKey: @"disabled"] boolValue];
|
|
|
|
_value = [dictionary objectForKey: @"value"];
|
2021-03-10 03:22:24 +00:00
|
|
|
//_devName = [dictionary objectForKey: @"devName"];
|
2021-03-08 23:59:02 +00:00
|
|
|
_title = [dictionary objectForKey: @"description"];
|
|
|
|
_media = MediaFromDictionary([dictionary objectForKey: @"media"]);
|
|
|
|
//_media = [dictionary objectForKey: @"media"];
|
|
|
|
return self;
|
|
|
|
}
|
2021-03-10 03:22:24 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
-(instancetype)initWithDictionary: (NSDictionary *)data devices: (NSDictionary *)devices {
|
|
|
|
|
|
|
|
_default = [(NSNumber *)[data objectForKey: @"default"] boolValue];
|
|
|
|
_disabled = [(NSNumber *)[data objectForKey: @"disabled"] boolValue];
|
|
|
|
_value = [data objectForKey: @"value"];
|
|
|
|
_title = [data objectForKey: @"description"];
|
|
|
|
_media = MediaFromDictionary([data objectForKey: @"media"]);
|
|
|
|
|
|
|
|
NSString *devName = [data objectForKey: @"devname"];
|
|
|
|
if (devName && devices) {
|
|
|
|
|
|
|
|
NSArray *tmp = [devices objectForKey: devName];
|
|
|
|
if (tmp) _children = DeepCopyArray(tmp);
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
-(void)reset {
|
|
|
|
for (Slot *s in _children) {
|
|
|
|
[s reset];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-(NSMenuItem *)menuItem {
|
|
|
|
NSMenuItem *item;
|
|
|
|
extern NSAttributedString *ItalicMenuString(NSString *);
|
|
|
|
|
|
|
|
item = [[NSMenuItem alloc] initWithTitle: _title action: NULL keyEquivalent: @""];
|
|
|
|
if (_disabled) {
|
|
|
|
[item setEnabled: NO];
|
|
|
|
}
|
|
|
|
if (_default) {
|
|
|
|
[item setAttributedTitle: ItalicMenuString(_title)];
|
|
|
|
}
|
|
|
|
[item setRepresentedObject: self];
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(id)copyWithZone:(NSZone *)zone {
|
|
|
|
|
|
|
|
SlotOption *child = [SlotOption new];
|
|
|
|
|
|
|
|
child->_default = _default;
|
|
|
|
child->_disabled = _disabled;
|
|
|
|
child->_media = _media;
|
|
|
|
child->_value = [_value copyWithZone: zone];
|
2021-03-10 03:22:24 +00:00
|
|
|
//child->_devName = [_devName copyWithZone: zone];
|
2021-03-08 23:59:02 +00:00
|
|
|
child->_title = [_title copyWithZone: zone];
|
|
|
|
//child->_media = [_media copyWithZone: zone];
|
|
|
|
child->_keyPath = [_keyPath copyWithZone: zone];
|
|
|
|
|
|
|
|
child->_children = DeepCopyArray(_children);
|
|
|
|
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-(void)buildArgs: (NSMutableArray *)args {
|
|
|
|
|
|
|
|
if (!_default) {
|
|
|
|
[args addObject: _keyPath];
|
|
|
|
[args addObject: _value];
|
|
|
|
}
|
|
|
|
for (Slot *s in _children) {
|
|
|
|
[[s selectedItem] buildArgs: args];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)buildMedia: (Media *)media {
|
|
|
|
|
|
|
|
#undef _
|
|
|
|
#define _(name) media->name += _media.name
|
|
|
|
|
|
|
|
_(cass);
|
|
|
|
_(cdrom);
|
|
|
|
_(hard);
|
|
|
|
_(floppy_3_5);
|
|
|
|
_(floppy_5_25);
|
|
|
|
_(pseudo_disk);
|
|
|
|
#undef _
|
|
|
|
|
|
|
|
for (Slot *s in _children) {
|
|
|
|
[[s selectedItem] buildMedia: media];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-(void)buildSerial: (NSMutableArray *)array {
|
|
|
|
|
|
|
|
if (!_default)
|
|
|
|
[array addObject: _keyPath];
|
|
|
|
|
|
|
|
for (Slot *s in _children)
|
|
|
|
[[s selectedItem] buildSerial: array];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// propogate
|
|
|
|
-(void)setKeyPath: (NSString *)path {
|
|
|
|
|
|
|
|
_keyPath = path;
|
|
|
|
if (!_children) return;
|
|
|
|
NSString *p = [path stringByAppendingFormat: @":%@", _value];
|
|
|
|
|
|
|
|
for (Slot *s in _children) {
|
|
|
|
[s setKeyPath: p];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
#if 0
|
2021-03-08 23:59:02 +00:00
|
|
|
-(BOOL)loadDeviceSlots: (NSDictionary *)devices {
|
|
|
|
NSArray *o = [devices objectForKey: _devName];
|
|
|
|
if (!o) return NO;
|
|
|
|
_children = DeepCopyArray(o);
|
|
|
|
return YES;
|
|
|
|
}
|
2021-03-10 03:22:24 +00:00
|
|
|
#endif
|
2021-03-08 23:59:02 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation SlotTableCellView
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
extern NSString *InternString(NSString *);
|
|
|
|
|
|
|
|
NSDictionary *BuildDevices(NSArray *array) {
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static NSCache *cache = nil;
|
|
|
|
|
|
|
|
if (!cache) {
|
|
|
|
cache = [NSCache new];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NSMutableDictionary *rv = [NSMutableDictionary dictionaryWithCapacity: [array count]];
|
|
|
|
for (NSDictionary *d in array) {
|
|
|
|
NSString *name = [d objectForKey: @"name"];
|
|
|
|
NSArray *slots = [d objectForKey: @"slots"];
|
|
|
|
|
|
|
|
if (!name) continue;
|
|
|
|
if (!slots) continue;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
name = InternString(name);
|
|
|
|
id x = [cache objectForKey: name];
|
|
|
|
if (x) {
|
|
|
|
[rv setObject: x forKey: name];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NSArray *data = MapArray(slots, ^(id o){
|
|
|
|
|
|
|
|
Slot *s = [[Slot alloc] initWithDictionary: o devices: nil];
|
|
|
|
return s;
|
|
|
|
});
|
|
|
|
|
|
|
|
[rv setObject: data forKey: name];
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
2021-03-08 23:59:02 +00:00
|
|
|
NSArray *BuildSlots(NSString *name, NSDictionary *data) {
|
|
|
|
|
|
|
|
static NSCache *cache = nil;
|
|
|
|
|
|
|
|
if (!cache) {
|
|
|
|
cache = [NSCache new];
|
|
|
|
}
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
|
2021-03-08 23:59:02 +00:00
|
|
|
name = InternString(name);
|
|
|
|
NSArray *x = [cache objectForKey: name];
|
|
|
|
if (x) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
NSArray *slots = [data objectForKey: @"slots"];
|
|
|
|
|
|
|
|
NSMutableArray *rv = [NSMutableArray arrayWithCapacity: [slots count]];
|
2021-03-08 23:59:02 +00:00
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
NSDictionary *devices = BuildDevices([data objectForKey: @"devices"]);
|
|
|
|
for (NSDictionary *d in slots) {
|
2021-03-08 23:59:02 +00:00
|
|
|
|
2021-03-10 03:22:24 +00:00
|
|
|
Slot *s = [[Slot alloc] initWithDictionary: d devices: devices];
|
2021-03-08 23:59:02 +00:00
|
|
|
[rv addObject: s];
|
|
|
|
}
|
|
|
|
|
|
|
|
[cache setObject: rv forKey: name];
|
|
|
|
return rv;
|
|
|
|
}
|