Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial Commit

  • Loading branch information...
commit d7378fd3301ad684d33f23d1ce81017b4add4280 0 parents
@PastorBones authored
6 .gitmodules
@@ -0,0 +1,6 @@
+[submodule "lib/LoU-PHP"]
+ path = lib/LoU-PHP
+ url = https://github.com/PastorBones/LoU-PHP
+[submodule "lib/Forum-Manager"]
+ path = lib/Forum-Manager
+ url = https://github.com/PastorBones/LoU-PHP-Forum-Manager
8 LICENSE
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2012 Roger Mayfield
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
95 README.md
@@ -0,0 +1,95 @@
+LoU-PHP Mailing List Generator
+=========================
+
+#### Version 0.0.1
+
+## Description
+
+A complete out-of-the-box script based on the [LoU-PHP](https://github.com/PastorBones/LoU-PHP) class that will generate continent specific mailing lists for multiple alliances and post those lists automagically to their respective continent threads in the alliance forum. Can also generate a text file listing every continent with members on them along with amounts of members on each continent.
+
+## Requirements
+
+This class requires a valid and authenticated LoU session using the [LoU-PHP](https://github.com/PastorBones/LoU-PHP) class and the [Forum Manager](https://github.com/PastorBones/LoU-PHP-Forum-Manager) class which is also based on LoU-PHP.
+
+## Installation
+
+It is highly advised that you clone this repository. That will not only download this class, but will also download all dependancies into their proper places.
+
+```bash
+
+~$ mkdir Mail-List-Generator
+~$ cd Mail-List-Generator/
+~/Mail-List-Generator$ git clone https://github.com/PastorBones/LoU-PHP-Mail-List-Generator
+
+```
+
+## Usage
+
+Begin by configuring the Mail List Generator by editing the config.ini file. You'll have to enter your LoU credentials, alliance name, and a few other options before it will work.
+
+Once your configuration is setup, simply open a terminal (command prompt) and start the script by running the _app.php_ file
+
+```bash
+
+~/Mail-List-Generator>php app.php
+
+```
+
+## Configuration Details
+
+I have tried to build in as many configuration options as possible. This allows you to customize the output of this script to meet your individual taste. The default configuration file is well documented and doesn't need much explanation, but I would like to explain the maillist.tpl file.
+
+The template file allows you to write your own post and include the data generated by the script wherever you want. This works by using template variable marked with {{ variable }} as shown in the example below.
+
+```
+
+This mailing list has been automatically generated and posted for your convenience. If it becomes incorrect or outdated, please mail me immediately
+and I will re-generate the lists. [b]Always check for outdated lists before sending sensitive information![/b]
+
+ [b][u]Last Update[/u]:[/b] {{ DATE }}
+
+[u]Alliance Leaders[/u]
+ {{ leaders }}
+
+[u]Alliance Officers[/u]
+ {{ officers }}
+
+[u]Continent Leaders[/u]
+ {{ cont-leaders }}
+
+{{ LOOP: alliance }}
+[u][{{ name }}][/u]
+ {{ list }}
+{{ ENDLOOP }}
+
+```
+
+As you can see this leaves alot of room for customization of the actual post sent to the forum. Here is a list of variables and their meanings
+
+* **{{ DATE }}** - The current date as formatted in the configuration options.
+
+* **{{ leaders }** - The list of alliance leaders exactly as written in the configuration file.
+
+* **{{ officers }}** - The list of of officers exactly as written in the configuration file.
+
+* **{{ cont-leaders }} - The list of continent leaders written in the config file that matches the continent forum for which we're posting in.
+
+* **{{ LOOP: alliance }} / {{ ENDLOOP }}** - Specifies the subsection that is replaced by each alliance for this continent.
+
+* **{{ name }} - The alliance name for the list we're posting in the current loop.
+
+* **{{ list }}** - The actual mailing list for the current alliance and continent.
+
+## Could there be more?
+
+Why yes, there can and there will be! This is only one simple application of the [LoU-PHP](https://github.com/PastorBones/LoU-PHP) class. I'll be making more of them as the ideas come along, but feel free to make your own script and have it listed on the [LoU-PHP Wiki](https:/github.com/PastorBones/LoU-PHP/wiki)!
+
+## License
+
+Copyright 2012, Roger Mayfield
+
+Licensed under the MIT License (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
+
+[http://opensource.org/licenses/mit-license.php](http://opensource.org/licenses/mit-license.php)
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
304 app.php
@@ -0,0 +1,304 @@
+<?php
+
+ require_once( 'lib/LoU-PHP/lou.class.php' );
+ require_once( 'mail-list-generator.class.php' );
+ require_once( 'lib/Forum-Manager/forum-manager.class.php' );
+
+ // Parse config file
+ $cfg = parse_ini_file( 'config.ini' );
+
+ // Ensure data path ends with trailing slash
+ $cfg[ 'data_path' ] = rtrim( $cfg[ 'data_path' ], DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
+
+ // Set timezone
+ if( isset( $cfg[ 'timezone' ] ) && !empty( $cfg[ 'timezone' ] ) )
+ {
+ date_default_timezone_set( $cfg[ 'timezone' ] );
+ }
+
+ $lou = LoU::createClient( $cfg[ 'data_path' ] );
+
+ // Begin by connecting to LoU
+ echo "\n" . appTitle() . "\n\n";
+ info( "Connecting to LoU" );
+
+ if( !$lou->login( $cfg[ 'email' ], $cfg[ 'password' ] ) )
+ {
+ info( 'FATAL', $lou->error );
+ }
+
+ if( !$lou->selectWorld( $cfg[ 'world_id' ] ) )
+ {
+ info( 'FATAL', $lou->error );
+ }
+
+ // Pull authenticated user info indirectly, without causing screen refresh
+ $me = new stdClass();
+ $res = $lou->poll( array( 'player' => '' ) );
+ foreach( $res as $r )
+ {
+ if( $r->C == 'PLAYER' )
+ {
+ $city_id = $r->D->c[ 0 ]->i;
+ $city = $lou->get( 'GetPublicCityInfo', array( 'id' => $city_id ) );
+
+ $me->id = $city->p;
+ $me->name = $city->pn;
+ }
+ }
+
+ // Instantiate our mail list class
+ $ml = new MailListGenerator( $cfg[ 'alliance' ] );
+
+ // Generate our list
+ info( 'Generating mailing list...please wait' );
+ $list = $ml->generate();
+
+ // Should we generate the text file?
+ if( $cfg[ 'generate_txt_file' ] )
+ {
+ info( 'Generating text file...' );
+ $time = time();
+ $txt = appTitle() . "\nThis file was generated: " . date( 'M j, Y h:i:s', $time ) . "\n\n";
+
+ // Continent list and numbers
+ $txt .= "Alliance member amounts per continent:\n\n";
+ foreach( $list as $cont => $l )
+ {
+ $txt .= "\tC" . $cont . " - ";
+ $counts = array();
+ foreach( $l as $aName => $names )
+ {
+ $counts[] = $aName . ": " . count( $names ) . " ";
+ }
+ $txt .= implode( ', ', $counts ) . "\n";
+ }
+ $txt .= "\nMailing Lists:\n\n";
+ foreach( $list as $cont => $l )
+ {
+ $txt .= "[ C" . $cont . " ]\n\n";
+ foreach( $l as $abbr => $names )
+ {
+ $txt .= "- $abbr -\n" . "\t" . implode(';', $names) . ";\n\n";
+ }
+ }
+
+ $filename = $cfg[ 'data_path' ] . date('Y-m-d_H:i:s') . '-mail_list.txt';
+ if( !file_put_contents( $filename, $txt, LOCK_EX ) )
+ {
+ info( 'fatal', 'Cannot create file: ' . $filename );
+ }
+ }
+
+ // Should we post to the forum?
+ if( $cfg[ 'post_to_forum'] )
+ {
+ info( 'Posting to forums' );
+
+ // Check for template file
+ if( !file_exists( $cfg[ 'template_file' ] ) )
+ {
+ info( 'fatal', 'Cannot locate the template file: ' . $tpl_file );
+ }
+
+ $tpl_file = file_get_contents( $cfg[ 'template_file' ] );
+
+ // Parse the date
+ $tpl_file = setDate( $tpl_file );
+
+ // Parse alliance leaders
+ $tpl_file = setLeadersAndOfficers( $tpl_file );
+
+ // Pull out our mailing list loop
+ preg_match( "/\{\{\s+LOOP:\s+alliance\s+\}\}(.*)\{\{\s+ENDLOOP\s+\}\}/is", $tpl_file, $match );
+ if( !isset( $match[1] ) )
+ {
+ info( 'fatal' ,'The template file does not contain {{ LOOP: alliance }}. There is nothing to post!' );
+ }
+ $repl_tpl = $match[ 1 ];
+ $tpl_file = str_replace( $repl_tpl, '', $tpl_file );
+
+ // Create our Forum Manager instance
+ $fm = new ForumManager();
+
+ foreach( $list as $cont => $l )
+ {
+ // Parse continent leaders
+ $post = setContinentLeaders( $cont, $tpl_file );
+
+ // Parse mailing list per alliance
+ $repl = '';
+ foreach( $l as $aName => $names )
+ {
+ $tmp = preg_replace("/\{\{\s*name\s*\}\}/i", $aName, $repl_tpl );
+ $tmp = preg_replace("/\{\{\s*list\s*\}\}/i", implode( ';', $names ) . ';', $tmp );
+ $repl .= $tmp . "\n\n";
+ }
+ $post = preg_replace( "/\{\{\s+LOOP:\s+alliance\s+\}\}(.*)\{\{\s+ENDLOOP\s+\}\}/", $repl, $post );
+
+ // Remove multiple line breaks
+ $post = preg_replace( "/\n\n++/","\n\n", $post );
+
+ // Check for post length - 3000 characters
+ if( strlen( $post ) > 3000 )
+ {
+ info( 'fatal', 'Post is too long.' );
+ }
+
+ $thread_title = preg_replace("/\{\{\s*cont\s*\}\}/i", $cont, $cfg[ 'forum_thread_tpl' ] );
+
+ // Find our continent thread
+ $forum = $fm->loadForum()->select( 'id' )->where( 'title', $thread_title )->find_one();
+
+ // Post only if this thread already exists
+ if( !empty( $forum ) )
+ {
+ // Find our Mailing List thread
+ $thread = $fm->loadThreads( $forum->id )->where( 'title', $cfg[ 'forum_title'] )->find_one();
+
+ // Create thread if one doesn't exist already
+ if( empty( $thread ) )
+ {
+ $fm->createThread( $forum->id, $cfg[ 'forum_title' ], $post );
+ }
+ else
+ {
+ // Search for any threads by me
+ $forum_posts = $fm->loadPosts( $forum->id, $thread->id )->where( 'author_id', $me->id )->find_many();
+
+ if( empty( $forum_posts ) )
+ {
+ // Create new post
+ $fm->createPost( $forum->id, $thread->id, $post );
+ }
+ else
+ {
+ // Edit first post
+ $fm->editPost( $forum->id, $thread->id, $forum_posts[ 0 ]->id, $post );
+ }
+
+ // Delete any other posts besides the one we just updated
+ if( $cfg[ 'erase_multiple' ] && count( $forum_posts ) > 1 )
+ {
+ info( 'Deleting mutiple posts' );
+ array_shift( $forum_posts );
+ foreach( $forum_posts as $forum_post )
+ {
+ $fm->deletePost( $forum->id, $thread->id, $forum_post->id );
+ }
+ }
+ info( 'Updated mailing list: ' . $thread_title );
+ }
+ }
+ }
+ }
+
+ info( 'Done' );
+
+ /*
+ * Shortcut method for displaying info on the screen
+ * @param string $type
+ * @param string $msg
+ */
+ function info( $type, $msg = '' )
+ {
+ if( empty( $msg ) )
+ {
+ $msg = $type;
+ $type = 'INFO';
+ }
+
+ if( strtolower( $type ) == 'fatal' )
+ {
+ echo date( 'H:i:s' ) . " [ERROR] - " . $msg . "\n\n\n";
+ exit;
+ }
+ else
+ {
+ echo date( 'H:i:s' ) . " [" . strtoupper( $type ) . "] - " . $msg . "\n";
+ }
+ return true;
+ }
+
+ /*
+ * Returns our app title string
+ * @return string
+ */
+ function appTitle()
+ {
+ return "Mail List Generator\nAuthor: PastorBones\nCopyright (c) 2012\nhttps://github.com/PastorBones/LoU-PHP-Mail-List-Generator";
+ }
+
+ /*
+ * Parses the date in our template
+ * @params string $tpl_file
+ * @return string
+ */
+ function setDate( $tpl_file )
+ {
+ global $cfg;
+
+ if( strstr( $tpl_file, '{% DATE %}' ) )
+ {
+ $tpl_file = str_replace( '{% DATE %}', date( $cfg[ 'date_format' ] ), $tpl_file );
+ }
+
+ return $tpl_file;
+ }
+
+ /*
+ * Parses the alliance leaders and officers in our template
+ * @params string $tpl_file
+ * @return string
+ */
+ function setLeadersAndOfficers( $tpl_file )
+ {
+ global $cfg;
+
+ // Fill Leaders
+ if( isset( $cfg[ 'alliance_leader_list'] ) && $cfg[ 'alliance_leader_list' ] )
+ {
+ $tpl_file = preg_replace( "/\{\{\s+leaders\s+\}\}/is", $cfg[ 'alliance_leader_list' ], $tpl_file );
+ }
+ else
+ {
+ $tpl_file = preg_replace( "/\{\{\s+leaders\s+\}\}/is", 'None Listed', $tpl_file );
+ }
+
+ // Fill Officers
+ if( isset( $cfg[ 'alliance_officer_list'] ) && $cfg[ 'alliance_officer_list' ] )
+ {
+ $tpl_file = preg_replace( "/\{\{\s+officers\s+\}\}/is", $cfg[ 'alliance_officer_list' ], $tpl_file );
+ }
+ else
+ {
+ $tpl_file = preg_replace( "/\{\{\s+officers\s+\}\}/is", 'None Listed', $tpl_file );
+ }
+
+ return $tpl_file;
+ }
+
+ /*
+ * Parses the continent leaders in our template
+ * @params string $cont
+ * @params string $tpl_file
+ * @return string
+ */
+ function setContinentLeaders( $cont, $tpl_file )
+ {
+ global $cfg;
+
+ // Fill Continent Leaders
+ if( isset( $cfg[ 'continent_leader_list'][ $cont ] ) && $cfg[ 'continent_leader_list' ][ $cont ] )
+ {
+ $tpl_file = preg_replace( "/\{\{\s+cont-leaders\s+\}\}/is", $cfg[ 'continent_leader_list' ][ $cont ], $tpl_file );
+ }
+ else
+ {
+ $tpl_file = preg_replace( "/\{\{\s+cont-leaders\s+\}\}/is", 'None Listed', $tpl_file );
+ }
+
+ return $tpl_file;
+ }
+
+
50 config.ini
@@ -0,0 +1,50 @@
+
+; The relative path to the writable data directory for cookie files
+data_path = './data'
+
+; The email, password, and world id of the account to post with
+email = 'xxxxxx@gmail.com'
+password = 'xxxxx'
+world_id = 'World 74'
+
+; The timezone the server is in. You can find acceptable timezone strings at
+; http://php.net/manual/en/timezones.php
+timezone = 'America/New_York'
+
+; A list of alliances to create mailing lists for - must be correctly spelled
+alliance[] = 'Draconic Knights'
+alliance[] = 'Order of the Drakul'
+
+; Post the generated mailing lists to the forum for existing threads? ( true | false )
+post_to_forum = true
+
+; Forum title - continents ALWAYS contain 2 digits, make sure forums are created
+forum_thread_tpl = 'C{{ cont }}'
+
+; The title of the thread to post in. If it does not exist it will be created.
+forum_title = 'Mailing List'
+
+; The relative path and filename to the template used when posting - see README.md
+; for a list of template variables
+template_file = './maillist.tpl'
+
+; The PHP format for the date template variable
+date_format = 'D F j, Y - H:i:s'
+
+; Erase mutiple postings by you in this thread - false to disable
+erase_multiple = true
+
+; Save a text file of ALL generated mailing lists to the data directory? ( true | false )
+generate_txt_file = true
+
+; Alliance leader mailing list posted on every continent mailing list
+; set to false or leave empty to disable
+alliance_leader_list = 'leader1;leader2;'
+
+; Officer mailing list posted on every continent mailing list
+; set to false or leave empty to disable
+alliance_officer_list = 'officer3;officer1;officer2;'
+
+; Continent leader lists are posted on the continent it's listed for
+; Only the ones provided will be used, use ## format for naming continents
+continent_leader_list['03'] = 'contleader1;contleader2;'
1  lib/Forum-Manager
@@ -0,0 +1 @@
+Subproject commit 7d42744e73e90d951ef0b6cecf51eaed45689839
1  lib/LoU-PHP
@@ -0,0 +1 @@
+Subproject commit 88241c912cb24a1d7b270ae378af092d21157085
201 mail-list-generator.class.php
@@ -0,0 +1,201 @@
+<?php
+
+Class MailListGenerator
+{
+ private $lou;
+
+ public $alliances;
+
+ private $cur_alliance;
+ private $cur_cont;
+
+ public $list = array();
+ public $alliance_list = array();
+ public $continent_list = array();
+
+ public function __construct( $alliances )
+ {
+ $this->lou = LoU::createClient();
+
+ // Check for valid session
+ $sess = $this->lou->getSessionInfo();
+ if( !isset( $sess->key ) || empty( $sess->key ) )
+ {
+ throw new Exception('Invalid LoU session');
+ }
+
+ // Ensure we have an array
+ if( !is_array( $alliances ) )
+ {
+ $alliances = array( $alliances );
+ }
+ $this->alliances = $alliances;
+
+ return true;
+ }
+
+ public function generate()
+ {
+ // Grab a complete list of alliances from rankings
+ $rankList = $this->getRankList( 'alliance' );
+
+ foreach( $rankList as $alliance )
+ {
+ foreach( $this->alliances as $aName )
+ {
+ // Is this one of our alliances?
+ if( strtolower( $alliance->n ) == strtolower( $aName ) )
+ {
+ // Set our alliance
+ $this->setAlliance( $alliance->i );
+
+ // Loop member list for this alliance
+ foreach( $this->getMembers( $alliance->i ) as $member )
+ {
+ foreach( $this->getCities( $member->i ) as $city )
+ {
+ $this->setContinent( $city->x, $city->y );
+ $this->addName( $member->n );
+ }
+ }
+ }
+ }
+ }
+ $this->sortList();
+ return $this->list;
+ }
+
+ private function sortList()
+ {
+ foreach( $this->list as $cont => $list )
+ {
+ foreach( $list as $abbr => $names )
+ {
+ $this->list[ $cont ][ $abbr ] = $this->natSort( $names );
+ }
+ ksort( $this->list[ $cont ] );
+ }
+ ksort( $this->list );
+ }
+
+ private function addName( $name )
+ {
+ if( !isset( $this->list[ $this->cur_cont ] ) )
+ {
+ $this->list[ $this->cur_cont ] = array( 'All' => array() );
+ }
+ if( !isset( $this->list[ $this->cur_cont ] [ $this->cur_alliance ] ) )
+ {
+ $this->list[ $this->cur_cont ] [ $this->cur_alliance ] = array();
+ }
+ if( !in_array( $name, $this->list[ $this->cur_cont ][ 'All' ] ) )
+ {
+ array_push( $this->list[ $this->cur_cont ] [ 'All' ], $name );
+ array_push( $this->list[ $this->cur_cont ] [ $this->cur_alliance ], $name );
+ }
+
+ return true;
+ }
+
+ private function getMembers( $id )
+ {
+ return $this->lou->get( 'GetPublicAllianceMemberList', array( 'id' => $id ) );
+ }
+
+ private function getCities( $id )
+ {
+ $player = $this->lou->get( 'GetPublicPlayerInfo', array( 'id' => $id ) );
+
+ if( isset( $player->c ) && !empty( $player->c ) )
+ {
+ return $player->c;
+ }
+ return array();
+ }
+
+ private function setAlliance( $id )
+ {
+ $alliance = $this->lou->get( 'GetPublicAllianceInfo', array( 'id' => $id ) );
+ $this->cur_alliance = $alliance->a;
+
+ // Add to our alliance list
+ if( !in_array( $alliance->a, $this->alliance_list ) )
+ {
+ array_push( $this->alliance_list, $alliance->a );
+
+ // Sort this list
+ $this->alliance_list = $this->natSort( $this->alliance_list );
+ }
+
+ return true;
+ }
+
+ private function setContinent( $x, $y )
+ {
+ $this->cur_cont = $this->getContFromCoords( $x, $y );
+
+ // Add to our continent list
+ if( !in_array( $this->cur_cont, $this->continent_list ) )
+ {
+ array_push( $this->continent_list, $this->cur_cont );
+
+ // Sort this list
+ $this->continent_list = $this->natSort( $this->continent_list );
+ }
+
+ return true;
+ }
+
+ private function natSort( $list )
+ {
+ natcasesort( $list );
+ return array_values( $list );
+ }
+
+ private function getContFromCoords( $x, $y )
+ {
+ $cont = strval( floor( $y / 100 ) ) . strval( floor( $x / 100 ) );
+
+ while( strlen( $cont ) < 2 )
+ $cont = '0' . $cont;
+ return $cont;
+ }
+
+ private function getRankList( $type )
+ {
+ $type = ucfirst( strtolower( $type ) );
+ $count = $this->lou->get( $type . 'GetCount', array( 'continent' => -1, 'sort' => 0, 'ascending' => true,'type' => 0 ) );
+
+ $iter = intval( $count / 400 );
+ $left = intval( $count % 400 );
+ $start = 0;
+ $end = 399;
+ $send = array();
+
+ for ($x = 0; $x < $iter; $x++)
+ {
+ $send[] = array( 'start' => $start, 'end' => $end );
+ $start += 400;
+ $end += 400;
+ }
+ if( $left > 0 )
+ {
+ $send[] = array( 'start' => ( $count - $left ), 'end' => ( $count - 1 ) );
+ }
+
+ $data = array();
+ foreach( $send as $s )
+ {
+ $s = array_merge( $s, array( 'continent' => -1, 'sort' => 0, 'ascending' => true,'type' => 0 ) );
+ $res = $this->lou->get( $type . 'GetRange', $s );
+
+ if( !is_array( $res ) )
+ {
+ info( 'fatal', 'Invalid response from LoU' );
+ }
+ $data = array_merge( $data, $res );
+ }
+
+ return $data;
+ }
+}
23 maillist.tpl
@@ -0,0 +1,23 @@
+This mailing list has been automatically generated and posted for your convenience. If it becomes incorrect or outdated, please mail me immediately and I will re-generate the lists. [b]Always check for outdated lists before sending sensitive information![/b]
+
+ [b][u]Last Update[/u]:[/b] {% DATE %}
+
+[u]Alliance Leaders[/u]
+ {{ leaders }}
+
+[u]Alliance Officers[/u]
+ {{ officers }}
+
+[u]Continent Leaders[/u]
+ {{ cont-leaders }}
+
+
+
+{{ LOOP: alliance }}
+[u][{{ name }}][/u]
+ {{ list }}
+{{ ENDLOOP }}
+
+
+
+[i]Make your own automatic mailing lists! [url]http://bit.ly/ROnv8Z[/url][/i]
Please sign in to comment.
Something went wrong with that request. Please try again.