<commit_before>import 'dart:async';

import "../SBURBSim.dart";
import "../formats/Formats.dart";
import "../includes/path_utils.dart";
import "resource.dart";

export "resource.dart";

abstract class Loader {

    static Map<String, Resource<dynamic>> _resources = <String, Resource<dynamic>>{};

    static void init() {
        Formats.init();
    }

    static Future<T> getResource<T, U>(String path, [FileFormat<U, T> format]) async {
        if (_resources.containsKey(path)) {
            Resource<dynamic> res = _resources[path];
            if (res is Resource<T>) {
                if (res.object != null) {
                    return res.object;
                } else {
                    return res.addListener();
                }
            } else {
                throw "Requested resource ($path) is ${res.object.runtimeType}. Expected $T";
            }
        } else {
            return _load(path, format);
        }
    }

    static Future<T> _load<T, U>(String path, [FileFormat<U, T> format = null]) {
        if(_resources.containsKey(path)) {
            throw "Resource $path has already been requested for loading";
        }

        if (format == null) {
            String extension = path.split(".").last;
            format = Formats.getFormatForExtension(extension);
        }

        Resource<T> res = new Resource<T>(path);
        _resources[path] = res;

        format.requestFromUrl(PathUtils.adjusted(path))..then((T item) => res.populate(item));

        return res.addListener();
    }
}<commit_msg>Remove unnecessary second generic which always ended up dynamic anyway<commit_after>import 'dart:async';

import "../SBURBSim.dart";
import "../formats/Formats.dart";
import "../includes/path_utils.dart";
import "resource.dart";

export "resource.dart";

abstract class Loader {

    static Map<String, Resource<dynamic>> _resources = <String, Resource<dynamic>>{};

    static void init() {
        Formats.init();
    }

    static Future<T> getResource<T>(String path, [FileFormat<dynamic, T> format]) async {
        if (_resources.containsKey(path)) {
            Resource<dynamic> res = _resources[path];
            if (res is Resource<T>) {
                if (res.object != null) {
                    return res.object;
                } else {
                    return res.addListener();
                }
            } else {
                throw "Requested resource ($path) is ${res.object.runtimeType}. Expected $T";
            }
        } else {
            return _load(path, format);
        }
    }

    static Future<T> _load<T>(String path, [FileFormat<dynamic, T> format = null]) {
        if(_resources.containsKey(path)) {
            throw "Resource $path has already been requested for loading";
        }

        if (format == null) {
            String extension = path.split(".").last;
            format = Formats.getFormatForExtension(extension);
        }

        Resource<T> res = new Resource<T>(path);
        _resources[path] = res;

        format.requestFromUrl(PathUtils.adjusted(path))..then((T item) => res.populate(item));

        return res.addListener();
    }
}
{'fraction_non_alphanumeric': 0.134134767478646, 'fraction_numerical': 0.0, 'mean_word_length': 2.106090373280943, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '753619', 'n_tokens_mistral': 900, 'n_tokens_neox': 864, 'n_words': 211}