%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /usr/share/gnome-shell/
Upload File :
Create Path :
Current File : //usr/share/gnome-shell/org.gnome.Extensions.src.gresource

GVariantp(


N
|pv�7�H�.7v@?%��Q�?%vP%-4��0*-4v@4?dVCb�?dLDdLdOq�eLdv`d�lKP��lL�l�l�s�	�lL�l�lԵ�����lL�l�l��$0�lLmm�	��m	vmJm�0IJmLPmdmextensionsWindow.js�import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Shew from 'gi://Shew';

const Package = imports.package;
import * as Gettext from 'gettext';

import * as Config from './misc/config.js';
import {ExtensionRow} from './extensionRow.js';

Gio._promisify(Adw.AlertDialog.prototype, 'choose');
Gio._promisify(Gio.DBusConnection.prototype, 'call');
Gio._promisify(Shew.WindowExporter.prototype, 'export');

export const ExtensionsWindow = GObject.registerClass({
    GTypeName: 'ExtensionsWindow',
    Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
    InternalChildren: [
        'sortModel',
        'searchFilter',
        'userListModel',
        'systemListModel',
        'searchListModel',
        'userGroup',
        'userList',
        'systemGroup',
        'systemList',
        'searchList',
        'mainStack',
        'searchBar',
        'searchEntry',
        'updatesBanner',
    ],
}, class ExtensionsWindow extends Adw.ApplicationWindow {
    _init(params) {
        super._init(params);

        if (Config.PROFILE === 'development')
            this.add_css_class('devel');

        this._exporter = new Shew.WindowExporter({window: this});
        this._exportedHandle = '';

        this.add_action_entries(
            [{
                name: 'show-about',
                activate: () => this._showAbout(),
            }, {
                name: 'logout',
                activate: () => this._logout(),
            }, {
                name: 'user-extensions-enabled',
                state: 'false',
                change_state: (a, state) => {
                    const {extensionManager} = this.application;
                    extensionManager.userExtensionsEnabled = state.get_boolean();
                },
            }]);

        const settings = new Gio.Settings({
            schema_id: 'org.gnome.Extensions',
        });

        settings.bind('window-width',
            this, 'default-width',
            Gio.SettingsBindFlags.DEFAULT);
        settings.bind('window-height',
            this, 'default-height',
            Gio.SettingsBindFlags.DEFAULT);
        settings.bind('window-maximized',
            this, 'maximized',
            Gio.SettingsBindFlags.DEFAULT);

        this._searchEntry.connect('search-changed',
            () => (this._searchFilter.search = this._searchEntry.text));
        this._searchBar.connect('notify::search-mode-enabled',
            () => this._syncVisiblePage());
        this._searchListModel.connect('notify::n-items',
            () => this._syncVisiblePage());

        this._userList.connect('row-activated', (_list, row) => row.activate());
        this._userGroup.connect('notify::visible', () => this._syncVisiblePage());

        this._systemList.connect('row-activated', (_list, row) => row.activate());
        this._systemGroup.connect('notify::visible', () => this._syncVisiblePage());

        const {extensionManager} = this.application;
        extensionManager.connect('notify::failed',
            () => this._syncVisiblePage());
        extensionManager.connect('notify::n-updates',
            () => this._checkUpdates());
        extensionManager.connect('notify::user-extensions-enabled',
            this._onUserExtensionsEnabledChanged.bind(this));
        this._onUserExtensionsEnabledChanged();

        this._sortModel.model = extensionManager.extensions;

        this._userList.bind_model(this._userListModel,
            extension => new ExtensionRow(extension));
        this._systemList.bind_model(this._systemListModel,
            extension => new ExtensionRow(extension));
        this._searchList.bind_model(this._searchListModel,
            extension => new ExtensionRow(extension));

        extensionManager.connect('extensions-loaded',
            () => this._extensionsLoaded());
    }

    async uninstall(extension) {
        const dialog = new Adw.AlertDialog({
            heading: _('Remove “%s”?').format(extension.name),
            body: _('If you remove the extension, you need to return to download it if you want to enable it again'),
        });

        dialog.add_response('cancel', _('_Cancel'));
        dialog.add_response('remove', _('_Remove'));

        dialog.set_response_appearance('remove',
            Adw.ResponseAppearance.DESTRUCTIVE);

        const {extensionManager} = this.application;
        const response = await dialog.choose(this, null);
        if (response === 'remove')
            extensionManager.uninstallExtension(extension.uuid);
    }

    async openPrefs(extension) {
        if (!this._exportedHandle) {
            try {
                this._exportedHandle = await this._exporter.export();
            } catch (e) {
                console.warn(`Failed to export window: ${e.message}`);
            }
        }

        const {extensionManager} = this.application;
        extensionManager.openExtensionPrefs(extension.uuid, this._exportedHandle);
    }

    _showAbout() {
        const [version] = Package.version.split(' ');
        const aboutDialog = Adw.AboutDialog.new_from_appdata(
            '/org/gnome/Extensions/metainfo.xml', version);

        aboutDialog.set({
            developers: [
                'Florian Müllner <fmuellner@gnome.org>',
                'Jasper St. Pierre <jstpierre@mecheye.net>',
                'Didier Roche <didrocks@ubuntu.com>',
                'Romain Vigier <contact@romainvigier.fr>',
            ],
            designers: [
                'Allan Day <allanpday@gmail.com>',
                'Tobias Bernard <tbernard@gnome.org>',
            ],
            translator_credits: _('translator-credits'),
            version: Package.version,
        });
        aboutDialog.present(this);
    }

    _logout() {
        this.application.get_dbus_connection().call(
            'org.gnome.SessionManager',
            '/org/gnome/SessionManager',
            'org.gnome.SessionManager',
            'Logout',
            new GLib.Variant('(u)', [0]),
            null,
            Gio.DBusCallFlags.NONE,
            -1,
            null);
    }

    _onUserExtensionsEnabledChanged() {
        const {userExtensionsEnabled} = this.application.extensionManager;
        const action = this.lookup_action('user-extensions-enabled');
        action.set_state(new GLib.Variant('b', userExtensionsEnabled));
    }

    _syncVisiblePage() {
        const {extensionManager} = this.application;
        const {searchModeEnabled} = this._searchBar;

        if (extensionManager.failed)
            this._mainStack.visible_child_name = 'noshell';
        else if (searchModeEnabled && this._searchListModel.get_n_items() > 0)
            this._mainStack.visible_child_name = 'search';
        else if (searchModeEnabled)
            this._mainStack.visible_child_name = 'noresults';
        else if (this._userGroup.visible || this._systemGroup.visible)
            this._mainStack.visible_child_name = 'main';
        else
            this._mainStack.visible_child_name = 'placeholder';
    }

    _checkUpdates() {
        const {nUpdates} = this.application.extensionManager;

        this._updatesBanner.title = Gettext.ngettext(
            '%d extension will be updated on next login.',
            '%d extensions will be updated on next login.',
            nUpdates).format(nUpdates);
        this._updatesBanner.revealed = nUpdates > 0;
    }

    _extensionsLoaded() {
        this._syncVisiblePage();
        this._checkUpdates();
    }
});
(uuay)main.js�import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';

import {setConsoleLogDomain} from 'console';
const Package = imports.package;

Package.initFormat();

import {ExtensionManager} from './extensionManager.js';
import {ExtensionsWindow} from './extensionsWindow.js';

var Application = GObject.registerClass(
class Application extends Adw.Application {
    _init() {
        GLib.set_prgname('gnome-extensions-app');
        super._init({
            application_id: Package.name,
            version: Package.version,
        });

        this.connect('window-removed', (a, window) => window.run_dispose());
    }

    get extensionManager() {
        return this._extensionManager;
    }

    vfunc_activate() {
        this._extensionManager.checkForUpdates();
        this._window.present();
    }

    vfunc_startup() {
        super.vfunc_startup();

        this.add_action_entries(
            [{
                name: 'quit',
                activate: () => this._window.close(),
            }]);

        this.set_accels_for_action('app.quit', ['<Primary>q']);

        this._extensionManager = new ExtensionManager();

        this._window = new ExtensionsWindow({application: this});
    }
});

/**
 * Main entrypoint for the app
 *
 * @param {string[]} argv - command line arguments
 * @returns {void}
 */
export async function main(argv) {
    Package.initGettext();
    setConsoleLogDomain('Extensions');

    await new Application().runAsync(argv);
}
(uuay)extensionRow.js�import Adw from 'gi://Adw?version=1';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';

import {ExtensionState}  from './misc/extensionUtils.js';
import {Extension} from './extensionManager.js';

export const ExtensionRow = GObject.registerClass({
    GTypeName: 'ExtensionRow',
    Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
    Properties: {
        'extension': GObject.ParamSpec.object(
            'extension', null, null,
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
            Extension),
    },
    InternalChildren: [
        'detailsPopover',
        'versionLabel',
        'switch',
        'actionsBox',
    ],
}, class ExtensionRow extends Adw.ActionRow {
    constructor(extension) {
        super({extension});

        this._app = Gio.Application.get_default();

        this._actionGroup = new Gio.SimpleActionGroup();
        this.insert_action_group('row', this._actionGroup);

        const actionEntries = [
            {
                name: 'show-prefs',
                activate: () => {
                    this._detailsPopover.popdown();
                    this.get_root().openPrefs(extension);
                },
                enabledProp: 'has-prefs',
            }, {
                name: 'show-url',
                activate: () => {
                    this._detailsPopover.popdown();
                    Gio.AppInfo.launch_default_for_uri(
                        extension.url, this.get_display().get_app_launch_context());
                },
                enabledProp: 'url',
                enabledTransform: s => s !== '',
            }, {
                name: 'uninstall',
                activate: () => {
                    this._detailsPopover.popdown();
                    this.get_root().uninstall(extension).catch(logError);
                },
                enabledProp: 'is-user',
            },
        ];
        this._actionGroup.add_action_entries(actionEntries);
        this._bindActionEnabled(actionEntries);

        this._switch.connect('state-set', (sw, state) => {
            const {uuid, enabled} = this._extension;
            if (enabled === state)
                return true;

            if (state)
                this._app.extensionManager.enableExtension(uuid);
            else
                this._app.extensionManager.disableExtension(uuid);
            return true;
        });

        this._extension.bind_property_full('state',
            this._switch, 'state',
            GObject.BindingFlags.SYNC_CREATE,
            (bind, source) => [true, source === ExtensionState.ACTIVE],
            null);

        this._extension.bind_property_full('version',
            this._versionLabel, 'label',
            GObject.BindingFlags.SYNC_CREATE,
            (bind, source) => [true, _('Version %s').format(source)],
            null);
    }

    get extension() {
        return this._extension ?? null;
    }

    set extension(ext) {
        this._extension = ext;
    }

    _bindActionEnabled(entries) {
        for (const entry of entries) {
            const {name, enabledProp, enabledTransform} = entry;
            if (!enabledProp)
                continue;

            const action = this._actionGroup.lookup_action(name);
            if (enabledTransform) {
                this._extension.bind_property_full(enabledProp,
                    action, 'enabled',
                    GObject.BindingFlags.SYNC_CREATE,
                    (bind, source) => [true, enabledTransform(source)],
                    null);
            } else {
                this._extension.bind_property(enabledProp,
                    action, 'enabled',
                    GObject.BindingFlags.SYNC_CREATE);
            }
        }
    }
});
(uuay)extensionManager.js�/import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';

import {
    ExtensionState, ExtensionType, deserializeExtension
}  from './misc/extensionUtils.js';

const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);

let shellVersion;

function loadInterfaceXML(iface) {
    const uri = `resource:///org/gnome/Extensions/dbus-interfaces/${iface}.xml`;
    const f = Gio.File.new_for_uri(uri);

    try {
        let [ok_, bytes] = f.load_contents(null);
        return new TextDecoder().decode(bytes);
    } catch (e) {
        console.error(`Failed to load D-Bus interface ${iface}`);
    }

    return null;
}

const Extension = GObject.registerClass({
    GTypeName: 'Extension',
    Properties: {
        'uuid': GObject.ParamSpec.string(
            'uuid', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'name': GObject.ParamSpec.string(
            'name', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'description': GObject.ParamSpec.string(
            'description', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'state': GObject.ParamSpec.int(
            'state', null, null,
            GObject.ParamFlags.READABLE,
            1, 99, ExtensionState.INITIALIZED),
        'enabled': GObject.ParamSpec.boolean(
            'enabled', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'creator': GObject.ParamSpec.string(
            'creator', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'url': GObject.ParamSpec.string(
            'url', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'version': GObject.ParamSpec.string(
            'version', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'error': GObject.ParamSpec.string(
            'error', null, null,
            GObject.ParamFlags.READABLE,
            ''),
        'has-error': GObject.ParamSpec.boolean(
            'has-error', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'has-prefs': GObject.ParamSpec.boolean(
            'has-prefs', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'has-update': GObject.ParamSpec.boolean(
            'has-update', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'has-version': GObject.ParamSpec.boolean(
            'has-version', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'can-change': GObject.ParamSpec.boolean(
            'can-change', null, null,
            GObject.ParamFlags.READABLE,
            false),
        'is-user': GObject.ParamSpec.boolean(
            'is-user', null, null,
            GObject.ParamFlags.READABLE,
            false),
    },
}, class Extension extends GObject.Object {
    constructor(variant) {
        super();
        this.update(variant);
    }

    update(variant) {
        const deserialized = deserializeExtension(variant);

        const {
            uuid, type, state, enabled, error, hasPrefs, hasUpdate, canChange, metadata,
        } = deserialized;

        if (!this._uuid)
            this._uuid = uuid;

        if (this._uuid !== uuid)
            throw new Error(`Invalid update of extension ${this._uuid} with data from ${uuid}`);

        this.freeze_notify();

        const {name} = metadata;
        if (this._name !== name) {
            this._name = name;
            this.notify('name');
        }

        const [desc] = metadata.description.split('\n');
        if (this._description !== desc) {
            this._description = desc;
            this.notify('description');
        }

        if (this._type !== type) {
            this._type = type;
            this.notify('is-user');
        }

        if (this._errorDetail !== error) {
            this._errorDetail = error;
            this.notify('error');
        }

        if (this._enabled !== enabled) {
            this._enabled = enabled;
            this.notify('enabled');
        }

        if (this._state !== state) {
            const hadError = this.hasError;
            this._state = state;
            this.notify('state');

            // Compat with older shell versions
            if (this._enabled === undefined)
                this.notify('enabled');

            if (this.hasError !== hadError) {
                this.notify('has-error');
                this.notify('error');
            }
        }

        const creator = metadata.creator ?? '';
        if (this._creator !== creator) {
            this._creator = creator;
            this.notify('creator');
        }

        const url = metadata.url ?? '';
        if (this._url !== url) {
            this._url = url;
            this.notify('url');
        }

        const version = String(
            metadata['version-name'] || metadata['version'] || '');
        if (this._version !== version) {
            this._version = version;
            this.notify('version');
            this.notify('has-version');
        }

        if (this._hasPrefs !== hasPrefs) {
            this._hasPrefs = hasPrefs;
            this.notify('has-prefs');
        }

        if (this._hasUpdate !== hasUpdate) {
            this._hasUpdate = hasUpdate;
            this.notify('has-update');
        }

        if (this._canChange !== canChange) {
            this._canChange = canChange;
            this.notify('can-change');
        }

        this.thaw_notify();
    }

    get uuid() {
        return this._uuid;
    }

    get name() {
        return this._name;
    }

    get description() {
        return this._description;
    }

    get state() {
        return this._state;
    }

    get enabled() {
        // Compat with older shell versions
        if (this._enabled === undefined) {
            return this.state === ExtensionState.ACTIVE ||
                   this.state === ExtensionState.ACTIVATING;
        }

        return this._enabled;
    }

    get creator() {
        return this._creator;
    }

    get url() {
        return this._url;
    }

    get version() {
        return this._version;
    }

    get error() {
        if (!this.hasError)
            return '';

        if (this.state === ExtensionState.OUT_OF_DATE) {
            return this.version !== ''
                ? _('The installed version of this extension (%s) is incompatible with the current version of GNOME (%s). The extension has been disabled.').format(this.version, shellVersion)
                : _('The installed version of this extension is incompatible with the current version of GNOME (%s). The extension has been disabled.').format(shellVersion);
        }

        const message = [
            _('An error has occurred in this extension. This could cause issues elsewhere in the system. It is recommended to turn the extension off until the error is resolved.'),
        ];

        if (this._errorDetail) {
            message.push(
                // translators: Details for an extension error
                _('Error details:'), this._errorDetail);
        }

        return message.join('\n\n');
    }

    get hasError() {
        return this.state === ExtensionState.OUT_OF_DATE ||
               this.state === ExtensionState.ERROR;
    }

    get hasPrefs() {
        return this._hasPrefs;
    }

    get hasUpdate() {
        return this._hasUpdate;
    }

    get hasVersion() {
        return this._version !== '';
    }

    get canChange() {
        return this._canChange;
    }

    get isUser() {
        return this._type === ExtensionType.PER_USER;
    }
});
const {$gtype: TYPE_EXTENSION} = Extension;
export {TYPE_EXTENSION as Extension};

export const ExtensionManager = GObject.registerClass({
    Properties: {
        'user-extensions-enabled': GObject.ParamSpec.boolean(
            'user-extensions-enabled', null, null,
            GObject.ParamFlags.READWRITE,
            true),
        'extensions': GObject.ParamSpec.object(
            'extensions', null, null,
            GObject.ParamFlags.READABLE,
            Gio.ListModel),
        'n-updates': GObject.ParamSpec.int(
            'n-updates', null, null,
            GObject.ParamFlags.READABLE,
            0, 999, 0),
        'failed': GObject.ParamSpec.boolean(
            'failed', null, null,
            GObject.ParamFlags.READABLE,
            false),
    },
    Signals: {
        'extensions-loaded': {},
    },
}, class ExtensionManager extends GObject.Object {
    constructor() {
        super();

        this._extensions = new Gio.ListStore({itemType: Extension});

        this._proxyReady = false;
        this._shellProxy = new GnomeShellProxy(Gio.DBus.session,
            'org.gnome.Shell.Extensions', '/org/gnome/Shell/Extensions',
            () => {
                this._proxyReady = true;
                shellVersion = this._shellProxy.ShellVersion;

                this._shellProxy.connect('notify::g-name-owner',
                    () => this.notify('failed'));
                this.notify('failed');
            });

        this._shellProxy.connect('g-properties-changed', (proxy, properties) => {
            const enabledChanged = !!properties.lookup_value('UserExtensionsEnabled', null);
            if (enabledChanged)
                this.notify('user-extensions-enabled');
        });
        this._shellProxy.connectSignal(
            'ExtensionStateChanged', this._onExtensionStateChanged.bind(this));

        this._loadExtensions().catch(console.error);
    }

    get extensions() {
        return this._extensions;
    }

    get userExtensionsEnabled() {
        return this._shellProxy.UserExtensionsEnabled ?? false;
    }

    set userExtensionsEnabled(enabled) {
        this._shellProxy.UserExtensionsEnabled = enabled;
    }

    get nUpdates() {
        let nUpdates = 0;
        for (const ext of this._extensions) {
            if (ext.isUser && ext.hasUpdate)
                nUpdates++;
        }
        return nUpdates;
    }

    get failed() {
        return this._proxyReady && this._shellProxy.gNameOwner === null;
    }

    enableExtension(uuid) {
        this._shellProxy.EnableExtensionAsync(uuid).catch(console.error);
    }

    disableExtension(uuid) {
        this._shellProxy.DisableExtensionAsync(uuid).catch(console.error);
    }

    uninstallExtension(uuid) {
        this._shellProxy.UninstallExtensionAsync(uuid).catch(console.error);
    }

    openExtensionPrefs(uuid, parentHandle) {
        this._shellProxy.OpenExtensionPrefsAsync(uuid,
            parentHandle,
            {modal: new GLib.Variant('b', true)}).catch(console.error);
    }

    checkForUpdates() {
        this._shellProxy.CheckForUpdatesAsync().catch(console.error);
    }

    async _loadExtensions() {
        const [extensionsMap] = await this._shellProxy.ListExtensionsAsync();

        for (let uuid in extensionsMap) {
            const extension = new Extension(extensionsMap[uuid]);
            this._extensions.append(extension);
        }
        this.emit('extensions-loaded');
    }

    _findExtension(uuid) {
        const len = this._extensions.get_n_items();
        for (let pos = 0; pos < len; pos++) {
            const extension = this._extensions.get_item(pos);
            if (extension.uuid === uuid)
                return [extension, pos];
        }

        return [null, -1];
    }

    _onExtensionStateChanged(p, sender, [uuid, newState]) {
        const [extension, pos] = this._findExtension(uuid);

        if (extension)
            extension.update(newState);

        if (!extension)
            this._extensions.append(new Extension(newState));
        else if (extension.state === ExtensionState.UNINSTALLED)
            this._extensions.remove(pos);

        if (this._updatesCheckId)
            return;

        this._updatesCheckId = GLib.timeout_add_seconds(
            GLib.PRIORITY_DEFAULT, 1, () => {
                this.notify('n-updates');

                delete this._updatesCheckId;
                return GLib.SOURCE_REMOVE;
            });
    }
});
(uuay)misc/
extensionUtils.jsk// Common utils for the extension system, the extensions D-Bus service
// and the Extensions app

import Gio from 'gi://Gio';
import GLib from 'gi://GLib';

export const ExtensionType = {
    SYSTEM: 1,
    PER_USER: 2,
};

/**
 * @enum {number}
 */
export const ExtensionState = {
    ACTIVE: 1,
    INACTIVE: 2,
    ERROR: 3,
    OUT_OF_DATE: 4,
    DOWNLOADING: 5,
    INITIALIZED: 6,
    DEACTIVATING: 7,
    ACTIVATING: 8,

    // Used as an error state for operations on unknown extensions,
    // should never be in a real extensionMeta object.
    UNINSTALLED: 99,
};

const SERIALIZED_PROPERTIES = [
    'type',
    'state',
    'enabled',
    'path',
    'error',
    'hasPrefs',
    'hasUpdate',
    'canChange',
];

/**
 * Serialize extension into an object that can be used
 * in a vardict {GLib.Variant}
 *
 * @param {object} extension - an extension object
 * @returns {object}
 */
export function serializeExtension(extension) {
    let obj = {...extension.metadata};

    SERIALIZED_PROPERTIES.forEach(prop => {
        obj[prop] = extension[prop];
    });

    let res = {};
    for (let key in obj) {
        let val = obj[key];
        let type;
        switch (typeof val) {
        case 'string':
            type = 's';
            break;
        case 'number':
            type = 'd';
            break;
        case 'boolean':
            type = 'b';
            break;
        default:
            continue;
        }
        res[key] = GLib.Variant.new(type, val);
    }

    return res;
}

/**
 * Deserialize an unpacked variant into an extension object
 *
 * @param {object} variant - an unpacked {GLib.Variant}
 * @returns {object}
 */
export function deserializeExtension(variant) {
    let res = {metadata: {}};
    for (let prop in variant) {
        let val = variant[prop].unpack();
        if (SERIALIZED_PROPERTIES.includes(prop))
            res[prop] = val;
        else
            res.metadata[prop] = val;
    }
    // add the 2 additional properties to create a valid extension object, as createExtensionObject()
    res.uuid = res.metadata.uuid;
    res.dir = Gio.File.new_for_path(res.path);
    return res;
}
(uuay)org/	Extensions//gnome/config.js"export const PROFILE = 'default';
(uuay)js/

Zerion Mini Shell 1.0