Beispiel #1
0
 /**
  * Get $num newest images
  * @since Version 3.10.0
  * @param int $num
  * @return array
  * @todo $cacheProvider doesn't seem to bloody work!
  */
 public static function getNewest($num = 5)
 {
     $cacheProvider = AppCore::GetMemcached();
     $mckey = sprintf("railpage:images.recent=%d;url.cached", $num);
     if ($newphotos = $cacheProvider->fetch($mckey)) {
         Debug::LogCLI("Fetched new photos from cache provider using cache key " . $mckey);
         return $newphotos;
     }
     $newphotos = (new Images())->getRecentAdditions(5);
     shuffle($newphotos);
     foreach ($newphotos as $id => $data) {
         $newphotos[$id]['meta']['sizes']['medium']['source'] = ImageCache::cache($newphotos[$id]['meta']['sizes']['medium']['source']);
     }
     $rs = $cacheProvider->save($mckey, $newphotos, 900);
     // save for 15 minutes
     Debug::LogCLI("Saved new photos in cache provider using cache key " . $mckey);
     if ($res = $cacheProvider->fetch($mckey)) {
         Debug::LogCLI("new photos found in cache, success");
     }
     return $newphotos;
 }
 /**
  * @depends test_createPhotos
  * @depends test_createUser
  */
 public function test_votePhotos($photoComp, $userObject)
 {
     $photoComp->SubmissionsDateOpen = (new DateTime())->sub(new DateInterval("P10D"));
     $photoComp->SubmissionsDateClose = (new DateTime())->sub(new DateInterval("P3D"));
     $photoComp->VotingDateOpen = (new DateTime())->sub(new DateInterval("P1D"));
     $photoComp->VotingDateClose = (new DateTime())->add(new DateInterval("P10D"));
     $this->assertTrue($photoComp->canUserVote($userObject));
     $this->assertFalse(empty($photoComp->getPhotosAsArray(true)));
     foreach ($photoComp->getPhotos() as $Photo) {
         Debug::LogCLI("Voting for photo ID " . $Photo->Image->id);
         $this->assertEquals(0, $photoComp->getNumVotesForImage($Photo->Image));
         $this->assertTrue($photoComp->canUserVote($userObject, $Photo->Image));
         $photoComp->submitVote($userObject, $Photo->Image);
         $this->assertfalse($photoComp->canUserVote($userObject, $Photo->Image));
         $this->assertEquals(1, $photoComp->getNumVotesForImage($Photo->Image));
         $this->winning_id = $Photo->Image->id;
         break;
     }
     $photoComp->getNumVotesForUser(new User());
     $photoComp->SubmissionsDateOpen->sub(new DateInterval("P10W"));
     $photoComp->SubmissionsDateClose->sub(new DateInterval("P10W"));
     $photoComp->VotingDateOpen->sub(new DateInterval("P10W"));
     $photoComp->VotingDateClose->sub(new DateInterval("P10W"));
     $photoComp->getVoteCountsPerDay();
     $winner = $photoComp->getWinningPhoto();
     $this->assertFalse($winner == false);
     $this->assertEquals($this->winning_id, $winner->Image->id);
 }
Beispiel #3
0
 /**
  * Get latest photo from this railcam
  * @since Version 3.10.0
  * @return \Railpage\Railcams\Photo
  * @param boolean $update Update cached data if it's stale
  */
 public function getLatest($update = true)
 {
     if ($footage = $this->getLatestFootage("image")) {
         return ["id" => $footage['id'], "title" => "", "description" => "", "dates" => ["taken" => $footage['datestored']], "sizes" => ["original" => ["source" => $footage['url']['original']]]];
     }
     $mckey = sprintf("railpage:railcam=%d;latest=1", $this->id);
     /**
      * Shitty, hacky way to handle Memcached expiry bug on Debian
      */
     $mckey_age = $mckey . ";expiry";
     $exp = $this->Memcached->fetch($mckey_age);
     if ($update && (!$exp || $exp < time())) {
         $this->Memcached->delete($mckey);
     }
     /**
      * Fetch from Memcached, or load from API
      */
     if (!($latest = $this->Memcached->fetch($mckey))) {
         $latest = $this->getPhotos(1);
         Debug::LogCLI("Fetched " . count($latest['photo']) . " photo(s)");
         foreach ($latest['photo'] as $key => $photo) {
             Debug::LogCLI("Processing photo...");
             $photo['timezone'] = $this->timezone;
             $Date = new DateTime($photo['datetaken']);
             $Date->setTimezone(new DateTimeZone($this->timezone));
             $photo['datetaken'] = $Date->format("c");
             $latest['photo'][$key] = $photo;
         }
         Debug::LogCLI("Saving photo in Memcached");
         $this->Memcached->save($mckey, $latest, 0);
         Debug::LogCLI("Saving photo expiry in Memcached");
         $this->Memcached->save($mckey_age, strtotime("+5 minutes"), 0);
     }
     return $this->getPhoto($latest['photo'][0]['id']);
 }
Beispiel #4
0
 /**
  * Create other sizes
  * @since Version 3.10.0
  * @return void
  */
 public static function createOtherSizes()
 {
     $sleep = 2;
     $sleep = false;
     $Database = (new AppCore())->getDatabaseConnection();
     $query = "SELECT i.id,\r\n                square.size AS square, square.source AS square_src, square.width AS square_w, square.height AS square_h,\r\n                large_square.size AS large_square, large_square.source AS large_square_src, large_square.width AS large_square_w, large_square.height AS large_square_h,\r\n                small.size AS small, small.source AS small_src, small.width AS small_w, small.height AS small_h,\r\n                small_320.size AS small_320, small_320.source AS small_320_src, small_320.width AS small_320_w, small_320.height AS small_320_h,\r\n                medium.size AS medium, medium.source AS medium_src, medium.width AS medium_w, medium.height AS medium_h,\r\n                medium_640.size AS medium_640, medium_640.source AS medium_640_src, medium_640.width AS medium_640_w, medium_640.height AS medium_640_h,\r\n                medium_800.size AS medium_800, medium_800.source AS medium_800_src, medium_800.width AS medium_800_w, medium_800.height AS medium_800_h,\r\n                original.size AS original, original.source AS original_src, original.width AS original_w, original.height AS original_h\r\n            FROM gallery_mig_image AS i\r\n                LEFT JOIN gallery_mig_image_sizes AS square ON square.photo_id = i.id AND square.size = 'square'\r\n                LEFT JOIN gallery_mig_image_sizes AS large_square ON large_square.photo_id = i.id AND large_square.size = 'large_square'\r\n                LEFT JOIN gallery_mig_image_sizes AS small ON small.photo_id = i.id AND small.size = 'small'\r\n                LEFT JOIN gallery_mig_image_sizes AS small_320 ON small_320.photo_id = i.id AND small_320.size = 'small_320'\r\n                LEFT JOIN gallery_mig_image_sizes AS medium ON medium.photo_id = i.id AND medium.size = 'medium'\r\n                LEFT JOIN gallery_mig_image_sizes AS medium_640 ON medium_640.photo_id = i.id AND medium_640.size = 'medium_640'\r\n                LEFT JOIN gallery_mig_image_sizes AS medium_800 ON medium_800.photo_id = i.id AND medium_800.size = 'medium_800'\r\n                LEFT JOIN gallery_mig_image_sizes AS original ON original.photo_id = i.id AND original.size = 'original'\r\n            WHERE i.hidden = 0\r\n            AND square.size IS NULL\r\n            AND large_square.size IS NULL\r\n            AND small.size IS NULL\r\n            AND small_320.size IS NULL\r\n            AND medium.size IS NULL\r\n            AND medium_640.size IS NULL\r\n            AND medium_800.size IS NULL\r\n            LIMIT 0, 250";
     $result = $Database->fetchAll($query);
     /**
      * Set our desired sizes
      */
     $sizes = ["square" => ["width" => 75, "height" => 75], "large_square" => ["width" => 150, "height" => 150], "small" => ["width" => 240, "height" => 0], "small_320" => ["width" => 320, "height" => 0], "medium" => ["width" => 500, "height" => 0], "medium_640" => ["width" => 640, "height" => 0], "medium_800" => ["width" => 800, "height" => 0]];
     /** 
      * Loop through the results and start building the sizes
      */
     foreach ($result as $row) {
         /**
          * Load the original image from disk. If it doesn't exist then continue to the next array item
          */
         $filename = sprintf("%s%s", Album::ALBUMS_DIR, $row['original_src']);
         if (!file_exists($filename)) {
             continue;
         }
         $ext = pathinfo($filename, PATHINFO_EXTENSION);
         $allowedtypes = ["jpeg", "jpg", "png", "gif"];
         if (!in_array($ext, $allowedtypes)) {
             continue;
         }
         $noext = str_replace("." . $ext, "", $filename);
         $image = file_get_contents($filename);
         Debug::LogCLI("Source image " . $filename);
         /**
          * Loop through each required size
          */
         foreach ($sizes as $key => $dims) {
             /**
              * If the size already exists in DB then proceed to the next size
              */
             if (!is_null($row[$key]) || $key == "original") {
                 continue;
             }
             /**
              * Break out of the loop if the desired size is larger than than the original image 
              */
             if ($dims['width'] > $row['original_w']) {
                 continue;
             }
             $dstfile = sprintf("%s.%s.%s", $noext, $key, $ext);
             if (file_exists($dstfile)) {
                 unlink($dstfile);
             }
             Debug::LogCLI("  Creating " . $key . " from image " . $filename);
             Debug::LogCLI("");
             $Image = WideImage::loadFromString($image);
             if ($dims['width'] == $dims['height']) {
                 $size = $Image->resize($dims['width'], $dims['height'], "outside");
                 $size = $size->crop(0, "middle", $dims['width'], $dims['height']);
             }
             if ($dims['width'] != $dims['height']) {
                 $size = $Image->resize($dims['width'], $dims['width'], "inside");
             }
             $quality = $dims['width'] <= 240 ? 80 : 100;
             file_put_contents($dstfile, $size->asString("jpg", $quality));
             if (file_exists($dstfile)) {
                 Debug::LogCLI("  Image created, inserting into DB");
                 Debug::LogCLI("  " . $dstfile);
                 $data = ["photo_id" => $row['id'], "size" => $key, "source" => $dstfile, "width" => $size->getWidth(), "height" => $size->getHeight()];
                 $Database->insert("gallery_mig_image_sizes", $data);
             }
             Debug::LogCLI("  ---");
         }
         if ($sleep) {
             Debug::LogCLI("-------------------------------");
             Debug::LogCLI("");
             Debug::LogCLI("Sleeping for two seconds");
             Debug::LogCLI("");
             sleep($sleep);
         }
         Debug::LogCLI("-------------------------------");
         Debug::LogCLI("");
     }
 }
Beispiel #5
0
 /**
  * Find an image by provider and provider image ID
  * @since Version 3.8.7
  * @param string $provider
  * @param int $photoId
  * @param mixed $option
  * @throws \Exception if $provider is null
  * @throws \Exception if $photoId is null
  * @param int $option
  */
 public function findImage($provider = null, $photoId = null, $option = null)
 {
     if (is_null($provider)) {
         throw new Exception("Cannot lookup image from image provider - no provider given (hint: Flickr, WestonLangford)");
     }
     if (!preg_match("/([a-zA-Z0-9]+)/", $photoId) || $photoId === 0) {
         throw new Exception("Cannot lookup image from image provider - no provider image ID given");
     }
     $mckey = sprintf("railpage:image;provider=%s;id=%s", $provider, $photoId);
     if (defined("NOREDIS") && NOREDIS == true || $option != self::OPT_REFRESH && !($id = $this->Redis->fetch($mckey))) {
         Debug::LogCLI("Found photo ID " . $photoId . " in database");
         $id = $this->db->fetchOne("SELECT id FROM image WHERE provider = ? AND photo_id = ?", array($provider, $photoId));
         $this->Redis->save($mckey, $id, strtotime("+1 month"));
     }
     if (isset($id) && filter_var($id, FILTER_VALIDATE_INT)) {
         return new Image($id, $option);
     }
     Debug::LogCLI("Photo ID " . $photoId . " not found in local cache");
     $Image = new Image();
     $Image->provider = $provider;
     $Image->photo_id = $photoId;
     $Image->populate(true, $option);
     return $Image;
 }
Beispiel #6
0
 /**
  * Update the geoplace reference for this image
  *
  * @since Version 3.9.1
  * @return void
  */
 public function updateGeoPlace()
 {
     if (!filter_var($this->lat, FILTER_VALIDATE_FLOAT) || !filter_var($this->lat, FILTER_VALIDATE_FLOAT)) {
         return;
     }
     $timer = microtime(true);
     $GeoPlaceID = PlaceUtility::findGeoPlaceID($this->lat, $this->lon);
     #var_dump($GeoPlaceID);die;
     $data = ["geoplace" => $GeoPlaceID];
     $where = ["id = ?" => $this->id];
     $this->db->update("image", $data, $where);
     $this->Memcached->delete($this->mckey);
     $this->Redis->delete($this->mckey);
     Debug::logEvent(__METHOD__, $timer);
     Debug::LogCLI(__METHOD__, $timer);
     return;
 }
Beispiel #7
0
 /**
  * Grab an image from the web and store it locally
  * @since Version 3.10.0
  * @param string $remoteFile
  * @param string $localFile
  * @return void
  */
 private function grab($remoteFile, $localFile)
 {
     $GuzzleClient = new GuzzleClient();
     Debug::LogCLI("Fetching {$remoteFile}");
     $response = $GuzzleClient->get($remoteFile);
     if ($response->getStatusCode() != 200 && $response->getStatusCode() != 304) {
         throw new Exception("Unexpected HTTP status code " . $response->getStatusCode() . " encountered when fetching " . $remoteFile);
     }
     $image = $response->getBody();
     if (!file_put_contents($localFile, $image)) {
         throw new Exception("File was fetched from remote source, but could not save to destination file " . $localFile);
     }
     return;
 }
Beispiel #8
0
 /**
  * Fetch the latest information on an album from the relevant provider
  * @since Version 3.10.0
  * @param array $album
  * @return void
  */
 public static function ScrapeAlbum($album)
 {
     Debug::LogCLI("Scraping album ID " . $album['album_id'] . " from provider " . $album['provider']);
     set_time_limit(30);
     $Database = AppCore::GetDatabase();
     $Provider = ImageUtility::CreateImageProvider($album['provider']);
     // Assume Flickr for now, we can update the internal code later
     $params = ["photoset_id" => $album['album_id']];
     $albumdata = $Provider->execute("flickr.photosets.getInfo", $params);
     // Insert this shit into the database
     $data = ["scraped" => new Zend_Db_Expr("NOW()"), "meta" => json_encode($albumdata['photoset'])];
     $where = ["id = ?" => $album['id']];
     $Database->update("image_scrape_album", $data, $where);
     // Fetch the photos
     $params['user_id'] = $albumdata['photoset']['owner'];
     $photos = $Provider->execute("flickr.photosets.getPhotos", $params);
     foreach ($photos['photoset']['photo'] as $photo) {
         Debug::LogCLI("Scraping photo ID " . $photo['id']);
         set_time_limit(10);
         ImageFactory::CreateImage($photo['id'], $album['provider']);
         Debug::LogCLI("Sleeping for 2 seconds...");
         sleep(2);
     }
 }
Beispiel #9
0
 /**
  * Queue the newsletter for dispatch
  * @since Version 3.10.0
  * @return \Railpage\Newsletters\Weekly
  */
 private function queue()
 {
     $this->Notification->subject = "[News] " . $this->Newsletter->subject;
     $this->Notification->body = $this->html;
     $this->Notification->meta['decoration'] = $this->replacements;
     $this->Notification->addHeader("List-Unsubscribe", "<http://railpage.com.au/unsubscribe?email=##email_encoded##&newsletter=weekly>");
     Debug::LogCLI("Queueing notification for dispatch");
     $this->Notification->commit();
     $this->Newsletter->status = Newsletter::STATUS_SENT;
     Debug::LogCLI("Commiting the newsletter to the database");
     $this->Newsletter->commit();
     /**
      * Update the last sent timestamp
      */
     foreach ($this->user_ids as $user_id) {
         $query = "INSERT INTO nuke_users_flags (user_id, newsletter_weekly_last) VALUES(" . $user_id . ", NOW()) ON DUPLICATE KEY UPDATE newsletter_weekly_last = NOW()";
         $ZendDB->query($query);
     }
     return $this;
 }
Beispiel #10
0
 /**
  * Render the page 
  * @since Version 3.10.0
  * @return string
  */
 public function render()
 {
     if (!$this->userObject instanceof User) {
         throw new InvalidArgumentException("No valid user object has been provided");
     }
     #$this->smarty->clearCache($this->template, $this->unique);
     if ($this->smarty->isCached($this->template, $this->unique)) {
         Debug::LogCLI("!! Template file " . $this->template . " is already cached for unique ID " . $this->unique);
         return $this->smarty->fetch($this->template, $this->unique);
     }
     Debug::LogCLI("Template file " . $this->template . " is NOT cached for unique ID \"" . $this->unique . "\"");
     /**
      * Get user alerts
      */
     if (!$this->userObject->guest) {
         global $acl;
         $alerts = $this->userObject->getAlerts($acl);
         $this->smarty->Assign("alerts", $alerts, true);
     }
     /**
      * Get the latest jobs
      */
     $newjobs = array();
     foreach ((new Jobs())->yieldNewJobs(5) as $Job) {
         $newjobs[] = $Job->getArray();
     }
     $this->smarty->Assign("jobs", $newjobs, true);
     /**
      * Upcoming events
      */
     $Memcached = AppCore::GetMemcached();
     $cachekey = "railpage.home.upcomingevents";
     $upcoming = [];
     if (!($upcoming = $Memcached->fetch($cachekey))) {
         $Events = new Events();
         $upcoming = [];
         foreach ($Events->getUpcomingEvents(5) as $row) {
             //$Event = EventsFactory::CreateEvent($row['event_id']);
             $EventDate = new EventDate($row['id']);
             $data = $EventDate->getArray();
             $upcoming[] = $data;
         }
         $Memcached->save("railpage.home.upcomingevents", $upcoming, strtotime("+5 minutes"));
     }
     $this->smarty->Assign("upcomingevents", $upcoming);
     /**
      * New photos
      */
     $this->smarty->Assign("newphotos", RecentImages::getNewest(5));
     /**
      * Chronicle
      */
     $Chronicle = new Chronicle();
     $this->smarty->Assign("chronicle", $Chronicle->getEntriesForToday(10));
     /**
      * Get the latest railcam photo
      */
     $Camera = new Camera(1);
     $Photo = $Camera->getLatest(false);
     $railcam = $Photo->getArray();
     $railcam['sizes']['small']['source'] = ImageCache::cache($railcam['sizes']['small']['source']);
     $this->smarty->Assign("railcam", $railcam);
     $this->smarty->Assign("railcam_updated", ContentUtility::relativeTime($railcam['dates']['taken']));
     /**
      * First check if this user has a personalised news feed
      */
     if (filter_var($this->userObject->id, FILTER_VALIDATE_INT) && $this->userObject->id > 0) {
         $Feed = new Feed();
         $Feed->setUser($this->userObject)->getFilters();
         if (count($Feed->filter_words) || count($Feed->filter_topics)) {
             $latest = $Feed->findArticles(0, 20);
             foreach ($latest as $id => $article) {
                 $article['sid'] = $article['story_id'];
                 $article['catid'] = $article['topic_id'];
                 $article['hometext'] = preg_replace("@(\\[b\\]|\\[\\/b\\])@", "", $article['story_blurb']);
                 $article['informant'] = $article['username'];
                 $article['informant_id'] = $article['user_id'];
                 $article['ForumThreadId'] = $article['forum_topic_id'];
                 $article['topictext'] = $article['topic_title'];
                 $article['topic'] = $article['topic_id'];
                 $article['featured_image'] = $article['story_image'];
                 $article['title'] = $article['story_title'];
                 $article['time_relative'] = time2str($article['story_time_unix']);
                 $latest[$id] = $article;
             }
         }
     }
     $this->smarty->Assign("personalfeed", isset($latest));
     /**
      * No personal news feed - go ahead as normal
      */
     if (!isset($latest)) {
         /**
          * Instantiate the base News module
          */
         $News = new Base();
         /**
          * Get the latest 15 news articles
          */
         $latest = $News->latest(20);
     }
     /**
      * Format titles and tags for the latest news articles
      */
     foreach ($latest as $id => $data) {
         /**
          * Load the JSON for this article
          */
         if (!isset($data['sid'])) {
             $data['sid'] = $data['story_id'];
         }
         $json = json_decode(News::getArticleJSON($data['sid']), true);
         $latest[$id]['hometext'] = isset($json['article']['blub']) ? wpautop(process_bbcode($json['article']['blub'])) : wpautop(process_bbcode($json['article']['blurb']));
         $latest[$id]['hometext'] = strip_tags($latest[$id]['hometext'], "<a><p><img><br><br /><strong><em>");
         $latest[$id]['title'] = format_topictitle($data['title']);
         $latest[$id]['topic'] = $json['article']['topic'];
         $latest[$id]['topic_highlight'] = ColourUtility::String2Hex($latest[$id]['topic_title']);
         $latest[$id]['url'] = $json['article']['url'];
         $latest[$id]['author'] = $json['article']['author'];
         $latest[$id]['staff'] = $json['article']['staff'];
         if (!empty($latest[$id]['featured_image'])) {
             $latest[$id]['featured_image'] = ImageCache::cache($latest[$id]['featured_image']);
         }
         // Get the first paragraph from the home text
         preg_match("/<p>(.*)<\\/p>/", $latest[$id]['hometext'], $matches);
         $latest[$id]['hometext'] = strip_tags($matches[1]);
         if (empty($json['article']['body']) && !empty($json['article']['source'])) {
             $latest[$id]['url'] = $json['article']['source'];
         }
         /**
          * Pre-rendering
          */
         $this->smarty->addHeadTag(sprintf("<link rel='prerender' href='%s'>", $json['article']['url']['url']));
     }
     /**
      * Slice the first news article off
      */
     $newsLatest = array_shift($latest);
     /**
      * Send them to Smarty
      */
     $this->smarty->assign("newsLatest", $newsLatest);
     $this->smarty->assign("news", $latest);
     $this->smarty->assign("pagecontrols", '<p style="background: #333; background: rgba(0, 0, 0, 0.6);margin: -20px;padding: 10px;margin-top: 20px; text-align: center;">Wasting time and bandwidth since 1992</p>');
     if ($this->params['handheld']) {
         $this->smarty->assign("pagecontrols", '<p style="background: #333; background: rgba(0, 0, 0, 0.6);margin: 0px -20px;padding: 0px;margin-top: 40px; text-align: center;font-size:1em;">Wasting time and bandwidth since 1992</p>');
     }
     return $this->smarty->fetch($this->template, $this->unique);
 }
Beispiel #11
0
 /**
  * Fetch EXIF data for the queued images
  * @since Version 3.10.0
  * @return void
  */
 public static function scrapeExifQueue()
 {
     $sleep = 10;
     $break = 50;
     $Database = (new AppCore())->getDatabaseConnection();
     $query = "SELECT f.image_id FROM image_flags AS f LEFT JOIN image AS i ON f.image_id = i.id WHERE f.exifqueue = 1 AND i.provider IS NOT NULL ORDER BY f.image_id DESC";
     $exif = new Exif();
     $ids = [];
     foreach ($Database->fetchAll($query) as $row) {
         $imageObject = new Image($row['image_id']);
         $exif->getImageExif($imageObject);
         $ids[] = $imageObject->id;
         if (count($ids) == $break) {
             Debug::LogCLI("Updating " . $break . " records");
             $query = "UPDATE image_flags SET exifqueue = 0 WHERE image_id IN (" . implode(",", $ids) . ")";
             $Database->query($query);
             $ids = [];
             break;
             sleep($sleep);
         }
     }
     Debug::LogCLI("Mark all queued images as scraped");
     $query = "UPDATE image_flags SET exifqueue = 0 WHERE exifqueue = 1";
     $Database->query($query);
     return;
 }
Beispiel #12
0
 /**
  * Assemble the collage
  * @since Version 3.10.0
  * @return \Railpage\Images\Collage
  */
 private function assemble()
 {
     Debug::LogCLI("Assembling the collage");
     $imageSize = $this->findThumbnailSize();
     $size = $imageSize['size'];
     $this->canvas = imagecreatetruecolor($this->width, $this->height);
     $counter_x = 0;
     $counter_y = 0;
     $offset_x = 0;
     $offset_y = 0;
     //$images_per_row = ceil($this->width / $size['thumbWidth']);
     foreach ($this->Images as $Image) {
         Debug::LogCLI("Running Image ID " . $Image->id);
         // Fetch the image
         $raw = $this->getImageString($Image->sizes[$size]['source']);
         $thumb = imagecreatefromstring($raw);
         // Place the thubmnail onto our canvas
         imagecopyresampled($this->canvas, $thumb, $offset_x, $offset_y, 0, 0, $imageSize['thumbWidth'], $imageSize['thumbHeight'], $imageSize['thumbWidth'], $imageSize['thumbHeight']);
         if (php_sapi_name() == "cli" && !defined("PHPUNIT_RAILPAGE_TESTSUITE")) {
             var_dump($offset_x);
             var_dump($offset_y);
             var_dump($offset_x + $imageSize['thumbWidth']);
             var_dump($offset_y + $imageSize['thumbHeight']);
             var_dump($imageSize['thumbWidth']);
             var_dump($imageSize['thumbHeight']);
         }
         $offset_x += $imageSize['thumbWidth'];
         $counter_x++;
         Debug::LogCLI("counter_x: " . $counter_x);
         Debug::LogCLI("offset_x: " . $offset_x);
         if ($offset_x >= $this->width) {
             Debug::LogCLI("Wrapping line");
             $counter_x = 0;
             $counter_y++;
             $offset_y += $imageSize['thumbHeight'];
             $offset_x = 0;
         }
     }
 }