/** * @dataProvider getKeys */ public function testKeys($key, $value, $method = null, $expectedValue = null) { $this->packageExpects('get' . ucfirst($method ?: $key), $value); $this->packageExpects('isAbandoned', $value); $config = $this->dumper->dump($this->package); $this->assertSame($expectedValue ?: $value, $config[$key]); }
function CreatePackageJson() { $extensionData = ExtensionData::get(); $count = 0; if ($extensionData && !empty($extensionData)) { $count = $extensionData->Count(); $filename = 'packages.json'; $repo = array('packages' => array()); foreach ($extensionData as $extension) { // Include only Approved extensions if ($extension->Accepted == '1') { $json = new JsonHandler($extension->Url); $jsonData = $json->cloneJson(); $packages = $jsonData['AllRelease']; $dumper = new ArrayDumper(); foreach ($packages as $package) { $repo['packages'][$package->getPrettyName()][$package->getPrettyVersion()] = $dumper->dump($package); } } } if (!empty($repo['packages'])) { $packagesJsonData = Convert::array2json($repo); $packageJsonFile = fopen(BASE_PATH . DIRECTORY_SEPARATOR . $filename, 'w'); fwrite($packageJsonFile, $packagesJsonData); fclose($packageJsonFile); echo "<br /><br /><strong> package.json file created successfully...</strong><br />"; } else { throw new InvalidArgumentException('package.json file could not be created'); } } }
/** * {@inheritdoc} */ public function init() { // Retrieve the configuration variables. $this->config = $this->composer->getConfig(); if (isset($this->config)) { if ($this->config->has('component-dir')) { $this->componentDir = $this->config->get('component-dir'); } } // Get the available packages. $locker = $this->composer->getLocker(); if (isset($locker)) { $lockData = $locker->getLockData(); $this->packages = isset($lockData['packages']) ? $lockData['packages'] : array(); // Also merge in any of the development packages. $dev = isset($lockData['packages-dev']) ? $lockData['packages-dev'] : array(); foreach ($dev as $package) { $this->packages[] = $package; } } // Add the root package to the packages list. $root = $this->composer->getPackage(); if ($root) { $dumper = new ArrayDumper(); $package = $dumper->dump($root); $package['is-root'] = true; $this->packages[] = $package; } return true; }
public function testParseDump() { $config = array('name' => 'A/B', 'version' => '1.2.3', 'version_normalized' => '1.2.3.0', 'description' => 'Foo bar', 'type' => 'library', 'keywords' => array('a', 'b', 'c'), 'homepage' => 'http://example.com', 'license' => array('MIT', 'GPLv3'), 'authors' => array(array('name' => 'Bob', 'email' => '*****@*****.**', 'homepage' => 'example.org', 'role' => 'Developer')), 'require' => array('foo/bar' => '1.0'), 'require-dev' => array('foo/baz' => '1.0'), 'replace' => array('foo/qux' => '1.0'), 'conflict' => array('foo/quux' => '1.0'), 'provide' => array('foo/quuux' => '1.0'), 'autoload' => array('psr-0' => array('Ns\\Prefix' => 'path'), 'classmap' => array('path', 'path2')), 'include-path' => array('path3', 'path4'), 'target-dir' => 'some/prefix', 'extra' => array('random' => array('things' => 'of', 'any' => 'shape')), 'bin' => array('bin1', 'bin/foo'), 'archive' => array('exclude' => array('/foo/bar', 'baz', '!/foo/bar/baz')), 'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem'))); $package = $this->loader->load($config); $dumper = new ArrayDumper(); $this->assertEquals($config, $dumper->dump($package)); }
public function init() { // Display a status update to the user. $message = $this->getMessage(); if (!empty($message)) { $this->io->write($message); } // Retrieve the configuration variables. $this->config = $this->composer->getConfig(); if (isset($this->config)) { if ($this->config->has('component-dir')) { $this->componentDir = $this->config->get('component-dir'); } } // Get the available packages. $locker = $this->composer->getLocker(); if (isset($locker)) { $lockData = $locker->getLockData(); $this->packages = isset($lockData['packages']) ? $lockData['packages'] : array(); } // Add the root package to the packages list. $root = $this->composer->getPackage(); if ($root) { $dumper = new ArrayDumper(); $package = $dumper->dump($root); $package['is-root'] = true; $this->packages[] = $package; } return true; }
/** * Writes writable repository. */ public function write() { $data = array(); $dumper = new ArrayDumper(); foreach ($this->getCanonicalPackages() as $package) { $data[] = $dumper->dump($package); } $this->file->write($data); }
/** * Writes writable repository. */ public function write() { $packages = array(); $dumper = new ArrayDumper(); foreach ($this->getPackages() as $package) { $packages[] = $dumper->dump($package); } $this->file->write($packages); }
/** * Writes writable repository. */ public function write() { $packages = array(); $dumper = new ArrayDumper(); foreach ($this->getPackages() as $package) { if (!$package instanceof AliasPackage) { $data = $dumper->dump($package); $packages[] = $data; } } $this->file->write($packages); }
/** * Writes writable repository. */ public function write() { $packages = array(); $dumper = new ArrayDumper(); foreach ($this->getPackages() as $package) { $data = $dumper->dump($package); if ($this instanceof InstalledRepositoryInterface && $package->isInstalledAsAlias()) { $data['installed-as-alias'] = true; } $packages[] = $data; } $this->file->write($packages); }
/** * Writes includes JSON Files. * * @param array $packages List of packages to dump * * @return string $filenameWithHash Includes JSON file name */ private function dumpPackageIncludeJson(array $packages) { $repo = array('packages' => array()); $dumper = new ArrayDumper(); foreach ($packages as $package) { $repo['packages'][$package->getName()][$package->getPrettyVersion()] = $dumper->dump($package); } $repoJson = new JsonFile($this->filenamePrefix); $repoJson->write($repo); $hash = hash_file('sha1', $this->filenamePrefix); $filenameWithHash = $this->filenamePrefix . '$' . $hash . '.json'; rename($this->filenamePrefix, $filenameWithHash); $this->output->writeln("<info>wrote packages json {$filenameWithHash}</info>"); return $filenameWithHash; }
/** * Given a concrete version, this returns a ~ constraint (when possible) * that should be used, for example, in composer.json. * * For example: * * 1.2.1 -> ~1.2 * * 1.2 -> ~1.2 * * v3.2.1 -> ~3.2 * * 2.0-beta.1 -> ~2.0@beta * * dev-master -> ~2.1@dev (dev version with alias) * * dev-master -> dev-master (dev versions are untouched) * * @param PackageInterface $package * @return string */ public function findRecommendedRequireVersion(PackageInterface $package) { $version = $package->getVersion(); if (!$package->isDev()) { return $this->transformVersion($version, $package->getPrettyVersion(), $package->getStability()); } $loader = new ArrayLoader($this->getParser()); $dumper = new ArrayDumper(); $extra = $loader->getBranchAlias($dumper->dump($package)); if ($extra) { $extra = preg_replace('{^(\\d+\\.\\d+\\.\\d+)(\\.9999999)-dev$}', '$1.0', $extra, -1, $count); if ($count) { $extra = str_replace('.9999999', '.0', $extra); return $this->transformVersion($extra, $extra, 'dev'); } } return $package->getPrettyVersion(); }
/** * Writes includes JSON Files. * * @param array $packages List of packages to dump * * @return array Definition of "includes" block for packages.json */ private function dumpPackageIncludeJson(array $packages) { $repo = array('packages' => array()); $dumper = new ArrayDumper(); foreach ($packages as $package) { $repo['packages'][$package->getName()][$package->getPrettyVersion()] = $dumper->dump($package); } // dump to temporary file $tempFilename = $this->outputDir . '/$include.json'; $repoJson = new JsonFile($tempFilename); $repoJson->write($repo); // rename file accordingly $includeFileHash = hash_file('sha1', $tempFilename); $includeFileName = str_replace('{sha1}', $includeFileHash, $this->includeFileName); $fs = new Filesystem(); $fs->ensureDirectoryExists(dirname($this->outputDir . '/' . $includeFileName)); $fs->rename($tempFilename, $this->outputDir . '/' . $includeFileName); $this->output->writeln("<info>Wrote packages json {$includeFileName}</info>"); $includes = array($includeFileName => array('sha1' => $includeFileHash)); return $includes; }
/** * {@inheritdoc} */ public function init() { // Retrieve the configuration variables. $this->config = $this->composer->getConfig(); if (isset($this->config)) { if ($this->config->has('component-dir')) { $this->componentDir = $this->config->get('component-dir'); } } // Get the available packages. $allPackages = array(); $locker = $this->composer->getLocker(); if (isset($locker)) { $lockData = $locker->getLockData(); $allPackages = isset($lockData['packages']) ? $lockData['packages'] : array(); // Also merge in any of the development packages. $dev = isset($lockData['packages-dev']) ? $lockData['packages-dev'] : array(); foreach ($dev as $package) { $allPackages[] = $package; } } // Only add those packages that we can reasonably // assume are components into our packages list foreach ($allPackages as $package) { $extra = isset($package['extra']) ? $package['extra'] : array(); if (isset($extra['component']) && is_array($extra['component'])) { $this->packages[] = $package; } } // Add the root package to the packages list. $root = $this->composer->getPackage(); if ($root) { $dumper = new ArrayDumper(); $package = $dumper->dump($root); $package['is-root'] = true; $this->packages[] = $package; } return true; }
/** * Builds the JSON stuff of the repository. * * @param \Composer\Package\PackageInterface[] $packages List of packages to dump */ public function dump(array $packages) { $packagesByName = []; $dumper = new ArrayDumper(); foreach ($packages as $package) { $packagesByName[$package->getName()][$package->getPrettyVersion()] = $dumper->dump($package); } $repo = ['packages' => []]; if (isset($this->config['providers']) && $this->config['providers']) { $providersUrl = 'p/%package%$%hash%.json'; if (!empty($this->config['homepage'])) { $repo['providers-url'] = parse_url(rtrim($this->config['homepage'], '/'), PHP_URL_PATH) . '/' . $providersUrl; } else { $repo['providers-url'] = $providersUrl; } $repo['providers'] = []; $i = 1; // Give each version a unique ID foreach ($packagesByName as $packageName => $versionPackages) { foreach ($versionPackages as $version => $versionPackage) { $packagesByName[$packageName][$version]['uid'] = $i++; } } // Dump the packages along with packages they're replaced by foreach ($packagesByName as $packageName => $versionPackages) { $dumpPackages = $this->findReplacements($packagesByName, $packageName); $dumpPackages[$packageName] = $versionPackages; $includes = $this->dumpPackageIncludeJson($dumpPackages, str_replace('%package%', $packageName, $providersUrl), 'sha256'); $repo['providers'][$packageName] = current($includes); } } else { $repo['includes'] = $this->dumpPackageIncludeJson($packagesByName, $this->includeFileName); } $this->dumpPackagesJson($repo); $this->pruneIncludeDirectories(); }
/** * {@inheritdoc} */ public function init() { // Retrieve the configuration variables. $this->config = $this->composer->getConfig(); if (isset($this->config)) { if ($this->config->has('component-dir')) { $this->componentDir = $this->config->get('component-dir'); } } // Get the available packages. $allPackages = array(); /** @var \Composer\Package\Locker $locker */ $locker = $this->composer->getLocker(); if ($locker !== null && $locker->isLocked()) { $lockData = $locker->getLockData(); $allPackages = $lockData['packages']; // Also merge in any of the development packages. $dev = isset($lockData['packages-dev']) ? $lockData['packages-dev'] : array(); foreach ($dev as $package) { $allPackages[] = $package; } } // Only add those packages that we can reasonably // assume are components into our packages list /** @var \Composer\Package\RootPackageInterface $rootPackage */ $rootPackage = $this->composer->getPackage(); $rootExtras = $rootPackage ? $rootPackage->getExtra() : array(); $customComponents = isset($rootExtras['component']) ? $rootExtras['component'] : array(); foreach ($allPackages as $package) { $name = $package['name']; if (isset($customComponents[$name]) && is_array($customComponents[$name])) { $package['extra'] = array('component' => $customComponents[$name]); $this->packages[] = $package; } else { $extra = isset($package['extra']) ? $package['extra'] : array(); if (isset($extra['component']) && is_array($extra['component'])) { $this->packages[] = $package; } } } // Add the root package to the packages list. $root = $this->composer->getPackage(); if ($root) { $dumper = new ArrayDumper(); $package = $dumper->dump($root); $package['is-root'] = true; $this->packages[] = $package; } return true; }
private function dumpJson(array $packages, OutputInterface $output, $filename) { $repo = array('packages' => array()); $dumper = new ArrayDumper(); foreach ($packages as $package) { $repo['packages'][$package->getPrettyName()][$package->getPrettyVersion()] = $dumper->dump($package); } $output->writeln('<info>Writing packages.json</info>'); $repoJson = new JsonFile($filename); $repoJson->write($repo); }
protected function execute(InputInterface $input, OutputInterface $output) { // init repos $composer = $this->getComposer(); $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $installedRepo = $composer->getRepositoryManager()->getLocalRepository(); $dm = $composer->getDownloadManager(); $im = $composer->getInstallationManager(); // Dispatch pre-status-command $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true); $errors = array(); $io = $this->getIO(); $unpushedChanges = array(); $vcsVersionChanges = array(); $parser = new VersionParser(); $guesser = new VersionGuesser($composer->getConfig(), new ProcessExecutor($io), $parser); $dumper = new ArrayDumper(); // list packages foreach ($installedRepo->getCanonicalPackages() as $package) { $downloader = $dm->getDownloaderForInstalledPackage($package); $targetDir = $im->getInstallPath($package); if ($downloader instanceof ChangeReportInterface) { if (is_link($targetDir)) { $errors[$targetDir] = $targetDir . ' is a symbolic link.'; } if ($changes = $downloader->getLocalChanges($package, $targetDir, true)) { $errors[$targetDir] = $changes; } } if ($downloader instanceof VcsCapableDownloaderInterface) { if ($currentRef = $downloader->getVcsReference($package, $targetDir)) { switch ($package->getInstallationSource()) { case 'source': $previousRef = $package->getSourceReference(); break; case 'dist': $previousRef = $package->getDistReference(); break; default: $previousRef = null; } $currentVersion = $guesser->guessVersion($dumper->dump($package), $targetDir); if ($previousRef && $currentVersion && $currentVersion['commit'] !== $previousRef) { $vcsVersionChanges[$targetDir] = array('previous' => array('version' => $package->getPrettyVersion(), 'ref' => $previousRef), 'current' => array('version' => $currentVersion['pretty_version'], 'ref' => $currentVersion['commit'])); } } } if ($downloader instanceof DvcsDownloaderInterface) { if ($unpushed = $downloader->getUnpushedChanges($package, $targetDir)) { $unpushedChanges[$targetDir] = $unpushed; } } } // output errors/warnings if (!$errors && !$unpushedChanges && !$vcsVersionChanges) { $io->writeError('<info>No local changes</info>'); return 0; } if ($errors) { $io->writeError('<error>You have changes in the following dependencies:</error>'); foreach ($errors as $path => $changes) { if ($input->getOption('verbose')) { $indentedChanges = implode("\n", array_map(function ($line) { return ' ' . ltrim($line); }, explode("\n", $changes))); $io->write('<info>' . $path . '</info>:'); $io->write($indentedChanges); } else { $io->write($path); } } } if ($unpushedChanges) { $io->writeError('<warning>You have unpushed changes on the current branch in the following dependencies:</warning>'); foreach ($unpushedChanges as $path => $changes) { if ($input->getOption('verbose')) { $indentedChanges = implode("\n", array_map(function ($line) { return ' ' . ltrim($line); }, explode("\n", $changes))); $io->write('<info>' . $path . '</info>:'); $io->write($indentedChanges); } else { $io->write($path); } } } if ($vcsVersionChanges) { $io->writeError('<warning>You have version variations in the following dependencies:</warning>'); foreach ($vcsVersionChanges as $path => $changes) { if ($input->getOption('verbose')) { // If we don't can't find a version, use the ref instead. $currentVersion = $changes['current']['version'] ?: $changes['current']['ref']; $previousVersion = $changes['previous']['version'] ?: $changes['previous']['ref']; if ($io->isVeryVerbose()) { // Output the ref regardless of whether or not it's being used as the version $currentVersion .= sprintf(' (%s)', $changes['current']['ref']); $previousVersion .= sprintf(' (%s)', $changes['previous']['ref']); } $io->write('<info>' . $path . '</info>:'); $io->write(sprintf(' From <comment>%s</comment> to <comment>%s</comment>', $previousVersion, $currentVersion)); } else { $io->write($path); } } } if (($errors || $unpushedChanges || $vcsVersionChanges) && !$input->getOption('verbose')) { $io->writeError('Use --verbose (-v) to see a list of files'); } // Dispatch post-status-command $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true); return ($errors ? self::EXIT_CODE_ERRORS : 0) + ($unpushedChanges ? self::EXIT_CODE_UNPUSHED_CHANGES : 0) + ($vcsVersionChanges ? self::EXIT_CODE_VERSION_CHANGES : 0); }
/** * Extracts the dev packages out of the localRepo * * This works by faking the operations so we can see what the dev packages * would be at the end of the operation execution. This lets us then remove * the dev packages from the list of operations accordingly if we are in a * --no-dev install or update. * * @return array */ private function extractDevPackages(array $operations, RepositoryInterface $localRepo, PlatformRepository $platformRepo, array $aliases) { if (!$this->package->getDevRequires()) { return array(); } // fake-apply all operations to this clone of the local repo so we see the complete set of package we would end up with $tempLocalRepo = clone $localRepo; foreach ($operations as $operation) { switch ($operation->getJobType()) { case 'install': case 'markAliasInstalled': if (!$tempLocalRepo->hasPackage($operation->getPackage())) { $tempLocalRepo->addPackage(clone $operation->getPackage()); } break; case 'uninstall': case 'markAliasUninstalled': $tempLocalRepo->removePackage($operation->getPackage()); break; case 'update': $tempLocalRepo->removePackage($operation->getInitialPackage()); if (!$tempLocalRepo->hasPackage($operation->getTargetPackage())) { $tempLocalRepo->addPackage(clone $operation->getTargetPackage()); } break; default: throw new \LogicException('Unknown type: ' . $operation->getJobType()); } } // we have to reload the local repo to handle aliases properly // but as it is not persisted on disk we use a loader/dumper // to reload it in memory $localRepo = new InstalledArrayRepository(array()); $loader = new ArrayLoader(null, true); $dumper = new ArrayDumper(); foreach ($tempLocalRepo->getCanonicalPackages() as $pkg) { $localRepo->addPackage($loader->load($dumper->dump($pkg))); } unset($tempLocalRepo, $loader, $dumper); $policy = $this->createPolicy(); $pool = $this->createPool(); $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo); $pool->addRepository($installedRepo, $aliases); // creating requirements request without dev requirements $request = $this->createRequest($this->package, $platformRepo); $request->updateAll(); foreach ($this->package->getRequires() as $link) { $request->install($link->getTarget(), $link->getConstraint()); } // solve deps to see which get removed $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo, $this->io); $ops = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops); $devPackages = array(); foreach ($ops as $op) { if ($op->getJobType() === 'uninstall') { $devPackages[] = $op->getPackage(); } } return $devPackages; }
public function testLoadVersions() { $expected = array('0.6.0' => true, '1.0.0' => true, '1.0.x-dev' => true, '1.1.x-dev' => true, 'dev-feature-b' => true, 'dev-feature-a' => true, 'dev-master' => true); $repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO()); $packages = $repo->getPackages(); $dumper = new ArrayDumper(); foreach ($packages as $package) { if (isset($expected[$package->getPrettyVersion()])) { unset($expected[$package->getPrettyVersion()]); } else { $this->fail('Unexpected version ' . $package->getPrettyVersion() . ' in ' . json_encode($dumper->dump($package))); } } $this->assertEmpty($expected, 'Missing versions: ' . implode(', ', array_keys($expected))); }
/** * Dump packages.json file used by composer repository. * * @param Composer $composer The Composer model * @param array $repositories The repositories to scan * @param string $directory The output directory */ protected function dumpPackagesJson(Composer $composer, array $repositories, $directory) { $repoJson = new JsonFile($directory . '/packages.json'); $manager = $composer->getRepositoryManager(); $packages = array(); foreach ($repositories as $config) { $repository = $manager->createRepository($config['type'], $config); foreach ($repository->getPackages() as $package) { // skip aliases if ($package instanceof AliasPackage) { continue; } $packages[] = $package; } } $repo = array('packages' => array()); $dumper = new ArrayDumper(); foreach ($packages as $package) { $name = $package->getPrettyName(); $version = $package->getPrettyVersion(); $repo['packages'][$name][$version] = $dumper->dump($package); } // Keep previous packages information if ($repoJson->exists()) { $data = $repoJson->read(); foreach ($data['packages'] as $name => $info) { if (!isset($repo['packages'][$name])) { $repo['packages'][$name] = $info; } } } $repoJson->write($repo); }
/** * {@inheritDoc} */ public function uninstall(RepositoryInterface $repo, UninstallOperation $operation) { $this->packageInformation->set($this->packageInformation->escape($operation->getPackage()->getPrettyName()), ['type' => 'uninstall', 'package' => $this->dumper->dump($operation->getPackage())]); parent::uninstall($repo, $operation); }
/** * @dataProvider testParseDumpProvider */ public function testParseDumpFalseLoadConfig($config) { $loader = new ArrayLoader(null, false); $package = $loader->load($config); $dumper = new ArrayDumper(); $expectedConfig = $this->fixConfigWhenLoadConfigIsFalse($config); $this->assertEquals($expectedConfig, $dumper->dump($package)); }
/** * @param string $targetDir * @param string $repositoryUrl * @param \Composer\Package\Dumper\ArrayDumper $dumper * @param \Composer\Package\PackageInterface $package * @param string $zipfileName * @return array */ protected function getPackageArray($targetDir, $repositoryUrl, \Composer\Package\Dumper\ArrayDumper $dumper, \Composer\Package\PackageInterface $package, $zipfileName) { $packageArray = $dumper->dump($package); if (!empty($packageArray['dist']['reference'])) { $reference = $packageArray['dist']['reference']; } else { if (!empty($packageArray['source']['reference'])) { $reference = $packageArray['source']['reference']; } else { $reference = ''; // e.g. zend packages } } unset($packageArray['installation-source']); unset($packageArray['source']); unset($packageArray['dist']); $packageArray['dist'] = array('type' => 'zip', 'url' => $repositoryUrl . '/dists/' . $zipfileName . '.zip', 'reference' => $reference, 'shasum' => hash_file('sha1', $targetDir . '/dists/' . $zipfileName . '.zip')); return $packageArray; }
/** * {@inheritDoc} */ public function getVcsReference(PackageInterface $package, $path) { $parser = new VersionParser(); $guesser = new VersionGuesser($this->config, $this->process, $parser); $dumper = new ArrayDumper(); $packageConfig = $dumper->dump($package); if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) { return $packageVersion['commit']; } }
/** * Writes package includes JSON Files. * * @param array $packages List of packages to dump * * @return string $hashes package hashes */ private function dumpPackageIncludeJson(array $packages) { $dumper = new ArrayDumper(); $providers = array(); $hashes = array(); foreach ($packages as $package) { $info = $dumper->dump($package); $info['uid'] = crc32($package->getPrettyVersion()); $providers[$package->getName()][$package->getPrettyVersion()] = $info; } foreach ($providers as $name => $versions) { $repo = array('packages' => array($name => $versions)); list($file, $hash, $updated) = $this->writeJson($repo, $this->filenamePrefix . '/' . $name . '$%hash%.json'); if ($updated) { $this->output->writeln("<info>wrote " . $name . " json {$file}</info>"); } $hashes[$name] = array('sha256' => $hash); } return $hashes; }