Commit 31e7b770 authored by nextime's avatar nextime

First github commit

parent 5716ee19

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

== 0.9.2 / 2010-12-05
* Added MANIFEST.in so ez_setup.py is included for users without setuptools
== 0.9.1 / 2010-02-16
* Bug Fix: Table/Column COMMENT and AUTO_INCREMENT Regular Expression is Greedy
* Bug Fix: Column sync misses columns changes once sequence is in order
* Improved file version Regular Expression
* Added tests for all Regular Expressions
== 0.9.0 / 2009-12-02
* Updated SchemaObject dependancy to version >= 0.5.2
* Fixes:
- Column DEFAULT now quoted if string
- CHARACTER SET, COLLATE omitted if same as parent Table
- Column definition syntax bug fixed
== 0.9.0 / 2009-11-10
* Initial Public Release
include README CHANGES *.py
recursive-include schemasync *.py
Metadata-Version: 1.0
Name: SchemaSync
Version: 0.9.2
Summary: A MySQL Schema Synchronization Utility
Home-page: UNKNOWN
Author: Mitch Matuson
Author-email: UNKNOWN
License: UNKNOWN
Description: Schema Sync will generate the SQL necessary to migrate the schema of a source database to a target database (patch script), as well as a the SQL necessary to undo the changes after you apply them (revert script).
Keywords: MySQL,database,schema,migration,SQL
Platform: UNKNOWN
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Topic :: Database
Classifier: Topic :: Database :: Front-Ends
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Utilities
Schema Sync v0.9.2
+++++++++++++++++++
a MySQL schema synchronization utility
http://www.schemasync.org
SYNOPSIS
========
schemasync [options] <source> <target>
# source/target format: mysql://user:pass@host:port/database
# output format: <database>[_<tag>].YYYYMMDD.(patch|revert)[_<version>].sql
DESCRIPTION
===========
Schema Sync will generate the SQL necessary to migrate the schema of a source database to a target database (patch script), as well as a the SQL necessary to undo the changes after you apply them (revert script).
* Schema Sync does not alter your database. It only generates the .sql files containing the differences. You must apply the changes.
* Schema Sync does not yet recognize Tables or Columns that have been renamed. A rename will result in the old table or column being dropped and the new one added.
* All ADD|MODIFY COLUMN statements have the AFTER (or FIRST) SQL syntax even if no move is required.
* COMMENTS and AUTO_INCREMENT values are not by synced by default. See help (-h) for details.
* Partitions (MySQL 5.1+) are not yet supported
OPTIONS
=================
-h, --help show this help message and exit
-V, --version show version and exit.
-r, --revision increment the migration script version number
if a file with the same name already exists.
-a, --sync-auto-inc sync the AUTO_INCREMENT value for each table.
-c, --sync-comments sync the COMMENT field for all tables AND columns
--tag=TAG tag the migration scripts as <database>_<tag>.
Valid characters include [A-Za-z0-9-_]
--output-directory=OUTPUT_DIRECTORY
directory to write the migration scrips.
The default is current working directory.
Must use absolute path if provided.
--log-directory=LOG_DIRECTORY
set the directory to write the log to.
Must use absolute path if provided.
Default is output directory.
Log filename is schemasync.log
Download and Install
====================
Prerequisites
-------------
* To run Schema Sync, you need to have:
- Python 2.4, 2.5, or 2.6
- MySQL <http://www.mysql.com/>, version 5.0 or higher
- MySQLdb <http://sourceforge.net/projects/mysql-python>, version 1.2.1p2 or higher
- SchemaObject <http://matuson.com/code/schemaobject> 0.5.3 or higher
* To run the test suite, you need to install a copy of the Sakila Database <http://dev.mysql.com/doc/sakila/en/sakila.html>, version 0.8
Standard Installation
---------------------
For installation instructions, see http://www.schemasync.org/install.htm
Status & License
================
Schema Sync is under active development and released under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>.
You can obtain a copy of the latest source code from the Git repository <http://github.com/mmatuson/SchemaSync>, or fork it on Github <http://www.github.com>.
You can report bugs via the Schema Sync Issues page <http://github.com/mmatuson/SchemaSync/issues>
Comments, questions, and feature requests can be sent to code at matuson com
\ No newline at end of file
Metadata-Version: 1.0
Name: SchemaSync
Version: 0.9.2
Summary: A MySQL Schema Synchronization Utility
Home-page: UNKNOWN
Author: Mitch Matuson
Author-email: UNKNOWN
License: UNKNOWN
Description: Schema Sync will generate the SQL necessary to migrate the schema of a source database to a target database (patch script), as well as a the SQL necessary to undo the changes after you apply them (revert script).
Keywords: MySQL,database,schema,migration,SQL
Platform: UNKNOWN
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Topic :: Database
Classifier: Topic :: Database :: Front-Ends
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Utilities
CHANGES
MANIFEST.in
README
ez_setup.py
setup.py
SchemaSync.egg-info/PKG-INFO
SchemaSync.egg-info/SOURCES.txt
SchemaSync.egg-info/dependency_links.txt
SchemaSync.egg-info/entry_points.txt
SchemaSync.egg-info/requires.txt
SchemaSync.egg-info/top_level.txt
schemasync/__init__.py
schemasync/schemasync.py
schemasync/syncdb.py
schemasync/utils.py
\ No newline at end of file
[console_scripts]
schemasync = schemasync.schemasync:main
SchemaObject >=0.5.3
\ No newline at end of file
schemasync
#!python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c9"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
}
import sys, os
try: from hashlib import md5
except ImportError: from md5 import md5
def _validate_md5(egg_name, data):
if egg_name in md5_data:
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
def do_download():
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
try:
import pkg_resources
except ImportError:
return do_download()
try:
pkg_resources.require("setuptools>="+version); return
except pkg_resources.VersionConflict, e:
if was_imported:
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first, using 'easy_install -U setuptools'."
"\n\n(Currently using %r)"
) % (version, e.args[0])
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return do_download()
except pkg_resources.DistributionNotFound:
return do_download()
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
egg = None
try:
egg = download_setuptools(version, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
if egg and os.path.exists(egg):
os.unlink(egg)
else:
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])
#!/usr/bin/python
__author__ = "Mitch Matuson"
__copyright__ = "Copyright 2009 Mitch Matuson"
__version__ = "0.9.1"
__license__ = "Apache 2.0"
import re
import sys
import os
import logging
import datetime
import optparse
import syncdb
import utils
import warnings
# supress MySQLdb DeprecationWarning in Python 2.6
warnings.simplefilter("ignore", DeprecationWarning)
try:
import MySQLdb
except ImportError:
print "Error: Missing Required Dependency MySQLdb."
sys.exit(1)
try:
import schemaobject
except ImportError:
print "Error: Missing Required Dependency SchemaObject"
sys.exit(1)
APPLICATION_VERSION = __version__
APPLICATION_NAME = "Schema Sync"
LOG_FILENAME = "schemasync.log"
DATE_FORMAT = "%Y%m%d"
TPL_DATE_FORMAT = "%a, %b %d, %Y"
PATCH_TPL = """--
-- Schema Sync %(app_version)s %(type)s
-- Created: %(created)s
-- Server Version: %(server_version)s
-- Apply To: %(target_host)s/%(target_database)s
--
%(data)s"""
def parse_cmd_line(fn):
"""Parse the command line options and pass them to the application"""
def processor(*args, **kwargs):
usage = """
%prog [options] <source> <target>
source/target format: mysql://user:pass@host:port/database"""
description = """
A MySQL Schema Synchronization Utility
"""
parser = optparse.OptionParser(usage=usage,
description=description)
parser.add_option("-V", "--version",
action="store_true",
dest="show_version",
default=False,
help=("show version and exit."))
parser.add_option("-r", "--revision",
action="store_true",
dest="version_filename",
default=False,
help=("increment the migration script version number "
"if a file with the same name already exists."))
parser.add_option("-a", "--sync-auto-inc",
dest="sync_auto_inc",
action="store_true",
default=False,
help="sync the AUTO_INCREMENT value for each table.")
parser.add_option("-c", "--sync-comments",
dest="sync_comments",
action="store_true",
default=False,
help=("sync the COMMENT field for all "
"tables AND columns"))
parser.add_option("--tag",
dest="tag",
help=("tag the migration scripts as <database>_<tag>."
" Valid characters include [A-Za-z0-9-_]"))
parser.add_option("--output-directory",
dest="output_directory",
default=os.getcwd(),
help=("directory to write the migration scrips. "
"The default is current working directory. "
"Must use absolute path if provided."))
parser.add_option("--log-directory",
dest="log_directory",
help=("set the directory to write the log to. "
"Must use absolute path if provided. "
"Default is output directory. "
"Log filename is schemasync.log"))
options, args = parser.parse_args(sys.argv[1:])
if options.show_version:
print APPLICATION_NAME, __version__
return 0
if (not args) or (len(args) != 2):
parser.print_help()
return 0
return fn(*args, **dict(version_filename=options.version_filename,
output_directory=options.output_directory,
log_directory=options.log_directory,
tag=options.tag,
sync_auto_inc=options.sync_auto_inc,
sync_comments=options.sync_comments))
return processor
def app(sourcedb='', targetdb='', version_filename=False,
output_directory=None, log_directory=None,
tag=None, sync_auto_inc=False, sync_comments=False):
"""Main Application"""
options = locals()
if not os.path.isabs(output_directory):
print "Error: Output directory must be an absolute path. Quiting."
return 1
if not os.path.isdir(output_directory):
print "Error: Output directory does not exist. Quiting."
return 1
if not log_directory or not os.path.isdir(log_directory):
if log_directory:
print "Log directory does not exist, writing log to %s" % output_directory
log_directory = output_directory
logging.basicConfig(filename=os.path.join(log_directory, LOG_FILENAME),
level=logging.INFO,
format= '[%(levelname)s %(asctime)s] %(message)s')
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
logging.getLogger('').addHandler(console)
if not sourcedb:
logging.error("Source database URL not provided. Exiting.")
return 1
source_info = schemaobject.connection.parse_database_url(sourcedb)
if not source_info:
logging.error("Invalid source database URL format. Exiting.")
return 1
if not source_info['protocol'] == 'mysql':
logging.error("Source database must be MySQL. Exiting.")
return 1
if 'db' not in source_info:
logging.error("Source database name not provided. Exiting.")
return 1
if not targetdb:
logging.error("Target database URL not provided. Exiting.")
return 1
target_info = schemaobject.connection.parse_database_url(targetdb)
if not target_info:
logging.error("Invalid target database URL format. Exiting.")
return 1
if not target_info['protocol'] == 'mysql':
logging.error("Target database must be MySQL. Exiting.")
return 1
if 'db' not in target_info:
logging.error("Target database name not provided. Exiting.")
return 1
source_obj = schemaobject.SchemaObject(sourcedb)
target_obj = schemaobject.SchemaObject(targetdb)
if source_obj.version < '5.0.0':
logging.error("%s requires MySQL version 5.0+ (source is v%s)"
% (APPLICATION_NAME, source_obj.version))
return 1
if target_obj.version < '5.0.0':
logging.error("%s requires MySQL version 5.0+ (target is v%s)"
% (APPLICATION_NAME, target_obj.version))
return 1
# data transformation filters
filters = (lambda d: utils.REGEX_MULTI_SPACE.sub(' ', d),
lambda d: utils.REGEX_DISTANT_SEMICOLIN.sub(';', d))
# Information about this run, used in the patch/revert templates
ctx = dict(app_version=APPLICATION_VERSION,
server_version=target_obj.version,
target_host=target_obj.host,
target_database=target_obj.selected.name,
created=datetime.datetime.now().strftime(TPL_DATE_FORMAT))
p_fname, r_fname = utils.create_pnames(target_obj.selected.name,
tag=tag,
date_format=DATE_FORMAT)
ctx['type'] = "Patch Script"
pBuffer = utils.PatchBuffer(name=os.path.join(output_directory, p_fname),
filters=filters, tpl=PATCH_TPL, ctx=ctx.copy(),
version_filename=version_filename)
ctx['type'] = "Revert Script"
rBuffer = utils.PatchBuffer(name=os.path.join(output_directory, r_fname),
filters=filters, tpl=PATCH_TPL, ctx=ctx.copy(),
version_filename=version_filename)
db_selected = False
for patch, revert in syncdb.sync_schema(source_obj.selected,
target_obj.selected, options):
if patch and revert:
if not db_selected:
pBuffer.write(target_obj.selected.select() + '\n')
rBuffer.write(target_obj.selected.select() + '\n')
db_selected = True
pBuffer.write(patch + '\n')
rBuffer.write(revert + '\n')
if not pBuffer.modified:
logging.info(("No migration scripts written."
" mysql://%s/%s and mysql://%s/%s were in sync.") %
(source_obj.host, source_obj.selected.name,
target_obj.host, target_obj.selected.name))
else:
try:
pBuffer.save()
rBuffer.save()
logging.info("Migration scripts created for mysql://%s/%s\n"
"Patch Script: %s\nRevert Script: %s"
% (target_obj.host, target_obj.selected.name,
pBuffer.name, rBuffer.name))
except OSError, e:
pBuffer.delete()
rBuffer.delete()
logging.error("Failed writing migration scripts. %s" % e)
return 1
return 0
def main():
try:
sys.exit(parse_cmd_line(app)())
except schemaobject.connection.DatabaseError, e:
logging.error("MySQL Error %d: %s" % (e.args[0], e.args[1]))
sys.exit(1)
except KeyboardInterrupt:
print "Sync Interrupted, Exiting."
sys.exit(1)
if __name__ == "__main__":
main()
This diff is collapsed.
"""Utility functions for Schema Sync"""
import re
import os
import datetime
import glob
import cStringIO
#REGEX_NO_TICKS = re.compile('`')
#REGEX_INT_SIZE = re.compile('int\(\d+\)')
REGEX_MULTI_SPACE = re.compile(r'\s\s+')
REGEX_DISTANT_SEMICOLIN = re.compile(r'(\s+;)$')
REGEX_FILE_COUNTER = re.compile(r"\_(?P<i>[0-9]+)\.(?:[^\.]+)$")
REGEX_TABLE_COMMENT = re.compile(r"COMMENT(?:(?:\s*=\s*)|\s*)'(.*?)'", re.I)
REGEX_TABLE_AUTO_INC = re.compile(r"AUTO_INCREMENT(?:(?:\s*=\s*)|\s*)(\d+)", re.I)
def versioned(filename):
"""Return the versioned name for a file.
If filename exists, the next available sequence # will be added to it.
file.txt => file_1.txt => file_2.txt => ...
If filename does not exist the original filename is returned.
Args:
filename: the filename to version (including path to file)
Returns:
String, New filename.
"""
name, ext = os.path.splitext(filename)
files = glob.glob(name + '*' + ext)
if not files:
return filename
files= map(lambda x: REGEX_FILE_COUNTER.search(x, re.I), files)
file_counters = [i.group('i') for i in files if i]
if file_counters:
i = int(max(file_counters)) + 1
else:
i = 1
return name + ('_%d' % i) + ext
def create_pnames(db, tag=None, date_format="%Y%m%d"):
"""Returns a tuple of the filenames to use to create the migration scripts.
Filename format: <db>[_<tag>].<date=DATE_FORMAT>.(patch|revert).sql
Args:
db: srting, databse name
tag: string, optional, tag for the filenames
date_format: string, the current date format
Default Format: 21092009
Returns:
tuple of strings (patch_filename, revert_filename)
"""
d = datetime.datetime.now().strftime(date_format)
if tag:
tag = re.sub('[^A-Za-z0-9_-]', '', tag)
basename = "%s_%s.%s" % (db, tag, d)
else:
basename = "%s.%s" % (db, d)
return ("%s.%s" % (basename, "patch.sql"),
"%s.%s" % (basename, "revert.sql"))
class PatchBuffer(object):
"""Class for creating patch files
Attributes:
name: String, filename to use when saving the patch
filters: List of functions to map to the patch data
tpl: The patch template where the data will be written
All data written to the PatchBuffer is palced in the
template variable %(data)s.
ctx: Dictionary of values to be put replaced in the template.
version_filename: Bool, version the filename if it already exists?
modified: Bool (default=False), flag to check if the
PatchBuffer has been written to.
"""
def __init__(self, name, filters, tpl, ctx, version_filename=False):
"""Inits the PatchBuffer class"""
self._buffer = cStringIO.StringIO()
self.name = name
self.filters = filters
self.tpl = tpl
self.ctx = ctx
self.version_filename = version_filename
self.modified = False
def write(self, data):
"""Write data to the buffer."""
self.modified = True
self._buffer.write(data)
def save(self):
"""Apply filters, template transformations and write buffer to disk"""
data = self._buffer.getvalue()
if not data:
return False
if self.version_filename:
self.name = versioned(self.name)
fh = open(self.name, 'w')
for f in self.filters:
data = f(data)
self.ctx['data'] = data
fh.write(self.tpl % self.ctx)
fh.close()
return True
def delete(self):
"""Delete the patch once it has been writen to disk"""
if os.path.isfile(self.name):
os.unlink(self.name)
def __del__(self):
self._buffer.close()
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
#!/usr/bin/env python
import ez_setup
ez_setup.use_setuptools()
from setuptools import setup
setup(
name='SchemaSync',
version='0.9.2',
description='A MySQL Schema Synchronization Utility',
author='Mitch Matuson',
packages=['schemasync'],
install_requires=['SchemaObject >=0.5.3'],
entry_points={
'console_scripts': [
'schemasync = schemasync.schemasync:main',
]
},
keywords = ["MySQL", "database", "schema", "migration", "SQL"],
classifiers = [
"Environment :: Console",
"Intended Audience :: Information Technology",
"Intended Audience :: System Administrators",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Topic :: Database",
"Topic :: Database :: Front-Ends",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Code Generators",
"Topic :: Utilities",
],
long_description = """\
Schema Sync will generate the SQL necessary to migrate the schema of a source database to a target database (patch script), as well as a the SQL necessary to undo the changes after you apply them (revert script).
"""
)
\ No newline at end of file
/***************************************************************************
* Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
* Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
*
* Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
*
* This file is part of domotikad.
*
* domotikad is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
CREATE DATABASE domotika;
CREATE USER 'domotika'@'localhost' IDENTIFIED BY 'dmdbpwdmsql';
GRANT USAGE ON * . * TO 'domotika'@'localhost' IDENTIFIED BY 'dmdbpwdmsql' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
GRANT ALL PRIVILEGES ON `domotika` . * TO 'domotika'@'localhost' WITH GRANT OPTION ;
FLUSH PRIVILEGES;
This diff is collapsed.
DELIMITER $$
CREATE TRIGGER relstatus_lastchange BEFORE UPDATE ON relstatus
FOR EACH ROW
BEGIN
IF NEW.status <> OLD.status OR NEW.ampere <> OLD.ampere THEN
SET NEW.lastchange = NEW.lastupdate;
END IF;
END$$
CREATE TRIGGER inpstatus_lastchange BEFORE UPDATE ON inpstatus
FOR EACH ROW
BEGIN
IF NEW.status <> OLD.status THEN
SET NEW.lastchange = NEW.lastupdate;
END IF;
END$$
CREATE TRIGGER anastatus_lastchange BEFORE UPDATE ON anastatus
FOR EACH ROW
BEGIN
IF NEW.status <> OLD.status THEN
SET NEW.lastchange = NEW.lastupdate;
END IF;
END$$
CREATE TRIGGER actstatus_lastchange BEFORE UPDATE ON actstatus
FOR EACH ROW
BEGIN
IF NEW.status <> OLD.status OR NEW.status2 <> OLD.status2 THEN
SET NEW.lastchange = NEW.lastupdate;
END IF;
END$$
DELIMITER ;
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
body { padding-top: 70px; }
.home-panel {
height: 200px;
overflow: auto;
}
@media (min-width: 1400px) {
.container {
max-width: 1370px;
}
}
@media (min-width: 1600px) {
.container {
max-width: 1570px;
}
}
@media (min-width: 1800px) {
.container {
max-width: 1770px;
}
}
@media (min-width: 2000px) {
.container {
max-width: 1970px;
}
}
<?
?>
<?
require_once("admin_functions.php");
?>
<? include("common_includes.php"); ?>
<!DOCTYPE html>
<html>
<head>
<title>Domotika Admin Dashboard</title>
<? include("parts/head.php");?>
</head>
<body>
<?
include("parts/alerts.php");
include("parts/navbar.php");
?>
<div class="container">
<h1>Dashboard</h1>
<div class="row">
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Q System</h3>
</div>
<div class="home-panel">
<h4>Q Daemon version: <span class="label pull-right">1.0</span></h4>
<h4>VPN Status: <button type="button" class="btn btn-success btn-small pull-right" style="padding:3px;">ACTIVE</button></h4>
<h4>IP Address: <span class="label pull-right">192.168.4.11</span></h4>
</div>
</div>
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Boards <a data-toggle="modal" href="#AutoDetect" class="btn btn-danger btn-small pull-right" style="padding:3px;">Autodetect</a></h3>
</div>
<div class="home-panel">
<table class="table table-condensed">
<thead>
<tr>
<th>Board Name</th>
<th>Type</th>
<th>Level</th>
<th>Firmware</th>
</tr>
</thead>
<tbody>
<?
foreach(DB::query("SELECT * FROM dmboards WHERE detected>0") as $board)
{
if($board['online']>0) $ttype="success";
else $ttype="danger";
?>
<tr class="<?=$ttype?>">
<td><?=$board['name']?></td>
<td><?=$board['type']?></td>
<td><?=$board['fwversion']?></td>
<td><?=$board['fwtype']?></td>
</tr>
<?
}
?>
</tbody>
</table>
</div>
</div>
<div class="modal fade" id="AutoDetect" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Board Autodetection</h4>
</div>
<div class="modal-body">
<b>WARNING: </b>you are starting Domotika Boards autodetection procedure. This will
delete any dynamic board in the Domotika database and then
they will be re-detected. Any change you have made on inputs
or outputs, any reference to ID of inputs and outputs will be
deleted or invalidated.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Discard</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" id="startdetection">Start Autodetection</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Timers</h3>
</div>
<div class="home-panel">
<table class="table table-condensed">
<thead>
<tr>
<th>timer name</th>
<th>status</th>
</tr>
</thead>
<tbody>
<?
foreach(DB::query("SELECT * FROM timers") as $timer)
{
?>
<tr>
<td><?=$timer['timer_name']?></td>
<? if($timer['active']>0) { ?>
<td><button class="btn btn-success btn-small pull-right">Active</button></td>
<? } else { ?>
<td><button class="btn btn-small pull-right">Disabled</button></td>
<? } ?>
</tr>
<?
}
?>
</tbody>
</table>
</div>
</div>
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Users</h3>
</div>
<div class="home-panel">
<table class="table table-condensed">
<thead>
<tr>
<th>user name</th>
</tr>
</thead>
<tbody>
<?
foreach(DB::query("SELECT * FROM users") as $user)
{
?>
<tr>
<td><?=$user['username']?></td>
</tr>
<?
}
?>
</tbody>
</table>
</div>
</div>
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Last news</h3>
</div>
<div class="home-panel">
<h3>Benvenuti in Domotika!</h3>
<p>Grazie per aver scelto il piu' avanzato sistema domotico esistente!
</p>
</div>
</div>
<div class="panel col-lg-4">
<div class="panel-heading">
<h3 class="panel-title">Media/Video</h3>
</div>
<div class="home-panel">
<table class="table table-condensed">
<thead>
<tr>
<th>name</th>
<th>websection</th>
<th>dynamic</th>
<th>channels</th>
</tr>
</thead>
<tbody>
<?
foreach(DB::query("SELECT * FROM video") as $video)
{
?>
<tr>
<td><?=$video['button_name']?></td>
<td><?=$video['websection']?></td>
<td><?if($video['dynamic']==1){echo 'yes';}else{echo 'no';}?></td>
<td>
<?
if($video['has_channels']=='yes')
{
?>
<a data-toggle="modal" href="#" class="btn btn-danger btn-small" style="padding:3px;">Scan</a>
<?
} else {
echo "-";
}
?>
</td>
</tr>
<?
}
?>
</tbody>
</table>
</p>
</div>
</div>
</div>
</div> <!-- container -->
<?include("parts/foot.php");?>
<script type="text/javascript">
$("#startdetection").click(
function() {
$.get("/rest/v1.2/boards/autodetect/json");
}
);
</script>
</body>
</html>
<div class="modal fade" id="modal_fixed" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static" data-keyboard=false></div>
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-hidden="true"></div>
<div class="modal fade" id="modal_offline" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static" data-keyboard=false>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div style="width:100%;text-align:center">
<h3><span class="label label-danger"><b>Server is disconnected</b></span></h3>
<img src="/resources/preloader/images/animated.gif"></img>
<h3><b>Please wait...</b></h3>
</div>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
<div id="alertContainer" class="alert-container" style="display:none">
<div id="alertPopup" class="alert" >
<strong id="alertTitle">Alert</strong><span id="alertMessage"></span>
</div>
</div>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/respond.min.js"></script>
<!-- bootstrap switch -->
<script src="/resources/bootstrap-switch/static/js/bootstrap-switch.min.yui.js"></script>
<script type="text/javascript">
var es = new EventSource("/sse");
var setDaemonStatus = function(event) {
var data=$.parseJSON(event.data);
if(data.data=='boardsdetection')
{
$("#modal_fixed").load('/resources/modals/autodetection_run.html');
$("#modal_fixed").modal('show');
} else if(data.data=='normal') {
$("#modal_fixed").modal('hide');
$("#modal_fixed").empty();
location.reload();
}
}
es.addEventListener("daemonstatus", setDaemonStatus);
es.onerror = function(event){
if(es.readystate=='CLOSED')
es = new EventSource("/sse");
}
$.get("/rest/v1.2/daemonstatus/json",
function(r){
if(r.data=='boardsdetection')
{
$("#modal_fixed").load('/resources/modals/autodetection_run.html');
$("#modal_fixed").modal('show');
}
}
);
setInterval(function(i){
$.get("/rest/v1.2/keepalive/json",
function(r){
if(r.data=='SLOGGEDOUT')
{
location.reload();
}
if($("#modal_offline").attr('aria-hidden')=='false')
$("#modal_offline").modal('hide');
}).fail(function(r){
$("#modal_offline").modal('show');
}
);
},5000);
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/resources/js/jquery-1.9.0.min.js" type="text/javascript" ></script>
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/resources/glyphicons/css/bootstrap-glyphicons.css" rel="stylesheet" media="screen">
<link href="/resources/full-glyphicons/css/glyphicons.css" rel="stylesheet" media="screen">
<link href="/resources/bootstrap-switch/static/stylesheets/bootstrap-switch.css" rel="stylesheet" media="screen">
<link href="/admin/css/style.css" rel="stylesheet" media="screen">
<?
function isActive($name)
{
if(is_array($name)) {
foreach($name as $n) {
if($_SERVER['PHP_SELF']==$n)
return 'class="active"';
}
} else {
if($_SERVER['PHP_SELF']==$name)
return 'class="active"';
}
return;
}
?>
<div class="navbar navbar-fixed-top">
<div class="container">
<!-- .navbar-toggle is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Be sure to leave the brand out there if you want it shown -->
<a class="navbar-brand" href="/admin/">Domotika Admin</a>
<!-- Place everything within .navbar-collapse to hide it until above 768px -->
<div class="nav-collapse collapse navbar-responsive-collapse">
<ul class="nav navbar-nav">
<li <?=isActive(array("/admin/", "/admin/index.php"));?>><a href="/admin/">Dashboard</a></li>
<li <?=isActive(array("/admin/qsystem.php","/admin/boards.php"));?> class="drowdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
Systems <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li <?=isActive("/admin/qsystem.php");?>><a href="/admin/qsystem.php">Q System</a></li>
<li <?=isActive("/admin/boards.php");?>><a href="/admin/boards.php">Boards</a></li>
</ul>
</li>
<li <?=isActive(array("/admin/timers.php","/admin/actions.php","/admin/sequences.php"));?>class="drowdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
Automations <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li <?=isActive("/admin/timers.php");?>><a href="/admin/timers.php">Timers</a></li>
<li <?=isActive("/admin/actions.php");?>><a href="/admin/actions.php">Actions</a></li>
<li <?=isActive("/admin/sequences.php");?>><a href="/admin/sequences.php">Sequences</a></li>
</ul>
</li>
<li <?=isActive(array());?>class="drowdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
Media <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li <?=isActive("/admin/telephony.php");?>><a href="/admin/telephony.php">Telephony</a></li>
<li <?=isActive("/admin/telephony.php");?>><a href="/admin/telephony.php">Citophony</a></li>
<li <?=isActive("/admin/audiovideo.php");?>><a href="/admin/audiovideo.php">Audio/Video</a></li>
</ul>
</li>
<li <?=isActive("/admin/stats.php");?>><a href="/admin/stats.php">Stats</a></li>
<li <?=isActive("/admin/users.php");?>><a href="/admin/users.php">Users</a></li>
</ul>
<ul class="nav navbar-nav pull-right">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<?=$_DOMOTIKA['username']?> <i class="glyphicon glyphicon-user"></i>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li><a href="#">Settings</a></li>
<li><a href="<?=$_DOMOTIKA['homepath']?>">user gui</a></li>
<li><a href="/__LOGOUT__/">Logout</a></li>
</ul>
</li>
</ul>
</div><!-- /.nav-collapse -->
</div><!-- /.container -->
</div><!-- /.navbar -->
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap 101 Template</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<?
include("parts/navbar.php");
?>
<h1>Not yet implemented!</h1>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.9.0.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
<script src="/resources/js/js/respond.js"></script>
</body>
</html>
function GMI(){
var pagedoc = document;
//Get top level window's document
if (top != this)
{
pagedoc = parent.document;
}
this.getNetWorkInfo = function()
{
pagedoc.title = "null";
pagedoc.title = "getNetWorkInfo";
}
this.getCurrentLanguage = function()
{
pagedoc.title = "null";
pagedoc.title = "getCurrentLanguage";
}
this.getCountry = function()
{
pagedoc.title = "null";
pagedoc.title = "getCountry";
}
this.getAccountInfo = function()
{
pagedoc.title = "null";
pagedoc.title = "getAccountInfo";
}
this.put = function( family, valuelist)
{
pagedoc.title = "null";
pagedoc.title = "put";
}
this.get = function( family, keylist)
{
pagedoc.title = "null";
pagedoc.title = "get";
}
this.gotoURL = function ( url)
{
pagedoc.title = "null";
pagedoc.title = "gotoURL";
}
}
GMIEngine = new GMI();
<html>
<head>
<title>GMI V2.0 Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script language="javascript" src="simpleGMI.js"></script>
<style>
#antani {
top: 100px;
left: 50px;
}
</style>
</head>
<body>
<div id="antani" onClick="alert('aaa'); alert(GMIEngine.getNetWorkInfo());simpleGMI.gotoURL('http://www.unixmedia.it');alert('ccc');">AIUTO!</div>
</body>
</html>
function SimpleGMI(){
var pagedoc = document;
//Get top level window's document
if (top != this)
{
pagedoc = parent.document;
}
this.refresh = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::refresh";
}
this.histroypage = function( times )
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::histroypage::" + times;
}
this.historypage = function( times )
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::histroypage::" + times;
}
this.gotoURL = function( url )
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::gotoURL::" + url;
}
this.udp = function( host, port, data, udp_cb )
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::udp::" + host + "::" + port + "::" + data + "::" + udp_cb.name;
}
this.post = function( url, data, post_cb )
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::post::" + url + "::" + data + "::" + post_cb.name;
}
this.hangup = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::hangup";
}
this.transfer = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::transfer";
}
this.transferTo = function( number)
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::transferTo::" + number;
}
this.debug = function( info )
{
pagedoc.title = "null";
pagedoc.title = "-gdebug-" + info;
}
this.play = function( url, mode )
{
var urls = url.split(";")
var total_url = "";
for (var count = 0; count < urls.length; count++)
{
if (urls[count].length < 4)
{
continue;
}
if (urls[count].indexOf("://") != -1)
{
final_url = urls[count];
}
else
{
var temp = this.reverse(location.toString());
temp = temp.substring(temp.indexOf("/"), temp.length);
final_url = this.reverse(temp) + urls[count];
}
total_url += final_url + ";";
}
pagedoc.title = "null";
pagedoc.title = "simpleGMI::play::" + total_url + "::" + mode;
}
this.stopPlay = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::stopPlay";
}
this.dial = function( account, isVideo, isDialPlan, number, headers )
{
pagedoc.title = "null";
if ( headers != undefined )
{
pagedoc.title = "simpleGMI::dial::" + account + "::" + isVideo
+ "::" + isDialPlan + "::" + number + "::" + headers;
}
else
{
pagedoc.title = "simpleGMI::dial::" + account + "::" + isVideo
+ "::" + isDialPlan + "::" + number;
}
}
this.launchService = function( service, account )
{
pagedoc.title = "null";
if ( account == undefined )
{
pagedoc.title = "simpleGMI::launchService::" + service;
}
else
{
pagedoc.title = "simpleGMI::launchService::" + service + "::" + account;
}
}
this.exit = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::exit";
}
this.fullScreen = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::fullScreen";
}
this.normalScreen = function()
{
pagedoc.title = "null";
pagedoc.title = "simpleGMI::normalScreen";
}
/*Internal use function*/
this.reverse = function(string)
{
var src = "";
var dst = "";
src = string;
while (src.length > 0)
{
dst += src.charAt(src.length - 1);
src = src.substring(0, src.length - 1);
}
return dst;
}
}
simpleGMI = new SimpleGMI();
FallbackResource /domotika/gui/index.php
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
<Files index.php>
Order Allow,Deny
Allow from all
</Files>
<?
@include("../includes/common.php");
//print_r($button);
$button_checked="";
$badgecolor="badge-".$dmcolors[$button['color2_off']];
$badgetext=$button['text2_off'];
if(intval($button['status2'])>0) {
$badgecolor="badge-".$dmcolors[$button['color2_on']];
$badgetext=$button['text2_on'];
}
?>
<div class="devlist-item">
<div class="devlist-row">
<div class="devlist-leftpart">
<h4 class="devlist-name"><?=$button['button_name']?></h4>
</div>
<div class="devlist-rightpart" data-snap-ignore="true">
<div class="badge devlist-topdata <?=$badgecolor?>" data-domotika-act2col="<?=$button['id']?>"
data-dmcolor-off="badge-<?=$dmcolors[$button['color2_off']]?>" data-dmcolor-on="badge-<?=$dmcolors[$button['color2_on']]?>">
<div style="width:100%;min-width:-moz-fit-content;"><span data-domotika-act2textid="<?=$button['id']?>"
data-dmtext-on=<?=$button['text2_on']?>"" data-dmtext-off="<?=$button['text2_off']?>"><?=$badgetext;?></span></div>
<?
if(is_array($button_switchar) && in_array($button['ctx'], $button_switchar)) {
if(intval($button['status'])>0) $button_checked="checked";
?>
<div class="make-switch switch-medium devlist-switch"
data-on="<?=$dmcolors[$button['color_on']]?>" data-off="<?=$dmcolors[$button['color_off']]?>"
data-domotika-actid="<?=$button['id']?>" data-on-label="<?=$button['text_on']?>" data-off-label="<?=$button['text_off']?>">
<input id="tts" type="checkbox" name="tts" <?=$button_checked?>/>
</div>
<?
} else {
$button_text=$button['text_off'];
$button_color="btn-".$dmcolors[$button['color_off']];
if(intval($button['status'])>0) {
$button_checked="btn-".$dmcolors[$button['color_on']];
$button_text=$button['text_on'];
}
?>
<button class="btn devlist-button <?=$button_checked?>" data-domotika-actid="<?=$button['id']?>"
data-dmcolor-on="btn-<?=$dmcolors[$button['color_on']]?>" data-dmcolor-off="btn-<?=$dmcolors[$button['color_off']]?>"
data-dmtext-on="<?=$button['text_on']?>" data-dmtext-off="<?=$button['text_off']?>"><?=$button_text?></button>
<?
}?>
</div>
</div> <!-- devlist-rightpart-->
</div> <!-- devlist-row -->
</div> <!-- devlist item -->
<?
@include("../includes/common.php");
//print_r($button);
//$button['status']=900;
//$button['divider']=10;
if(floatval($button['status'])==floatval($button['minval']))
{
$anacol="progress-bar-".$dmcolors[$button['color_min']];
$btncol="btn-".$dmcolors[$button['color_min']];
} elseif(floatval($button['status'])>floatval($button['minval']) && floatval($button['status'])<=floatval($button['lowval']))
{
$anacol="progress-bar-".$dmcolors[$button['color_low']];
$btncol="btn-".$dmcolors[$button['color_low']];
} elseif(floatval($button['status'])>floatval($button['lowval']) && floatval($button['status'])<=floatval($button['highval']))
{
$anacol="progress-bar-".$dmcolors[$button['color_medium']];
$btncol="btn-".$dmcolors[$button['color_medium']];
} elseif(floatval($button['status'])>floatval($button['highval']))
{
$anacol="progress-bar-".$dmcolors[$button['color_high']];
$btncol="btn-".$dmcolors[$button['color_high']];
}
$pbcoln="progress-bar-";
$perc=(floatval($button['status'])-floatval($button['minval']))*100/(floatval($button['maxval'])-floatval($button['minval']))
?>
<div class="devlist-item">
<div class="devlist-row">
<div class="devlist-leftpart">
<h4 class="devlist-name"><?=$button['button_name']?></h4>
<div class="progress">
<div class="progress-bar <?=$anacol?>" role="progressbar" aria-valuenow="<?=floatval($button['status'])/$button['divider']?>" aria-valuemin="<?=$button['minval']?>"
aria-valuemax="<?=$button['maxval']?>" style="width: <?=$perc?>%;"
data-dmcolor-min="<?=$pbcoln.$dmcolors[$button['color_min']]?>" data-dmcolor-low="<?=$pbcoln.$dmcolors[$button['color_low']]?>"
data-dmcolor-med="<?=$pbcoln.$dmcolors[$button['color_medium']]?>" data-dmcolor-high="<?=$pbcoln.$dmcolors[$button['color_high']]?>"
data-dmval-min="<?=floatval($button['minval'])?>" data-dmval-low="<?=floatval($button['lowval'])?>"
data-dmval-high="<?=floatval($button['highval'])?>" data-dmval-max="<?=floatval($button['maxval'])?>"
data-dmval-divider="<?=floatval($button['divider'])?>" data-domotika-anaprog="<?=$button['id']?>">
<span class="sr-only"><?=floatval($button['status'])/$button['divider']?></span>
</div>
</div>
</div>
<div class="devlist-rightpart" data-snap-ignore="true">
<button class="btn devlist-button <?=$btncol?>" data-domotika-anaid="<?=$button['id']?>"
data-dmcolor-min="btn-<?=$dmcolors[$button['color_min']]?>" data-dmcolor-low="btn-<?=$dmcolors[$button['color_low']]?>"
data-dmcolor-med="btn-<?=$dmcolors[$button['color_medium']]?>" data-dmcolor-high="btn-<?=$dmcolors[$button['color_high']]?>"
><span><?=$button['unit']?>:</span> <span><?=floatval($button['status'])/$button['divider']?></span></button>
</div> <!-- devlist-rightpart-->
</div> <!-- devlist-row -->
</div> <!-- devlist item -->
<?
@include("../includes/common.php");
//print_r($button);
$onTemplate="success";
$button_checked="";
$button_switchar=array(
IKAP_CTX_LIGHT,
IKAP_CTX_SOCKET,
IKAP_CTX_VALVE,
IKAP_CTX_GENERIC_SWITCH,
IKAP_CTX_PUMP,
IKAP_CTX_MOTOR
);
$button_text=$button['text_off'];
$button_checked="btn-".$dmcolors[$button['color_off']];
if(intval($button['status'])>0) {
$button_checked="btn-".$dmcolors[$button['color_on']];
$button_text=$button['text_on'];
}
?>
<div class="devlist-item">
<div class="devlist-row">
<div class="devlist-leftpart">
<h4 class="devlist-name"><?=$button['button_name']?></h4>
</div>
<div class="devlist-rightpart" data-snap-ignore="true">
<button class="btn devlist-button <?=$button_checked?>" data-domotika-inpid="<?=$button['id']?>"
data-dmcolor-on="btn-<?=$dmcolors[$button['color_on']]?>" data-dmcolor-off="btn-<?=$dmcolors[$button['color_off']]?>"
data-dmtext-on="<?=$button['text_on']?>" data-dmtext-off="<?=$button['text_off']?>"><?=$button_text?></button>
</div> <!-- devlist-rightpart-->
</div> <!-- devlist-row -->
</div> <!-- devlist item -->
<?
@include("../includes/common.php");
//print_r($button);
$button_checked="";
$button_switchar=array(
IKAP_CTX_LIGHT,
IKAP_CTX_SOCKET,
IKAP_CTX_VALVE,
IKAP_CTX_GENERIC_SWITCH,
IKAP_CTX_PUMP,
IKAP_CTX_MOTOR
);
?>
<?=$aaa;//print_r($button['inputs']);?>
<div class="devlist-item">
<div class="devlist-row">
<div class="devlist-leftpart">
<h4 class="devlist-name"><?=$button['button_name']?></h4>
<div class="devlist-ledscontainer">
<?
foreach($button['inputs'] as $inp) {
$button_text="status";
$tmpname=ltrim(str_replace($button['button_name'], "", $inp['button_name']));
if(strlen($inp['text_led'])>0)
$button_text=$inp['text_led'];
elseif(strlen($tmpname)>0)
$button_text=$tmpname;
$ledcolor="label-".$dmcolors[$inp['color_off']];
if(intval($inp['status'])>0) $ledcolor="label-".$dmcolors[$inp['color_on']];
?>
<div class="label <?=$ledcolor?> devlist-leds" data-domotika-inpled="<?=$inp['id']?>"
data-dmcolor-on="label-<?=$dmcolors[$inp['color_on']]?>" data-dmcolor-off="label-<?=$dmcolors[$inp['color_off']]?>"><?=$button_text?></div>
<? }
$pbcoln="label-";
foreach($button['analogs'] as $ana) {
$button_text="";
$tmpname=ltrim(str_replace($button['button_name'], "", $ana['button_name']));
if(strlen($tmpname)>0)
$button_text=$tmpname;
$button_text." ".$ana['unit'].": ";
if(floatval($ana['status'])==floatval($ana['minval']))
{
$anacol="label-".$dmcolors[$ana['color_min']];
} elseif(floatval($ana['status'])>floatval($ana['minval']) && floatval($ana['status'])<=floatval($ana['lowval']))
{
$anacol="label-".$dmcolors[$ana['color_low']];
} elseif(floatval($ana['status'])>floatval($ana['lowval']) && floatval($ana['status'])<=floatval($ana['highval']))
{
$anacol="label-".$dmcolors[$ana['color_medium']];
} elseif(floatval($ana['status'])>floatval($ana['highval']))
{
$anacol="label-".$dmcolors[$ana['color_high']];
}
?>
<div class="label <?=$anacol?> devlist-leds" data-domotika-analed="<?=$ana['id']?>"
data-dmcolor-min="<?=$pbcoln.$dmcolors[$ana['color_min']]?>" data-dmcolor-low="<?=$pbcoln.$dmcolors[$ana['color_low']]?>"
data-dmcolor-med="<?=$pbcoln.$dmcolors[$ana['color_medium']]?>" data-dmcolor-high="<?=$pbcoln.$dmcolors[$ana['color_high']]?>"
data-dmval-min="<?=floatval($ana['minval'])?>" data-dmval-low="<?=floatval($ana['lowval'])?>"
data-dmval-high="<?=floatval($ana['highval'])?>" data-dmval-max="<?=floatval($ana['maxval'])?>"
data-dmval-divider="<?=floatval($ana['divider'])?>">
<span><?=$button_text?></span>
<span data-domotika-anaval="<?=$ana['id']?>"><?=floatval($ana['status'])/$ana['divider']?></span>
</div>
<? }?>
</div>
</div>
<div class="devlist-rightpart" data-snap-ignore="true">
<?
foreach($button['relays'] as $rel) {
$ampere=$rel['ampere']/10;
$badgecolor="";
if($ampere>0 && $ampere<8) {
$badgecolor="badge-success";
}elseif($ampere>=8 && $ampere<11) {
$badgecolor="badge-info";
}elseif($ampere>=11 && $ampere<14) {
$badgecolor="badge-warning";
}elseif($ampere>=14) {
$badgecolor="badge-danger";
}
?>
<div class="badge devlist-topdata <?=$badgecolor?>" data-domotika-ampcol="<?=$rel['id']?>" style="width:100%;">
<div style="width:100%;min-width:-moz-fit-content;">
<? if($rel['has_amp']>0) { ?>
<span data-domotika-ampid="<?=$rel['id']?>"><?=($rel['ampere']/10);?></span> A
<?} else { ?>
<span>No Amp </span>
<?}?>
</div>
<?
if(in_array($rel['ctx'], $button_switchar)) {
if(intval($rel['status'])>0) $button_checked="checked";
?>
<div class="make-switch switch-medium devlist-switch" data-on="<?=$dmcolors[$rel['color_on']]?>"
data-off="<?=$dmcolors[$rel['color_off']]?>" data-domotika-relid="<?=$rel['id']?>"
data-on-label="<?=$rel['text_on']?>" data-off-label="<?=$rel['text_off']?>">
<input id="tts" type="checkbox" name="tts" <?=$button_checked?>/>
</div>
<?
} else {
$button_text=$rel['text_off'];
$button_color='btn-'.$dmcolors[$rel['color_off']];
if(intval($rel['status'])>0) {
$button_checked='btn-'.$dmcolors[$rel['color_on']];
$button_text=$rel['text_on'];
}
?>
<button class="btn devlist-button <?=$button_checked?>" data-domotika-relid="<?=$rel['id']?>"
data-dmcolor-on="btn-<?=$dmcolors[$rel['color_on']]?>" data-dmcolor-off="btn-<?=$dmcolors[$rel['color_off']]?>"
data-dmtext-on="<?=$rel['text_on']?>" data-dmtext-off="<?=$rel['text_off']?>"
style="width:100%;width:-moz-available;"><?=$button_text?></button>
<?
}
?>
</div>
<?}?>
</div> <!-- devlist-rightpart-->
</div> <!-- devlist-row -->
</div> <!-- devlist item -->
<?
@include("../includes/common.php");
//print_r($button);
$button_checked="";
$button_switchar=array(
IKAP_CTX_LIGHT,
IKAP_CTX_SOCKET,
IKAP_CTX_VALVE,
IKAP_CTX_GENERIC_SWITCH,
IKAP_CTX_PUMP,
IKAP_CTX_MOTOR
);
$ampere=$button['ampere']/10;
$badgecolor="";
if($ampere>0 && $ampere<8) {
$badgecolor="badge-success";
}elseif($ampere>=8 && $ampere<11) {
$badgecolor="badge-info";
}elseif($ampere>=11 && $ampere<14) {
$badgecolor="badge-warning";
}elseif($ampere>=14) {
$badgecolor="badge-danger";
}
?>
<div class="devlist-item">
<div class="devlist-row">
<div class="devlist-leftpart">
<h4 class="devlist-name"><?=$button['button_name']?></h4>
</div>
<div class="devlist-rightpart" data-snap-ignore="true">
<div class="badge devlist-topdata <?=$badgecolor?>" data-domotika-ampcol="<?=$button['id']?>">
<div style="width:100%;min-width:-moz-fit-content;">
<? if($button['has_amp']>0) { ?>
<span data-domotika-ampid="<?=$button['id']?>"><?=($button['ampere']/10);?></span> A
<?} else { ?>
<span>No Amp </span>
<?}?>
</div>
<?
if(in_array($button['ctx'], $button_switchar)) {
if(intval($button['status'])>0) $button_checked="checked";
?>
<div class="make-switch switch-medium devlist-switch"
data-on="<?=$dmcolors[$button['color_on']]?>" data-off="<?=$dmcolors[$button['color_off']]?>"
data-domotika-relid="<?=$button['id']?>" data-on-label="<?=$button['text_on']?>" data-off-label="<?=$button['text_off']?>">
<input id="tts" type="checkbox" name="tts" <?=$button_checked?>/>
</div>
<?
} else {
$button_text=$button['text_off'];
$button_color=$dmcolors[$button['color_off']];
if(intval($button['status'])>0) {
$button_checked=$dmcolors[$button['color_on']];
$button_text=$button['text_on'];
}
?>
<button class="btn devlist-button <?=$button_checked?>" data-domotika-relid="<?=$button['id']?>"
data-dmcolor-on="btn-<?=$dmcolors[$button['color_on']]?>" data-dmcolor-off="btn-<?=$dmcolors[$button['color_off']]?>"
data-dmtext-on="<?=$button['text_on']?>" data-dmtext-off="<?=$button['text_off']?>"><?=$button_text?></button>
<?
}?>
</div>
</div> <!-- devlist-rightpart-->
</div> <!-- devlist-row -->
</div> <!-- devlist item -->
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
File added
File added
This diff is collapsed.
File added
File added
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<? @include_once("../includes/common.php"); ?>
<div class="left-drawer">
<div id="websectionlist" class="panel drawer-container scrollable">
<a href="<?=$BASEGUIPATH?>" class="btn btn-block btn-default">home</a>
<?
$links=array();
foreach(getWebSections(array('home'), array(), 'devsection') as $ws)
{
$links[$tr->Get($ws)]=$ws;
}
ksort($links, SORT_NATURAL | SORT_FLAG_CASE);
foreach($links as $k => $v)
{
?>
<a href="<?=$BASEGUIPATH."/actuations/".$v?>" class="btn btn-block btn-default"><?=$k?></a>
<?
}
?>
</div>
</div>
This diff is collapsed.
actuations.php
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<? @include_once("parts/flowplayer_foot.php"); ?>
This diff is collapsed.
<? @include_once("parts/flowplayer_foot.php"); ?>
<? include_once("parts/flowplayer_head.php"); ?>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment