function globstar($pattern, $flags = 0)
 {
     // if not using ** then just use PHP's glob()
     if (stripos($pattern, '**') === false) {
         // turn off the custom flags
         $files = glob($pattern, $flags);
         sort($files);
         return $files;
     }
     $patterns = array();
     // if globstar is inside braces
     if ($flags & GLOB_BRACE) {
         $regexp = '/\\{(.+)?([\\*]{2}[^,]?)(.?)\\}/i';
         // check if this situation really occurs (otherwise we can end up with infinite nesting)
         if (preg_match($regexp, $pattern)) {
             // extract the globstar from inside the braces and add a new pattern to patterns list
             $patterns[] = preg_replace_callback('/(.+)?\\{(.+)?([\\*]{2}[^,]?)(.?)\\}(.?)/i', function ($matches) {
                 $brace = '{' . $matches[2] . $matches[4] . '}';
                 if ($brace === '{,}' || $brace === '{}') {
                     $brace = '';
                 }
                 $pattern = $matches[1] . $brace . $matches[5];
                 return str_replace('//', '/', $pattern);
             }, $pattern);
             // and now change the braces in the main pattern to globstar
             $pattern = preg_replace_callback($regexp, function ($matches) {
                 return $matches[2];
             }, $pattern);
         }
     }
     $pos = stripos($pattern, '**');
     $rootPattern = substr($pattern, 0, $pos) . '*';
     $restPattern = substr($pattern, $pos + 2);
     $patterns[] = ltrim($restPattern, '/');
     while ($dirs = glob($rootPattern, GLOB_ONLYDIR)) {
         $rootPattern = $rootPattern . '/*';
         foreach ($dirs as $dir) {
             $patterns[] = $dir . $restPattern;
         }
     }
     $files = array();
     foreach ($patterns as $pat) {
         $files = array_merge($files, globstar($pat, $flags));
     }
     $files = array_unique($files);
     sort($files);
     return $files;
 }
 public static function process($configPathOrObject)
 {
     $config = self::parseConfig($configPathOrObject);
     // Check if keys were provided by the configuration file
     if (empty($config->keys) || empty($config->keys->accessKey) || empty($config->keys->secretKey)) {
         throw new Exception('Access key and secret key must be provided in the configuration file.');
     }
     $accessKey = $config->keys->accessKey;
     $secretKey = $config->keys->secretKey;
     // Check if host was provided and assign it to a variable
     if (!empty($config->host)) {
         $host = $config->host;
     } else {
         $host = null;
     }
     // Check if port was provided and assign it to a variable
     if (!empty($config->port)) {
         $port = $config->port;
     } else {
         $port = null;
     }
     // Check if the api version was provided and assign it to a variable
     if (!empty($config->apiVersion)) {
         $apiVersion = $config->apiVersion;
     } else {
         $apiVersion = null;
     }
     // Instance a JScrambler client
     $client = new Jscrambler($accessKey, $secretKey, $host, $port, $apiVersion);
     // Check for source files and add them to the parameters
     if (empty($config->filesSrc)) {
         throw new Exception('Source files must be provided.');
     }
     // Check if output directory was provided
     if (empty($config->filesDest)) {
         throw new Exception('Output directory must be provided.');
     }
     $dest = $config->filesDest;
     $files = $config->filesSrc;
     $filesSrc = array();
     for ($i = 0, $l = count($files); $i < $l; ++$i) {
         $filesSrc = array_merge(globstar($files[$i]), $filesSrc);
     }
     // Prepare object to post
     // Check if params were provided and assign them to a variable
     if (!empty($config->params)) {
         $params = get_object_vars($config->params);
     } else {
         $params = array();
     }
     $params['files'] = $filesSrc;
     // Send the project to the JScrambler API
     $projectId = self::uploadCode($client, $params)->id;
     // Clean the temporary zip file
     self::cleanZipFile();
     // Download the project and unzip it
     $zipContent = self::downloadCode($client, $projectId);
     if (!self::$silent) {
         echo "Writing...\n";
     }
     self::unzipProject($zipContent, $dest);
     if (!self::$silent) {
         echo "Written\n";
     }
     if (isset($config->deleteProject) && $config->deleteProject) {
         self::deleteCode($client, $projectId);
     }
 }