Jonas Erixon avatar Jonas Erixon committed 6504c67

initial commit

Comments (0)

Files changed (99)

docs/design_stuff.txt

+vill kunna säga att zzzarka har:
+	land 196 
+	email jonas.erixon@gmail.com 
+	tele +46733715487
+	smsmail: N/A
+	
+	.. hur skajag göra för att klara av 
+		* multipla IRC nicks
+		* multipla länder för tex FFA
+	
+	Table: members
+		mem_nick
+		mem_email
+		mem_tele
+		mem_smsmail
+		mem_comment
+		mem_lastemail
+		
+TODO LIST:
+
+    being able to register with the bot, information it collects is:
+
+        Country number .. might make it possible to have multiple country numbers assosiated with 1 nick .. but not to start with
+
+        Email address
+
+        Phone number
+
+        SMS email address thingy
+
+        General comment .. like ex:call me and i keel uuuu!!
+
+	Searching for country number/nick and get info
+
+    Say in the chat when someone is hit and what with
+
+    Perhaps an auto email/sms option when someone has gotten hit more then X time .. this needs to like limited to avoid spam ..
+
+    Allow for nick aliases .. or something ..
+
+
+War Tools
+
+
+    Simulated chem rush (basicly a clone of my javascript)
+
+    Maybe a simulation for BR and GS aswell ..
+
+
+War chat helpers:
+
+
+    being able to initiate and end a warchat session
+
+    Collect stats from the particpants
+
+    Setting a target
+
+    Automagicaly updating the breaks
+
+    Warning system for when the target gets online (20a bonus maybe)
+
+    Warning system when more the X fails in a row has been encountered
+
+    Insults for slow hitting (heh .. yes this is the most important feature :P)
+
+    Collect statistics to get a good overview of what kind of turns etc is available
+
+    Maybe have a way to upload spyops to it so it can have some nice data to start crunching
+
+        if we get this we could make a reasonably nice break calc .. like ".canbreak 196 123" and it woyld answer "Yes send 1M jets" or "No, need atleast 1M jets"
+
+

docs/warbot_docs.zdoc

+@pre=+
+#h1 Zzzarkas War bot
+$TOC$
+#h2 General Usage
+Commands are executed in a fashion similar to a *nix command line, most commands have a set off different flags that changes the behavior of the command. most commands have a '-h' flag wich will make the bot spit out a hopefully helpfull message about how the command is used 
+
+#h2 Available Commands
+#h3 General Commands
+#h4 %pre%mem (-h -c <country number> -p <phone> -e <email> -s <sms email>  -n nick)
+adds/updates members to the member database, when a user is registered in the members database he/she will get notified when hit, currently just in IRC but email and SMS is planned
+#ul
+* -c country number
+* -p telephone number
+* -e email address
+* -s sms email number
+* -n nick to add/update (optinal, if not provided uses the nick off the issuing user)
+#end
+#h4 list (-n <nick> -c <country number>)
+list registered members
+#ul
+* -c filter on country number
+* -n filter on nick nicks can be partial, ex: "%pre%list -n zzz" will list all registered memebrs with 3 consecutive z's in the nick. % means "any string of characters"
+#end
+#h4 %pre%spyup (-t <tag list> -c <country list>)
+Updates the bots internal spyop database, needs one of below flags
+#ul
+* -t takes acomma separated list of tags, you can extract available tag's from the help command
+* -c update specific countries (NOT IMPLEMENTED YET!)
+#end
+#h4 %pre%spy <country number>
+send a private message with spy info about the provided country number
+
+#h3 Simulation Commands
+#h4 %pre%cr
+Simulates a chemrush
+
+#h3 War Commands
+#h4 %pre%setTarget <country number>
+sets the current target, will start to sniff the news for incomming attacks on the target and do a shout out of the current break.
+#h4 %pre%clearTarget
+clear the current target

docs/warbot_docs.zdoc.html

+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title></title><style type="text/css">
+			body { font-family: verdana; font-size: 10px; }
+			h1 { font-family: times; font-size: 24px; }
+			h2 { font-family: times; font-size: 18px; margin-left: 10px; }
+			h3 { font-family: times; font-size: 14px; margin-left: 20px; }
+			h4 { font-family: times; font-size: 12px; font-weight: bold; margin-left: 30px; }
+			pre { font-size: 12px; border: 1px dashed black; margin-left: 10px; padding: 5px; }
+			.section_2 { margin-left: 20px; }
+			.section_3 { margin-left: 30px; }
+			.section_4 { margin-left: 40px; }
+			li { padding-left: 5px; }
+			table { border: 1px solid black; border-collapse: collapse; border-spacing: 0px; font-family: verdana; font-size: 10px; }
+			table td { padding: 2px; border: 1px solid black; border-collapse: collapse; border-spacing: 0px;}
+			table th { padding: 2px; text-align:left; border: 1px solid black; border-collapse: collapse; border-spacing: 0px;}
+		</style><script language="text/javascript"></script></head><body>
+</div><h1>Zzzarkas War bot</h1>
+<div class="section_1"><ol><li>General Usage</li><li>Available Commands</li><ol><li>General Commands</li><ol><li>+mem (-h -c &lt;country number&gt; -p &lt;phone&gt; -e &lt;email&gt; -s &lt;sms email&gt;  -n nick)</li><li>list (-n &lt;nick&gt; -c &lt;country number&gt;)</li><li>+spyup (-t &lt;tag list&gt; -c &lt;country list&gt;)</li><li>+spy &lt;country number&gt;</li></ol><li>Simulation Commands</li><ol><li>+cr</li></ol><li>War Commands</li><ol><li>+setTarget &lt;country number&gt;</li><li>+clearTarget</li></ol></ol></ol></div><h2>General Usage</h2>
+<div class="section_2"><p>Commands are executed in a fashion similar to a *nix command line, most commands have a set off different flags that changes the behavior of the command. most commands have a '-h' flag wich will make the bot spit out a hopefully helpfull message about how the command is used</p>
+<br/>
+</div><h2>Available Commands</h2>
+<div class="section_2"></div><h3>General Commands</h3>
+<div class="section_3"></div><h4>+mem (-h -c &lt;country number&gt; -p &lt;phone&gt; -e &lt;email&gt; -s &lt;sms email&gt;  -n nick)</h4>
+<div class="section_4"><p>adds/updates members to the member database, when a user is registered in the members database he/she will get notified when hit, currently just in IRC but email and SMS is planned</p>
+<ul><li>-c country number</li><li>-p telephone number</li><li>-e email address</li><li>-s sms email number</li><li>-n nick to add/update (optinal, if not provided uses the nick off the issuing user)</li></ul></div><h4>list (-n &lt;nick&gt; -c &lt;country number&gt;)</h4>
+<div class="section_4"><p>list registered members</p>
+<ul><li>-c filter on country number</li><li>-n filter on nick nicks can be partial, ex: "+list -n zzz" will list all registered memebrs with 3 consecutive z's in the nick. % means "any string of characters"</li></ul></div><h4>+spyup (-t &lt;tag list&gt; -c &lt;country list&gt;)</h4>
+<div class="section_4"><p>Updates the bots internal spyop database, needs one of below flags</p>
+<ul><li>-t takes acomma separated list of tags, you can extract available tag's from the help command</li><li>-c update specific countries (NOT IMPLEMENTED YET!)</li></ul></div><h4>+spy &lt;country number&gt;</h4>
+<div class="section_4"><p>send a private message with spy info about the provided country number</p>
+<br/>
+</div><h3>Simulation Commands</h3>
+<div class="section_3"></div><h4>+cr</h4>
+<div class="section_4"><p>Simulates a chemrush</p>
+<br/>
+</div><h3>War Commands</h3>
+<div class="section_3"></div><h4>+setTarget &lt;country number&gt;</h4>
+<div class="section_4"><p>sets the current target, will start to sniff the news for incomming attacks on the target and do a shout out of the current break.</p>
+</div><h4>+clearTarget</h4>
+<div class="section_4"><p>clear the current target</p>
+</body></html>

nbproject/private/private.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
+    <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
+</project-private>

nbproject/project.properties

+java.lib.path=
+platform.active=Python_2.6.1
+python.lib.path=
+src.dir=src

nbproject/project.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.python.project</type>
+    <configuration>
+        <data xmlns="http://nbpython.dev.java.net/ns/php-project/1">
+            <name>EarthBot2</name>
+            <sources>
+                <root id="src.dir"/>
+            </sources>
+            <tests/>
+        </data>
+    </configuration>
+</project>

Binary file added.

+# Makefile
+# Copyright 2008, Sean B. Palmer, inamidst.com
+# Licensed under the Eiffel Forum License 2.
+
+# archive - Create phenny.tar.bz2 using git archive
+archive: ;
+	# hg archive -t tbz2 phenny-hg.tar.bz2
+	git archive --format=tar --prefix=phenny/ HEAD | bzip2 > phenny.tar.bz2
+
+# ci - Check the code into git and push to github
+ci: ;
+	# hg ci
+	git commit -a && git push origin master
+
+# log - Show a log of recent updates
+log: ;
+	# git log --date=short --format='%h %ad %s'
+	git graph
+
+# sync - Push phenny to pubble:opt/phenny/
+sync: ;
+	rsync -avz ./ pubble:opt/phenny/
+
+help: ;
+	@egrep '^# [a-z]+ - ' Makefile | sed 's/# //'
+Installation &c.
+
+1) Run ./phenny - this creates a default config file
+2) Edit ~/.phenny/default.py
+3) Run ./phenny - this now runs phenny with your settings
+
+Enjoy!
+
+-- 
+Sean B. Palmer, http://inamidst.com/sbp/
+#!/usr/bin/env python
+"""
+__init__.py - Phenny Init Module
+Copyright 2008, Sean B. Palmer, inamidst.com
+Licensed under the Eiffel Forum License 2.
+
+http://inamidst.com/phenny/
+"""
+
+import sys, os, time, threading, signal
+import bot
+
+class Watcher(object): 
+   # Cf. http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496735
+   def __init__(self):
+      self.child = os.fork()
+      if self.child != 0: 
+         self.watch()
+
+   def watch(self):
+      try: os.wait()
+      except KeyboardInterrupt:
+         self.kill()
+      sys.exit()
+
+   def kill(self):
+      try: os.kill(self.child, signal.SIGKILL)
+      except OSError: pass
+
+def run_phenny(config): 
+   if hasattr(config, 'delay'): 
+      delay = config.delay
+   else: delay = 20
+
+   def connect(config): 
+      p = bot.Phenny(config)
+      p.run(config.host, config.port)
+
+   try: Watcher()
+   except Exception, e: 
+      print >> sys.stderr, 'Warning:', e, '(in __init__.py)'
+
+   while True:
+      try: connect(config)
+      except KeyboardInterrupt: 
+         sys.exit()
+
+      if not isinstance(delay, int): 
+         break
+
+      warning = 'Warning: Disconnected. Reconnecting in %s seconds...' % delay
+      print >> sys.stderr, warning
+      time.sleep(delay)
+
+def run(config):
+	t = threading.Thread(target=run_phenny, args=(config,))
+	try:
+		t.run()
+	except KeyboardInterrupt:
+		pass
+
+if __name__ == '__main__': 
+   print __doc__

Binary file added.

+#!/usr/bin/env python
+"""
+bot.py - Phenny IRC Bot
+Copyright 2008, Sean B. Palmer, inamidst.com
+Licensed under the Eiffel Forum License 2.
+
+http://inamidst.com/phenny/
+"""
+
+import sys, os, re, threading, imp
+import irc
+
+home = os.getcwd()
+
+def decode(bytes): 
+   try: text = bytes.decode('utf-8')
+   except UnicodeDecodeError: 
+      try: text = bytes.decode('iso-8859-1')
+      except UnicodeDecodeError: 
+         text = bytes.decode('cp1252')
+   return text
+
+
+class Phenny(irc.Bot): 
+   def __init__(self, config): 
+      args = (config.nick, config.name, config.channels, config.password)
+      irc.Bot.__init__(self, *args)
+      self.config = config
+      self.doc = {}
+      self.stats = {}
+      self.setup()
+
+   def setup(self): 
+      self.variables = {}
+
+      filenames = []
+      if not hasattr(self.config, 'enable'): 
+         for fn in os.listdir(os.path.join(home, 'modules')): 
+            if fn.endswith('.py') and not fn.startswith('_'): 
+               filenames.append(os.path.join(home, 'modules', fn))
+      else: 
+         for fn in self.config.enable: 
+            filenames.append(os.path.join(home, 'modules', fn + '.py'))
+
+      if hasattr(self.config, 'extra'): 
+         for fn in self.config.extra: 
+            if os.path.isfile(fn): 
+               filenames.append(fn)
+            elif os.path.isdir(fn): 
+               for n in os.listdir(fn): 
+                  if n.endswith('.py') and not n.startswith('_'): 
+                     filenames.append(os.path.join(fn, n))
+
+      modules = []
+      excluded_modules = getattr(self.config, 'exclude', [])
+      for filename in filenames: 
+         name = os.path.basename(filename)[:-3]
+         if name in excluded_modules: continue
+         # if name in sys.modules: 
+         #    del sys.modules[name]
+         try: module = imp.load_source(name, filename)
+         except Exception, e: 
+            print >> sys.stderr, "Error loading %s: %s (in bot.py)" % (name, e)
+         else: 
+            if hasattr(module, 'setup'): 
+               module.setup(self)
+            self.register(vars(module))
+            modules.append(name)
+
+      if modules: 
+         print >> sys.stderr, 'Registered modules:', ', '.join(modules)
+      else: print >> sys.stderr, "Warning: Couldn't find any modules"
+
+      self.bind_commands()
+      
+
+   def register(self, variables): 
+      # This is used by reload.py, hence it being methodised
+      for name, obj in variables.iteritems(): 
+         if hasattr(obj, 'commands') or hasattr(obj, 'rule'): 
+            self.variables[name] = obj
+
+   def bind_commands(self): 
+      self.commands = {'high': {}, 'medium': {}, 'low': {}}
+      
+      def bind(self, priority, regexp, func): 
+         print priority, regexp.pattern.encode('utf-8'), func
+         # register documentation
+         if not hasattr(func, 'name'): 
+            func.name = func.__name__
+         if func.__doc__: 
+            if hasattr(func, 'example'): 
+               example = func.example
+               example = example.replace('$nickname', self.nick)
+            else: example = None
+            self.doc[func.name] = (func.__doc__, example)
+         self.commands[priority].setdefault(regexp, []).append(func)
+
+      def sub(pattern, self=self): 
+         # These replacements have significant order
+         pattern = pattern.replace('$nickname', re.escape(self.nick))
+         return pattern.replace('$nick', r'%s[,:] +' % re.escape(self.nick))
+
+      for name, func in self.variables.iteritems(): 
+         # print name, func
+         if not hasattr(func, 'priority'): 
+            func.priority = 'medium'
+
+         if not hasattr(func, 'thread'): 
+            func.thread = True
+
+         if not hasattr(func, 'event'): 
+            func.event = 'PRIVMSG'
+         else: func.event = func.event.upper()
+
+         if hasattr(func, 'rule'): 
+            if isinstance(func.rule, str): 
+               pattern = sub(func.rule)
+               regexp = re.compile(pattern)
+               bind(self, func.priority, regexp, func)
+
+            if isinstance(func.rule, tuple): 
+               # 1) e.g. ('$nick', '(.*)')
+               if len(func.rule) == 2 and isinstance(func.rule[0], str): 
+                  prefix, pattern = func.rule
+                  prefix = sub(prefix)
+                  regexp = re.compile(prefix + pattern)
+                  bind(self, func.priority, regexp, func)
+
+               # 2) e.g. (['p', 'q'], '(.*)')
+               elif len(func.rule) == 2 and isinstance(func.rule[0], list): 
+                  prefix = self.config.prefix
+                  commands, pattern = func.rule
+                  for command in commands: 
+                     command = r'(%s)\b(?: +(?:%s))?' % (command, pattern)
+                     regexp = re.compile(prefix + command)
+                     bind(self, func.priority, regexp, func)
+
+               # 3) e.g. ('$nick', ['p', 'q'], '(.*)')
+               elif len(func.rule) == 3: 
+                  prefix, commands, pattern = func.rule
+                  prefix = sub(prefix)
+                  for command in commands: 
+                     command = r'(%s) +' % command
+                     regexp = re.compile(prefix + command + pattern)
+                     bind(self, func.priority, regexp, func)
+
+         if hasattr(func, 'commands'): 
+            for command in func.commands: 
+               template = r'^%s(%s)(?: +(.*))?$'
+               pattern = template % (self.config.prefix, command)
+               regexp = re.compile(pattern)
+               bind(self, func.priority, regexp, func)
+
+   def wrapped(self, origin, text, match): 
+      class PhennyWrapper(object): 
+         def __init__(self, phenny): 
+            self.bot = phenny
+
+         def __getattr__(self, attr): 
+            sender = origin.sender or text
+            if attr == 'reply': 
+               return (lambda msg: 
+                  self.bot.msg(sender, origin.nick + ': ' + msg))
+            elif attr == 'say': 
+               return lambda msg: self.bot.msg(sender, msg)
+            return getattr(self.bot, attr)
+
+      return PhennyWrapper(self)
+
+   def input(self, origin, text, bytes, match, event, args): 
+      class CommandInput(unicode): 
+         def __new__(cls, text, origin, bytes, match, event, args): 
+            s = unicode.__new__(cls, text)
+            s.sender = origin.sender
+            s.nick = origin.nick
+            s.event = event
+            s.bytes = bytes
+            s.match = match
+            s.group = match.group
+            s.groups = match.groups
+            s.args = args
+            s.admin = origin.nick in self.config.admins
+            s.owner = origin.nick == self.config.owner
+            return s
+
+      return CommandInput(text, origin, bytes, match, event, args)
+
+   def call(self, func, origin, phenny, input): 
+      try: func(phenny, input)
+      except Exception, e: 
+         self.error(origin)
+
+   def limit(self, origin, func): 
+      if origin.sender and origin.sender.startswith('#'): 
+         if hasattr(self.config, 'limit'): 
+            limits = self.config.limit.get(origin.sender)
+            if limits and (func.__module__ not in limits): 
+               return True
+      return False
+
+   def dispatch(self, origin, args): 
+      bytes, event, args = args[0], args[1], args[2:]
+      text = decode(bytes)
+      for priority in ('high', 'medium', 'low'): 
+         items = self.commands[priority].items()
+         for regexp, funcs in items: 
+            for func in funcs: 
+               if event != func.event: continue
+
+               match = regexp.match(text)
+               if match: 
+                  if self.limit(origin, func): continue
+
+                  phenny = self.wrapped(origin, text, match)
+                  input = self.input(origin, text, bytes, match, event, args)
+
+                  if func.thread: 
+                     targs = (func, origin, phenny, input)
+                     t = threading.Thread(target=self.call, args=targs)
+                     t.start()
+                  else: self.call(func, origin, phenny, input)
+
+                  for source in [origin.sender, origin.nick]: 
+                     try: self.stats[(func.name, source)] += 1
+                     except KeyError: 
+                        self.stats[(func.name, source)] = 1
+
+if __name__ == '__main__': 
+   print __doc__

Binary file added.

src/config/debug_conf.py

+nick = 'bot'
+#host = 'irc.earthempires.com'
+host = 'localhost'
+channels = ['#zzztest', '#zzznews']
+activein = ['#zzztest']
+warchan='#zzztest'
+owner = 'zzzarka'
+prefix = r'\+'
+
+# password is the NickServ password, serverpass is the server password
+# password = 'example'
+# serverpass = 'serverpass'
+
+# These are people who will be able to use admin.py's functions...
+admins = [owner]
+# But admin.py is disabled by default, as follows:
+exclude = ['calc', 'clock', 'codepoints', 'etymology', 'head', 'hello', 'info', 'oblique', 'ping', 'tell', 'translate', 'validate']
+
+# If you want to enumerate a list of modules rather than disabling
+# some, use "enable = ['example']", which takes precedent over exclude
+#
+# enable = []
+
+# Directories to load user modules from
+# e.g. /path/to/my/modules
+extra = ['/Users/zzzarka/Programmering/Personal/CLI_tools/EarthBot2/src/earthmods']
+
+# Services to load: maps channel names to white or black lists
+external = {
+   '#liberal': ['!'], # allow all
+   '#conservative': [], # allow none
+   '*': ['!'] # default whitelist, allow all
+}
+
+# EOF
Add a comment to this file

src/config/debug_conf.pyc

Binary file added.

src/config/live_conf.py

+nick = 'Zzzbot'
+host = 'irc.earthempires.com'
+channels = ['#alliance.uknksf', '#ksfwar']
+activein = ['#ksfwar']
+warchan='#ksfwar'
+owner = 'zzzarka'
+prefix = r'\+'
+
+# password is the NickServ password, serverpass is the server password
+# password = 'example'
+# serverpass = 'serverpass'
+
+# These are people who will be able to use admin.py's functions...
+admins = [owner]
+# But admin.py is disabled by default, as follows:
+exclude = ['calc', 'clock', 'codepoints', 'etymology', 'head', 'hello', 'info', 'oblique', 'ping', 'tell', 'translate', 'validate']
+
+# If you want to enumerate a list of modules rather than disabling
+# some, use "enable = ['example']", which takes precedent over exclude
+#
+# enable = []
+
+# Directories to load user modules from
+# e.g. /path/to/my/modules
+extra = ['/Users/zzzarka/Programmering/Personal/CLI_tools/EarthBot2/src/earthmods']
+
+# Services to load: maps channel names to white or black lists
+external = {
+   '#liberal': ['!'], # allow all
+   '#conservative': [], # allow none
+   '*': ['!'] # default whitelist, allow all
+}
+
+# EOF
Add a comment to this file

src/config/live_conf.pyc

Binary file added.

Binary file added.

Add a comment to this file

src/earthmods/__init__.py

Empty file added.

Add a comment to this file

src/earthmods/__init__.pyc

Binary file added.

src/earthmods/chemrush.py

+import earthtools.input_tools as inp
+import earthtools.db_tools as db
+import earthtools.earthcalc as calc
+import re, math, random
+def help(bot):
+	bot.say('usage: .cr -p <enemy population> -s <enemy sdi (% or pts)> -l <enemy land (only needed when sdi is pts)> -g <enemy goverment (only needed when sdi is pts)>')
+
+def response(bot, killneed, approxfail, start_sdi, end_sdi):
+	bot.say("Need "+str(killneed)+" for kill, approx "+str(approxfail)+" will bounce make sure you have "+str(round((approxfail+killneed)*1.1))+" chems for the rush (target starts with "+str(round(start_sdi, 2))+"% SDI and ends with "+str(round(end_sdi, 2))+"%)");
+
+def simpleChem(bot, pop, sdi):
+	pop=int(pop)
+	sdi=float(sdi)
+	startsdi=float(sdi)
+	suc = 0;
+	while pop > 0:
+		if 1500 < suc: break #sanity check ..
+		pop -= max((25, pop*0.13))
+		suc+=1
+	sdi = sdi-(sdi/8) #Lower SDI by 1/8th to estimate for sdi loss during attacks ..
+	mult = 1 / (1-(sdi/100)) #used to estimate how many missiles will bounce
+	chems = round(suc*mult);
+	response(bot, suc, chems-suc, startsdi, sdi)
+def chemSim(yourpop, enemypop, sdi_tech, land, gov):
+	chems=0
+	suc=0
+	fail=0
+	
+	sdi = calc.Tech.sdi(sdi_tech, land, gov);
+	#Begin chem rush simulation!
+	while(enemypop > 0):
+		if chems > 1500: break; #Sanity check to not loop forever ...
+		chems +=1;
+		#Will the missile break?
+		if random.random() < (1-(sdi/100)):
+			#extract population
+			returns = 0
+			if yourpop <= 0:
+				returns = max(25, (enemypop*0.13)); #Assume everyon has a good population
+			else:
+				returns = min((yourpop*0.2), max(25, (enemypop*0.13))); #exact fomula..
+			
+			enemypop-=returns;
+			suc += 1;
+		else:
+			#lower sdi!
+			sdi_tech -= 0.01*sdi_tech;
+			sdi = calc.Tech.sdi(sdi_tech, land, gov);
+			fail += 1;
+	return {'chems':chems,'suc':suc,'fail':fail,'end_sdi':sdi};
+
+def chem(bot, pop, sdi, land, gov):
+	TRIES=50; #Simulate this many times (increese for accuracy)
+	chems=0
+	suc=0
+	end_sdi=0
+	for i in range(TRIES):
+		r = chemSim(0, pop, sdi, land, gov)
+		chems += r['chems']
+		suc += r['suc']
+		end_sdi += r['end_sdi']
+	response(bot, round(suc/TRIES), round((chems-suc)/TRIES), calc.Tech.sdi(sdi, land, gov), round(end_sdi/TRIES))
+
+def chemrush(bot, input):
+	if input.sender not in bot.config.activein: return
+	args = inp.getArgs(input.group(), 'hp:s:l:g:c:')
+	pop = 0
+	sdi = 0
+	land = 0
+	gov = 'mon'
+	if len(args) <= 1 or '-h' in args:
+		help(bot)
+		return
+	if '-c' in args:
+		spydb=db.SpyOp()
+		spy=spydb.get(args['-c'])
+		if None == spy:
+			bot.say("Bad arguments!")
+			help(bot)
+			return
+		pop = int(spy['spy_pop'])
+		sdi = spy['spy_tech']['sdi'].replace(',','')
+		land = int(spy['spy_land'].replace(',',''))
+		gov = spy['spy_gov']
+	else:
+		try:
+			if '-p' in args: pop = int(args['-p'])
+			if '-s' in args: sdi = args['-s']
+			if '-l' in args: land = int(args['-l'])
+			if '-g' in args: gov = args['-g']
+		except:
+			bot.say("Bad arguments!")
+			help(bot)
+			return
+
+	if re.search('%', str(sdi)):
+		simpleChem(bot, pop, float(sdi.replace('%', '')))
+	else:
+		chem(bot, pop, float(sdi), land, gov)
+
+chemrush.commands = ['cr']
+chemrush.priority = 'high'
+if __name__ == '__main__':
+	print __doc__.strip()
+	
Add a comment to this file

src/earthmods/chemrush.pyc

Binary file added.

Add a comment to this file

src/earthmods/db_tools.pyc

Binary file added.

Add a comment to this file

src/earthmods/input_tools.pyc

Binary file added.

Add a comment to this file

src/earthmods/ksfmail.pyc

Binary file added.

src/earthmods/member.py

+import earthtools.input_tools as inp
+import earthtools.db_tools as db
+
+def help(bot):
+	bot.say("-c <counttry #> -e <email address> -p <phone number> -s <sms email number> -n <nick(if this is not provided it uses the nick of the person that ran the command>")
+
+def member(bot, input):
+	if input.sender not in bot.config.activein: return
+	args = inp.getArgs(input.group(), 'hc:e:p:s:n:')# ['-h','-c','-e', '-p', '-s', '-n'])
+	if len(args) < 1 or '-h' in args:
+		help(bot)
+		return
+	nick = input.nick
+	if '-n' in args:
+		nick = args['-n']
+	sql = db.Member()
+	sql.checkCreateMember(nick)
+	updates = {}
+	updates['mem_chan'] = input.sender
+	if '-c' in args:
+		updates['mem_country'] = args['-c']
+	if '-e' in args:
+		updates['mem_email'] = args['-e']
+	if '-p' in args:
+		updates['mem_tele'] = args['-p']
+	if '-s' in args:
+		updates['mem_smsmail'] = args['-s']
+	if len(args['rest']) > 0:
+		updates['mem_comment'] = " ".join(args['rest'])
+	sql.updateMember(nick, updates);
+	
+	
+member.commands = ['mem']
+member.priority = 'high'
+
+def listMember(bot, input):
+	if input.sender not in bot.config.activein: return
+	args = inp.getArgs(input.group(), 'hc:n:e:')#['-h','-c', '-n', '-e'])
+	sql = db.Member()
+	buf = [];
+	for mem in sql.getMember(args).fetchall():
+		buf.append(str(mem['mem_nick'])+" #"+str(mem['mem_country'])+' email "'+str(mem['mem_email'])+'", tele: "'+str(mem['mem_tele'])+'", text: "'+str(mem['mem_smsmail'])+'" comment:"'+str(mem['mem_comment'])+'"')
+	for msg in buf:
+		bot.say(msg);
+
+
+listMember.commands = ['list', 'search']
+listMember.priority = 'high'
+
+if __name__ == '__main__': 
+   print __doc__.strip()
Add a comment to this file

src/earthmods/member.pyc

Binary file added.

src/earthmods/newssniffer.py

+import earthtools.input_tools as inp
+import earthtools.db_tools as db
+import earthtools.newsreader as news
+import earthmods.target as target
+import time
+
+class TargetSystem:
+	cur_target=None
+	cur_break=0
+	cur_attack_type='GS'
+	cur_multiplier=0.95
+	timer=0
+	def checkTarget(self, bot):
+		print self.cur_target
+	def setTarget(self,target, attack_type, bot):
+		print "ST"
+		self.cur_target=db.SpyOp().get(target)
+		self.cur_attack_type=attack_type
+		if self.cur_target:
+			print "YAY"
+			self.setBreakStrength()
+			bot.say("Set target to "+self.cur_target['spy_name']+" (#"+str(self.cur_target['spy_cou'])+") starting pop: "+self.cur_target['spy_pop']);
+			bot.msg(bot.config.warchan, "BREAK! "+self.cur_target['spy_name']+" (#"+str(self.cur_target['spy_cou'])+") "+str(self.cur_break)+' '+self.cur_attack_type)
+			return True;
+		self.cur_target=None
+		print "BOO"
+		return False
+
+	def clearTarget(self):
+		self.cur_target=None
+		self.timer=0
+
+	def newsupdate(self, newsdata, bot):
+		if self.cur_target is not None and int(self.cur_target['spy_cou'])==int(newsdata['def_num']):
+			self.cur_break = ceil(self.cur_break*self.cur_multiplier)
+			if self.cur_break < 5000:
+				self.cur_break=5000
+			if int(time.time())>self.timer+2:
+				bot.msg(bot.config.warchan, 'BREAK! '+str(self.cur_break)+' '+self.cur_attack_type)
+				self.timer=int(time.time())
+
+	def setBreakStrength(self):
+		if not self.cur_target: return
+		if 'GS'==self.cur_attack_type.upper():
+			self.cur_break = int(self.cur_target['spy_mil']['troops'].replace(',',''))
+		elif 'BR'==self.cur_attack_type.upper():
+			self.cur_break = int(self.cur_target['spy_mil']['turrets'].replace(',',''))
+
+target_sys=None;
+def getTargetSystem():
+	global target_sys
+	if target_sys is None:
+		target_sys=TargetSystem()
+	return target_sys
+
+def targetSysNews(newsdata, bot):
+	getTargetSystem().newsupdate(newsdata, bot)
+
+def setTarget(bot, input):
+	print "calling: "+str(input.split(' '))
+	if input.sender not in bot.config.activein: return
+	if not getTargetSystem().setTarget(input.split(' ')[2], input.split(' ')[1], bot):
+		bot.say('Could not find country #'+input.split(' ')[2]+' in the spyop database, try running +spyup -t for the countrys tag')
+setTarget.commands = ['setTarget', 'st']
+setTarget.priority='high'
+
+def remTarget(bot, input):
+	if input.sender not in bot.config.activein: return
+	getTargetSystem().clearTarget()
+remTarget.commands = ['remTarget', 'rt']
+remTarget.priority='high'
+
+def checkTarget(bot, input):
+	if input.sender not in bot.config.activein: return
+	getTargetSystem().checkTarget(bot)
+checkTarget.commands = ['checkTarget', 'ct']
+checkTarget.priority='high'
+
+
+printchan='#zzztest'
+def warningsystem(newsdata, bot):
+	global printchan
+	con=db.Member()
+	defender=con.getMember({'-c':newsdata['def_num']}).fetchall()
+	curtime = time.time()
+	if len(defender)>0:
+		for d in defender:
+			alertedAt = float(con.alertedAt(d['mem_nick']))
+			if curtime-alertedAt > 60*5:
+				bot.msg(printchan, d['mem_nick']+" Is under attack! ("+newsdata['type']+")")
+				con.setAlert(d['mem_nick'])
+
+
+def logsystem(newsdata, bot):
+	#print newsdata
+	log=db.NewsLog()
+	log.add(newsdata);
+	
+
+
+
+read = news.NewsReader()
+read.addListner(warningsystem)
+read.addListner(logsystem)
+read.addListner(targetSysNews)
+
+def newssniffer(bot, input):
+	global read
+	if str(input.nick) not in ['ee', 'zzzarka']:
+		return;
+	read.checkStr(input, bot);
+
+newssniffer.rule = r'(.*)\s*\w\w\s+(?:[\w\s]+)\(#[0-9]+\)'
+newssniffer.priority = 'high'
+newssniffer.thread = False
+
+#def logger(bot, input):
+#	print input
+#logger.rule = r'.*'
+#logger.priority = 'high'
+#logger.thread = False
+
+if __name__ == "__main__":
+	print __doc__.strip()
Add a comment to this file

src/earthmods/newssniffer.pyc

Binary file added.

src/earthmods/spyop.py

+from earthtools import spyop_rip
+from earthtools import db_tools as db
+import earthtools.input_tools as inp
+
+tags_to_id= {
+	'UT':2,
+	'KSF':1793,
+	'LAF':5,
+	'EVO':1050,
+	'LCN':48,
+	'SOF':163,
+	'MD':1655,
+	'SOL':1810,
+	'RIVAL':60,
+	'SANCT':949,
+	'TIE':181,
+	'NA':1809,
+	'IMAG':185,
+	'OMEGA':284,
+	'MONSTERS':295,
+	'ICN':274,
+	'RD':615,
+	'RAGE':132,
+	'SAMCRO':1815,
+	'SFR':1781,
+	'WALA':1812,
+	'NBK':6,
+	'BIGWOOD':1814,
+	'2025':1180,
+	'PDM':1811,
+}
+
+def spyop(bot, input):
+	global tags_to_id
+	if input.sender not in bot.config.activein: return
+	args = inp.getArgs(input.group(), 'ht:c:')
+	if '-h' in args:
+		bot.say("!spyup -t KSF,NA")
+		return
+	ripper = spyop_rip.Boxcar()
+	ripper.login()
+	if '-t' in args:
+		for tag in args['-t'].split(','):
+			ripper.getClan(tags_to_id[tag.upper()])
+	bot.say("Done updating spyops")
+spyop.commands=['spyup']
+spyop.priority='high'
+
+def spyInfo(bot, input):
+	if input.sender not in bot.config.activein: return
+	cou = input.split(' ')[1]
+	spyopdb = db.SpyOp()
+	inf = spyopdb.get(cou)
+	bot.msg(input.nick, 'Country of '+inf['spy_name']+' (#'+str(inf['spy_cou'])+'): land: '+inf['spy_land']+' pop: '+inf['spy_pop'])
+spyInfo.commands=['spy']
+spyInfo.priority='high'
+
+
+if __name__ == "__main__":
+	print __doc__.strip()
Add a comment to this file

src/earthmods/spyop.pyc

Binary file added.

src/earthmods/target.py

+import earthtools.db_tools as db
+
+
+if __name__ == "__main__":
+	print __doc__.strip()
Add a comment to this file

src/earthmods/target.pyc

Binary file added.

Add a comment to this file

src/earthtools/__init__.py

Empty file added.

Add a comment to this file

src/earthtools/__init__.pyc

Binary file added.

src/earthtools/db_tools.py

+import sqlite3
+import datetime
+import time
+import cPickle
+
+def sqlite_lower(in_str):
+	return str(in_str).lower()
+
+class EarthDB:
+	def __init__(self):
+		self.dbcon = sqlite3.connect('earthinf.db')
+		self.dbcon.row_factory=sqlite3.Row
+		self.dbcon.create_function('pyLower', 1, sqlite_lower)
+	def commit(self):
+		self.dbcon.commit()
+	dbcon=None
+
+class Member:
+	def __init__(self):
+		self.db=EarthDB()
+	def alertedAt(self, nick):
+		c = self.db.dbcon.cursor()
+		c.execute("select al_timestamp from alert where al_nick=?", (nick,))
+		r = c.fetchone()
+		if None == r:
+			return 0
+		return r[0]
+	
+	def setAlert(self, nick):
+		t = time.time()
+		self.db.dbcon.execute("REPLACE INTO alert (al_nick, al_timestamp) VALUES (?, ?)", (nick, t))
+		self.db.dbcon.commit();
+	def getMember(self, params):
+		where = []
+		sqlinp = []
+		if '-nex' in params:
+			where.append("pyLower(mem_nick)=?")
+			sqlinp.append(params['-nex'].lower())
+		if '-n' in params:
+			where.append("pyLower(mem_nick) LIKE ?")
+			sqlinp.append('%'+params['-n'].lower()+'%')
+		if '-c' in params:
+			where.append('mem_country=?')
+			sqlinp.append(int(params['-c']))
+		where_str=''
+		if len(where) > 0:
+			where_str = ' WHERE '+(' AND '.join(where))
+
+		c = self.db.dbcon.cursor()
+		c.execute('select * from member'+where_str, sqlinp)
+
+		return c
+	def checkCreateMember(self, nick):
+		has = self.getMember({'-nex': nick}).fetchone()
+		if has != None:
+			return
+		self.db.dbcon.execute("INSERT INTO member (mem_nick, mem_email, mem_country, mem_tele, mem_smsmail, mem_comment) VALUES (?, ?, ?, ?, ?, ?)", (nick, '', 0, '', '', ''))
+		self.db.dbcon.commit();
+	def updateMember(self, nick, updates):
+		if(len(updates)<=0):
+			return;
+		upd = []
+		up_params = []
+		for key in updates.keys():
+			upd.append(key+" = ?")
+			up_params.append(updates[key])
+		upd_str = ", ".join(upd)
+		up_params.append(nick.lower())
+		self.db.dbcon.execute("UPDATE member SET "+upd_str+" WHERE pyLower(mem_nick)=?", up_params)
+		self.db.dbcon.commit()
+		return
+
+class NewsLog:
+	def __init__(self):
+		self.db = EarthDB()
+	def search(self, params):
+		pass
+	def add(self, newsdata):
+		self.db.dbcon.execute("""
+			INSERT INTO news_log
+			(nwl_type, nwl_attack_num, nwl_def_num, nwl_result, nwl_timestamp, nwl_attack_name, nwl_def_name, nwl_attack_clan, nwl_def_clan) VALUES(?,?,?,?,?,?,?,?,?)""",
+			(newsdata['type'], newsdata['att_num'], newsdata['def_num'], newsdata['info'], time.time(), newsdata['att_cou'], newsdata['def_cou'], newsdata['att_clan'], newsdata['def_clan'])
+		)
+		self.db.dbcon.commit();
+
+class SpyOp:
+	def __init__(self):
+		self.db = EarthDB()
+	def get(self, cou):
+		c = self.db.dbcon.cursor()
+		c.execute('select * from spyop WHERE spy_cou=?', (cou,))
+		row = c.fetchone()
+		if None == row:
+			return None
+		return {
+			'spy_cou':row['spy_cou'],
+			'spy_name':row['spy_name'],
+			'spy_gov':row['spy_gov'],
+			'spy_land':row['spy_land'],
+			'spy_pop':row['spy_pop'].replace(',',''),
+			'spy_mil': cPickle.loads(str(row['spy_mil'])),
+			'spy_tech': cPickle.loads(str(row['spy_tech'])),
+		}
+
+	def update(self, spydata):
+		c = self.db.dbcon.cursor()
+		c.execute('select * from spyop WHERE spy_cou=?', (spydata['spy_cou'],))
+		spydata['spy_mil'] = cPickle.dumps(spydata['spy_mil'], cPickle.HIGHEST_PROTOCOL)
+		spydata['spy_tech'] = cPickle.dumps(spydata['spy_tech'], cPickle.HIGHEST_PROTOCOL)
+		if None == c.fetchone():
+			#insert
+			self.db.dbcon.execute("""INSERT INTO spyop
+				(spy_cou, spy_name, spy_gov, spy_land, spy_pop, spy_mil, spy_tech, spy_timestamp)
+				VALUES(?,?,?,?,?,?,?,?)""",
+				(int(spydata['spy_cou']), spydata['spy_name'], spydata['spy_gov'], spydata['spy_land'], spydata['spy_pop'], sqlite3.Binary(spydata['spy_mil']), sqlite3.Binary(spydata['spy_tech']), time.time())
+			)
+		else:
+			self.db.dbcon.execute("""UPDATE spyop SET
+				spy_name=?, spy_gov=?, spy_land=?, spy_pop=?, spy_mil=?, spy_tech=?, spy_timestamp=? WHERE spy_cou=?""",
+				(spydata['spy_name'], spydata['spy_gov'], spydata['spy_land'], spydata['spy_pop'], sqlite3.Binary(spydata['spy_mil']), sqlite3.Binary(spydata['spy_tech']), time.time(), int(spydata['spy_cou']))
+			)
+		self.db.dbcon.commit()
+
+if __name__ == "__main__":
+	print __doc__.strip()
Add a comment to this file

src/earthtools/db_tools.pyc

Binary file added.

src/earthtools/earthcalc.py

+__author__="zzzarka"
+__date__ ="$Oct 16, 2011 11:28:18 PM$"
+import math
+
+"""
+C1
+Normal Techs	192
+Military Tech	780
+Medical Tech	1650
+C2
+Normal Techs	6.795
+Military Tech	5.75
+Medical Tech	4.62
+"""
+"""
+old sdi:
+	#=BaseTech%+(MaxTech%-BaseTech%)*GvtTech*(1-EXP(-GvtEff*TechPts/(C1+C2*Land)))
+	base_tech = 1
+	max_tech = 90
+	gvt_tech, gvt_eff = govTech(gov)
+	exp = math.exp(-gvt_eff*tech/(c1('sdi')+c2('sdi')*land));
+	return base_tech+((max_tech-base_tech)*gvt_tech*(1-exp));
+old weapon:
+	#=BaseTech%+(MaxTech%-BaseTech%)*GvtTech*(1-EXP(-GvtEff*TechPts/(C1+C2*Land)))
+	base_tech = 100
+	max_tech = 150
+	gvt_tech, gvt_eff = govTech(gov)
+	exp = math.exp(-gvt_eff*tech/(c1('wep')+c2('wep')*land));
+	return base_tech+((max_tech-base_tech)*gvt_tech*(1-exp));
+"""
+class Tech():
+	@staticmethod
+	def c1(tech):
+		if 'mil'==tech:
+			return 780
+		if 'med'==tech:
+			return 1650
+		return 192
+	@staticmethod
+	def c2(tech):
+		if 'mil'==tech:
+			return 5.75
+		if 'med'==tech:
+			return 4.62
+		return 6.795
+	@staticmethod
+	def govBonus(gov):
+		gvt_tech = 1.0;
+		gvt_eff = 1.0;
+		if('H' == gov):
+			gvt_tech = 0.65
+		elif('D' == gov):
+			gvt_tech = 1.1
+		elif('C' == gov):
+			gvt_eff = 1.2
+		return (gvt_tech, gvt_eff)
+	@staticmethod
+	def minmax(techname):
+		if 'sdi' == techname:
+			return (1, 90)
+		elif 'wep' == techname:
+			return (100, 150)
+		raise "Implement more techs!"
+		return (0, 0)
+	@staticmethod
+	def calc(techname, points, land, gov):
+		base_tech, max_tech = Tech.minmax(techname)
+		gvt_tech, gvt_eff = Tech.govBonus(gov)
+		exp = math.exp(-gvt_eff*points/(Tech.c1('sdi')+Tech.c2('sdi')*land));
+		return base_tech+((max_tech-base_tech)*gvt_tech*(1-exp));
+
+	@staticmethod
+	def sdi(points, land, gov): return Tech.calc('sdi', points, land, gov)
+	@staticmethod
+	def weapons(points, land, gov): return Tech.calc('wep', points, land, gov)
+
+
+
+
+if __name__ == "__main__":
+    print __doc__.strip()
Add a comment to this file

src/earthtools/earthcalc.pyc

Binary file added.

src/earthtools/input_tools.py

+import getopt
+def getArgs(ph_input, flags, long_opts=[]):
+	argv = ph_input.split(" ")[1:];
+	try: opts, args = getopt.gnu_getopt(argv, flags, long_opts)
+	except getopt.GetoptError: opts, args = ([], argv)
+	ret= {'rest':args}
+	for opt,val in opts: ret[opt]=val
+	return ret
+
+import sys
+if __name__ == "__main__":
+	parsed = getArgs(" ".join(sys.argv), ['-n','-c','-e', '-t', '-s'])
+	print(parsed)
+	print(parsed['-n'])
+	
Add a comment to this file

src/earthtools/input_tools.pyc

Binary file added.

src/earthtools/ksfmail.py

+import smtplib
+from email.mime.text import MIMEText
+def sendksfmail(toaddrs, title, msg):
+	fromaddr = 'ksfmailer@gmail.com'
+	# Credentials (if needed)
+	username = 'ksfmailer'
+	password = 'ksf-is-so-good-#1-forsure'
+
+	mimemsg = MIMEText(msg);
+	mimemsg['Subject'] = title;
+	mimemsg['From'] = fromaddr
+	mimemsg['To'] = toaddrs
+
+	# The actual mail send
+	server = smtplib.SMTP('smtp.gmail.com:587')
+	server.starttls()
+	server.login(username,password)
+	server.sendmail(fromaddr, toaddrs, mimemsg.as_string())
+	server.quit()
+
+if __name__ == "__main__":
+    print __doc__.strip()

src/earthtools/nameconvert.py

+__author__="zzzarka"
+__date__ ="$Oct 24, 2011 9:27:25 PM$"
+
+def govDict(single):
+	return {
+		'M':'Monarchy',
+		'D':'Democrazy',
+		'R':'Republic',
+		'H':'Theocracy',
+		'C':'Communism',
+		'I':'Dictatorship',
+		'T':'Tyrrany',
+		'F':'Fascism',
+	}
+
+def singleToFull(single):
+	return govDict()[single]
+def fullToSingle(full):
+	return [single for single, v in symbol_dic.iteritems() if v == full][0]

src/earthtools/newsreader.py

+"""
+[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 62A/84A
+[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 29A/33A
+[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 29A/33A
+[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 29A/33A
+[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 20A/20A
+[10:45am] ee:  GS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#196)        [] -- bah
+"""
+import re
+class NewsReader:
+	newsregex=None
+	listeners=[]
+	def __init__(self):
+		self.newsregex=re.compile(r'\s*(?P<type>\w\w)\s*(?P<att_cou>[\w\s]+)\(#(?P<att_num>[0-9]+)\)\s*\[(?P<att_clan>[^]]*)\]\s*-->\s*(?P<def_cou>[\w\s]+)\(#(?P<def_num>[0-9]+)\)\s*\[(?P<def_clan>[^]]*)\]\s*--\s*(?P<info>.*)')
+	def checkStr(self, newsitem, extra):
+		newsdata=self.newsregex.search(newsitem).groupdict()
+		if None != newsdata:
+			self.handle(newsdata, extra)
+	def handle(self, newsdata, extra):
+		for evt in self.listeners:
+			evt(newsdata, extra)
+	def addListner(self, listener):
+		#if hasattr(listener, 'newsupdate'):
+			self.listeners.append(listener)
+		#else:
+		#	raise AttributeError("newsitem Listeners need to have a newsupdate method")
+
+
+class TestListen:
+	def newsupdate(self, newsdata, extra):
+		print newsdata
+if __name__ == "__main__":
+	read=NewsReader()
+	read.addListner(TestListen())
+	txt = "SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 62A/84A"
+	read.checkStr(txt)
+	txt='[10:45am] ee:  SS Walls Of Odengrad (#235)        [UKNKSF] --> hello hello goodbye good (#443)        [] -- 20A/20A'
+	read.checkStr(txt)
+	#print __doc__.strip()
Add a comment to this file

src/earthtools/newsreader.pyc

Binary file added.

src/earthtools/spyop_rip.py

+from hgext.keyword import match
+import urllib, urllib2, cookielib
+from lxml import etree
+import re
+import db_tools as db
+
+class SpyRipper():
+	def getClan(self, id):
+		pass
+
+class Boxcar(SpyRipper):
+	clanurl='http://www.boxcarhosting.com/portal/countryresults.php?submittype=search&clanID='
+	countryurl='http://www.boxcarhosting.com/portal/viewspyop.php?countryNum='
+	connection=None
+	def __init__(self):
+		pass
+	def login(self):
+		username = 'zzzbot'
+		password = 'oh-my-god-its-a-robot'
+		cj = cookielib.CookieJar()
+		self.connection = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
+		login_data = urllib.urlencode({'username' : username, 'password' : password})
+		self.connection.open('http://www.boxcarhosting.com/public/login.php', login_data)
+	def getClan(self, id):
+		resp = self.connection.open(self.clanurl+str(id))
+		self.parseSpyops(resp.read())
+		
+	def getCountry(self, cou_num):
+		resp = self.connection.open(self.countryurl+str(cou_num))
+		print resp.read()
+
+	def _runXPath(self, node, xpath, d=""):
+		try:
+			return node.xpath(xpath)[0].text
+		except:
+			return d
+	def parseSpyops(self, html):
+		tree = etree.HTML(html)
+		spyops = tree.xpath("//*[contains(@id, 'spyop')]/td[2]/center")
+		xp_gov="./b[1]"
+		xp_num="./b[2]/a"
+		xp_name="./b[2]"
+		xp_pop="./table/tr[1]/td[3]/table/tr[3]/td[2]"
+		xp_land="./table/tr[1]/td[3]/table/tr[4]/td[2]"
+		xp_mil="./table/tr[3]/td[3]/table/tr/td[2]"
+		xp_tech="./table/tr[3]/td[5]/table/tr/td[2]"
+		xp_mil_tech="./table/tr[3]/td[5]/table/tr/td[2]" #grrr broken html
+
+		spyopdb=db.SpyOp()
+		for op in spyops:
+			data = {
+				'spy_gov':self._runXPath(op,xp_gov,'0'),
+				'spy_cou':re.match(r'#([0-9]+)',self._runXPath(op,xp_num,'0')).group(1),
+				'spy_name':re.match(r'^([\w,.-_\s]+)', self._runXPath(op,xp_name,'')).group(1).strip(),
+				'spy_land':re.match(r'^([\w,.]+)', self._runXPath(op,xp_land,'0')).group(1),
+				'spy_pop':self._runXPath(op,xp_pop,'0'),
+				'spy_mil':dict(zip(['spies', 'troops', 'jets', 'turrets', 'tanks', 'nuke', 'chem', 'cruise'], [ m.text for m in op.xpath(xp_mil) ])),
+				'spy_tech':dict(zip(['med', 'bus', 'res', 'agri', 'war', 'strat', 'wep', 'ind', 'spy', 'sdi'], [ re.match('^([0-9,]+)', m.text).group(1) for m in op.xpath(xp_tech) ])),
+			}
+			#Broken html for military tech hax0r
+			data['spy_tech']['mil'] = re.match('^([0-9,]+)', self._runXPath(op,xp_mil_tech,'0')).group(1)
+			spyopdb.update(data)
+
+		
+
+if __name__ == "__main__":
+	con = Boxcar()
+	#con.login()
+	#con.getClan(1793)
+	con.parseSpyops(open('tmpalliancepage.html').read())
+	#print __doc__.strip()
Add a comment to this file

src/earthtools/spyop_rip.pyc

Binary file added.

+#!/usr/bin/env python
+"""
+icao.py - Phenny ICAO Codes Data
+This data and module are in the public domain.
+
+http://inamidst.com/phenny/
+"""
+
+data = (
+   ("AYGA", -6.08166666667, 145.391666667), 
+   ("AYMD", -5.20694444444, 145.788611111), 
+   ("AYMH", -5.82611111111, 144.296111111), 
+   ("AYNZ", -6.56972222222, 146.726111111), 
+   ("AYPY", -9.44333333333, 147.22), 
+   ("AYWK", -3.58361111111, 143.669166667), 
+   ("BGBW", 61.1611111111, -45.4275), 
+   ("BGCO", 70.7394444444, -22.6458333333), 
+   ("BGGH", 64.1908333333, -51.6780555556), 
+   ("BGJN", 69.2333333333, -51.0666666667), 
+   ("BGKK", 65.5833333333, -37.15), 
+   ("BGSF", 67.0169444444, -50.6891666667), 
+   ("BGTL", 76.5311111111, -68.7030555556), 
+   ("BIAR", 65.6597222222, -18.0725), 
+   ("BIEG", 65.2833333333, -14.4013888889), 
+   ("BIHN", 64.2955555556, -15.2272222222), 
+   ("BIHU", 65.9522222222, -17.4258333333), 
+   ("BIIS", 66.0580555556, -23.1352777778), 
+   ("BIKF", 63.985, -22.6055555556), 
+   ("BIKP", 66.3136111111, -16.4611111111), 
+   ("BIPA", 65.5558333333, -23.965), 
+   ("BIRK", 64.13, -21.9405555556), 
+   ("BISI", 66.1333333333, -18.9166666667), 
+   ("BIVM", 63.4241666667, -20.2786111111), 
+   ("CYAM", 46.485, -84.5094444444), 
+   ("CYAV", 50.0563888889, -97.0325), 
+   ("CYAW", 44.6397222222, -63.4994444444), 
+   ("CYAY", 51.3916666667, -56.0844444444), 
+   ("CYAZ", 49.0822222222, -125.7725), 
+   ("CYBB", 68.5344444444, -89.8080555556), 
+   ("CYBC", 49.1322222222, -68.2072222222), 
+   ("CYBG", 48.3305555556, -70.9963888889), 
+   ("CYBK", 64.2988888889, -96.0777777778), 
+   ("CYBL", 49.9508333333, -125.270833333), 
+   ("CYBR", 49.91, -99.9519444444), 
+   ("CYCB", 69.1080555556, -105.138333333), 
+   ("CYCD", 49.0522222222, -123.87), 
+   ("CYCG", 49.2963888889, -117.6325), 
+   ("CYCH", 47.0077777778, -65.4491666667), 
+   ("CYCL", 47.9905555556, -66.3313888889), 
+   ("CYCO", 67.8166666667, -115.143888889), 
+   ("CYCT", 52.075, -111.445277778), 
+   ("CYCW", 49.1527777778, -121.938888889), 
+   ("CYCY", 70.4861111111, -68.5166666667), 
+   ("CYCZ", 50.3319444444, -115.873611111), 
+   ("CYDA", 64.0430555556, -139.127777778), 
+   ("CYDB", 61.3711111111, -139.040555556), 
+   ("CYDC", 49.4675, -120.511944444), 
+   ("CYDF", 49.2108333333, -57.3913888889), 
+   ("CYDL", 58.4222222222, -130.032222222), 
+   ("CYDN", 51.1008333333, -100.0525), 
+   ("CYDQ", 55.7416666667, -120.181944444), 
+   ("CYED", 53.6666666667, -113.466666667), 
+   ("CYEG", 53.3097222222, -113.579722222), 
+   ("CYEK", 61.0941666667, -94.0708333333), 
+   ("CYEN", 49.2102777778, -102.965833333), 
+   ("CYET", 53.5788888889, -116.465), 
+   ("CYEU", 79.9947222222, -85.8133333333), 
+   ("CYEV", 68.3041666667, -133.482777778), 
+   ("CYFB", 63.7563888889, -68.5558333333), 
+   ("CYFC", 45.8694444444, -66.5316666667), 
+   ("CYFE", 48.7461111111, -69.0972222222), 
+   ("CYFO", 54.6780555556, -101.681666667), 
+   ("CYFR", 61.1808333333, -113.689722222), 
+   ("CYFS", 61.7602777778, -121.236666667), 
+   ("CYGK", 44.2252777778, -76.5969444444), 
+   ("CYGL", 53.6252777778, -77.7041666667), 
+   ("CYGP", 48.7752777778, -64.4786111111), 
+   ("CYGQ", 49.7783333333, -86.9394444444), 
+   ("CYGR", 47.4247222222, -61.7780555556), 
+   ("CYGW", 55.2833333333, -77.7666666667), 
+   ("CYGX", 56.35, -94.7), 
+   ("CYHB", 52.8166666667, -102.311388889), 
+   ("CYHD", 49.8316666667, -92.7441666667), 
+   ("CYHI", 70.7630555556, -117.805833333), 
+   ("CYHK", 68.6355555556, -95.8497222222), 
+   ("CYHM", 43.1730555556, -79.935), 
+   ("CYHU", 45.5175, -73.4169444444), 
+   ("CYHY", 60.8397222222, -115.782777778), 
+   ("CYHZ", 44.8808333333, -63.5086111111), 
+   ("CYIB", 48.7738888889, -91.6386111111), 
+   ("CYIO", 72.6833333333, -77.9666666667), 
+   ("CYJN", 45.2944444444, -73.2811111111), 
+   ("CYJT", 48.5441666667, -58.55), 
+   ("CYKA", 50.7022222222, -120.441944444), 
+   ("CYKF", 43.4588888889, -80.3844444444), 
+   ("CYKL", 54.805, -66.8052777778), 
+   ("CYKY", 51.5175, -109.180833333), 
+   ("CYKZ", 43.8622222222, -79.37), 
+   ("CYLD", 47.82, -83.3463888889), 
+   ("CYLJ", 54.1252777778, -108.522777778), 
+   ("CYLL", 53.3091666667, -110.0725), 
+   ("CYLT", 82.5177777778, -62.2805555556), 
+   ("CYLW", 49.9561111111, -119.377777778), 
+   ("CYMA", 63.6166666667, -135.866666667), 
+   ("CYMJ", 50.3302777778, -105.559166667), 
+   ("CYMM", 56.6533333333, -111.221944444), 
+   ("CYMO", 51.2911111111, -80.6077777778), 
+   ("CYMW", 46.2744444444, -75.99), 
+   ("CYMX", 45.6797222222, -74.0386111111), 
+   ("CYNA", 50.1897222222, -61.7891666667), 
+   ("CYND", 45.5213888889, -75.5641666667), 
+   ("CYNM", 49.7616666667, -77.8027777778), 
+   ("CYOC", 67.5705555556, -139.839166667), 
+   ("CYOD", 54.405, -110.279444444), 
+   ("CYOJ", 58.6213888889, -117.164722222), 
+   ("CYOW", 45.3225, -75.6691666667), 
+   ("CYPA", 53.2141666667, -105.672777778), 
+   ("CYPE", 56.2269444444, -117.447222222), 
+   ("CYPG", 49.9027777778, -98.2747222222), 
+   ("CYPK", 49.2161111111, -122.71), 
+   ("CYPL", 51.4463888889, -90.2141666667), 
+   ("CYPN", 49.8363888889, -64.2886111111), 
+   ("CYPQ", 44.23, -78.3633333333), 
+   ("CYPR", 54.2861111111, -130.444722222), 
+   ("CYPY", 58.7672222222, -111.117222222), 
+   ("CYQA", 44.9747222222, -79.3033333333), 
+   ("CYQB", 46.7883333333, -71.3975), 
+   ("CYQF", 52.1786111111, -113.893055556), 
+   ("CYQG", 42.2755555556, -82.9555555556), 
+   ("CYQH", 60.1177777778, -128.821944444), 
+   ("CYQK", 49.7883333333, -94.3630555556), 
+   ("CYQL", 49.6302777778, -112.799722222), 
+   ("CYQM", 46.1122222222, -64.6786111111), 
+   ("CYQN", 50.1827777778, -86.6963888889), 
+   ("CYQQ", 49.7108333333, -124.886666667), 
+   ("CYQR", 50.4319444444, -104.665833333), 
+   ("CYQT", 48.3719444444, -89.3238888889), 
+   ("CYQU", 55.1797222222, -118.885), 
+   ("CYQV", 51.2647222222, -102.461666667), 
+   ("CYQW", 52.7691666667, -108.243611111), 
+   ("CYQX", 48.9369444444, -54.5680555556), 
+   ("CYQY", 46.1613888889, -60.0477777778), 
+   ("CYQZ", 53.0261111111, -122.51), 
+   ("CYRB", 74.7169444444, -94.9694444444), 
+   ("CYRI", 47.7644444444, -69.5847222222), 
+   ("CYRJ", 48.52, -72.2655555556), 
+   ("CYRM", 52.4297222222, -114.904166667), 
+   ("CYRT", 62.8113888889, -92.1158333333), 
+   ("CYSB", 46.625, -80.7988888889), 
+   ("CYSC", 45.4380555556, -71.6905555556), 
+   ("CYSJ", 45.3161111111, -65.8902777778), 
+   ("CYSM", 60.0222222222, -111.960277778), 
+   ("CYSR", 72.9822222222, -84.6136111111), 
+   ("CYSU", 46.4427777778, -63.8311111111), 
+   ("CYSY", 71.9938888889, -125.2425), 
+   ("CYTE", 64.23, -76.5266666667), 
+   ("CYTH", 55.8011111111, -97.8641666667), 
+   ("CYTR", 44.1188888889, -77.5280555556), 
+   ("CYTS", 48.5697222222, -81.3766666667), 
+   ("CYTZ", 43.6275, -79.3961111111), 
+   ("CYUB", 69.4333333333, -133.026388889), 
+   ("CYUL", 45.4680555556, -73.7413888889), 
+   ("CYUT", 66.5213888889, -86.2247222222), 
+   ("CYUX", 68.7761111111, -81.2436111111), 
+   ("CYUY", 48.2061111111, -78.8355555556), 
+   ("CYVC", 55.1513888889, -105.261944444), 
+   ("CYVG", 53.3558333333, -110.823888889), 
+   ("CYVM", 67.5458333333, -64.0313888889), 
+   ("CYVO", 48.0533333333, -77.7827777778), 
+   ("CYVP", 58.0961111111, -68.4269444444), 
+   ("CYVQ", 65.2825, -126.800277778), 
+   ("CYVR", 49.195, -123.181944444), 
+   ("CYVT", 55.8419444444, -108.4175), 
+   ("CYVV", 44.7458333333, -81.1072222222), 
+   ("CYWA", 45.9522222222, -77.3191666667), 
+   ("CYWG", 49.91, -97.2344444444), 
+   ("CYWK", 52.9219444444, -66.8644444444), 
+   ("CYWL", 52.1830555556, -122.054166667), 
+   ("CYWY", 63.2094444444, -123.436666667), 
+   ("CYXC", 49.6102777778, -115.7825), 
+   ("CYXD", 53.5725, -113.520555556), 
+   ("CYXE", 52.1708333333, -106.699722222), 
+   ("CYXH", 50.0188888889, -110.720833333), 
+   ("CYXJ", 56.2380555556, -120.740277778), 
+   ("CYXL", 50.1144444444, -91.9041666667), 
+   ("CYXP", 66.145, -65.7136111111), 
+   ("CYXR", 47.695, -79.8488888889), 
+   ("CYXS", 53.8894444444, -122.678888889), 
+   ("CYXT", 54.4663888889, -128.5775), 
+   ("CYXU", 43.0355555556, -81.1538888889), 
+   ("CYXX", 49.0252777778, -122.363333333), 
+   ("CYXY", 60.7094444444, -135.068333333), 
+   ("CYYB", 46.3636111111, -79.4227777778), 
+   ("CYYC", 51.1138888889, -114.020277778), 
+   ("CYYD", 54.8247222222, -127.182777778), 
+   ("CYYE", 58.8363888889, -122.596944444), 
+   ("CYYF", 49.4627777778, -119.602222222), 
+   ("CYYG", 46.29, -63.1211111111), 
+   ("CYYH", 69.5466666667, -93.5766666667), 
+   ("CYYJ", 48.6469444444, -123.425833333), 
+   ("CYYL", 56.8638888889, -101.076111111), 
+   ("CYYN", 50.2919444444, -107.690555556), 
+   ("CYYQ", 58.7391666667, -94.065), 
+   ("CYYR", 53.3191666667, -60.4258333333), 
+   ("CYYT", 47.6186111111, -52.7519444444), 
+   ("CYYU", 49.4138888889, -82.4675), 
+   ("CYYW", 50.2902777778, -88.9097222222), 
+   ("CYYY", 48.6086111111, -68.2080555556), 
+   ("CYYZ", 43.6772222222, -79.6305555556), 
+   ("CYZD", 43.7425, -79.4655555556), 
+   ("CYZE", 45.8852777778, -82.5677777778), 
+   ("CYZF", 62.4627777778, -114.440277778), 
+   ("CYZH", 55.2933333333, -114.778333333), 
+   ("CYZP", 53.2541666667, -131.813888889), 
+   ("CYZR", 42.9994444444, -82.3088888889), 
+   ("CYZT", 50.6805555556, -127.366666667), 
+   ("CYZU", 54.1438888889, -115.786666667), 
+   ("CYZV", 50.2233333333, -66.2655555556), 
+   ("CYZW", 60.1727777778, -132.742777778), 
+   ("CYZX", 44.9844444444, -64.9169444444), 
+   ("CZFA", 62.2075, -133.375833333), 
+   ("CZFM", 67.4077777778, -134.860277778), 
+   ("DAAB", 36.5036111111, 2.81416666667), 
+   ("DAAD", 35.3325, 4.20638888889), 
+   ("DAAE", 36.7119444444, 5.06972222222), 
+   ("DAAG", 36.6908333333, 3.21527777778), 
+   ("DAAJ", 24.2925, 9.45222222222), 
+   ("DAAK", 36.5458333333, 2.87611111111), 
+   ("DAAM", 36.1086111111, 6.36444444444), 
+   ("DAAN", 26.71, 0.285555555556), 
+   ("DAAP", 26.5733333333, 8.48361111111), 
+   ("DAAQ", 35.5252777778, 2.87861111111), 
+   ("DAAS", 36.1780555556, 5.32444444444), 
+   ("DAAT", 22.8108333333, 5.45083333333), 
+   ("DAAV", 36.795, 5.87333333333), 
+   ("DAAY", 33.5358333333, -0.242222222222), 
+   ("DAAZ", 35.7522222222, 0.626111111111), 
+   ("DABB", 36.8222222222, 7.80916666667), 
+   ("DABC", 36.2766666667, 6.62388888889), 
+   ("DABS", 35.4313888889, 8.12055555556), 
+   ("DAFH", 32.9297222222, 3.31222222222), 
+   ("DAOB", 35.3411111111, 1.46305555556), 
+   ("DAOE", 35.7352777778, -0.805277777778), 
+   ("DAOF", 27.7002777778, -8.16694444444), 
+   ("DAOI", 36.2125, 1.33166666667), 
+   ("DAOL", 35.5422222222, -0.532222222222), 
+   ("DAON", 35.0166666667, -1.45), 
+   ("DAOO", 35.6236111111, -0.621111111111), 
+   ("DAOS", 35.1716666667, -0.593055555556), 
+   ("DAOV", 35.2075, 0.146944444444), 
+   ("DAUA", 27.8375, -0.186388888889), 
+   ("DAUB", 34.7930555556, 5.73805555556), 
+   ("DAUE", 30.5711111111, 2.85944444444), 
+   ("DAUG", 32.3838888889, 3.79388888889), 
+   ("DAUH", 31.6727777778, 6.14027777778), 
+   ("DAUI", 27.2508333333, 2.51194444444), 
+   ("DAUK", 33.0677777778, 6.08861111111), 
+   ("DAUL", 33.7638888889, 2.92722222222), 
+   ("DAUT", 29.2369444444, 0.275833333333), 
+   ("DAUU", 31.9172222222, 5.41277777778), 
+   ("DAUZ", 28.0513888889, 9.64277777778), 
+   ("DBBB", 6.35722222222, 2.38416666667), 
+   ("DBBP", 9.35694444444, 2.60888888889), 
+   ("DFFD", 12.3530555556, -1.51222222222), 
+   ("DFOO", 11.16, -4.33083333333), 
+   ("DGAA", 5.60277777778, -0.168055555556), 
+   ("DGLE", 9.56333333333, -0.863333333333), 
+   ("DGLW", 10.0825, -2.5075), 
+   ("DGSN", 7.36166666667, -2.32861111111), 
+   ("DGTK", 4.89333333333, -1.775), 
+   ("DIAP", 5.25972222222, -3.92638888889), 
+   ("DIBK", 7.73861111111, -5.07361111111), 
+   ("DIDL", 6.7925, -6.47305555556), 
+   ("DIKO", 9.38694444444, -5.55638888889), 
+   ("DIMN", 7.27194444444, -7.58694444444), 
+   ("DISP", 4.74666666667, -6.66055555556), 
+   ("DIYO", 6.90305555556, -5.36583333333), 
+   ("DNAA", 9.00666666667, 7.26305555556), 
+   ("DNAK", 7.24666666667, 5.30083333333), 
+   ("DNBE", 6.31722222222, 5.59944444444), 
+   ("DNCA", 4.97583333333, 8.34694444444), 
+   ("DNEN", 6.47416666667, 7.56194444444), 
+   ("DNGU", 12.1716666667, 6.69611111111), 
+   ("DNIB", 7.36222222222, 3.97833333333), 
+   ("DNIL", 8.44, 4.49388888889), 
+   ("DNJO", 9.63972222222, 8.86888888889), 
+   ("DNKA", 10.6958333333, 7.32), 
+   ("DNKN", 12.0475, 8.52444444444), 
+   ("DNMA", 11.8552777778, 13.0808333333), 
+   ("DNMK", 7.70361111111, 8.61388888889), 
+   ("DNMM", 6.57722222222, 3.32111111111), 
+   ("DNMN", 9.65194444444, 6.46222222222), 
+   ("DNPO", 5.01527777778, 6.94944444444), 
+   ("DNSO", 12.9161111111, 5.20694444444), 
+   ("DNYO", 9.26027777778, 12.4297222222), 
+   ("DNZA", 11.13, 7.68555555556), 
+   ("DRRM", 13.5025, 7.12666666667), 
+   ("DRRN", 13.4813888889, 2.18361111111), 
+   ("DRRT", 14.8755555556, 5.26527777778), 
+   ("DRZA", 16.9647222222, 7.99694444444), 
+   ("DRZD", 18.9686111111, 12.8686111111), 
+   ("DRZF", 13.3727777778, 12.6266666667), 
+   ("DRZR", 13.7788888889, 8.98361111111), 
+   ("DRZT", 14.9994444444, 8.76694444444), 
+   ("DTMB", 35.7580555556, 10.7547222222), 
+   ("DTTA", 36.8508333333, 10.2269444444), 
+   ("DTTB", 37.2452777778, 9.79138888889), 
+   ("DTTD", 32.3061111111, 10.3819444444), 
+   ("DTTF", 34.4219444444, 8.8225), 
+   ("DTTG", 33.8766666667, 10.1033333333), 
+   ("DTTI", 36.7211111111, 9.94305555556), 
+   ("DTTJ", 33.875, 10.7752777778), 
+   ("DTTR", 31.7041666667, 9.25444444444), 
+   ("DTTX", 34.7177777778, 10.6908333333), 
+   ("DTTZ", 33.9397222222, 8.11055555556), 
+   ("DXNG", 9.76722222222, 1.09111111111), 
+   ("DXXX", 6.16555555556, 1.25388888889), 
+   ("EBAW", 51.19, 4.46277777778), 
+   ("EBBE", 50.7586111111, 4.76833333333), 
+   ("EBBL", 51.1677777778, 5.47083333333), 
+   ("EBBR", 50.9022222222, 4.49861111111), 
+   ("EBBT", 51.3333333333, 4.5), 
+   ("EBBX", 49.8872222222, 5.22861111111), 
+   ("EBCI", 50.4591666667, 4.45361111111), 
+   ("EBCV", 50.5758333333, 3.83083333333), 
+   ("EBFN", 51.09, 2.65277777778), 
+   ("EBFS", 50.2436111111, 4.64861111111), 
+   ("EBKT", 50.8177777778, 3.20833333333), 
+   ("EBLG", 50.6372222222, 5.44305555556), 
+   ("EBOS", 51.1988888889, 2.86222222222), 
+   ("EBSL", 50.9483333333, 5.59166666667), 
+   ("EBST", 50.7883333333, 5.19277777778), 
+   ("EBUL", 51.1438888889, 3.47416666667), 
+   ("EBWE", 51.395, 4.96055555556), 
+   ("EBZR", 51.2655555556, 4.75472222222), 
+   ("EDAB", 51.1933333333, 14.5197222222), 
+   ("EDAC", 50.9816666667, 12.5061111111), 
+   ("EDAD", 51.8319444444, 12.1858333333), 
+   ("EDAE", 52.1972222222, 14.5855555556), 
+   ("EDAH", 53.8786111111, 14.1522222222), 
+   ("EDAK", 51.3080555556, 13.5547222222), 
+   ("EDAM", 51.3627777778, 11.9408333333), 
+   ("EDAQ", 51.5519444444, 12.0525), 
+   ("EDAU", 51.2944444444, 13.3588888889), 
+   ("EDAX", 53.3063888889, 12.7530555556), 
+   ("EDAY", 52.5797222222, 13.9155555556), 
+   ("EDAZ", 52.2033333333, 13.1586111111), 
+   ("EDBC", 51.8558333333, 11.4180555556), 
+   ("EDBG", 35.4605555556, -77.9647222222), 
+   ("EDBH", 54.3380555556, 12.71), 
+   ("EDBJ", 50.9172222222, 11.7136111111), 
+   ("EDBK", 52.9186111111, 12.4252777778), 
+   ("EDBM", 52.0736111111, 11.6263888889), 
+   ("EDBN", 51.3280555556, 12.6566666667), 
+   ("EDBR", 51.3644444444, 14.9519444444), 
+   ("EDCA", 53.8325, 13.6688888889), 
+   ("EDCD", 51.8894444444, 14.5316666667), 
+   ("EDCK", 51.7211111111, 11.9616666667), 
+   ("EDCM", 51.2961111111, 14.1288888889), 
+   ("EDDB", 52.38, 13.5225), 
+   ("EDDC", 51.1325, 13.7669444444), 
+   ("EDDE", 50.98, 10.9580555556), 
+   ("EDDF", 50.0263888889, 8.54305555556), 
+   ("EDDG", 52.1344444444, 7.68472222222), 
+   ("EDDH", 53.6302777778, 9.98805555556), 
+   ("EDDI", 52.4727777778, 13.4038888889), 
+   ("EDDK", 50.8658333333, 7.1425), 
+   ("EDDL", 51.2894444444, 6.76666666667), 
+   ("EDDM", 48.3536111111, 11.7858333333), 
+   ("EDDN", 49.4986111111, 11.0780555556), 
+   ("EDDP", 51.4238888889, 12.2361111111), 
+   ("EDDR", 49.2144444444, 7.10944444444), 
+   ("EDDS", 48.6897222222, 9.22194444444), 
+   ("EDDT", 52.5594444444, 13.2875), 
+   ("EDDV", 52.4608333333, 9.685), 
+   ("EDDW", 53.0475, 8.78666666667), 
+   ("EDFE", 49.9608333333, 8.64361111111), 
+   ("EDFH", 49.9497222222, 7.26388888889), 
+   ("EDFM", 49.4725, 8.51361111111), 
+   ("EDFQ", 51.0352777778, 8.67888888889), 
+   ("EDFV", 49.6063888889, 8.36833333333), 
+   ("EDFZ", 49.9688888889, 8.1475), 
+   ("EDGE", 50.9927777778, 10.4725), 
+   ("EDGS", 50.7075, 8.08194444444), 
+   ("EDHI", 53.5352777778, 9.83527777778), 
+   ("EDHK", 54.3794444444, 10.145), 
+   ("EDHL", 53.8052777778, 10.7191666667), 
+   ("EDKA", 50.8227777778, 6.18722222222), 
+   ("EDKV", 50.4058333333, 6.52805555556), 
+   ("EDKZ", 51.0994444444, 7.60194444444), 
+   ("EDLA", 51.4833333333, 7.89916666667), 
+   ("EDLC", 51.5302777778, 6.53694444444), 
+   ("EDLE", 51.4013888889, 6.93583333333), 
+   ("EDLN", 51.2302777778, 6.50444444444), 
+   ("EDLP", 51.6141666667, 8.61611111111), 
+   ("EDLS", 51.9958333333, 6.84027777778), 
+   ("EDLW", 51.5180555556, 7.61222222222), 
+   ("EDMA", 48.425, 10.9316666667), 
+   ("EDMB", 48.1108333333, 9.76277777778), 
+   ("EDME", 48.3961111111, 12.7236111111), 
+   ("EDMO", 48.0813888889, 11.2833333333), 
+   ("EDMS", 48.9008333333, 12.5180555556), 
+   ("EDMV", 48.6363888889, 13.1952777778), 
+   ("EDNL", 47.8588888889, 10.0144444444), 
+   ("EDNY", 47.6711111111, 9.51138888889), 
+   ("EDOP", 53.4269444444, 11.7833333333), 
+   ("EDOV", 52.6288888889, 11.8197222222), 
+   ("EDPA", 48.7777777778, 10.2644444444), 
+   ("EDQC", 50.2625, 10.9958333333), 
+   ("EDQD", 49.9841666667, 11.6383333333), 
+   ("EDQE", 49.7941666667, 11.1322222222), 
+   ("EDQM", 50.2886111111, 11.8547222222), 
+   ("EDQP", 49.8627777778, 11.7877777778), 
+   ("EDQT", 50.0177777778, 10.5294444444), 
+   ("EDRK", 50.3247222222, 7.53083333333), 
+   ("EDRT", 49.8633333333, 6.78888888889), 
+   ("EDRY", 49.3025, 8.45111111111), 
+   ("EDRZ", 49.2094444444, 7.40055555556), 
+   ("EDTB", 48.7911111111, 8.18694444444), 
+   ("EDTD", 47.9730555556, 8.52222222222), 
+   ("EDTF", 48.0202777778, 7.83361111111), 
+   ("EDTK", 48.9822222222, 8.33333333333), 
+   ("EDTM", 48.0536111111, 9.37277777778), 
+   ("EDTY", 49.1180555556, 9.77722222222), 
+   ("EDUS", 51.6075, 13.7377777778), 
+   ("EDVE", 52.3191666667, 10.5561111111), 
+   ("EDVK", 51.4083333333, 9.3775), 
+   ("EDVM", 52.1775, 9.94555555556), 
+   ("EDWB", 53.5033333333, 8.57333333333), 
+   ("EDWD", 53.1430555556, 8.62333333333), 
+   ("EDWE", 53.3911111111, 7.22722222222), 
+   ("EDWF", 53.2719444444, 7.44277777778), 
+   ("EDWI", 53.5047222222, 8.05333333333), 
+   ("EDWR", 53.5952777778, 6.70916666667), 
+   ("EDWY", 53.7066666667, 7.23), 
+   ("EDXF", 54.7716666667, 9.37805555556), 
+   ("EDXR", 54.2208333333, 9.60055555556), 
+   ("EDXW", 54.9130555556, 8.34027777778), 
+   ("EEEI", 59.2594444444, 24.2044444444), 
+   ("EEKA", 58.9905555556, 22.8305555556), 
+   ("EEKE", 58.2297222222, 22.5094444444), 
+   ("EEPU", 58.4188888889, 24.4727777778), 
+   ("EETN", 59.4130555556, 24.8327777778), 
+   ("EETU", 58.3072222222, 26.6902777778), 
+   ("EFET", 68.3625, 23.4241666667), 
+   ("EFEU", 61.1161111111, 22.2013888889), 
+   ("EFHA", 61.8558333333, 24.7863888889), 
+   ("EFHF", 60.2544444444, 25.0427777778), 
+   ("EFHK", 60.32, 24.9561111111), 
+   ("EFHM", 61.6894444444, 23.0736111111), 
+   ("EFHN", 59.8486111111, 23.0833333333), 
+   ("EFHV", 60.6544444444, 24.8811111111), 
+   ("EFIK", 60.4625, 23.6525), 
+   ("EFIM", 61.2491666667, 28.9036111111), 
+   ("EFIT", 62.1661111111, 30.0736111111), 
+   ("EFIV", 68.6072222222, 27.4052777778), 
+   ("EFJO", 62.6588888889, 29.6244444444), 
+   ("EFJY", 62.3994444444, 25.6780555556), 
+   ("EFKA", 63.1269444444, 23.0513888889), 
+   ("EFKE", 65.7816666667, 24.5988888889), 
+   ("EFKI", 64.2852777778, 27.6922222222), 
+   ("EFKJ", 62.4625, 22.3930555556), 
+   ("EFKK", 63.7211111111, 23.1430555556), 
+   ("EFKM", 66.7127777778, 27.1566666667), 
+   ("EFKS", 65.9875, 29.2391666667), 
+   ("EFKT", 67.7008333333, 24.8466666667), 
+   ("EFKU", 63.0069444444, 27.7975), 
+   ("EFLA", 61.1438888889, 25.6933333333), 
+   ("EFLP", 61.0444444444, 28.1441666667), 
+   ("EFMA", 60.1219444444, 19.8980555556), 
+   ("EFME", 62.9466666667, 23.5188888889), 
+   ("EFMI", 61.6863888889, 27.2016666667), 
+   ("EFNU", 60.3338888889, 24.2963888889), 
+   ("EFOU", 64.93, 25.3544444444), 
+   ("EFPI", 61.2455555556, 22.1933333333), 
+   ("EFPO", 61.4616666667, 21.7997222222), 
+   ("EFPU", 65.4022222222, 26.9469444444), 
+   ("EFPY", 63.7316666667, 25.9261111111), 
+   ("EFRH", 64.6880555556, 24.6958333333), 
+   ("EFRN", 62.0652777778, 28.3563888889), 
+   ("EFRO", 66.5647222222, 25.8302777778), 
+   ("EFRY", 60.7447222222, 24.1077777778), 
+   ("EFSA", 61.9430555556, 28.945), 
+   ("EFSE", 61.0622222222, 26.7986111111), 
+   ("EFSO", 67.395, 26.6188888889), 
+   ("EFTP", 61.4138888889, 23.6041666667), 
+   ("EFTS", 61.7733333333, 24.0269444444), 
+   ("EFTU", 60.5138888889, 22.2627777778), 
+   ("EFUT", 60.8963888889, 26.9383333333), 
+   ("EFVA", 63.0511111111, 21.7613888889), 
+   ("EFVR", 62.1711111111, 27.8686111111), 
+   ("EFYL", 64.0602777778, 24.7158333333), 
+   ("EGAA", 54.6575, -6.21583333333), 
+   ("EGAB", 54.3988888889, -7.65166666667), 
+   ("EGAC", 54.6180555556, -5.8725), 
+   ("EGAE", 55.0427777778, -7.16111111111), 
+   ("EGBB", 52.4536111111, -1.74777777778), 
+   ("EGBE", 52.3697222222, -1.47972222222), 
+   ("EGBG", 52.6077777778, -1.03194444444), 
+   ("EGBJ", 51.8941666667, -2.16722222222), 
+   ("EGBN", 52.92, -1.07916666667), 
+   ("EGBO", 52.5175, -2.25972222222), 
+   ("EGBP", 51.6680555556, -2.05694444444), 
+   ("EGBT", 52.0408333333, -1.09555555556), 
+   ("EGCC", 53.3536111111, -2.27472222222), 
+   ("EGCD", 53.3380555556, -2.14888888889), 
+   ("EGCF", 53.5597222222, -0.858333333333), 
+   ("EGDC", 51.0869444444, -4.15027777778), 
+   ("EGDG", 50.4405555556, -4.99527777778), 
+   ("EGDL", 51.505, -1.99333333333), 
+   ("EGDM", 51.1519444444, -1.74722222222), 
+   ("EGDR", 50.0858333333, -5.25555555556), 
+   ("EGDX", 51.4047222222, -3.43555555556), 
+   ("EGDY", 51.0091666667, -2.63861111111), 
+   ("EGFE", 51.8330555556, -4.96111111111), 
+   ("EGFF", 51.3966666667, -3.34333333333), 
+   ("EGFH", 51.6052777778, -4.06777777778), 
+   ("EGGD", 51.3825, -2.71888888889), 
+   ("EGGP", 53.3336111111, -2.84972222222), 
+   ("EGGW", 51.8744444444, -0.368333333333), 
+   ("EGHD", 50.4227777778, -4.10583333333), 
+   ("EGHH", 50.78, -1.8425), 
+   ("EGHI", 50.95, -1.35666666667), 
+   ("EGHL", 51.185, -1.03222222222), 
+   ("EGJB", 49.4347222222, -2.60194444444), 
+   ("EGJJ", 49.2077777778, -2.19527777778), 
+   ("EGKA", 50.8355555556, -0.297222222222), 
+   ("EGKB", 51.3308333333, 0.0325), 
+   ("EGKK", 51.1480555556, -0.190277777778), 
+   ("EGLC", 51.505, 0.0541666666667), 
+   ("EGLF", 51.2758333333, -0.776111111111), 
+   ("EGLJ", 51.6761111111, -1.08083333333), 
+   ("EGLK", 51.3238888889, -0.8475), 
+   ("EGLL", 51.4775, -0.461388888889), 
+   ("EGMC", 51.5713888889, 0.695555555556), 
+   ("EGMD", 50.9561111111, 0.939166666667), 
+   ("EGMH", 51.3422222222, 1.34611111111), 
+   ("EGNB", 53.7194444444, -0.566111111111), 
+   ("EGNC", 54.9375, -2.80916666667), 
+   ("EGNH", 53.7716666667, -3.02861111111), 
+   ("EGNJ", 53.5744444444, -0.350833333333), 
+   ("EGNL", 54.1297222222, -3.25611111111), 
+   ("EGNM", 53.8658333333, -1.66055555556), 
+   ("EGNO", 53.745, -2.88305555556), 
+   ("EGNR", 53.1780555556, -2.97777777778), 
+   ("EGNS", 54.0833333333, -4.62388888889), 
+   ("EGNT", 55.0375, -1.69166666667), 
+   ("EGNV", 54.5091666667, -1.42916666667), 
+   ("EGNX", 52.8311111111, -1.32805555556), 
+   ("EGOD", 52.8116666667, -4.12333333333), 
+   ("EGOE", 52.8711111111, -2.53333333333), 
+   ("EGOQ", 53.2583333333, -4.37333333333), 
+   ("EGOS", 52.7980555556, -2.66777777778), 
+   ("EGOV", 53.2480555556, -4.53527777778), 
+   ("EGOW", 53.5813888889, -3.05527777778), 
+   ("EGOY", 54.8511111111, -4.94777777778), 
+   ("EGPA", 58.9580555556, -2.905), 
+   ("EGPB", 59.8788888889, -1.29555555556), 
+   ("EGPC", 58.4586111111, -3.09277777778), 
+   ("EGPD", 57.2041666667, -2.20027777778), 
+   ("EGPE", 57.54, -4.05), 
+   ("EGPF", 55.8719444444, -4.43305555556), 
+   ("EGPH", 55.95, -3.3725), 
+   ("EGPI", 55.6819444444, -6.25666666667), 
+   ("EGPK", 55.5077777778, -4.58666666667), 
+   ("EGPL", 57.4811111111, -7.36277777778), 
+   ("EGPM", 60.4322222222, -1.29805555556), 
+   ("EGPN", 56.4525, -3.02583333333), 
+   ("EGPO", 58.2136111111, -6.32888888889), 
+   ("EGPU", 56.4991666667, -6.86916666667), 
+   ("EGQL", 56.3727777778, -2.86833333333), 
+   ("EGQS", 57.705, -3.33916666667), 
+   ("EGRR", 51.3833333333, -0.783333333333), 
+   ("EGSC", 52.205, 0.175), 
+   ("EGSF", 52.4680555556, -0.251111111111), 
+   ("EGSH", 52.6758333333, 1.28277777778), 
+   ("EGSS", 51.885, 0.235), 
+   ("EGSX", 51.7216666667, 0.154166666667), 
+   ("EGSY", 53.3941666667, -1.38833333333), 
+   ("EGTC", 52.0722222222, -0.616666666667), 
+   ("EGTD", 51.1166666667, -0.534444444444), 
+   ("EGTE", 50.7344444444, -3.41388888889), 
+   ("EGTG", 51.5194444444, -2.59083333333), 
+   ("EGTH", 51.7666666667, 0.25), 
+   ("EGTK", 51.8369444444, -1.32), 
+   ("EGUB", 51.6161111111, -1.09555555556), 
+   ("EGUL", 52.4091666667, 0.560833333333), 
+   ("EGUN", 52.3608333333, 0.488333333333), 
+   ("EGUW", 52.1272222222, 0.955833333333), 
+   ("EGUY", 52.3572222222, -0.107777777778), 
+   ("EGVA", 51.6819444444, -1.79), 
+   ("EGVN", 51.7497222222, -1.58361111111), 
+   ("EGVO", 51.2341666667, -0.942777777778), 
+   ("EGWC", 52.64, -2.30555555556), 
+   ("EGWU", 51.5527777778, -0.418055555556), 
+   ("EGXC", 53.0927777778, -0.165833333333), 
+   ("EGXD", 54.1369444444, -1.42), 
+   ("EGXE", 54.2922222222, -1.535), 
+   ("EGXG", 53.8341666667, -1.19527777778), 
+   ("EGXH", 52.3425, 0.772777777778), 
+   ("EGXJ", 52.7355555556, -0.648611111111), 
+   ("EGXP", 53.3075, -0.550833333333), 
+   ("EGXT", 52.6125, -0.476388888889), 
+   ("EGXU", 54.0494444444, -1.25194444444), 
+   ("EGXW", 53.1661111111, -0.523611111111), 
+   ("EGXZ", 54.2055555556, -1.38222222222), 
+   ("EGYC", 52.7547222222, 1.35722222222), 
+   ("EGYD", 53.0305555556, -0.481111111111), 
+   ("EGYE", 52.9622222222, -0.561388888889), 
+   ("EGYM", 52.6483333333, 0.550277777778), 
+   ("EGYP", -51.8227777778, -58.4472222222), 
+   ("EHAM", 52.3086111111, 4.76388888889), 
+   ("EHBD", 51.2552777778, 5.60138888889), 
+   ("EHBK", 50.9113888889, 5.77), 
+   ("EHDL", 52.0605555556, 5.87305555556), 
+   ("EHDR", 53.1191666667, 6.12972222222), 
+   ("EHEH", 51.45, 5.37444444444), 
+   ("EHGG", 53.1194444444, 6.57944444444), 
+   ("EHGR", 51.5677777778, 4.93305555556), 
+   ("EHKD", 52.9233333333, 4.78055555556), 
+   ("EHLE", 52.4602777778, 5.52722222222), 
+   ("EHLW", 53.2286111111, 5.76055555556), 
+   ("EHRD", 51.9572222222, 4.44166666667), 
+   ("EHSB", 52.1269444444, 5.27638888889), 
+   ("EHTW", 52.27, 6.87416666667), 
+   ("EHVB", 52.1697222222, 4.42611111111), 
+   ("EHWO", 51.4488888889, 4.34194444444), 
+   ("EICK", 51.8427777778, -8.49194444444), 
+   ("EICM", 53.3013888889, -8.93916666667), 
+   ("EIDL", 55.0441666667, -8.34083333333), 
+   ("EIDW", 53.4211111111, -6.27), 
+   ("EIKN", 53.9102777778, -8.81833333333), 
+   ("EIKY", 52.1808333333, -9.52361111111), 
+   ("EIME", 53.3027777778, -6.44277777778), 
+   ("EINN", 52.7019444444, -8.92472222222), 
+   ("EISG", 54.28, -8.59916666667), 
+   ("EIWF", 52.1869444444, -7.08694444444), 
+   ("EKAH", 56.3041666667, 10.6194444444), 
+   ("EKBI", 55.7402777778, 9.15166666667), 
+   ("EKCH", 55.6177777778, 12.6558333333), 
+   ("EKEB", 55.5258333333, 8.55333333333), 
+   ("EKGH", 55.9411111111, 12.3822222222), 
+   ("EKHO", 56.3966666667, 8.44333333333), 
+   ("EKKA", 56.2972222222, 9.12444444444), 
+   ("EKLS", 57.2777777778, 11.0013888889), 
+   ("EKMB", 54.6991666667, 11.44), 
+   ("EKOD", 55.4761111111, 10.3291666667), 
+   ("EKPB", 54.8702777778, 9.27916666667), 
+   ("EKRK", 55.5855555556, 12.1313888889), 
+   ("EKRN", 55.0630555556, 14.7594444444), 
+   ("EKSB", 54.9641666667, 9.79166666667), 
+   ("EKSN", 57.5033333333, 10.2291666667), 
+   ("EKSP", 55.2252777778, 9.26388888889), 
+   ("EKSV", 56.55, 9.17277777778), 
+   ("EKTS", 57.0686111111, 8.705), 
+   ("EKVA", 55.6969444444, 9.19333333333), 
+   ("EKVD", 55.4361111111, 9.33083333333), 
+   ("EKVG", 62.0636111111, -7.27694444444), 
+   ("EKVH", 56.8469444444, 9.45861111111), 
+   ("EKVJ", 55.99, 8.35388888889), 
+   ("EKVL", 55.7672222222, 12.3433333333), 
+   ("EKYT", 57.0927777778, 9.84888888889), 
+   ("ELLX", 49.6263888889, 6.21138888889), 
+   ("ENAL", 62.5602777778, 6.11), 
+   ("ENAN", 69.2925, 16.1441666667), 
+   ("ENAT", 69.9769444444, 23.3661111111), 
+   ("ENBL", 61.3925, 5.76416666667), 
+   ("ENBM", 60.6386111111, 6.50138888889), 
+   ("ENBN", 65.4591666667, 12.2136111111), 
+   ("ENBO", 67.2688888889, 14.3633333333),