CheckoutableTemplates/ 0000755 0001750 0001750 00000000000 11030137651 015161 5 ustar peterbe peterbe CheckoutableTemplates/Permission.py 0000644 0001750 0001750 00000000425 11030137651 017664 0 ustar peterbe peterbe # CheckoutableTemplates Permission settings
#
# Peter Bengtsson, Fry-IT Ltd, 2003-2004
# License: ZPL
#
# Credits to Stefan H. Holek and his DocFinderEverywhere
#
__doc__="""See README.txt"""
ViewCTPermission = 'View CheckoutableTemplates'
ViewCTDefaultRoles = ('Manager',)
CheckoutableTemplates/version.txt 0000644 0001750 0001750 00000000007 11030137651 017404 0 ustar peterbe peterbe 0.2.10
CheckoutableTemplates/showCheckoutableTemplates.dtml 0000644 0001750 0001750 00000032041 11030137651 023214 0 ustar peterbe peterbe
Show Checkoutable Templates
Checkoutable Templates
Difference between source and checked out template
Cancel,
/manage_main">Edit
Error
Idenfifier expired.
Please reload the page
Objects written back to file
">
Retract now
None
Error
Idenfifier expired.
Please reload the page
Error
Template could not be checked out again.
Please reload the page
Objects created!
Error
Identifier has expired. Please reload the page
Templates checked out
No templates checked out
Templates not checked out
There are no templates that can be checked out
How it works
Checkoutable Templates are Python product templates that have been
created by the CTDTMLFile(DTMLFile) and
CTPageTemplateFile(PageTemplateFile)
classes.
These templates belong to the Python products as templates run off
the file system. Checkoutable Templates makes a
copy of these as Zope objects.
When it does so, it creates a Zope object (DTML Method or Page Template)
based on the filesystem filename and
the default extension.
So if your product uses a file called manage_edi.tdtml,
then the object that is created
becomes manage_edit.dtml.
Checkoutable Templates can not know what the name of the method
is that the filesystem based template used for.
For example, if your Python product defines something like this:
class MyProduct:
...
viewStatistics = CTDTMLFile('dtml/statistics', globals())
d='Setting a description is optional')
...
updateStats = CTPageTemplateFile('zpt/updatestats', globals(),
d='Description of this template')
...
# Not necessary to set this attribute but
# with it set, the showCheckoutableTemplates shows
# only relevant files which is helpful if you
# have several products that use CheckoutableTemplates.
this_package_home = package_home(globals())
...
Then, that the method name becomes viewStatistics is
impossible to know.
When these Checkoutable Templates are run, theres a quick check
if the template exists as a Zope object based on
its name. If so, run that instead. If not, run the filesystem based template
as normal.
CheckoutableTemplates/__init__.py 0000644 0001750 0001750 00000003365 11030137651 017301 0 ustar peterbe peterbe ##
## CheckoutableTemplates,
## By Peter Bengtsson, mail@peterbe.com, www.peterbe.com
## Copyright 2003-2005
## License ZPL
##
__doc__="""CheckoutableTemplates by Peter Bengtsson,
Fry-IT Ltd, 2003-2005.
CheckoutableTemplates allows you to make exceptions
with DTML and PageTemplate attributes of a Python product.
This is highly usable if you have an instance of a Python
product class, and you want to change some little thing in one
of its templates.
"""
__refresh_module__ = 0
# python
import os
# Zope
from OFS.Application import Application
from Globals import HTMLFile
from AccessControl.Permission import registerPermissions
from OFS.SimpleItem import Item
from AccessControl.PermissionRole import PermissionRole
# Product
from Permission import ViewCTPermission, ViewCTDefaultRoles
from CTFiles import CTDTMLFile, CTPageTemplateFile
from Constants import *
from findCTs import CheckoutableTemplatesBase
# Delete the old config file when Zope starts
#if os.path.isfile(CONFIGFILEPATH):
# Delete it!
#os.remove(CONFIGFILEPATH)
def initialize(context):
registerPermissions(((ViewCTPermission, (), ViewCTDefaultRoles),))
if DISABLE_CHECKOUTABLETEMPLATES:
from zLOG import LOG, WARNING
LOG('CheckoutableTemplates', WARNING, 'CheckoutableTemplates disabled')
else:
Application.CheckoutableTemplates = CheckoutableTemplatesBase()
showCT = HTMLFile('showCheckoutableTemplates', globals())
ViewCTRoles = PermissionRole(ViewCTPermission, ViewCTDefaultRoles)
Item.showCheckoutableTemplates = showCT
Item.showCheckoutableTemplates__roles__ = ViewCTRoles
if DEBUG:
from zLOG import LOG, INFO
LOG('CheckoutableTemplates', INFO, 'installed')
CheckoutableTemplates/CTFiles.py 0000644 0001750 0001750 00000025666 11030137651 017043 0 ustar peterbe peterbe ##
## CheckoutableTemplates,
## By Peter Bengtsson, mail@peterbe.com, www.peterbe.com
## Copyright 2003-2005
## License ZPL
##
import os, cPickle, stat, sys, re
from types import DictType, ListType, StringType
from time import time
import marshal
from pprint import pprint
from random import shuffle
from Globals import DTMLFile
from zLOG import LOG, INFO, WARNING
from AccessControl import ClassSecurityInfo
from Acquisition import aq_parent, aq_inner, aq_base
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Constants import *
import logging
logger = logging.getLogger('CheckoutableTemplates')
if DISABLE_CHECKOUTABLETEMPLATES:
logger.info("CheckoutableTemplates is disabled")
try:
from slimmer import slimmer, acceptableSyntax
except ImportError:
def acceptableSyntax(*a, **k):
return None
def slimmer(inputtext, *a, **k):
return inputtext
if DEBUG:
m = "slimmer not installed. Whitespace optimization disbled."
m += " (see www.issuetrackerproduct.com)"
LOG("CheckoutableTemplates", WARNING, m)
try:
__test_dict={'a':'A'}
__test_dict.pop('a')
Python21 = 0
except:
Python21 = 1
def dict_popper(dict, key):
""" simulate what {}.pop() does in Python 2.3 """
if not dict:
raise KeyError, 'dict_popper(): dictionary is empty'
if not dict.has_key(key):
raise KeyError, repr(key)
new_dict = {}
for k, v in dict.items():
if k == key:
value = v
else:
new_dict[k] = v
return value, new_dict
def debug(debug_output):
if DEBUG:
print "CT|",
if type(debug_output)==StringType:
print debug_output
else:
pprint(debug_output)
open('output.log','a').write(debug_output.strip()+'\n')
_id_junk_regex = re.compile('[\\/\s\.:]')
def _generateIdentifier(basepath, relpath, mtime):
id = basepath + relpath
id = _id_junk_regex.sub('', id)
id = list(id[:3]+id[-3:]+str(mtime)[-5:])
shuffle(id)
id = "".join(id)
return id
def _getAllconfigs():
raise "NotUsed"
def _readAllConfigs():
if os.path.isfile(CONFIGFILEPATH):
try:
#items, finder = cPickle.load(open(CONFIGFILEPATH))
items, finder = cPickle.load(open(CONFIGFILEPATH,'rb'))
#items, finder = marshal.load(open(CONFIGFILEPATH))
except ValueError, e:
if str(e) == "unpack list of wrong size":
# Wohw! the config file is corrupted which could very
# much be because it's from an ancient version of
# CheckoutableTemplates
return [], {}
try:
assert type(items)==ListType, "items is not a list"
assert type(finder)==DictType, "finder is not a dictionary"
except AssertionError:
return [], {}
else:
items, finder = [], {} # this is how it starts
return items, finder
#def _findConfig(key):
# """ key can be an identifier or basepath,relpath,filetype """
# items, finder = _readAllConfigs()
# if finder.has_key(key):
# return items[finder.get(key)]
# else:
# return None
def _writeAllConfigs(items, finder):
combined = items, finder
# save new file
cPickle.dump(combined, open(CONFIGFILEPATH, 'wb'), -1)
def _clean_itemlist(itemslist, basepath, relpath, filetype):
""" return a _new list_ which doesn't have duplicate combinations of
basepath, relpath and filetype and nothing of the params """
copy = []
newfinder = {}
_template = "%s/%s/%s"
skip_combo = _template%(basepath, relpath, filetype)
for each in itemslist:
combo = _template%(each['basepath'], each['relpath'], each['filetype'])
if not newfinder.has_key(combo):
if combo != skip_combo:
copy.append(each)
newfinder[combo] = copy.index(each)
else:
debug("Duplicate combo: %s"%combo)
return copy, newfinder
def _write2config(basepath, relpath, description, mtime, filetype='DTML'):
""" save an item serialized file """
items, finder = _readAllConfigs()
key = "%s/%s/%s" % (basepath, relpath, filetype)
addthis = 1
item_no = finder.get(key)
if item_no is None:
# ah! Nothing in the finder
addthis = 1
else:
try:
item = items[item_no]
# we have it already
addthis = 0
except IndexError:
# Ghaa! we're out-of-sync with the finder
addthis = 1 # force a new addition
# test if we can change our mind based on the mtime
if not addthis and mtime > item['mtime']: # has changed
# remove it
items.pop(item_no)
if Python21:
_value, finder = dict_popper(finder, key)
else:
finder.pop(key)
addthis = 1
if addthis:
if CLEAN_CHECK: # read Constants.py
items, finder = _clean_itemlist(items, basepath, relpath, filetype)
identifier = _generateIdentifier(basepath, relpath, mtime)
d = {'description':description,
'filetype':filetype,
'relpath':relpath,
'basepath':basepath,
'mtime':mtime,
'identifier':identifier
}
items.append(d)
item_no = items.index(d)
finder[key] = item_no
finder[identifier] = item_no
debug("Write new identifier %s"%identifier)
_writeAllConfigs(items, finder)
return 1
else:
return 0
def write2config(basepath, relpath, description, mtime,
filetype='DTML'):
""" save a config item """
return _write2config(basepath, relpath, description, mtime,
filetype=filetype)
class _CTDTMLFile(DTMLFile):
def __init__(self, name, _prefix=None, **kw):
" doc string "
description = kw.get('description',kw.get('d',''))
# 'optimize' argument
optimize = kw.get('optimize', kw.get('opt', None))
self.optimize = acceptableSyntax(optimize)
if not kw.has_key('uncheckoutable'):
sep = name[max(name.find('\\'), name.find('/'))]
self.ctnamesplit = name.split(sep)
prodpath = _prefix['__name__'].split('.')[:-1]
prodpath = ".".join(prodpath).replace('.',os.sep)
basepath = os.path.join(CT_INSTANCE_HOME, prodpath)
if not os.path.isdir(basepath):
basepath = os.path.join(CT_SOFTWARE_HOME, prodpath)
# first, open file to see how old it is.
name = name.replace('/', os.sep).replace('\\',os.sep)
t = os.stat(os.path.join(basepath, name+ '.dtml'))
mtime = t[stat.ST_MTIME]
# if already there there's no point to
# add it again
added = write2config(basepath, name, description,
mtime, 'DTML')
if DEBUG and added:
LOG(self.__class__.__name__, INFO, name)
apply(DTMLFile.__init__, (self, name, _prefix), kw)
def _exec(self, bound_data, args, kw):
""" Execute the template but first look for one instanciated
in the ZODB based on the some filename conversion. """
ctnamesplit = bound_data['self'].ctnamesplit
if len(self.ctnamesplit) == 1:
possibletemplate = ctnamesplit[0] + '.dtml'
else:
possibletemplate = '.'.join(ctnamesplit[1:]) + '.dtml'
base = bound_data['context']
if hasattr(base, possibletemplate):
request = bound_data['context'].REQUEST
params = (bound_data['context'], request)
result = apply(getattr(base, possibletemplate), params, kw)
else:
result = apply(DTMLFile._exec, (self, bound_data, args, kw))
if self.optimize and OPTIMIZE:
result = slimmer(result, self.optimize)
return result
class _CTPageTemplateFile(PageTemplateFile):
""" CTPageTemplateFile subclasses PageTemplateFile and
intercepts the __init__ and the _exec methods """
def __init__(self, name, _prefix=None, **kw):
""" doc string """
description = kw.get('description',kw.get('d',''))
# 'optimize' argument
optimize = kw.get('optimize', kw.get('opt', None))
self.optimize = acceptableSyntax(optimize)
if not kw.has_key('uncheckoutable'):
sep = name[max(name.find('\\'), name.find('/'))]
self.ctnamesplit = name.split(sep)
prodpath = _prefix['__name__'].split('.')[:-1]
prodpath = ".".join(prodpath).replace('.',os.sep)
basepath = os.path.join(CT_INSTANCE_HOME, prodpath)
if not os.path.isdir(basepath):
basepath = os.path.join(CT_SOFTWARE_HOME, prodpath)
# first, open file to see how long it is.
name = name.replace('/', os.sep).replace('\\',os.sep)
template_path = os.path.join(basepath, name)
if not os.path.splitext(template_path)[1]:
template_path += '.zpt'
t = os.stat(template_path)
mtime = t[stat.ST_MTIME]
added = write2config(basepath, name, description,
mtime, 'ZPT')
if DEBUG and added:
LOG(self.__class__.__name__, INFO, name)
apply(PageTemplateFile.__init__, (self, name, _prefix), kw)
def _exec(self, bound_data, args, kw):
""" doc string """
if len(self.ctnamesplit) == 1:
possibletemplate = self.ctnamesplit[0]
else:
possibletemplate = '.'.join(self.ctnamesplit[1:])
if not possibletemplate.endswith('.zpt'):
possibletemplate += '.zpt'
base = self
if hasattr(base, possibletemplate):
request = self.REQUEST
result = apply(getattr(base, possibletemplate), (self, request), kw)
else:
result = apply(PageTemplateFile._exec, (self, bound_data, args, kw))
if self.optimize and OPTIMIZE:
try:
result = slimmer(result, self.optimize)
except:
try:
err_log = self.error_log
err_log.raising(sys.exc_info())
except:
pass
return result
if DISABLE_CHECKOUTABLETEMPLATES:
CTPageTemplateFile = PageTemplateFile
CTDTMLFile = DTMLFile
else:
CTPageTemplateFile = _CTPageTemplateFile
CTDTMLFile = _CTDTMLFile CheckoutableTemplates/Constants.py 0000644 0001750 0001750 00000003601 11030137651 017507 0 ustar peterbe peterbe # Suppose you have done:
# $ ln -s zope261b1 Zope-2.6.2b2-linux2-x86
# or some similar setup, then CLIENT_HOME becomes the latter but
# globals() will have the former.
# This hack makes sure that CT_HOME becomes like
# globals()
#
# To set this variable, edit you ./start script to have the following:
#
# CT_HOME=/home/zope/zope123/var
# export CT_HOME
#
# The same goes for the CT_SOFTWARE_HOME and you set it like this:
#
# CT_SOFTWARE_HOME=/home/zope/zope123/lib/python/Products
# export CT_SOFTWARE_HOME
#
import os
CT_HOME = os.environ.get('CT_HOME', CLIENT_HOME)
CT_SOFTWARE_HOME = os.environ.get('CT_SOFTWARE_HOME', SOFTWARE_HOME)
CT_INSTANCE_HOME = os.environ.get('CT_INSTANCE_HOME', INSTANCE_HOME)
def _getVariable(key, default):
value = os.environ.get(key, default)
try:
value = not not int(value)
except:
if str(value).lower().strip() in ['yes','on']:
value = 1
elif str(value).lower().strip() in ['no','off']:
value = 0
else:
value = default
return value
DISABLE_CHECKOUTABLETEMPLATES = _getVariable('DISABLE_CHECKOUTABLETEMPLATES', 0)
# Allows to write back to file from showCheckoutableTemplate
CAN_WRITEBACK = _getVariable('CT_CAN_WRITEBACK', 0)
# Writes to Log() every time we store a template
DEBUG = _getVariable('CT_DEBUG',0)
# Attempts to optimize the output
OPTIMIZE = _getVariable('CT_OPTIMIZE',1)
CONFIGFILEPATH = os.path.join(CT_HOME, "CTConfig")
CONFIGFILEPATH = CONFIGFILEPATH + '.dump'
# It's good to have CLEAN_CHECK on if you have upgraded from
# an old CheckoutableTemplates and you might have old information
# in your pickled file in 'var/CTConfig.dump'
# If you switch CLEAN_CHECK off you might gain some speed but
# this should only be done once you know you've at least once
# deleted the CTConfig.dump file sometime before Zope started.
CLEAN_CHECK = _getVariable('CT_CLEAN_CHECK', 1) CheckoutableTemplates/README.txt 0000644 0001750 0001750 00000016115 11030137651 016663 0 ustar peterbe peterbe CheckoutableTemplates by Peter Bengtsson,
Fry-IT Ltd, 2003-2004.
This software is released under the ZPL license.
Credits to Dieter Maurer and his code that inspired me to
enable the 'showCheckoutableTemplates' page.
Credits to the MoinMoin project (http://sourceforge.net/projects/moin/)
for the inspiration and code used in diff.py
CheckoutableTemplates allows you to make exceptions
to DTMLFile and PageTemplateFile attributes of a Python product.
This is highly usable if you have an instance of a Python
product class, and you want to change some little thing in one
of its templates.
In Zope, it is NOT possible to subclass an template attribute
from withing the ZMI. Having templates as attributes in a
Python product class is useful because when you roll out a new
version, it's easy to include your changes. It's also useful in
that you can make the Zope object instance very simple.
The advantage about only having templates instanciated inside
the class instance in Zope is that you can make changes to the
look and feel of one and only one instance.
Suppose your Python product defines a template like this::
class MyProduct(ObjectManager):
meta_type = 'My Meta Type'
def __init__(self, id, title=''):
...
show_page = DTMLFile('dtml/show_page', globals())
edit_page = PageTemplateFile('zpt/edit_page', globals())
Then you can use these templates by visiting
http://localhost:8080/myinstance/show_page
Suppose you're **not** the author of the Python product but have
found a spelling misstake or an invalid HTML tag in show_page.dtml,
or suppose you have two instance of the product; one
called 'myinstance' and one called 'herinstance'. For the 'herinstance'
instance you want the show_page to look slightly different.
How do you fix that without editing the sourcecode of the Python
product? You simply can't!
Suppose instead that you have CheckoutableTemplates installed and
define your Python product like this::
from Products.CheckoutableTemplates \
import CTPageTemplateFile, CTDTMLFile
class MyProduct(ObjectManager):
meta_type = 'My Meta Type'
def __init__(self, id, title=''):
...
show_page = CTDTMLFile('dtml/show_page', globals())
edit_page = CTPageTemplateFile('zpt/edit_page', globals())
Then, visit http://localhost:8080/myinstance/showCheckoutableTemplates
and you'll see a list of templates that you can make exceptions
on. When you use that interface to check out a template, an object
is created called show_page.dtml and/or edit_page.zpt.
Their Id "protected", so you can't call it whatever you want. The only
thing that links these template objects with your python product is
the Id.
If you have SilverCity (http://silvercity.sourceforge.net/) installed
code syntax will be shown more nicely. It is not a necessity.
Again, you visit http://localhost:8080/myinstance/show_page,
CheckoutableTemplates makes a check if there is an object called
'show_page.dtml'. If so, use that instead; if not, use the file system
template as normal.
If you have installed several Python products that use
CheckoutableTemplates, then the showCheckoutableTemplates page will
list the templates of all Python products. To help you with this, the
Python product can define an attributes called 'this_package_home'
like this::
from Globals import package_home
from Products.CheckoutableTemplates \
import CTPageTemplateFile, CTDTMLFile
class MyProduct(ObjectManager):
meta_type = 'My Meta Type'
def __init__(self, id, title=''):
...
show_page = CTDTMLFile('dtml/show_page', globals())
edit_page = CTPageTemplateFile('zpt/edit_page', globals())
this_package_home = package_home(globals())
Generally you don't have to worry about this option.
Refreshing a Python product is something you don't have to be
worried about. When you refresh the Python product
CheckoutableTemplates rechecks all template attributes but only
changes those which have changed.
Just because you have defined your template attributes with
CheckoutableTemplates doesn't mean that you have to use it. It's just
extremely useful IF you will need it at a later point. It also makes
it possible to edit your templates via the web if you for some reason
can't do it on the command line in emacs.
When you start Zope, CheckoutableTemplates keeps a record of
all templates your Python product uses. It stores this in
'/var/CTConfig.dump' which is a pickle dump.
If you have your zoperoot linked as a symbolic link, you'll
have to set this as an environment variable in your start
script::
CT_HOME=/home/peterbe/zope261b2/var
CT_SOFTWARE_HOME=/home/peterbe/zope261b2/lib/python
export CT_HOME
export CT_SOFTWARE_HOME
Set this appropriatly to how you have your Zope set up. I
guess that if you do, you know enough about Zope and sys admin
to be able to see what needs to be done.
The best way to test your settings is that you use the
showCheckoutableTemplates page.
It is not recommended for live environments, but useful when
debugging your python product, you can enable 'CT_CAN_WRITEBACK'
which allows you to save a Zope object template back onto the file system.
Set this in your start script like this::
export CT_CAN_WRITEBACK=1
To do this on Windows, in start.bat you write::
SET CT_CAN_WRITEBACK=1
This product was developed to be used in a live environment,
but comes with absolutely no warrenty. I advice that you
familiarize yourself with CheckoutableTemplates before you
decide to enroll it in your best Python products.
All bug reports and suggestions are welcome to peter@fry-it.com.
The CTPageTemplateFile and CTDTMLFile also accepts a parameter called
'optimize' which can (at the time of writing this) accept values
like 'CSS', 'HTML' or 'XHTML'. If any of these are set, the output
CSS/HTML/XHTML will be optimized but stripping out everything excessive
such as excess whitespace and comments. The 'XHTML' optimizer is less
rough than the 'HTML' optimizer which strips unnecessary quotes. NOTE!
This only works if you have the slimmer.py module installed.
As an example, some CSS can be changed from::
/* Header 1 */
h1 {
font-family: Verdana, Arial;
color: #123456;
}
To this::
h1{font-family:Verdana,Arial;color:#123456;}
Of course it depends on how your HTML output looks like but
preliminary calculations have shown that you get on average a 10-20%
time gain average. I.e. the time to download the document plus the
time to optimize the output.
Note: Always test your pages after you have switched on the optimization.
Note2: Don't optimize twice. Use sparingly.::
from Products.CheckoutableTemplates \
import CTPageTemplateFile, CTDTMLFile
class MyProduct(ObjectManager):
meta_type = 'My Meta Type'
def __init__(self, id, title=''):
...
show_page = CTDTMLFile('dtml/show_page', globals(),
optimize='XHTML')
edit_page = CTPageTemplateFile('zpt/edit_page', globals(),
optimize='HTML')
styles_css = CTDTMLFile('dtml/show_page', globals(),
optimize='CSS')
CheckoutableTemplates/CHANGES.txt 0000644 0001750 0001750 00000007550 11030137651 017001 0 ustar peterbe peterbe 0.2.10
- Fixed a bug which made it impossible to include templates that
already had an extension like 'screen.css.dtml'
0.2.9
- Templates specified without an extension are assumed to be .zpt
in the end for ZPT.
0.2.8
- Important bugfix, keyword arguments passed to checked out
templates did not reach the template code.
0.2.7
- showCheckoutableTemplates is not XHTML Transitional compliant.
- No "diff" link on checked out templates that aren't different.
- Excessive LOG() messages removed (unless in CT_DEBUG mode)
- Corrected sourcecode to use 4 spaces for tabs ONLY.
0.2.6
- Exit link in showCheckoutableTemplates.
- Made it Python2.1 compatible again after a Python2.>1 feature
was introduced. See CTFiles.py/dict_popper()
- Differ feature greatly improved thanks to MoinMoin project.
0.2.5
- _write2config() now prevents duplicates in the pickle file useful
to have when you upgrade to this latest version.
- Draft of differ for checked out templates in showCheckoutableTemplates
0.2.4
- marshal module used in CTFiles.py caused a memory leak in one
of my Gentoo Linux servers so to be on the safe side I resided
back to using cPickle.
0.2.3
- write2config() greatly optimized. (see
http://www.peterbe.com/plog/python-optimization-anecdote)
- PUT_REQUEST_NOTE constant for 'DebugFilterCTFilesPH' in REQUEST
- _generateIdentifier() optimized to generate more unique
identifiers faster.
0.2.2
- slimmer.py thrown out. It was too different and slimmer.py
is now going to become a standalone Open Source package.
0.2.1
- Executing CTDTML instances did not use Zope acquisition.
CTPageTemplates did. (Thanks Ria Marinussen)
0.2.0
- Fixed bug the way CheckoutableTemplates finds the Products directory.
Now no extra configuration settings necessary for Zope2.7.x on win32.
- Fixed a bug recently introduced in html_slimmer() that
was related to unquoted attributes.
- Improved (x)html_slimmer() to not strip excess whitespace in
tags like this:
- Major speed improvement in (x)html_slimmer(). Sometimes three
times faster.
0.1.9
- Fixed bug in (x)html_slimmer() that tried to slimmer inline
JavaScript.
- Rewrote some of the tests.
- Fixed bug in css_slimmer() with line breaks and selectors starting
with '#'.
- Improved css_slimmer() to replace '#FFCCFF' to '#FCF'
- Fixed bug in css_slimmer() when using IE hacks.
- Tweak slimmer.py css_slimmer() to replace ': 10px' to ':10px'.
0.1.8
- Prepared for public release to the Zope community by deleting
unnecessary files, silly comments and improved README.txt
0.1.7
- Fixed a bug that added duplicates when a product using CT
refreshes a template.
0.1.6
- Added some basic unittesting cases for slimmer module.
0.1.5
- Added basic support for HTML and CSS optimization. To use,
add a keyword argument to the constructor or CTPageTemplateFile
and CTDTMLFile like this optimize='CSS' or optimize='HTML'.
0.1.4
- Fixed security bug that allowed Anonymous access to
showCheckoutableTemplates
- Improved identifier checks in showCheckoutableTemplates
- Beautified showCheckoutableTemplates. If SilverCity is importable,
showing source is done with nice XML stylesheets.
0.1.3
- Changed use of os.stat to be backcompatible with python 2.1
0.1.2
- Removed all XML storage facilities. Nice to look at but too slow
- Changed the "checker" from length-of-document to modification time os.stat()
0.1.1
First release to Zope.org
0.1.0
First release zipped up.
CheckoutableTemplates/diff.py 0000644 0001750 0001750 00000011610 11030137651 016442 0 ustar peterbe peterbe # -*- coding: iso-8859-1 -*-
"""
MoinMoin - Side by side diffs
@copyright: 2005 by Peter Bengtsson
@copyright: 2002 by Jürgen Hermann
@copyright: 2002 by Scott Moonen
@license: GNU GPL, see COPYING for details.
"""
import difflib
#from MoinMoin.wikiutil import escape
def escape(s, quote=0):
""" Escape possible html tags
Replace special characters '&', '<' and '>' by SGML entities.
(taken from cgi.escape so we don't have to include that, even if we
don't use cgi at all)
FIXME: should return string or unicode?
@param s: (unicode) string to escape
@param quote: bool, should transform '\"' to '"'
@rtype: (unicode) string
@return: escaped version of s
"""
if not isinstance(s, (str, unicode)):
s = str(s)
# Must first replace &
s = s.replace("&", "&")
# Then other...
s = s.replace("<", "<")
s = s.replace(">", ">")
if quote:
s = s.replace('"', """)
return s
def indent(line):
eol = ''
while line and line[0] == '\n':
eol += '\n'
line = line[1:]
stripped = line.lstrip()
if len(line) - len(stripped):
line = " " * (len(line) - len(stripped)) + stripped
#return "%d / %d / %s" % (len(line), len(stripped), line)
return eol + line
# This code originally by Scott Moonen, used with permission.
# The copied from MoinMoin 1.3.3 and modified by Peter Bengtsson
def diff(old, new):
""" Find changes between old and new and return
HTML markup visualising them.
"""
#_ = request.getText
#t_line = _("Line") + " "
t_line = "Line "
seq1 = old.splitlines()
seq2 = new.splitlines()
seqobj = difflib.SequenceMatcher(None, seq1, seq2)
linematch = seqobj.get_matching_blocks()
if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)):
# No differences.
return "No differences found!"
lastmatch = (0, 0)
result = """
| Checked out template (modified) |
Original template (source) |
|
%s
|
%s
|
""" % ('Deletions are marked like this.', 'Additions are marked like this.')
# Print all differences
for match in linematch:
# Starts of pages identical?
if lastmatch == match[0:2]:
lastmatch = (match[0] + match[2], match[1] + match[2])
continue
result += """
|
%s %s:
|
%s %s:
|
""" % ( t_line, str(lastmatch[0] + 1),
t_line, str(lastmatch[1] + 1),)
leftpane = ''
rightpane = ''
linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1])
for line in range(linecount):
if line < match[0] - lastmatch[0]:
if line > 0:
leftpane += '\n'
leftpane += seq1[lastmatch[0] + line]
if line < match[1] - lastmatch[1]:
if line > 0:
rightpane += '\n'
rightpane += seq2[lastmatch[1] + line]
charobj = difflib.SequenceMatcher(None, leftpane, rightpane)
charmatch = charobj.get_matching_blocks()
if charobj.ratio() < 0.5:
# Insufficient similarity.
if leftpane:
leftresult = """%s""" % indent(escape(leftpane))
else:
leftresult = ''
if rightpane:
rightresult = """%s""" % indent(escape(rightpane))
else:
rightresult = ''
else:
# Some similarities; markup changes.
charlast = (0, 0)
leftresult = ''
rightresult = ''
for thismatch in charmatch:
if thismatch[0] - charlast[0] != 0:
leftresult += """%s""" % indent(
escape(leftpane[charlast[0]:thismatch[0]]))
if thismatch[1] - charlast[1] != 0:
rightresult += """%s""" % indent(
escape(rightpane[charlast[1]:thismatch[1]]))
leftresult += escape(leftpane[thismatch[0]:thismatch[0] + thismatch[2]])
rightresult += escape(rightpane[thismatch[1]:thismatch[1] + thismatch[2]])
charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2])
leftpane = '
\n'.join(map(indent, leftresult.splitlines()))
rightpane = '
\n'.join(map(indent, rightresult.splitlines()))
# removed width="50%%"
result += """
|
%s
|
%s
|
""" % (leftpane, rightpane)
lastmatch = (match[0] + match[2], match[1] + match[2])
result += '
\n'
return result
CheckoutableTemplates/findCTs.py 0000644 0001750 0001750 00000034423 11030137651 017073 0 ustar peterbe peterbe ##
## CheckoutableTemplates,
## By Peter Bengtsson, mail@peterbe.com, www.peterbe.com
## Copyright 2003-2008
## License ZPL
##
__doc__="""extract which templates can be checked out"""
import os, StringIO, re
from Products.PythonScripts.standard import html_quote, newline_to_br
from ExtensionClass import Base
from AccessControl.SecurityInfo import ClassSecurityInfo
# Attempt to import fancy SilverCity formatting
try:
from SilverCity import XML as SC_XML
try:
import SilverCity
_SC_stylesheet_location = SilverCity.get_default_stylesheet_location()
SC_stylesheet = open(_SC_stylesheet_location).read()
except:
SC_XML = None
except ImportError:
SC_XML = None
from Constants import *
import CTFiles
from diff import diff
#-----------------------------------------------------------------------------
def sgmlDiff(a, b):
out = []
isjunk = lambda x: not not re.search("\s", x)
d = difflib.SequenceMatcher(isjunk, a, b)
for e in d.get_opcodes():
if e[0] == "replace":
out.append(''+''.join(a[e[1]:e[2]]) + ''+''.join(b[e[3]:e[4]])+"")
elif e[0] == "delete":
out.append(''+ ''.join(a[e[1]:e[2]]) + "")
elif e[0] == "insert":
out.append(''+''.join(b[e[3]:e[4]]) + "")
elif e[0] == "equal":
out.append(''.join(b[e[3]:e[4]]))
else:
raise "OpcodesError", "Unrecognized %r"%e[0]
return "".join(out)
#-----------------------------------------------------------------------------
class CheckoutableTemplatesBase(Base):
""" the purpose of this class is to
use the XML config file to extract which templates that can be
checked out in this instance.
"""
_secInfo= ClassSecurityInfo()
_secInfo.declarePublic('__getitem__','__len__','tpValues', 'tpId',
'getCTFiles')
_secInfo.declarePrivate('View management screens','doCheckout',
'doWriteback','canWriteback', 'doRetract'
'showCheckoutableTemplates',
'hasCheckedout',
'hasFileitemFromIdentifier',
'getFileitemFromIdentifier',
)
def __init__(self):
""" no doc string """
pass
def getCTFiles(self, zope, filter=None):
""" returns which templates are checkoutable.
The 'filter' parameter can be used to:
- None: no filtering
- 'Deployed': those that have been deployed
- 'Deployed here': like 'Deployed' but only 'here'.
- 'Undeployed': those not yet deployed.
- 'Undeployed here': like 'Undeployed' but only 'here'.
"""
fileitems = []
# read config file
fileitems, finder = CTFiles._readAllConfigs()
fileitems = self._appendMoreInfo2Items(fileitems)
if zope is None:
return fileitems
if filter is not None:
filter = filter.lower().replace(' ','').strip()
checked = []
if filter == 'deployed':
# only those where objectid exists as zope object
for fileitem in fileitems:
if hasattr(zope, fileitem['objectid']):
checked.append(fileitem)
elif filter == 'deployedhere':
# only those where objectid exists here without
# acquisition.
base = getattr(zope, 'aq_base', zope)
for fileitem in fileitems:
if hasattr(base, fileitem['objectid']):
checked.append(fileitem)
elif filter == 'undeployed':
# only those where objectid does not exists
# as zope object.
for fileitem in fileitems:
if not hasattr(zope, fileitem['objectid']):
checked.append(fileitem)
elif filter == 'undeployedhere':
# only those where objectid does not exists
# here without acquisition.
base = getattr(zope, 'aq_base', zope)
for fileitem in fileitems:
if not hasattr(base, fileitem['objectid']):
checked.append(fileitem)
else:
checked = fileitems
base = getattr(zope, 'aq_base', zope)
# Inspect if 'base' has a this_package_home attribute,
# and if so, filter 'checked' based on that.
if hasattr(base, 'this_package_home'):
req_basepath = base.this_package_home
# Make note that we do this:
zope.REQUEST.set('DebugFilterCTFilesPH',
req_basepath)
doublechecked = []
for item in checked:
if item['basepath'].find(req_basepath) > -1:
doublechecked.append(item)
checked = doublechecked
return checked
def _appendMoreInfo2Items(self, fileitems):
" using the data we have create few more interesting things "
newfileitems = []
for fileitem in fileitems:
newd = fileitem
ikey = 'filetypeicon'
if fileitem['filetype'].lower()=='dtml':
newd[ikey] = '''
'''
extension = '.dtml'
elif fileitem['filetype'].lower()=='zpt':
newd[ikey] = '''
'''
extension = '.zpt'
else:
# Unrecognized!!
continue
basepath = fileitem['basepath']
basepath = basepath.replace('\\',os.sep).replace('/',os.sep)
relpath = fileitem['relpath']
relpath = relpath.replace('\\',os.sep).replace('/',os.sep)
if not os.path.splitext(relpath)[1]:
relpath = relpath + extension
fullpath = os.path.join(basepath, relpath)
newd['fullpath'] = fullpath
relpath = fileitem['relpath']
sep = relpath[max(relpath.rfind('\\'), relpath.rfind('/'))]
objectidlist = [str(x) for x in relpath.split(sep)]
if len(objectidlist) == 1:
objectid = objectidlist[0]
else:
objectid = '.'.join(objectidlist[1:])
if os.path.splitext(objectid)[1] not in ('.dtml','.zpt'):
objectid += extension
newd['objectid'] = objectid
# keep it
newfileitems.append(newd)
return newfileitems
def hasCheckedout(self, zope, identifiers):
""" return true if any identifier is already checked out """
if type(identifiers)==type('s'):
identifiers = [identifiers]
base = getattr(zope, 'aq_base', zope)
for identifier in identifiers:
fileitem = self.getFileitemFromIdentifier(identifier)
if hasattr(base, fileitem['objectid']):
return 1
return 0
def doCheckout(self, zope, identifiers):
""" create template objects """
objects_created=[]
if type(identifiers)==type('s'):
identifiers = [identifiers]
for identifier in identifiers:
fileitem = self.getFileitemFromIdentifier(identifier)
id = fileitem['objectid']
fr = open(fileitem['fullpath'], 'r')
code = fr.read()
fr.close()
title = ''
if fileitem['filetype'].lower()=='dtml':
obj=self._createDTMLMethod(zope, id, code, title)
objects_created.append(obj)
elif fileitem['filetype'].lower()=='zpt':
obj=self._createPageTemplate(zope, id, code, title)
objects_created.append(obj)
else:
raise "UnrecognizedFiletype", fileitem['filetype']
return objects_created
def _createDTMLMethod(self, zope, id, code, title=''):
""" create a DTML object in zope """
with = zope.manage_addProduct['OFSP']
with.addDTMLMethod(id, title)
dtmlmethod = getattr(zope, id)
dtmlmethod.manage_edit(code, title)
return dtmlmethod
def _createPageTemplate(self, zope, id, code, title=''):
""" create a PageTemplate object in zope """
with = zope.manage_addProduct['PageTemplates']
with.manage_addPageTemplate(id, title, code)
pagetemplate = getattr(zope, id)
return pagetemplate
def doRetract(self, zope, identifiers):
""" delete some zope objects """
if type(identifiers)==type('s'):
identifiers = [identifiers]
objectids= []
for fileitem in self.getCTFiles(zope, 'deployed'):
if fileitem['identifier'] in identifiers:
objectids.append(fileitem['objectid'])
objectids_copy = objectids[:]
zope.manage_delObjects(objectids)
return objectids_copy
def getSourcecode(self, identifier):
" read file and return source code "
fullpath = self.getFullpathFromIdentifier(identifier)
if fullpath is None:
return "NONE FOUND!!"
fr = open(fullpath, 'r')
code = fr.read()
fr.close()
return code
def showSourcecode(self, identifier):
""" return source code htmlified """
code = self.getSourcecode(identifier)
return self._niceSourceFormat(code)
def _niceSourceFormat(self, code):
if SC_XML is not None:
generator = SC_XML.XMLHTMLGenerator()
file = StringIO.StringIO()
generator.generate_html(file, code)
code = file.getvalue()
file.close()
del generator
css = '\n\n'%SC_stylesheet
code = '%s
'%code
return css + code
else:
code = html_quote(code)
code = newline_to_br(code)
code = code.replace('\t',' '*4)
return "%s"%code
def showDifference(self, zope, identifier, objectid):
""" return a nice formatted difference string """
code_source = self.getSourcecode(identifier)
object = getattr(zope, objectid)
assert hasattr(object, 'absolute_url'), "%r not a ZODB object" % object
code_object = object.document_src()
#difference = diff(html_quote(code_source), html_quote(code_object))
difference = diff(code_object, code_source)
return difference # this is a HTML
def _niceDifference(self, difference):
""" return a nice explaination of the difference """
#difference = newline_to_br(difference)
lines = difference.splitlines(1)
lineitemer = lambda x, c: "%s %s"%(c, x)
newlines = []
for i in range(len(lines)):
newlines.append(lines[i])
difference = "
".join(newlines)
difference = difference.replace("\t", " "*4)
return '%s
'%difference
def hasFileitemFromIdentifier(self, identifiers):
""" search to see if this identifier exists """
if type(identifiers)==type('s'):
identifiers = [identifiers]
for fileitem in self.getCTFiles(None):
if fileitem['identifier'] in identifiers:
return 1
return 0
def getFileitemFromIdentifier(self, identifier):
""" search through all files and match identifier,
then return fileitem (dict) of the found one.
"""
for fileitem in self.getCTFiles(None):
if fileitem['identifier'] == identifier:
return fileitem
else:
return None
def getFullpathFromIdentifier(self, identifier):
""" get the full path from an identifier """
found = self.getFileitemFromIdentifier(identifier)
if found is not None:
fullpath = found['fullpath']
if found['filetype'] == 'DTML' and os.path.splitext(fullpath)[1] != '.dtml':
fullpath += '.dtml'
elif found['filetype'] == 'ZPT' and os.path.splitext(fullpath)[1] not in ('.zpt','.pt'):
fullpath += '.zpt'
return fullpath
else:
return None
def doWriteback(self, zope, identifiers, makebackupcopy=1):
""" From the identifier, find the equivalent Zope object
and use it's document_src to write to file """
objects =[] # list of all object we manage to write back
for identifier in identifiers:
fileitem = self.getFileitemFromIdentifier(identifier)
if fileitem is None:
raise "InvalidIdentifier", "No file in config found with"\
"this identifier %s"%identifier
else:
fullpath = fileitem['fullpath']
objectid = fileitem['objectid']
# get it as Zope object
object = getattr(zope, objectid)
document_src = object.document_src()
if makebackupcopy:
incr = 1
while os.path.isfile(fullpath + '.bak%s'%incr):
incr += 1
fullpath_backup = fullpath + '.bak%s'%incr
fbr = open(fullpath, 'r')
fbw = open(fullpath_backup, 'w')
fbw.write(fbr.read())
fbw.close()
fbr.close()
# nice and simple write
fw = open(fullpath, 'w')
fw.write(document_src)
fw.close()
# remember that we wrote this back
objects.append([object, identifier])
return objects
def canWriteback(self):
""" true if CAN_WRITEBACK """
return CAN_WRITEBACK
CheckoutableTemplatesBase._secInfo.apply(CheckoutableTemplatesBase)
CheckoutableTemplates/styles.css 0000644 0001750 0001750 00000042670 11030137651 017227 0 ustar peterbe peterbe
div.callink {
font-family:verdana, arial, helvetica; text-align:left; color:#3366B4;
font-size:14px; font-style:normal; font-weight:bold; text-decoration:none; line-height:16px;
}
.bluetitle{
font-family:verdana, arial, helvetica; text-align:left; color:#3366B4;
font-size:14px; font-style:normal; font-weight:bold; text-decoration:none; line-height:16px;
}
.calendardropdown{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#3366B4; text-decoration:none;
}
a:link{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#000000; text-decoration:underline;
}
.link{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#000000; text-decoration:underline;
}
a:visited {
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#000000; text-decoration:underline;
}
a:hover{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#C31111; text-decoration:underline;
}
a:active{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#000000; text-decoration:underline;
}
body{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; color:#000000;
}
p{
font-family:verdana, arial, helvetica; text-align:justify;
font-size:11px; font-style:normal; font-weight:normal; color:#000000;
line-height:14px;
}
b{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#000000; line-height:14px;
}
.bblue{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#3366B4; text-decoration:none; line-height:14px;
}
.bred{
font-family:verdana, arial, helvetica; font-size:12px; font-style:normal;
font-weight:bold; color:#C31111; text-decoration:none; line-height:14px;
}
s{
font-family:verdana, arial, helvetica; font-size:9px; font-style:normal;
font-weight:normal; color:#000000; text-decoration:none; line-height:14px;
}
.sblue{
font-family:verdana, arial, helvetica; font-size:10px; font-style:normal;
font-weight:normal; color:#3366B4; line-height:11px;
}
td{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; line-height:14px;
}
ul{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; line-height:14px;
}
li{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:normal; line-height:14px;
}
.title{
font-family:verdana, arial, helvetica; text-align:left; color:#444444;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:none; line-height:16px;
}
i{
font-style:italic;
}
em{
font-style:italic;
}
.just{
text-align:justify;
}
.center{
text-align:center;
}
.left{
text-align:left;
}
.right{
text-align:right;
}
.progress{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#000000; text-decoration:none; line-height:13px;
}
.progress_selected{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#B5B5B5; text-decoration:none; line-height:13px;
}
h1{
font-family:Arial Black, verdana, arial, helvetica; color:#8a8a8a;
font-size:13pt; font-style:normal; font-weight:bold; text-decoration:none; line-height:19px;
}
h2{
font-family:Arial Black, verdana, arial, helvetica; color:#8a8a8a;
font-size:10pt; font-style:normal; font-weight:bold; text-decoration:none; line-height:19px;
}
.form{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:normal; color:#000000; text-decoration:none;
}
.calendardropdown{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#3366B4; text-decoration:none;
}
.formbold{
font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:bold; color:#000000; text-decoration:none;
}
.dark{
background-color:#dddddd; font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:normal; color:#000000; text-decoration:none;
}
.light{
background-color:#f2f2f2; font-family:verdana, arial, helvetica; font-size:11px; font-style:normal;
font-weight:normal; color:#000000; text-decoration:none;
}
.tableheader{
font-family:verdana, arial, helvetica; font-size:12px; font-style:normal;
font-weight:bold; color:#ffffff; text-decoration:none;
background-color:#3366B4;
}
LI.img {
list-style-image : url(http://www.quietdays.com/images/orange_bullet.gif); font-family:verdana, arial, helvetica; font-size:11px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none; line-height:17px
}
LI.img_treatments {
list-style-image : url(http://www.quietdays.com/images/ailments_bullet.gif); font-family:verdana, arial, helvetica; font-size:12px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
.CellLightOff
{ background-color: #FFFFFF; }
.CellLightOn
{ background-color: #FFF5E8; }
.siteframe{
background-color:#9DB8DD;
}
.maintbl{
background-color:#FFFFFF;
}
.lefttbl{
background: url(http://www.quietdays.com/images/left-bg.gif) #6898D0;
}
.blue{
background-color:#6898D0;
}
.lightblue{
background-color:#9DB8DD;
}
.stats{
font-family:verdana, arial, helvetica; background-color:#FFFFFF; vertical-align:bottom;
font-size:9px; font-style:normal; font-weight:normal; color:#7F7F7F; text-decoration:none;
}
.systemmsg {
font-family:Verdana, Arial, Helvetica;
background-color:#FFFFFF;
vertical-align:bottom;
font-size:10px;
font-style:normal;
font-weight:bold;
color:#2A63A6;
text-decoration:none;
}
.bluebutton {
font-family: Arial, Helvetica, sans-serif;
color: #FFFFFF;
background-color: #336699;
text-transform: uppercase;
font-size: 9px;
font-weight: bold;
border-top-color: #CCCCCC;
border-right-color: #000033;
border-bottom-color: #000033;
border-left-color: #CCCCCC;
}
.searchnotused{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.searchbig{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:14px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.searcht{
font-family:verdana, arial, helvetica;
font-size:13px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.searchb{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:11px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.searcherror{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:10px; font-style:normal; font-weight:bold; color:#D90000; text-decoration:none;
}
.search{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:10px; font-style:normal; font-weight:normal; color:#FFFFFF; text-decoration:none;
}
.searchform{
font-family:verdana, arial, helvetica; width:102px;
font-size:10px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
.searchform_unfixed {
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
.searchform2{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
.loginnotused{
font-family:verdana, arial, helvetica; background-color:#336AB4;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.logint{
font-family:verdana, arial, helvetica; background-color:#336AB4;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.loginb{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:10px; font-style:normal; font-weight:bold; color:#000000; text-decoration:none;
}
.login{
font-family:verdana, arial, helvetica; line-height:20px;
font-size:9px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
.loginform{
font-family:verdana, arial, helvetica; width:75px;
font-size:10px; font-style:normal; font-weight:normal; color:#000000; text-decoration:none;
}
a.loginlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
.loginlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
a.loginlink:visited{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
a.loginlink:hover{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#5395DB; text-decoration:none;
}
a.loginlink:active{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#FFFFFF; text-decoration:none;
}
a.navlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
.navlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
a.navlink:visited{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
a.navlink:hover{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
a.navlink:active{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
.nav{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#5395DB; text-decoration:none;
}
a.navlinkon{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:underline;
}
.navlinkon{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
a.navlinkon:visited{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
a.navlinkon:hover{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
a.navlinkon:active{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
.nav{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#5395DB; text-decoration:none;
}
a.slink{
font-family:verdana, arial, helvetica;
font-size:9px; font-style:normal; font-weight:normal; color:#5395DB; text-decoration:none;
}
.slink{
font-family:verdana, arial, helvetica;
font-size:9px; font-style:normal; font-weight:normal; color:#5395DB; text-decoration:none;
}
a.slink:visited{
font-family:verdana, arial, helvetica;
font-size:9px; font-style:normal; font-weight:normal; color:#5395DB; text-decoration:none;
}
a.slink:hover{
font-family:verdana, arial, helvetica;
font-size:9px; font-style:normal; font-weight:normal; color:#C31111; text-decoration:underline;
}
a.slink:active{
font-family:verdana, arial, helvetica;
font-size:9px; font-style:normal; font-weight:normal; color:#5395DB; text-decoration:none;
}
a.boldlink{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:underline;
}
.boldlink{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:underline;
}
a.boldlink:visited{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:underline;
}
a.boldlink:hover{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:underline;
}
a.boldlink:active{
font-family:verdana, arial, helvetica;
font-size:11px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:underline;
}
a.smalllink{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
.smalllink{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.smalllink:visited{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.smalllink:hover{
font-family:verdana, arial, helvetica; color:#C31111;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.smalllink:active{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.golink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
.golink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
a.golink:visited{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
a.golink:hover{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#C31111; text-decoration:none;
}
a.golink:active{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:bold; color:#3366B4; text-decoration:none;
}
a.breadcrumblink{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:underline; text-align:left;
}
.breadcrumblink{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:underline; text-align:left;
}
.breadcrumb{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:none; text-align:left;
}
a.breadcrumblink:visited{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:underline; text-align:left;
}
a.breadcrumblink:hover{
font-family:verdana, arial, helvetica; color:#C31111;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:underline; text-align:left;
}
a.breadcrumblink:active{
font-family:verdana, arial, helvetica; color:#3366B4;
font-size:12px; font-style:normal; font-weight:bold; text-decoration:underline; text-align:left;
}
a.passwordlink{
font-family:verdana, arial, helvetica; color:#000000;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
.passwordlink{
font-family:verdana, arial, helvetica; color:#000000;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.passwordlink:visited{
font-family:verdana, arial, helvetica; color:#000000;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.passwordlink:hover{
font-family:verdana, arial, helvetica; color:#C31111;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.passwordlink:active{
font-family:verdana, arial, helvetica; color:#000000;
font-size:9px; font-style:normal; font-weight:normal; text-decoration:underline;
}
a.tldlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#7B7B7B; text-decoration:none;
}
.tldlink{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#7B7B7B; text-decoration:none;
}
a.tldlink:visited{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#7B7B7B; text-decoration:none;
}
a.tldlink:hover{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#A3CA00; text-decoration:underline;
}
a.tldlink:active{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#7B7B7B; text-decoration:none;
}
.tld{
font-family:verdana, arial, helvetica;
font-size:10px; font-style:normal; font-weight:normal; color:#7B7B7B; text-decoration:none; line-height:15px; background-color:#FFFFFF;
}
td.weekdays{
font-family:verdana, arial, helvetica;
font-weight:bold;
}
td.weekcounter{
font-family:verdana, arial, helvetica;
font-size:70%;
font-weight:bold;
}
td.selected_directory {
background-color:#cccccc;
}
td.unselected_directory {
}
td.calendar_month_header{
color:blue;
font-size:120%;
font-weight:bold;
}