Jump to content
Latest News: (loading..)
RobAnderson

Article Manager v1.0

Recommended Posts

Trouble with OSC 2.3.4
catalog/tell-a-friend.php

The current tell-a-friend.php file is very different. I can't find the script as suggested in readme.txt
So I decide to skip it.


 

Share this post


Link to post
Share on other sites
5 hours ago, jabjab2 said:

what is the difference between article and blog?

The difference is that with a blog article, customers can reply to it. So an article might be a page explaining how to use a knife. While a blog article would be about the various knifes you sell and where customer can respond with their views on which is the best one. Getting customers involved is a way of keeping them coming back. I have one client that sells baby clothes and the site has a blog article where customers can post images of their babies.

Share this post


Link to post
Share on other sites

Hi,

Excellent addon, really impressive. I've been using it since years ago as a way to get more SEO juice and for engagement purposes with my customers.

When trying to share an article on Facebook, there is an extrange text that says "You must have JavaScript enabled in your browser to utilize the functionality of this website. Click here for instructions on enabling javascript in your browser."

It happens both doing it through Header Tags or simply copy-pasting on a browser, or even through the Social Share addon. It only happens on Fb. I mean, it doesn't happen when sharing with Linkedin, or Google+ etc. Also, it doesn't show the title of the article nor the image of it (and this is always, no matter how you share it). I think that I've done something wrong. Can anyone give me an idea or clue about it, please?

Regards


Shopowner, not coder, experienced copypaster  :D

Share this post


Link to post
Share on other sites

There's noting in this addon to do with social links. There was a problem found in Header Tags SEO with regards to FB. That fix is in the new version but it hasn't been uploaded so you would need to get it from the thread.

Share this post


Link to post
Share on other sites

Thanks, Jack. I'll go to the threads for it.


Shopowner, not coder, experienced copypaster  :D

Share this post


Link to post
Share on other sites

Hello Jack

The module is working, but an error is displayed:

Undefined variable: tPath in /home/---/---/---/includes/modules/boxes/bm_articles.php on line 121
 

           //------------------------
line#121    if (tep_not_null($tPath)) {
             $new_path = '';
             reset($tPath_array);

How can this error be corrected?

Thanks.


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Thank You Raiwa!

I fixed the code. Now everything works fine!


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Error fixed, articles box not work prop. not see categories.  😞

Edited by Fredi

Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Can you please give more information:

- your exact OsCommerce version

- your php version

- switch error reporting on or check your error log file for errors related with this box

- post the complete bm_articles.php code including the modification you applied

Share this post


Link to post
Share on other sites

https://github.com/gburton/Responsive-osCommerce    Updated to Bootstrap 4

PHP-7.0

<?php
/*
  $Id$

  osCommerce, Open Source E-Commerce Solutions
  http://www.oscommerce.com

  Copyright (c) 2018 osCommerce

  Released under the GNU General Public License
*/

  class bm_articles {
    var $code = 'bm_articles';
    var $group = 'boxes';
    var $title;
    var $description;
    var $sort_order;
    var $enabled = false;

    function __construct() {
      $this->title = MODULE_BOXES_ARTICLES_TITLE;
      $this->description = MODULE_BOXES_ARTICLES_DESCRIPTION;

      if ( defined('MODULE_BOXES_ARTICLES_STATUS') ) {
        $this->sort_order = MODULE_BOXES_ARTICLES_SORT_ORDER;
        $this->enabled = (MODULE_BOXES_ARTICLES_STATUS == 'True');

        $this->group = ((MODULE_BOXES_ARTICLES_CONTENT_PLACEMENT == 'Left Column') ? 'boxes_column_left' : 'boxes_column_right');
      }
    }

    function execute() {
      global $languages_id, $currencies, $oscTemplate;

        $topicCtr = 0;
        $topics_string = '';
        $articlesArray = array();
        $tree = array();
        function GetBoldTags($page, $id = 0) {
           $boldTags = array();
           if (basename($_SERVER['PHP_SELF']) === $page) {
               if ($id == 0) {
                   $boldTags['start'] = '<b>';
                   $boldTags['stop'] = '</b>';
               }
               else if ((int)$_GET['articles_id'] == $id)  {
                   $boldTags['start'] = '<b>';
                   $boldTags['stop'] = '</b>';
               }
           } else {
                $boldTags['start'] = '';     //fill these in to prevent STRICT errors
                $boldTags['stop'] = '';
           }
           return $boldTags;
        }
        function SortBySetting($a, $b) {
          return strnatcasecmp($a["sort_order"], $b["sort_order"]);
        }
        function tep_show_topic($counter, $tree, &$topics_string) {
          global $tPath_array, $topicCtr;
          for ($i=0; $i<$tree[$counter]['level']; $i++) {
            $topics_string .= "&nbsp;&nbsp;";
          }
//          $topics_string .= '<h5>-&nbsp;<a href="';
         $topics_string .= '<span class="articleLinkMarker">-&nbsp;<a href="';
          if ($tree[$counter]['parent'] == 0) {
            $tPath_new = 'tPath=' . $counter;
          } else {
            $tPath_new = 'tPath=' . $tree[$counter]['path'];
          }
          $topics_string .= tep_href_link('articles.php', $tPath_new) . '">';
          if (isset($tPath_array) && in_array($counter, $tPath_array)) {
            $topics_string .= '<b>';
          }
      // display topic name
          $topics_string .= $tree[$counter]['name'];
          if (isset($tPath_array) && in_array($counter, $tPath_array)) {
            $topics_string .= '</b>';
          }
          if (tep_has_topic_subtopics($counter)) {
            $topics_string .= ' -&gt;';
          }
          $topics_string .= '</a>';
          if (SHOW_ARTICLE_COUNTS == 'true') {
            $articles_in_topic = tep_count_articles_in_topic($counter);
            if ($articles_in_topic > 0) {
              $topics_string .= '&nbsp;(' . $articles_in_topic . ')';
            }
          }
          $topics_string .= '</span><br />';
          if (tep_not_null(ARTICLE_BOX_DISPLAY_TOPICS_LINKS_LIMIT) && $topicCtr >= ARTICLE_BOX_DISPLAY_TOPICS_LINKS_LIMIT) {
              $topics_string .= '<span class="articleLinkMarker">-&nbsp;<a href="' . tep_href_link('article-topics.php', '', 'SSL') . '">' . '<div style="float:right; color:red;">...more</div>' . '</a></span><br />';
              return;
          }
          $topicCtr++;
          if ($tree[$counter]['next_id'] != false) {
            tep_show_topic($tree[$counter]['next_id'], $tree, $topics_string);
          }
        }
        /** <!-- topics //--> **/
        if (ARTICLE_BOX_DISPLAY_TOPICS_SECTION == 'true')
        {
           $tree = array();
           $topics_query = tep_db_query("select t.topics_id, td.topics_name, t.parent_id from " . TABLE_TOPICS . " t, " . TABLE_TOPICS_DESCRIPTION . " td where t.parent_id = '0' and t.topics_id = td.topics_id and td.language_id = '" . (int)$languages_id . "' order by sort_order, td.topics_name");
           while ($topics = tep_db_fetch_array($topics_query))  {
             $tree[$topics['topics_id']] = array('name' => $topics['topics_name'],
                                                 'parent' => $topics['parent_id'],
                                                 'level' => 0,
                                                 'path' => $topics['topics_id'],
                                                 'next_id' => false);
             if (isset($parent_id)) {
               $tree[$parent_id]['next_id'] = $topics['topics_id'];
             }
             $parent_id = $topics['topics_id'];
             if (!isset($first_topic_element)) {
               $first_topic_element = $topics['topics_id'];
             }
           }
           //------------------------
   if ( isset($tPath) && tep_not_null($tPath) ) {  //Correct from Raiwa
             $new_path = '';
             reset($tPath_array);
             while (list($key, $value) = each($tPath_array)) {
               unset($parent_id);
               unset($first_id);
               $topics_query = tep_db_query("select t.topics_id, td.topics_name, t.parent_id from " . TABLE_TOPICS . " t, " . TABLE_TOPICS_DESCRIPTION . " td where t.parent_id = '" . (int)$value . "' and t.topics_id = td.topics_id and td.language_id = '" . (int)$languages_id . "' order by sort_order, td.topics_name");
               if (tep_db_num_rows($topics_query)) {
                 $new_path .= $value;
                 while ($row = tep_db_fetch_array($topics_query)) {
                   $tree[$row['topics_id']] = array('name' => $row['topics_name'],
                                                    'parent' => $row['parent_id'],
                                                    'level' => $key+1,
                                                    'path' => $new_path . '_' . $row['topics_id'],
                                                    'next_id' => false);
                   if (isset($parent_id)) {
                     $tree[$parent_id]['next_id'] = $row['topics_id'];
                   }
                   $parent_id = $row['topics_id'];
                   if (!isset($first_id)) {
                     $first_id = $row['topics_id'];
                   }
                   $last_id = $row['topics_id'];
                 }
                 $tree[$last_id]['next_id'] = $tree[$value]['next_id'];
                 $tree[$value]['next_id'] = $first_id;
                 $new_path .= '_';
               } else {
                 break;
               }
             }
           }
           $topicCtr = 1;
           tep_show_topic($first_topic_element, $tree, $topics_string);
        }


        /********************* BUILD ALL ARTICLES ********************/
        if (ARTICLE_BOX_DISPLAY_ALL_ARTICLES_SECTION == 'true') {
           $articles_all_count = '';
           if (SHOW_ARTICLE_COUNTS == 'true') {
               $articles_new_query = tep_db_query("SELECT a.articles_id from " . TABLE_ARTICLES . " a, " . TABLE_ARTICLES_TO_TOPICS . " a2t, " . TABLE_TOPICS_DESCRIPTION . " td, " . TABLE_AUTHORS . " au, " . TABLE_ARTICLES_DESCRIPTION . " ad where a.authors_id = au.authors_id and a2t.topics_id = td.topics_id and (a.articles_date_available IS NULL or to_days(a.articles_date_available) <= to_days(now())) and a.articles_id = a2t.articles_id and a.articles_status = '1' and a.articles_is_blog = 0 and a.articles_id = ad.articles_id and ad.language_id = '" . (int)$languages_id . "' and td.language_id = '" . (int)$languages_id . "'");
               $articles_all_count = (tep_db_num_rows($articles_new_query) ? tep_db_num_rows($articles_new_query) : '');
           }
           $articlesArray['all_articles']['sort_order'] = ARTICLE_BOX_DISPLAY_ALL_ARTICLES_SECTION_SORT_ORDER;
           $boldTags = array();
           $boldTags = GetBoldTags('articles.php');
           $articlesArray['all_articles']['string'] = '<span class="h4"><b>';
           $articlesArray['all_articles']['string'] .= '<a href="' . tep_href_link('articles.php', '', 'SSL') . '">' . $boldTags['start'] . BOX_ALL_ARTICLES . $boldTags['stop'] . '</a>';
           $articlesArray['all_articles']['string'] .= '&nbsp;' . $articles_all_count . '</span><br />';
           if (ARTICLE_BOX_DISPLAY_All_ARTICLES_LINKS == 'true') {
              $allArticles = tep_get_all_articles_array();
              $ctr = 0;
              foreach ($allArticles as $all) {
                 if (! tep_not_null(ARTICLE_BOX_DISPLAY_ALL_ARTICLES_LINKS_LIMIT) || (tep_not_null(ARTICLE_BOX_DISPLAY_ALL_ARTICLES_LINKS_LIMIT) && $ctr < ARTICLE_BOX_DISPLAY_ALL_ARTICLES_LINKS_LIMIT)) {
                     $boldTags = GetBoldTags('article_info.php', $all['id']);
                     $articlesArray['all_articles']['string'] .= '<span class="h4">-&nbsp;<a href="' . tep_href_link('article_info.php', 'articles_id='.$all['id'], 'SSL') . '">' . $boldTags['start'] . $all['text'] . $boldTags['stop'] . '</a></span>' . (SEPARATE_ARTICLES == 'true' ? '<hr class="separatorArticle">' : '<br />');
                 } else {
                     $articlesArray['all_articles']['string'] .= '<span class="h5">-&nbsp;<a class="list-group-item list-group-item-action" href="' . tep_href_link('articles.php', '', 'SSL') . '">' . $boldTags['start'] . '<div style="float:right; color:red;">...more</div>' . $boldTags['stop'] . '</span></a>';
                     break;
                 }
                 $ctr++;
              }
           }
        }

        /********************* ADD BLOG TOPICS ********************/
        if (ARTICLE_BOX_DISPLAY_ALL_BLOG_SECTION == 'true')
        {
           $articles_all_count = '';
           if (SHOW_ARTICLE_COUNTS == 'true') {
               $articles_new_query = tep_db_query("SELECT a.articles_id from " . TABLE_ARTICLES . " a, " . TABLE_ARTICLES_TO_TOPICS . " a2t, " . TABLE_TOPICS_DESCRIPTION . " td, " . TABLE_AUTHORS . " au, " . TABLE_ARTICLES_DESCRIPTION . " ad where a.authors_id = au.authors_id and a2t.topics_id = td.topics_id and (a.articles_date_available IS NULL or to_days(a.articles_date_available) <= to_days(now())) and a.articles_id = a2t.articles_id and a.articles_status = '1' and a.articles_is_blog = 1 and a.articles_id = ad.articles_id and ad.language_id = '" . (int)$languages_id . "' and td.language_id = '" . (int)$languages_id . "'");
               $articles_all_count = (tep_db_num_rows($articles_new_query) ? tep_db_num_rows($articles_new_query) : '');
      }
           $articlesArray['blog']['sort_order'] = ARTICLE_BOX_DISPLAY_ALL_BLOG_SECTION_SORT_ORDER;
           $boldTags = array();
           $boldTags = GetBoldTags('article_blog.php');

           $articlesArray['blog']['string'] = '<span class="h5"><b>';
           $articlesArray['blog']['string'] .= '<a href="' . tep_href_link('articles.php', 'showblogarticles=true', 'SSL') . '">' . $boldTags['start'] . BOX_ALL_BLOG_ARTICLES . $boldTags['stop'] . '</a>';
           $articlesArray['blog']['string'] .= '&nbsp;' . $articles_all_count . '</span><br />';

           if (ARTICLE_BOX_DISPLAY_All_BLOG_LINKS == 'true') {
              $allArticles = tep_get_all_blog_articles_array();
              $ctr = 0;
              foreach ($allArticles as $all) {
                 if (! tep_not_null(ARTICLE_BOX_DISPLAY_ALL_BLOG_LINKS_LIMIT) || (tep_not_null(ARTICLE_BOX_DISPLAY_ALL_BLOG_LINKS_LIMIT) && $ctr < ARTICLE_BOX_DISPLAY_ALL_BLOG_LINKS_LIMIT)) {
                     $boldTags = GetBoldTags('article_blog.php', $all['id']);
                     $articlesArray['blog']['string'] .= '<span class="h5">-&nbsp;<a href="' . tep_href_link('article_blog.php', 'articles_id='.$all['id'], 'SSL') . '">' . $boldTags['start'] . $all['text'] . $boldTags['stop'] . '</a></span>' . (SEPARATE_BLOG_ARTICLES == 'true' ? '<hr class="separatorBlogArticle">' : '<br />');
                 } else {
                     $articlesArray['blog']['string'] .= '<span class="h5">-&nbsp;<a href="' . tep_href_link('articles.php', '', 'SSL') . '">' . $boldTags['start'] . '<div style="float:right; color:red;">...more</div>' . $boldTags['stop'] . '</a></span><br />';
                     break;
                 }
                 $ctr++;
              }
           }
        }
        /********************* SORT THE DISPLAY  ********************/
        usort($articlesArray, "SortBySetting");
        $content = '';
        foreach ($articlesArray as $line) {
            $content .= $line['string'];
        }
        /********************* DISPLAY IT ALL ********************/
      $data = '<div class="card">' .
                '  <div class="card-header">' . MODULE_BOXES_ARTICLES_BOX_TITLE . '</div>' .
                '  <div class="card-body">' . $content . '</div>' .
                '</div>';
      $oscTemplate->addBlock($data, $this->group);
    }

    function isEnabled() {
      return $this->enabled;
    }

    function check() {
      return defined('MODULE_BOXES_ARTICLES_STATUS');
    }

    function install() {
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Article Manager Authors Infobox', 'MODULE_BOXES_ARTICLES_STATUS', 'True', 'Do you want to add the module to your shop?', '6', '1', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Content Placement', 'MODULE_BOXES_ARTICLES_CONTENT_PLACEMENT', 'Left Column', 'Should the module be loaded in the left or right column?', '6', '1', 'tep_cfg_select_option(array(\'Left Column\', \'Right Column\'), ', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort Order', 'MODULE_BOXES_ARTICLES_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
    }

    function remove() {
      tep_db_query("delete from configuration where configuration_key in ('" . implode("', '", $this->keys()) . "')");
    }

    function keys() {
      return array('MODULE_BOXES_ARTICLES_STATUS', 'MODULE_BOXES_ARTICLES_CONTENT_PLACEMENT', 'MODULE_BOXES_ARTICLES_SORT_ORDER');
    }
  }
?>

 


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

It looks good so far to work up to PHP 7.1, but I do not know enough about this add-on to say more details.

It may not be updated yet for this EDGE version and BS4,

Let's see what Jack @Jack_mcssays about.

Edited by raiwa

Share this post


Link to post
Share on other sites

Let's wait for a response from @Jack_mcs .
For me, the module of articles (blogs) is very important, because I have a large amount of information important for the work of the store.
The article manager is a little naughty kid. It has unnecessary functions, such as adding articles by the user - this option is not needed in the store.
The module is built on the principle of the Catalog, but the management and menu are unnecessarily complex. Many unnecessary additional features.


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Made a correction. Restored block:

 

        /********************* BUILD TOPICS ********************/
        if (ARTICLE_BOX_DISPLAY_TOPICS_SECTION == 'true') {
          $articlesArray['all_topics']['sort_order'] = ARTICLE_BOX_DISPLAY_TOPICS_SECTION_SORT_ORDER;
          $boldTags = GetBoldTags('article-topics.php');
          $articlesArray['all_topics']['string'] = '<span class="h5"><b><a href="' . tep_href_link('article-topics.php', '', 'SSL') . '">' . $boldTags['start'] . BOX_ARTICLE_TOPICS . $boldTags['stop'] . '</a></b></span><br />';
          if (ARTICLE_BOX_DISPLAY_TOPICS_LINKS == 'true') {
             $articlesArray['all_topics']['string'] .= preg_replace('/(<br \/>)+$/', '', $topics_string); 
          }   
          $articlesArray['all_topics']['string'] .= (SEPARATE_TOPICS == 'true' ? '<hr class="separatorArticle">' : '<br />');
        }

Menu work.


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites
1 hour ago, raiwa said:

It may not be updated yet for this EDGE version and BS4,

That's correct. The last updated version is not useable in a CE shop without editing. From the code @fredi posted, he has edited the files. I have a working version for CE Final but I haven't done any testing with BS4 so I don't know if it will work with it or not. The release of the new version is on my todo list so I will upload when I can.

Share this post


Link to post
Share on other sites

Thanks Jack!

 


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Hello Jack, Guten morgen!
My request: The article manager must be adapted to the modern requirements of Gogle. Google requires an adaptation for mobile devices from our stores. This is primarily needed for the Articles menu. A style that is not adapted to mobile devices. Cannot select menu item. It is desirable that the menu format be similar with the menu of products.

Danke.


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites
4 hours ago, Fredi said:

This is primarily needed for the Articles menu

Please explain what you mean by the menu. I don't understand the reference.

Share this post


Link to post
Share on other sites

Box "Articles".
2018-11-19_144756.jpg.7a8e5ad7f9351910d1fc567bab52f170.jpg2018-11-19_144711.jpg.bb8b8e3d38120f3910784a1ca8bba28a.jpg Screenshots boxes Articles and new BS box Categories.2018-11-19_145400.jpg.e9f98b3fd6abe6cb292ade288db0b131.jpg

Difference in usability. On mobile devices, the lines in the Boxing Articles are located very close to each other and there is no way to select the one you want.

The second screenshot of boxing articles is my attempt to make it more convenient.

 


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Thank you for the images. I don't recall what's in the version you are using but the latest, unreleased, version has css to control how the text is displayed so that is not an issue.

Share this post


Link to post
Share on other sites

Ok, I will try it today.

Thank You Jack.


Support forum for osCommerce in russian language - from Ashkelon. Support since 2002.

Best regards,

Fredi

Share this post


Link to post
Share on other sites

Some comments regarding Articles Manager V 1.57_8:

======================

in articles.php

I could not find any definition for $articles_all_split.

This condition:

if (ARTICLE_LIST_FILTER) {

should be:

if (ARTICLE_LIST_FILTER != 'false')

======================

in includes/modules/article_listing.php

this code:

      if (DISPLAY_ABSTRACT_ARTICLE_LISTING == 'true') {
?>
            <div class="main" style="padding-left:15px"><?php echo clean_html_comments(substr($articles_listing['articles_head_desc_tag'],0, MAX_ARTICLE_ABSTRACT_LENGTH)) . ((strlen($articles_listing['articles_head_desc_tag']) >= MAX_ARTICLE_ABSTRACT_LENGTH) ? '...' : ''); ?></div>
<?php
      }
      
breaks the html, if MAX_ARTICLE_ABSTRACT_LENGTH is exceeded. I noticed this when one $articles_listing['articles_head_desc_tag'] contained <div> ... </div>

We should preserve all html tags even if the string gets truncated.

I found one solution here:
https://gist.github.com/JayWood/348752b568ecd63ae5ce

Maybe you guys can find a better solution. This seems to work for me (incl. Finnish language). I have no idea of possible performance impact.

      if (DISPLAY_ABSTRACT_ARTICLE_LISTING == 'true') {
        $articles_head_desc_tag = $articles_listing['articles_head_desc_tag'];
        if (strlen($articles_listing['articles_head_desc_tag']) > MAX_ARTICLE_ABSTRACT_LENGTH) {
            $articles_head_desc_tag = substr($articles_head_desc_tag,0, MAX_ARTICLE_ABSTRACT_LENGTH);
            $articles_head_desc_tag .= ' ... ';

            libxml_use_internal_errors(true);

            $dom = new \DOMDocument;
            $dom->loadHTML($articles_head_desc_tag);

            // Strip wrapping <html> and <body> tags
            $mock = new \DOMDocument;
            $body = $dom->getElementsByTagName('body')->item(0);
            foreach ($body->childNodes as $child) {
                $mock->appendChild($mock->importNode($child, true));
            }

            $articles_head_desc_tag = trim($mock->saveHTML());
        }
?>
            <div class="main" style="padding-left:15px"><?php echo clean_html_comments($articles_head_desc_tag); ?></div>
<?php
      }

 

Share this post


Link to post
Share on other sites

@vmnThank you for posting the problems you found. I will check them in the next version,

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×