protected static function scanAddon($dir) {
        $dir = rtrim($dir, '/');
        $addon_key = strtolower(basename($dir));

        // Look for the addon info array.
        $info_path = $dir.'/addon.json';
        $info = false;
        if (file_exists($info_path)) {
            $info = json_decode(file_get_contents($info_path), true);
        }
        if (!$info) {
            $info = array();
        }
        array_touch('name', $info, $addon_key);
        array_touch('version', $info, '0.0');

        // Look for the bootstrap.
        $bootstrap = $dir.'/bootstrap.php';
        if (!file_exists($dir.'/bootstrap.php')) {
            $bootstrap = null;
        }

        // Scan the appropriate subdirectories  for classes.
        $subdirs = array('', '/library', '/controllers', '/models', '/modules', '/settings');
        $classes = array();
        foreach ($subdirs as $subdir) {
            // Get all of the php files in the subdirectory.
            $paths = glob($dir.$subdir.'/*.php');
            foreach ($paths as $path) {
                $decls = static::scanFile($path);
                foreach ($decls as $namespace_row) {
                    if (isset($namespace_row['namespace']) && $namespace_row) {
                        $namespace = rtrim($namespace_row['namespace'], '\\').'\\';
                        $namespace_classes = $namespace_row['classes'];
                    } else {
                        $namespace = '';
                        $namespace_classes = $namespace_row;
                    }

                    foreach ($namespace_classes as $class_row) {
                        $classes[strtolower($class_row['name'])] = [$namespace.$class_row['name'], $path];
                    }
                }
            }
        }

        $addon = array(
            self::K_BOOTSTRAP => $bootstrap,
            self::K_CLASSES => $classes,
            self::K_DIR => $dir,
            self::K_INFO => $info
        );

        return array($addon_key, $addon);
    }