Compare commits

...

64 Commits

Author SHA1 Message Date
8e79998e95 Tune sqlite to use write-ahead-logging
Enable the following pragmas: synchronous=NORMAL, journal_mode=WAL.
This offers a significant speedup to INSERT times compared to
synchronous=FULL, and is roughly the same as synchronous=OFF
but should be a bit safer.
2013-03-11 15:13:43 -04:00
9f914598c2 Make /stream/list give some more extended info, like row count
Also changes the HTTP parameter from "extent" to "extended",
and the commandline parameter from "extent" to "ext".
2013-03-11 15:13:43 -04:00
0468b04538 Fix pyrocket to handle comments better 2013-03-11 15:13:43 -04:00
232a3876c2 Clean up imports to separate client and server more.
"import nilmdb" doesn't do much; "import nilmdb.client" or "import
nilmdb.server" is now required.
2013-03-11 15:13:42 -04:00
1c27dd72d6 Fill out client tests and fix various bugs
Fixes various corner cases and other bugs regarding lines with
comments, having data but no endpoints, etc.
2013-03-08 12:36:17 -05:00
de5e474001 Update benchmarks in design.md 2013-03-07 20:33:30 -05:00
0fc092779d Big rework of stream_insert_context and places that use it.
Things are now block-focused, rather than line-focused.  This should
give a pretty big speedup to inserting client data, especially when
inserting preformatted data.
2013-03-07 20:30:11 -05:00
7abfdfbf3e Add const qualifier to strings we get from Python 2013-03-07 16:27:07 -05:00
92724d10ba Rework 'nilmtool insert' and some client stuff to speed up inserting data
Still needs work.
2013-03-06 20:49:14 -05:00
1d7acbf916 Remove null timestamper, speed up insert --none a tiny bit 2013-03-06 20:46:51 -05:00
ea3ea487bc Merge branch 'rocket-insert'
Conflicts:
	nilmdb/server/bulkdata.py
	nilmdb/server/server.py
	nilmdb/utils/__init__.py
2013-03-06 20:46:04 -05:00
69ad8c4842 Merge branch 'rocket' 2013-03-06 20:38:02 -05:00
0047e0360a Implement Rocket.append_string() in C; misc cleanups along the way
This should more or less complete the rocket interface.
2013-03-06 15:50:00 -05:00
1ac6abdad0 Fix rocket.ParseError exception handling
Before, a tuple was crammed into args[0].  Now, the three arguments are
args[0:2].
2013-03-05 22:05:17 -05:00
65f09f793c When re-raising exceptions in the server, preserve original tracebacks 2013-03-05 21:48:40 -05:00
84e21ff467 Move ASCII data parsing from the server to the rocket interface.
The server buffers the string and passes it to nilmdb.  Nilmdb passes
the string to bulkdata.  Bulkdata uses the rocket interface to parse
it in chunks, as necessary.  Everything gets passed back up and
everyone is happy.

Currently, only pyrocket implements append_string.
2013-03-05 17:51:17 -05:00
11b228f77a Convert times to microsecond precision strings more consistently.
Use a new helper, nilmdb.utils.time.float_to_time_string().
This will help if we ever want to change representation (like using
uint64 microseconds since epoch, which saves us from having to
waste bits on the floating-point exponent)
2013-03-05 17:07:39 -05:00
7860a6aefb Make helper for removing or truncating a file; use it 2013-03-05 15:27:12 -05:00
454e561d69 Verify that metadata values are numbers or strings 2013-03-05 13:22:17 -05:00
fe91ff59a3 Better handling of JSON requests 2013-03-05 12:38:08 -05:00
64c24a00d6 Add --traceback argument to nilmdb-server script 2013-03-05 12:20:07 -05:00
58c0ae72f6 Support application/json POST bodies as well as x-www-form-urlencoded 2013-03-05 11:54:29 -05:00
c5f079f61f When removing data from files, try to punch a hole.
Requires fallocate(2) support with FALLOC_FL_PUNCH_HOLE, as
well as a filesystem that supports it (in Linux 3.7,
tmpfs, btrfs, xfs, or ext4)
2013-03-04 20:31:14 -05:00
16f23f4a91 Fill out pyrocket.py to fit new interfaces; fix small bugs 2013-03-04 17:01:53 -05:00
b0f12d55dd Fully replace bulkdata.File with rocket.Rocket 2013-03-04 16:43:26 -05:00
8a648c1b97 Move towards replacing bulkdata.File with rocket.Rocket
There isn't much left in File, so let's move as much as possible
over to C.
2013-03-04 16:28:40 -05:00
2d45466f66 Print version at server startup 2013-03-04 15:43:45 -05:00
c6a0e6e96f More complete CORS handling, including preflight requests (hopefully) 2013-03-04 15:40:35 -05:00
79755dc624 Fix Allow: header by switching to cherrypy's built in tools.allow().
Replaces custom tools.allow_methods which didn't return the Allow: header.
2013-03-04 14:08:37 -05:00
f260f2c83d Remove unnecessary layout argument to nilmdb.stream_extract 2013-03-04 11:09:54 -05:00
14402005bf Remove extraneous flush 2013-03-03 21:52:45 -05:00
0d372fb878 Modify old formatter to match rocket's formatting style 2013-03-03 21:50:29 -05:00
5eac924118 Ignore built modules 2013-03-03 21:44:08 -05:00
0b75da7a8f Normalize the floating point formats to %.6e and %.16e
This is mostly a matter of taste, but it matches more closely with the
old way that prep did it, and it's more consistent.  It should roughly
match the available precision of floats and doubles.
2013-03-03 21:43:04 -05:00
2dfc94b566 Remove old code 2013-03-03 21:40:48 -05:00
e318888a06 Finish Rocket.extract_string; clean up code for other functions too
This is maybe 2.5-3 times faster than the list-based code, which
still isn't amazing, but is decent.
2013-03-03 21:25:00 -05:00
7c95934cc2 Add rocket.extract_list; still not as complete as pyrocket 2013-03-03 19:04:26 -05:00
96df9d8323 Starting the C version of rocket
Currently, only append_list is written (and hardly tested)
2013-03-03 16:54:11 -05:00
31e2c7c8b4 Add some notes about rocket interface to design.md 2013-03-03 14:43:16 -05:00
2a725ee13f Add version 1 database format backwards compatibility 2013-03-03 14:37:58 -05:00
eb8037ee3c Add a description for the rocket interface 2013-03-03 14:13:26 -05:00
fadb84d703 Move ascii formatting into nilmdb thread via rocket interface 2013-03-03 14:12:01 -05:00
9d0d2415be Test bulkdata a little more carefully 2013-03-03 14:00:00 -05:00
130dae0734 Add extract_string to pyrocket 2013-03-03 13:59:47 -05:00
402234dfc3 Better layout handling in pyrocket 2013-03-03 13:37:02 -05:00
4406d51a98 First pass at Python implementation of rocket 2013-03-03 13:37:02 -05:00
9b6de6ecb7 Replace old layout strings everywhere 2013-03-03 13:37:02 -05:00
c512631184 bulkdata: Build up rows and write to disk all at once 2013-03-03 12:03:44 -05:00
19d27c31bc Fix streaming requests like stream_extract 2013-03-03 11:37:47 -05:00
28310fe886 Add test for extents 2013-03-02 15:19:25 -05:00
1ccc2bce7e Add commandline support for listing extents 2013-03-02 15:19:19 -05:00
00237e30b2 Add "extent" option to stream_list in client, server, and nilmdb 2013-03-02 15:18:54 -05:00
521ff88f7c Support 'nilmtool help command' just like 'nilmtool command --help' 2013-03-02 13:56:03 -05:00
64897a1dd1 Change port from 12380 -> 32180 when running tests
This is so tests can be run without interfering with a normal server.
2013-03-02 13:19:44 -05:00
41ce8480bb cmdline: Support NILMDB_URL environment variable for default URL 2013-03-02 13:18:33 -05:00
204a6ecb15 Optimize bulkdata.append() by postponing flushes & mmap resize
Rather than flushing and resizing after each row is written to the
file, have the file object iterate by itself and do all of the
writes.  Only flush and resize the mmap after finishing.  This should
be pretty safe to do, especially since nothing is concurrent at the
moment.
2013-03-01 16:30:49 -05:00
5db3b186a4 Make test_mustclose more complete 2013-03-01 16:30:22 -05:00
fe640cf421 Remove must_close verification wrappers on bulkdata
At this point we know that the close() behavior is correct, so it's
not worth slowing everything down for these checks.
2013-03-01 16:11:44 -05:00
ca67c79fe4 Improve test_layout_speed 2013-03-01 16:04:10 -05:00
8917bcd4bf Fix test case failures due to increased client chunk size 2013-03-01 16:04:00 -05:00
a75ec98673 Slight speed improvements in layout.pyx 2013-03-01 16:03:38 -05:00
e476338d61 Remove outdated numpy dependency 2013-03-01 16:03:19 -05:00
d752b882f2 Bump up block sizes in client
This will help amortize the sqlite synchronization costs.
2013-02-28 21:11:57 -05:00
ade27773e6 Add --nosync option to nilmdb-server script 2013-02-28 20:45:08 -05:00
47 changed files with 2855 additions and 1418 deletions

4
.gitignore vendored
View File

@@ -8,11 +8,9 @@ docs/*.html
build/ build/
*.pyc *.pyc
nilmdb/server/interval.c nilmdb/server/interval.c
nilmdb/server/interval.so
nilmdb/server/layout.c nilmdb/server/layout.c
nilmdb/server/layout.so
nilmdb/server/rbtree.c nilmdb/server/rbtree.c
nilmdb/server/rbtree.so *.so
# Setup junk # Setup junk
dist/ dist/

View File

@@ -14,6 +14,9 @@ sdist:
install: install:
python setup.py install python setup.py install
develop:
python setup.py develop
docs: docs:
make -C docs make -C docs
@@ -23,6 +26,7 @@ lint:
test: test:
ifeq ($(INSIDE_EMACS), t) ifeq ($(INSIDE_EMACS), t)
# Use the slightly more flexible script # Use the slightly more flexible script
python setup.py build_ext --inplace
python tests/runtests.py python tests/runtests.py
else else
# Let setup.py check dependencies, build stuff, and run the test # Let setup.py check dependencies, build stuff, and run the test

View File

@@ -266,3 +266,65 @@ Each table contains:
from the end of the file will not shorten it; it will only be from the end of the file will not shorten it; it will only be
deleted when it has been fully filled and all of the data has been deleted when it has been fully filled and all of the data has been
subsequently removed. subsequently removed.
Rocket
------
Original design had the nilmdb.nilmdb thread (through bulkdata)
convert from on-disk layout to a Python list, and then the
nilmdb.server thread (from cherrypy) converts to ASCII. For at least
the extraction side of things, it's easy to pass the bulkdata a layout
name instead, and have it convert directly from on-disk to ASCII
format, because this conversion can then be shoved into a C module.
This module, which provides a means for converting directly from
on-disk format to ASCII or Python lists, is the "rocket" interface.
Python is still used to manage the files and figure out where the
data should go; rocket just puts binary data directly in or out of
those files at specified locations.
Before rocket, testing speed with uint16_6 data, with an end-to-end
test (extracting data with nilmtool):
- insert: 65 klines/sec
- extract: 120 klines/sec
After switching to the rocket design, but using the Python version
(pyrocket):
- insert: 57 klines/sec
- extract: 120 klines/sec
After switching to a C extension module (rocket.c)
- insert: 74 klines/sec through insert.py; 99.6 klines/sec through nilmtool
- extract: 335 klines/sec
After client block updates (described below):
- insert: 180 klines/sec through nilmtool (pre-timestamped)
- extract: 390 klines/sec through nilmtool
Using "insert --timestamp" or "extract --bare" cuts the speed in half.
Blocks versus lines
-------------------
Generally want to avoid parsing the bulk of the data as lines if
possible, and transfer things in bigger blocks at once.
Current places where we use lines:
- All data returned by `client.stream_extract`, since it comes from
`httpclient.get_gen`, which iterates over lines. Not sure if this
should be changed, because a `nilmtool extract` is just about the
same speed as `curl -q .../stream/extract`!
- `client.StreamInserter.insert_iter` and
`client.StreamInserter.insert_line`, which should probably get
replaced with block versions. There's no real need to keep
updating the timestamp every time we get a new line of data.
- Finished. Just a single insert() that takes any length string and
does very little processing until it's time to send it to the
server.

View File

@@ -1,7 +1,9 @@
"""Main NilmDB import""" """Main NilmDB import"""
from nilmdb.server import NilmDB, Server # These aren't imported automatically, because loading the server
from nilmdb.client import Client # stuff isn't always necessary.
#from nilmdb.server import NilmDB, Server
#from nilmdb.client import Client
from nilmdb._version import get_versions from nilmdb._version import get_versions
__version__ = get_versions()['version'] __version__ = get_versions()['version']

View File

@@ -2,17 +2,15 @@
"""Class for performing HTTP client requests via libcurl""" """Class for performing HTTP client requests via libcurl"""
import nilmdb
import nilmdb.utils import nilmdb.utils
import nilmdb.client.httpclient import nilmdb.client.httpclient
from nilmdb.client.errors import ClientError
import time import time
import simplejson as json import simplejson as json
import contextlib import contextlib
def float_to_string(f): from nilmdb.utils.time import float_time_to_string
"""Use repr to maintain full precision in the string output."""
return repr(float(f))
def extract_timestamp(line): def extract_timestamp(line):
"""Extract just the timestamp from a line of data text""" """Extract just the timestamp from a line of data text"""
@@ -21,8 +19,12 @@ def extract_timestamp(line):
class Client(object): class Client(object):
"""Main client interface to the Nilm database.""" """Main client interface to the Nilm database."""
def __init__(self, url): def __init__(self, url, post_json = False):
self.http = nilmdb.client.httpclient.HTTPClient(url) """Initialize client with given URL. If post_json is true,
POST requests are sent with Content-Type 'application/json'
instead of the default 'x-www-form-urlencoded'."""
self.http = nilmdb.client.httpclient.HTTPClient(url, post_json)
self.post_json = post_json
# __enter__/__exit__ allow this class to be a context manager # __enter__/__exit__ allow this class to be a context manager
def __enter__(self): def __enter__(self):
@@ -31,8 +33,11 @@ class Client(object):
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
self.close() self.close()
def _json_param(self, data): def _json_post_param(self, data):
"""Return compact json-encoded version of parameter""" """Return compact json-encoded version of parameter"""
if self.post_json:
# If we're posting as JSON, we don't need to encode it further here
return data
return json.dumps(data, separators=(',',':')) return json.dumps(data, separators=(',',':'))
def close(self): def close(self):
@@ -52,12 +57,14 @@ class Client(object):
as a dictionary.""" as a dictionary."""
return self.http.get("dbinfo") return self.http.get("dbinfo")
def stream_list(self, path = None, layout = None): def stream_list(self, path = None, layout = None, extended = False):
params = {} params = {}
if path is not None: if path is not None:
params["path"] = path params["path"] = path
if layout is not None: if layout is not None:
params["layout"] = layout params["layout"] = layout
if extended:
params["extended"] = 1
return self.http.get("stream/list", params) return self.http.get("stream/list", params)
def stream_get_metadata(self, path, keys = None): def stream_get_metadata(self, path, keys = None):
@@ -71,7 +78,7 @@ class Client(object):
metadata.""" metadata."""
params = { params = {
"path": path, "path": path,
"data": self._json_param(data) "data": self._json_post_param(data)
} }
return self.http.post("stream/set_metadata", params) return self.http.post("stream/set_metadata", params)
@@ -79,7 +86,7 @@ class Client(object):
"""Update stream metadata from a dictionary""" """Update stream metadata from a dictionary"""
params = { params = {
"path": path, "path": path,
"data": self._json_param(data) "data": self._json_post_param(data)
} }
return self.http.post("stream/update_metadata", params) return self.http.post("stream/update_metadata", params)
@@ -100,9 +107,9 @@ class Client(object):
"path": path "path": path
} }
if start is not None: if start is not None:
params["start"] = float_to_string(start) params["start"] = float_time_to_string(start)
if end is not None: if end is not None:
params["end"] = float_to_string(end) params["end"] = float_time_to_string(end)
return self.http.post("stream/remove", params) return self.http.post("stream/remove", params)
@contextlib.contextmanager @contextlib.contextmanager
@@ -115,36 +122,31 @@ class Client(object):
Example: Example:
with client.stream_insert_context('/path', start, end) as ctx: with client.stream_insert_context('/path', start, end) as ctx:
ctx.insert_line('1234567890.0 1 2 3 4\\n') ctx.insert('1234567890.0 1 2 3 4\\n')
ctx.insert_line('1234567891.0 1 2 3 4\\n') ctx.insert('1234567891.0 1 2 3 4\\n')
For more details, see help for nilmdb.client.client.StreamInserter For more details, see help for nilmdb.client.client.StreamInserter
This may make multiple requests to the server, if the data is This may make multiple requests to the server, if the data is
large enough or enough time has passed between insertions. large enough or enough time has passed between insertions.
""" """
ctx = StreamInserter(self, path, start, end) ctx = StreamInserter(self.http, path, start, end)
yield ctx yield ctx
ctx.finalize() ctx.finalize()
def stream_insert(self, path, data, start = None, end = None): def stream_insert(self, path, data, start = None, end = None):
"""Insert rows of data into a stream. data should be an """Insert rows of data into a stream. data should be a string
iterable object that provides ASCII data that matches the or iterable that provides ASCII data that matches the database
database layout for path. See stream_insert_context for layout for path. See stream_insert_context for details on the
details on the 'start' and 'end' parameters.""" 'start' and 'end' parameters."""
with self.stream_insert_context(path, start, end) as ctx: with self.stream_insert_context(path, start, end) as ctx:
ctx.insert_iter(data) if isinstance(data, basestring):
ctx.insert(data)
else:
for chunk in data:
ctx.insert(chunk)
return ctx.last_response return ctx.last_response
def stream_insert_block(self, path, block, start, end):
"""Insert an entire block of data into a stream. Like
stream_insert, except 'block' contains multiple lines of ASCII
text and is sent in one single chunk."""
params = { "path": path,
"start": float_to_string(start),
"end": float_to_string(end) }
return self.http.put("stream/insert", block, params)
def stream_intervals(self, path, start = None, end = None): def stream_intervals(self, path, start = None, end = None):
""" """
Return a generator that yields each stream interval. Return a generator that yields each stream interval.
@@ -153,9 +155,9 @@ class Client(object):
"path": path "path": path
} }
if start is not None: if start is not None:
params["start"] = float_to_string(start) params["start"] = float_time_to_string(start)
if end is not None: if end is not None:
params["end"] = float_to_string(end) params["end"] = float_time_to_string(end)
return self.http.get_gen("stream/intervals", params) return self.http.get_gen("stream/intervals", params)
def stream_extract(self, path, start = None, end = None, count = False): def stream_extract(self, path, start = None, end = None, count = False):
@@ -171,9 +173,9 @@ class Client(object):
"path": path, "path": path,
} }
if start is not None: if start is not None:
params["start"] = float_to_string(start) params["start"] = float_time_to_string(start)
if end is not None: if end is not None:
params["end"] = float_to_string(end) params["end"] = float_time_to_string(end)
if count: if count:
params["count"] = 1 params["count"] = 1
return self.http.get_gen("stream/extract", params) return self.http.get_gen("stream/extract", params)
@@ -193,8 +195,10 @@ class StreamInserter(object):
The basic data flow is that we are filling a contiguous interval The basic data flow is that we are filling a contiguous interval
on the server, with no gaps, that extends from timestamp 'start' on the server, with no gaps, that extends from timestamp 'start'
to timestamp 'end'. Data timestamps satisfy 'start <= t < end'. to timestamp 'end'. Data timestamps satisfy 'start <= t < end'.
Data is provided by the user one line at a time with
.insert_line() or .insert_iter(). Data is provided to .insert() as ASCII formatted data separated by
newlines. The chunks of data passed to .insert() do not need to
match up with the newlines; less or more than one line can be passed.
1. The first inserted line begins a new interval that starts at 1. The first inserted line begins a new interval that starts at
'start'. If 'start' is not given, it is deduced from the first 'start'. If 'start' is not given, it is deduced from the first
@@ -207,7 +211,9 @@ class StreamInserter(object):
3. The current contiguous interval can be completed by manually 3. The current contiguous interval can be completed by manually
calling .finalize(), which the context manager will also do calling .finalize(), which the context manager will also do
automatically. This will send any remaining data to the server, automatically. This will send any remaining data to the server,
using the 'end' timestamp to end the interval. using the 'end' timestamp to end the interval. If no 'end'
was provided, it is deduced from the last timestamp seen,
plus a small delta.
After a .finalize(), inserting new data goes back to step 1. After a .finalize(), inserting new data goes back to step 1.
@@ -216,23 +222,20 @@ class StreamInserter(object):
to change the end time for the interval. to change the end time for the interval.
""" """
# See design.md for a discussion of how much data to send. # See design.md for a discussion of how much data to send. This
# These are soft limits -- actual data might be rounded up. # is a soft limit -- we might send up to twice as much or so
# We send when we have a certain amount of data queued, or _max_data = 2 * 1024 * 1024
# when a certain amount of time has passed since the last send.
_max_data = 1048576
_max_time = 30
# Delta to add to the final timestamp, if "end" wasn't given # Delta to add to the final timestamp, if "end" wasn't given
_end_epsilon = 1e-6 _end_epsilon = 1e-6
def __init__(self, client, path, start = None, end = None): def __init__(self, http, path, start = None, end = None):
"""'http' is the httpclient object. 'path' is the database """'http' is the httpclient object. 'path' is the database
path to insert to. 'start' and 'end' are used for the first path to insert to. 'start' and 'end' are used for the first
contiguous interval.""" contiguous interval."""
self.last_response = None self.last_response = None
self._client = client self._http = http
self._path = path self._path = path
# Start and end for the overall contiguous interval we're # Start and end for the overall contiguous interval we're
@@ -240,60 +243,33 @@ class StreamInserter(object):
self._interval_start = start self._interval_start = start
self._interval_end = end self._interval_end = end
# Data for the specific block we're building up to send # Current data we're building up to send. Each string
# goes into the array, and gets joined all at once.
self._block_data = [] self._block_data = []
self._block_len = 0 self._block_len = 0
self._block_start = None
# Time of last request def insert(self, data):
self._last_time = time.time() """Insert a chunk of ASCII formatted data in string form. The
overall data must consist of lines terminated by '\\n'."""
length = len(data)
maxdata = self._max_data
# We keep a buffer of the two most recently inserted lines. if length > maxdata:
# Only the older one actually gets processed; the newer one # This could make our buffer more than twice what we
# is used to "look-ahead" to the next timestamp if we need # wanted to send, so split it up. This is a bit
# to internally split an insertion into two requests. # inefficient, but the user really shouldn't be providing
self._line_old = None # this much data at once.
self._line_new = None for cut in range(0, length, maxdata):
self.insert(data[cut:(cut + maxdata)])
def insert_iter(self, iter):
"""Insert all lines of ASCII formatted data from the given
iterable. Lines must be terminated with '\\n'."""
for line in iter:
self.insert_line(line)
def insert_line(self, line, allow_intermediate = True):
"""Insert a single line of ASCII formatted data. Line
must be terminated with '\\n'."""
if line and (len(line) < 1 or line[-1] != '\n'):
raise ValueError("lines must end in with a newline character")
# Store this new line, but process the previous (old) one.
# This lets us "look ahead" to the next line.
self._line_old = self._line_new
self._line_new = line
if self._line_old is None:
return return
# If starting a new block, pull out the timestamp if needed. # Append this string to our list
if self._block_start is None: self._block_data.append(data)
if self._interval_start is not None: self._block_len += length
# User provided a start timestamp. Use it once, then
# clear it for the next block.
self._block_start = self._interval_start
self._interval_start = None
else:
# Extract timestamp from the first row
self._block_start = extract_timestamp(self._line_old)
# Save the line # Send the block once we have enough data
self._block_data.append(self._line_old) if self._block_len >= maxdata:
self._block_len += len(self._line_old) self._send_block(final = False)
if allow_intermediate:
# Send an intermediate block to the server if needed.
elapsed = time.time() - self._last_time
if (self._block_len > self._max_data) or (elapsed > self._max_time):
self._send_block_intermediate()
def update_start(self, start): def update_start(self, start):
"""Update the start time for the next contiguous interval. """Update the start time for the next contiguous interval.
@@ -316,63 +292,109 @@ class StreamInserter(object):
If more data is inserted after a finalize(), it will become If more data is inserted after a finalize(), it will become
part of a new interval and there may be a gap left in-between.""" part of a new interval and there may be a gap left in-between."""
# Special marker tells insert_line that this is the end self._send_block(final = True)
self.insert_line(None, allow_intermediate = False)
if self._block_len > 0: def _get_first_noncomment(self, block):
# We have data pending, so send the final block """Return the (start, end) indices of the first full line in
self._send_block_final() block that isn't a comment, or raise IndexError if
elif None not in (self._interval_start, self._interval_end): there isn't one."""
# We have no data, but enough information to create an start = 0
# empty interval. while True:
self._block_start = self._interval_start end = block.find('\n', start)
if end < 0:
raise IndexError
if block[start] != '#':
return (start, (end + 1))
start = end + 1
def _get_last_noncomment(self, block):
"""Return the (start, end) indices of the last full line in
block[:length] that isn't a comment, or raise IndexError if
there isn't one."""
end = block.rfind('\n')
if end <= 0:
raise IndexError
while True:
start = block.rfind('\n', 0, end)
if block[start + 1] != '#':
return ((start + 1), end)
if start == -1:
raise IndexError
end = start
def _send_block(self, final = False):
"""Send data currently in the block. The data sent will
consist of full lines only, so some might be left over."""
# Build the full string to send
block = "".join(self._block_data)
start_ts = self._interval_start
if start_ts is None:
# Pull start from the first line
try:
(spos, epos) = self._get_first_noncomment(block)
start_ts = extract_timestamp(block[spos:epos])
except (ValueError, IndexError):
pass # no timestamp is OK, if we have no data
if final:
# For a final block, it must end in a newline, and the
# ending timestamp is either the user-provided end,
# or the timestamp of the last line plus epsilon.
end_ts = self._interval_end
try:
if block[-1] != '\n':
raise ValueError("final block didn't end with a newline")
if end_ts is None:
(spos, epos) = self._get_last_noncomment(block)
end_ts = extract_timestamp(block[spos:epos])
end_ts += self._end_epsilon
except (ValueError, IndexError):
pass # no timestamp is OK, if we have no data
self._block_data = []
self._block_len = 0
# Next block is completely fresh
self._interval_start = None self._interval_start = None
self._send_block_final()
else:
# No data, and no timestamps to use to create an empty
# interval.
pass
# Make sure both timestamps are emptied for future intervals.
self._interval_start = None
self._interval_end = None
def _send_block_intermediate(self):
"""Send data, when we still have more data to send.
Use the timestamp from the next line, so that the blocks
are contiguous."""
block_end = extract_timestamp(self._line_new)
if self._interval_end is not None and block_end > self._interval_end:
# Something's fishy -- the timestamp we found is after
# the user's specified end. Limit it here, and the
# server will return an error.
block_end = self._interval_end
self._send_block(block_end)
def _send_block_final(self):
"""Send data, when this is the last block for the interval.
There is no next line, so figure out the actual interval end
using interval_end or end_epsilon."""
if self._interval_end is not None:
# Use the user's specified end timestamp
block_end = self._interval_end
# Clear it in case we send more intervals in the future.
self._interval_end = None self._interval_end = None
else: else:
# Add an epsilon to the last timestamp we saw # An intermediate block, e.g. "line1\nline2\nline3\nline4"
block_end = extract_timestamp(self._line_old) + self._end_epsilon # We need to save "line3\nline4" for the next block, and
self._send_block(block_end) # use the timestamp from "line3" as the ending timestamp
# for this one.
try:
(spos, epos) = self._get_last_noncomment(block)
end_ts = extract_timestamp(block[spos:epos])
except (ValueError, IndexError):
# If we found no timestamp, give up; we'll send this
# block later when we have more data.
return
if spos == 0:
# Not enough data to send an intermediate block
return
if self._interval_end is not None and end_ts > self._interval_end:
# User gave us bad endpoints; send it anyway, and let
# the server complain so that the error is the same
# as if we hadn't done this chunking.
end_ts = self._interval_end
self._block_data = [ block[spos:] ]
self._block_len = (epos - spos)
block = block[:spos]
def _send_block(self, block_end): # Next block continues where this one ended
"""Send current block to the server""" self._interval_start = end_ts
self.last_response = self._client.stream_insert_block(
self._path, "".join(self._block_data),
self._block_start, block_end)
# Clear out the block # Double check endpoints
self._block_data = [] if start_ts is None or end_ts is None:
self._block_len = 0 # If the block has no non-comment lines, it's OK
self._block_start = None try:
self._get_first_noncomment(block)
except IndexError:
return
raise ClientError("have data to send, but no start/end times")
# Note when we sent it # Send it
self._last_time = time.time() params = { "path": self._path,
"start": float_time_to_string(start_ts),
"end": float_time_to_string(end_ts) }
self.last_response = self._http.put("stream/insert", block, params)

View File

@@ -1,6 +1,5 @@
"""HTTP client library""" """HTTP client library"""
import nilmdb
import nilmdb.utils import nilmdb.utils
from nilmdb.client.errors import ClientError, ServerError, Error from nilmdb.client.errors import ClientError, ServerError, Error
@@ -10,7 +9,7 @@ import requests
class HTTPClient(object): class HTTPClient(object):
"""Class to manage and perform HTTP requests from the client""" """Class to manage and perform HTTP requests from the client"""
def __init__(self, baseurl = ""): def __init__(self, baseurl = "", post_json = False):
"""If baseurl is supplied, all other functions that take """If baseurl is supplied, all other functions that take
a URL can be given a relative URL instead.""" a URL can be given a relative URL instead."""
# Verify / clean up URL # Verify / clean up URL
@@ -26,6 +25,10 @@ class HTTPClient(object):
# Saved response, so that tests can verify a few things. # Saved response, so that tests can verify a few things.
self._last_response = {} self._last_response = {}
# Whether to send application/json POST bodies (versus
# x-www-form-urlencoded)
self.post_json = post_json
def _handle_error(self, url, code, body): def _handle_error(self, url, code, body):
# Default variables for exception. We use the entire body as # Default variables for exception. We use the entire body as
# the default message, in case we can't extract it from a JSON # the default message, in case we can't extract it from a JSON
@@ -57,12 +60,14 @@ class HTTPClient(object):
def close(self): def close(self):
self.session.close() self.session.close()
def _do_req(self, method, url, query_data, body_data, stream): def _do_req(self, method, url, query_data, body_data, stream, headers):
url = urlparse.urljoin(self.baseurl, url) url = urlparse.urljoin(self.baseurl, url)
try: try:
response = self.session.request(method, url, response = self.session.request(method, url,
params = query_data, params = query_data,
data = body_data) data = body_data,
stream = stream,
headers = headers)
except requests.RequestException as e: except requests.RequestException as e:
raise ServerError(status = "502 Error", url = url, raise ServerError(status = "502 Error", url = url,
message = str(e.message)) message = str(e.message))
@@ -76,12 +81,13 @@ class HTTPClient(object):
return (response, False) return (response, False)
# Normal versions that return data directly # Normal versions that return data directly
def _req(self, method, url, query = None, body = None): def _req(self, method, url, query = None, body = None, headers = None):
""" """
Make a request and return the body data as a string or parsed Make a request and return the body data as a string or parsed
JSON object, or raise an error if it contained an error. JSON object, or raise an error if it contained an error.
""" """
(response, isjson) = self._do_req(method, url, query, body, False) (response, isjson) = self._do_req(method, url, query, body,
stream = False, headers = headers)
if isjson: if isjson:
return json.loads(response.content) return json.loads(response.content)
return response.content return response.content
@@ -92,24 +98,31 @@ class HTTPClient(object):
def post(self, url, params = None): def post(self, url, params = None):
"""Simple POST (parameters in body)""" """Simple POST (parameters in body)"""
return self._req("POST", url, None, params) if self.post_json:
return self._req("POST", url, None,
json.dumps(params),
{ 'Content-type': 'application/json' })
else:
return self._req("POST", url, None, params)
def put(self, url, data, params = None): def put(self, url, data, params = None):
"""Simple PUT (parameters in URL, data in body)""" """Simple PUT (parameters in URL, data in body)"""
return self._req("PUT", url, params, data) return self._req("PUT", url, params, data)
# Generator versions that return data one line at a time. # Generator versions that return data one line at a time.
def _req_gen(self, method, url, query = None, body = None): def _req_gen(self, method, url, query = None, body = None, headers = None):
""" """
Make a request and return a generator that gives back strings Make a request and return a generator that gives back strings
or JSON decoded lines of the body data, or raise an error if or JSON decoded lines of the body data, or raise an error if
it contained an eror. it contained an eror.
""" """
(response, isjson) = self._do_req(method, url, query, body, True) (response, isjson) = self._do_req(method, url, query, body,
for line in response.iter_lines(): stream = True, headers = headers)
if isjson: if isjson:
for line in response.iter_lines():
yield json.loads(line) yield json.loads(line)
else: else:
for line in response.iter_lines():
yield line yield line
def get_gen(self, url, params = None): def get_gen(self, url, params = None):

View File

@@ -1,18 +1,20 @@
"""Command line client functionality""" """Command line client functionality"""
import nilmdb import nilmdb.client
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.utils import datetime_tz from nilmdb.utils import datetime_tz
import nilmdb.utils.time import nilmdb.utils.time
import sys import sys
import os
import argparse import argparse
from argparse import ArgumentDefaultsHelpFormatter as def_form from argparse import ArgumentDefaultsHelpFormatter as def_form
# Valid subcommands. Defined in separate files just to break # Valid subcommands. Defined in separate files just to break
# things up -- they're still called with Cmdline as self. # things up -- they're still called with Cmdline as self.
subcommands = [ "info", "create", "list", "metadata", "insert", "extract", subcommands = [ "help", "info", "create", "list", "metadata",
"remove", "destroy" ] "insert", "extract", "remove", "destroy" ]
# Import the subcommand modules # Import the subcommand modules
subcmd_mods = {} subcmd_mods = {}
@@ -29,6 +31,8 @@ class Cmdline(object):
def __init__(self, argv = None): def __init__(self, argv = None):
self.argv = argv or sys.argv[1:] self.argv = argv or sys.argv[1:]
self.client = None self.client = None
self.def_url = os.environ.get("NILMDB_URL", "http://localhost:12380")
self.subcmd = {}
def arg_time(self, toparse): def arg_time(self, toparse):
"""Parse a time string argument""" """Parse a time string argument"""
@@ -50,18 +54,17 @@ class Cmdline(object):
group = self.parser.add_argument_group("Server") group = self.parser.add_argument_group("Server")
group.add_argument("-u", "--url", action="store", group.add_argument("-u", "--url", action="store",
default="http://localhost:12380/", default=self.def_url,
help="NilmDB server URL (default: %(default)s)") help="NilmDB server URL (default: %(default)s)")
sub = self.parser.add_subparsers(title="Commands", sub = self.parser.add_subparsers(
dest="command", title="Commands", dest="command",
description="Specify --help after " description="Use 'help command' or 'command --help' for more "
"the command for command-specific " "details on a particular command.")
"options.")
# Set up subcommands (defined in separate files) # Set up subcommands (defined in separate files)
for cmd in subcommands: for cmd in subcommands:
subcmd_mods[cmd].setup(self, sub) self.subcmd[cmd] = subcmd_mods[cmd].setup(self, sub)
def die(self, formatstr, *args): def die(self, formatstr, *args):
fprintf(sys.stderr, formatstr + "\n", *args) fprintf(sys.stderr, formatstr + "\n", *args)
@@ -82,13 +85,15 @@ class Cmdline(object):
if "verify" in self.args: if "verify" in self.args:
self.args.verify(self) self.args.verify(self)
self.client = nilmdb.Client(self.args.url) self.client = nilmdb.client.Client(self.args.url)
# Make a test connection to make sure things work # Make a test connection to make sure things work,
try: # unless the particular command requests that we don't.
server_version = self.client.version() if "no_test_connect" not in self.args:
except nilmdb.client.Error as e: try:
self.die("error connecting to server: %s", str(e)) server_version = self.client.version()
except nilmdb.client.Error as e:
self.die("error connecting to server: %s", str(e))
# Now dispatch client request to appropriate function. Parser # Now dispatch client request to appropriate function. Parser
# should have ensured that we don't have any unknown commands # should have ensured that we don't have any unknown commands

View File

@@ -1,5 +1,4 @@
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
import nilmdb
import nilmdb.client import nilmdb.client
from argparse import RawDescriptionHelpFormatter as raw_form from argparse import RawDescriptionHelpFormatter as raw_form
@@ -26,6 +25,7 @@ Layout types are of the format: type_count
help="Path (in database) of new stream, e.g. /foo/bar") help="Path (in database) of new stream, e.g. /foo/bar")
group.add_argument("layout", group.add_argument("layout",
help="Layout type for new stream, e.g. float32_8") help="Layout type for new stream, e.g. float32_8")
return cmd
def cmd_create(self): def cmd_create(self):
"""Create new stream""" """Create new stream"""

View File

@@ -1,5 +1,4 @@
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
import nilmdb
import nilmdb.client import nilmdb.client
from argparse import ArgumentDefaultsHelpFormatter as def_form from argparse import ArgumentDefaultsHelpFormatter as def_form
@@ -16,6 +15,7 @@ def setup(self, sub):
group = cmd.add_argument_group("Required arguments") group = cmd.add_argument_group("Required arguments")
group.add_argument("path", group.add_argument("path",
help="Path of the stream to delete, e.g. /foo/bar") help="Path of the stream to delete, e.g. /foo/bar")
return cmd
def cmd_destroy(self): def cmd_destroy(self):
"""Destroy stream""" """Destroy stream"""

View File

@@ -30,6 +30,7 @@ def setup(self, sub):
help="Show raw timestamps in annotated information") help="Show raw timestamps in annotated information")
group.add_argument("-c", "--count", action="store_true", group.add_argument("-c", "--count", action="store_true",
help="Just output a count of matched data points") help="Just output a count of matched data points")
return cmd
def cmd_extract_verify(self): def cmd_extract_verify(self):
if self.args.start is not None and self.args.end is not None: if self.args.start is not None and self.args.end is not None:
@@ -43,7 +44,7 @@ def cmd_extract(self):
layout = streams[0][1] layout = streams[0][1]
if self.args.timestamp_raw: if self.args.timestamp_raw:
time_string = repr time_string = nilmdb.utils.time.float_time_to_string
else: else:
time_string = nilmdb.utils.time.format_time time_string = nilmdb.utils.time.format_time

26
nilmdb/cmdline/help.py Normal file
View File

@@ -0,0 +1,26 @@
from nilmdb.utils.printf import *
import argparse
import sys
def setup(self, sub):
cmd = sub.add_parser("help", help="Show detailed help for a command",
description="""
Show help for a command. 'help command' is
the same as 'command --help'.
""")
cmd.set_defaults(handler = cmd_help)
cmd.set_defaults(no_test_connect = True)
cmd.add_argument("command", nargs="?",
help="Command to get help about")
cmd.add_argument("rest", nargs=argparse.REMAINDER,
help=argparse.SUPPRESS)
return cmd
def cmd_help(self):
if self.args.command in self.subcmd:
self.subcmd[self.args.command].print_help()
else:
self.parser.print_help()
return

View File

@@ -1,4 +1,4 @@
import nilmdb import nilmdb.client
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.utils import human_size from nilmdb.utils import human_size
@@ -12,6 +12,7 @@ def setup(self, sub):
version. version.
""") """)
cmd.set_defaults(handler = cmd_info) cmd.set_defaults(handler = cmd_info)
return cmd
def cmd_info(self): def cmd_info(self):
"""Print info about the server""" """Print info about the server"""

View File

@@ -1,5 +1,4 @@
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
import nilmdb
import nilmdb.client import nilmdb.client
import nilmdb.utils.timestamper as timestamper import nilmdb.utils.timestamper as timestamper
import nilmdb.utils.time import nilmdb.utils.time
@@ -11,42 +10,67 @@ def setup(self, sub):
description=""" description="""
Insert data into a stream. Insert data into a stream.
""") """)
cmd.set_defaults(handler = cmd_insert) cmd.set_defaults(verify = cmd_insert_verify,
handler = cmd_insert)
cmd.add_argument("-q", "--quiet", action='store_true', cmd.add_argument("-q", "--quiet", action='store_true',
help='suppress unnecessary messages') help='suppress unnecessary messages')
group = cmd.add_argument_group("Timestamping", group = cmd.add_argument_group("Timestamping",
description=""" description="""
If timestamps are already provided in the To add timestamps, specify the
input date, use --none. Otherwise, arguments --timestamp and --rate,
provide --start, or use --filename to and provide a starting time.
try to deduce timestamps from the file.
Set the TZ environment variable to change
the default timezone.
""") """)
group.add_argument("-t", "--timestamp", action="store_true",
help="Add timestamps to each line")
group.add_argument("-r", "--rate", type=float, group.add_argument("-r", "--rate", type=float,
help=""" help="Data rate, in Hz")
If needed, rate in Hz (required when using --start)
""") group = cmd.add_argument_group("Start time",
description="""
Start time may be manually
specified with --start, or guessed
from the filenames using
--filename. Set the TZ environment
variable to change the default
timezone.""")
exc = group.add_mutually_exclusive_group() exc = group.add_mutually_exclusive_group()
exc.add_argument("-s", "--start", exc.add_argument("-s", "--start",
metavar="TIME", type=self.arg_time, metavar="TIME", type=self.arg_time,
help="Starting timestamp (free-form)") help="Starting timestamp (free-form)")
exc.add_argument("-f", "--filename", action="store_true", exc.add_argument("-f", "--filename", action="store_true",
help=""" help="Use filename to determine start time")
Use filenames to determine start time
(default, if filenames are provided) group = cmd.add_argument_group("End time",
""") description="""
exc.add_argument("-n", "--none", action="store_true", End time for the overall stream.
help="Timestamp is already present, don't add one") (required when not using --timestamp).
Set the TZ environment
variable to change the default
timezone.""")
group.add_argument("-e", "--end",
metavar="TIME", type=self.arg_time,
help="Ending timestamp (free-form)")
group = cmd.add_argument_group("Required parameters") group = cmd.add_argument_group("Required parameters")
group.add_argument("path", group.add_argument("path",
help="Path of stream, e.g. /foo/bar") help="Path of stream, e.g. /foo/bar")
group.add_argument("file", nargs="*", default=['-'], group.add_argument("file", nargs = '?', default='-',
help="File(s) to insert (default: - (stdin))") help="File to insert (default: - (stdin))")
return cmd
def cmd_insert_verify(self):
if self.args.timestamp:
if not self.args.rate:
self.die("error: --rate is needed, but was not specified")
if not self.args.filename and self.args.start is None:
self.die("error: need --start or --filename when adding timestamps")
else:
if self.args.start is None or self.args.end is None:
self.die("error: when not adding timestamps, --start and "
"--end are required")
def cmd_insert(self): def cmd_insert(self):
# Find requested stream # Find requested stream
@@ -54,51 +78,50 @@ def cmd_insert(self):
if len(streams) != 1: if len(streams) != 1:
self.die("error getting stream info for path %s", self.args.path) self.die("error getting stream info for path %s", self.args.path)
if self.args.start and len(self.args.file) != 1: arg = self.args
self.die("error: --start can only be used with one input file")
for filename in self.args.file: try:
filename = arg.file
if filename == '-': if filename == '-':
infile = sys.stdin infile = sys.stdin
else: else:
try: try:
infile = open(filename, "r") infile = open(filename, "rb")
except IOError: except IOError:
self.die("error opening input file %s", filename) self.die("error opening input file %s", filename)
# Build a timestamper for this file if arg.start is None:
if self.args.none: try:
ts = timestamper.TimestamperNull(infile) arg.start = nilmdb.utils.time.parse_time(filename).totimestamp()
except ValueError:
self.die("error extracting start time from filename '%s'",
filename)
if arg.timestamp:
data = timestamper.TimestamperRate(infile, arg.start, arg.rate)
else: else:
if self.args.start: data = iter(lambda: infile.read(1048576), '')
start = self.args.start
else:
try:
start = nilmdb.utils.time.parse_time(filename)
except ValueError:
self.die("error extracting time from filename '%s'",
filename)
if not self.args.rate:
self.die("error: --rate is needed, but was not specified")
rate = self.args.rate
ts = timestamper.TimestamperRate(infile, start, rate)
# Print info # Print info
if not self.args.quiet: if not arg.quiet:
printf("Input file: %s\n", filename) printf(" Input file: %s\n", filename)
printf("Timestamper: %s\n", str(ts)) printf(" Start time: %s\n",
nilmdb.utils.time.format_time(arg.start))
if arg.end:
printf(" End time: %s\n",
nilmdb.utils.time.format_time(arg.end))
if arg.timestamp:
printf("Timestamper: %s\n", str(data))
# Insert the data # Insert the data
try: self.client.stream_insert(arg.path, data, arg.start, arg.end)
self.client.stream_insert(self.args.path, ts)
except nilmdb.client.Error as e: except nilmdb.client.Error as e:
# TODO: It would be nice to be able to offer better errors # TODO: It would be nice to be able to offer better errors
# here, particularly in the case of overlap, which just shows # here, particularly in the case of overlap, which just shows
# ugly bracketed ranges of 16-digit numbers and a mangled URL. # ugly bracketed ranges of 16-digit numbers and a mangled URL.
# Need to consider adding something like e.prettyprint() # Need to consider adding something like e.prettyprint()
# that is smarter about the contents of the error. # that is smarter about the contents of the error.
self.die("error inserting data: %s", str(e)) self.die("error inserting data: %s", str(e))
return return

View File

@@ -24,17 +24,28 @@ def setup(self, sub):
group.add_argument("-l", "--layout", default="*", group.add_argument("-l", "--layout", default="*",
help="Match only this stream layout") help="Match only this stream layout")
group = cmd.add_argument_group("Interval info")
group.add_argument("-E", "--ext", action="store_true",
help="Show extended stream info, like interval "
"extents and row count")
group = cmd.add_argument_group("Interval details") group = cmd.add_argument_group("Interval details")
group.add_argument("-d", "--detail", action="store_true", group.add_argument("-d", "--detail", action="store_true",
help="Show available data time intervals") help="Show available data time intervals")
group.add_argument("-T", "--timestamp-raw", action="store_true",
help="Show raw timestamps in time intervals")
group.add_argument("-s", "--start", group.add_argument("-s", "--start",
metavar="TIME", type=self.arg_time, metavar="TIME", type=self.arg_time,
help="Starting timestamp (free-form, inclusive)") help="Starting timestamp for intervals "
"(free-form, inclusive)")
group.add_argument("-e", "--end", group.add_argument("-e", "--end",
metavar="TIME", type=self.arg_time, metavar="TIME", type=self.arg_time,
help="Ending timestamp (free-form, noninclusive)") help="Ending timestamp for intervals "
"(free-form, noninclusive)")
group = cmd.add_argument_group("Misc options")
group.add_argument("-T", "--timestamp-raw", action="store_true",
help="Show raw timestamps when printing times")
return cmd
def cmd_list_verify(self): def cmd_list_verify(self):
# A hidden "path_positional" argument lets the user leave off the # A hidden "path_positional" argument lets the user leave off the
@@ -51,28 +62,41 @@ def cmd_list_verify(self):
if self.args.start >= self.args.end: if self.args.start >= self.args.end:
self.parser.error("start must precede end") self.parser.error("start must precede end")
if self.args.start is not None or self.args.end is not None:
if not self.args.detail:
self.parser.error("--start and --end only make sense with --detail")
def cmd_list(self): def cmd_list(self):
"""List available streams""" """List available streams"""
streams = self.client.stream_list() streams = self.client.stream_list(extended = True)
if self.args.timestamp_raw: if self.args.timestamp_raw:
time_string = repr time_string = nilmdb.utils.time.float_time_to_string
else: else:
time_string = nilmdb.utils.time.format_time time_string = nilmdb.utils.time.format_time
for (path, layout) in streams: for stream in streams:
(path, layout, int_min, int_max, rows, seconds) = stream[:6]
if not (fnmatch.fnmatch(path, self.args.path) and if not (fnmatch.fnmatch(path, self.args.path) and
fnmatch.fnmatch(layout, self.args.layout)): fnmatch.fnmatch(layout, self.args.layout)):
continue continue
printf("%s %s\n", path, layout) printf("%s %s\n", path, layout)
if not self.args.detail:
continue
printed = False if self.args.ext:
for (start, end) in self.client.stream_intervals(path, self.args.start, if int_min is None or int_max is None:
self.args.end): printf(" interval extents: (no data)\n")
printf(" [ %s -> %s ]\n", time_string(start), time_string(end)) else:
printed = True printf(" interval extents: %s -> %s\n",
if not printed: time_string(int_min), time_string(int_max))
printf(" (no intervals)\n") printf(" total data: %d rows, %.6f seconds\n",
rows or 0, seconds or 0);
if self.args.detail:
printed = False
for (start, end) in self.client.stream_intervals(
path, self.args.start, self.args.end):
printf(" [ %s -> %s ]\n", time_string(start), time_string(end))
printed = True
if not printed:
printf(" (no intervals)\n")

View File

@@ -26,6 +26,7 @@ def setup(self, sub):
exc.add_argument("-u", "--update", nargs="+", metavar="key=value", exc.add_argument("-u", "--update", nargs="+", metavar="key=value",
help="Update metadata using provided " help="Update metadata using provided "
"key=value pairs") "key=value pairs")
return cmd
def cmd_metadata(self): def cmd_metadata(self):
"""Manipulate metadata""" """Manipulate metadata"""

View File

@@ -1,5 +1,4 @@
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
import nilmdb
import nilmdb.client import nilmdb.client
def setup(self, sub): def setup(self, sub):
@@ -23,6 +22,7 @@ def setup(self, sub):
group = cmd.add_argument_group("Output format") group = cmd.add_argument_group("Output format")
group.add_argument("-c", "--count", action="store_true", group.add_argument("-c", "--count", action="store_true",
help="Output number of data points removed") help="Output number of data points removed")
return cmd
def cmd_remove(self): def cmd_remove(self):
try: try:

View File

@@ -25,6 +25,9 @@ def main():
default = os.path.join(os.getcwd(), "db")) default = os.path.join(os.getcwd(), "db"))
group.add_argument('-q', '--quiet', help = 'Silence output', group.add_argument('-q', '--quiet', help = 'Silence output',
action = 'store_true') action = 'store_true')
group.add_argument('-t', '--traceback',
help = 'Provide tracebacks in client errors',
action = 'store_true', default = False)
group = parser.add_argument_group("Debug options") group = parser.add_argument_group("Debug options")
group.add_argument('-y', '--yappi', help = 'Run under yappi profiler and ' group.add_argument('-y', '--yappi', help = 'Run under yappi profiler and '
@@ -35,7 +38,7 @@ def main():
# Create database object. Needs to be serialized before passing # Create database object. Needs to be serialized before passing
# to the Server. # to the Server.
db = nilmdb.utils.serializer_proxy(nilmdb.NilmDB)(args.database) db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(args.database)
# Configure the server # Configure the server
if args.quiet: if args.quiet:
@@ -45,10 +48,12 @@ def main():
server = nilmdb.server.Server(db, server = nilmdb.server.Server(db,
host = args.address, host = args.address,
port = args.port, port = args.port,
embedded = embedded) embedded = embedded,
force_traceback = args.traceback)
# Print info # Print info
if not args.quiet: if not args.quiet:
print "Version: %s" % nilmdb.__version__
print "Database: %s" % (os.path.realpath(args.database)) print "Database: %s" % (os.path.realpath(args.database))
if args.address == '0.0.0.0' or args.address == '::': if args.address == '0.0.0.0' or args.address == '::':
host = socket.getfqdn() host = socket.getfqdn()

View File

@@ -16,7 +16,6 @@ try: # pragma: no cover
except (ImportError, TypeError): # pragma: no cover except (ImportError, TypeError): # pragma: no cover
pass pass
import nilmdb.server.layout
from nilmdb.server.nilmdb import NilmDB from nilmdb.server.nilmdb import NilmDB
from nilmdb.server.server import Server from nilmdb.server.server import Server
from nilmdb.server.errors import NilmDBError, StreamError, OverlapError from nilmdb.server.errors import NilmDBError, StreamError, OverlapError

View File

@@ -4,31 +4,24 @@
# nilmdb.py, but will pull the parent nilmdb module instead. # nilmdb.py, but will pull the parent nilmdb module instead.
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
import nilmdb
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.utils.time import float_time_to_string as ftts
import nilmdb.utils
import os import os
import cPickle as pickle import cPickle as pickle
import struct
import mmap
import re import re
import sys
# If we have the faulthandler module, use it. All of the mmap stuff #from . import pyrocket as rocket
# might trigger a SIGSEGV or SIGBUS if we're not careful, and from . import rocket
# faulthandler will give a traceback in that case. (the Python
# interpreter will still die either way).
try: # pragma: no cover
import faulthandler
faulthandler.enable()
except: # pragma: no cover
pass
# Up to 256 open file descriptors at any given time. # Up to 256 open file descriptors at any given time.
# These variables are global so they can be used in the decorator arguments. # These variables are global so they can be used in the decorator arguments.
table_cache_size = 16 table_cache_size = 16
fd_cache_size = 16 fd_cache_size = 16
@nilmdb.utils.must_close(wrap_verify = True) @nilmdb.utils.must_close(wrap_verify = False)
class BulkData(object): class BulkData(object):
def __init__(self, basepath, **kwargs): def __init__(self, basepath, **kwargs):
self.basepath = basepath self.basepath = basepath
@@ -83,26 +76,6 @@ class BulkData(object):
raise ValueError("invalid path; path must contain at least one " raise ValueError("invalid path; path must contain at least one "
"folder") "folder")
# Get layout, and build format string for struct module
try:
layout = nilmdb.server.layout.get_named(layout_name)
struct_fmt = '<d' # Little endian, double timestamp
struct_mapping = {
"int8": 'b',
"uint8": 'B',
"int16": 'h',
"uint16": 'H',
"int32": 'i',
"uint32": 'I',
"int64": 'q',
"uint64": 'Q',
"float32": 'f',
"float64": 'd',
}
struct_fmt += struct_mapping[layout.datatype] * layout.count
except KeyError:
raise ValueError("no such layout, or bad data types")
# Create the table. Note that we make a distinction here # Create the table. Note that we make a distinction here
# between NilmDB paths (always Unix style, split apart # between NilmDB paths (always Unix style, split apart
# manually) and OS paths (built up with os.path.join) # manually) and OS paths (built up with os.path.join)
@@ -122,11 +95,20 @@ class BulkData(object):
raise ValueError("subdirs of this path already exist") raise ValueError("subdirs of this path already exist")
os.mkdir(ospath) os.mkdir(ospath)
# Write format string to file try:
Table.create(ospath, struct_fmt, self.file_size, self.files_per_dir) # Write format string to file
Table.create(ospath, layout_name, self.file_size,
self.files_per_dir)
# Open and cache it # Open and cache it
self.getnode(unicodepath) self.getnode(unicodepath)
except:
exc_info = sys.exc_info()
try:
os.rmdir(ospath)
except OSError:
pass
raise exc_info[1], None, exc_info[2]
# Success # Success
return return
@@ -171,53 +153,7 @@ class BulkData(object):
ospath = os.path.join(self.root, *elements) ospath = os.path.join(self.root, *elements)
return Table(ospath) return Table(ospath)
@nilmdb.utils.must_close(wrap_verify = True) @nilmdb.utils.must_close(wrap_verify = False)
class File(object):
"""Object representing a single file on disk. Data can be appended,
or the self.mmap handle can be used for random reads."""
def __init__(self, root, subdir, filename):
# Create path if it doesn't exist
try:
os.mkdir(os.path.join(root, subdir))
except OSError:
pass
# Open/create file
self._f = open(os.path.join(root, subdir, filename), "a+b", 0)
# Seek to end, and get size
self._f.seek(0, 2)
self.size = self._f.tell()
# Open mmap object
self.mmap = None
self._mmap_reopen()
def _mmap_reopen(self):
if self.size == 0:
# Don't mmap if the file is empty; it would fail
pass
elif self.mmap is None:
# Not opened yet, so open it
self.mmap = mmap.mmap(self._f.fileno(), 0)
else:
# Already opened, so just resize it
self.mmap.resize(self.size)
def close(self):
if self.mmap is not None:
self.mmap.close()
self._f.close()
def append(self, data):
# Write data, flush it, and resize our mmap accordingly
self._f.write(data)
self._f.flush()
self.size += len(data)
self._mmap_reopen()
@nilmdb.utils.must_close(wrap_verify = True)
class Table(object): class Table(object):
"""Tools to help access a single table (data at a specific OS path).""" """Tools to help access a single table (data at a specific OS path)."""
# See design.md for design details # See design.md for design details
@@ -229,19 +165,20 @@ class Table(object):
return os.path.isfile(os.path.join(root, "_format")) return os.path.isfile(os.path.join(root, "_format"))
@classmethod @classmethod
def create(cls, root, struct_fmt, file_size, files_per_dir): def create(cls, root, layout, file_size, files_per_dir):
"""Initialize a table at the given OS path. """Initialize a table at the given OS path with the
'struct_fmt' is a Struct module format description""" given layout string"""
# Calculate rows per file so that each file is approximately # Calculate rows per file so that each file is approximately
# file_size bytes. # file_size bytes.
packer = struct.Struct(struct_fmt) rkt = rocket.Rocket(layout, None)
rows_per_file = max(file_size // packer.size, 1) rows_per_file = max(file_size // rkt.binary_size, 1)
rkt.close()
fmt = { "rows_per_file": rows_per_file, fmt = { "rows_per_file": rows_per_file,
"files_per_dir": files_per_dir, "files_per_dir": files_per_dir,
"struct_fmt": struct_fmt, "layout": layout,
"version": 1 } "version": 2 }
with open(os.path.join(root, "_format"), "wb") as f: with open(os.path.join(root, "_format"), "wb") as f:
pickle.dump(fmt, f, 2) pickle.dump(fmt, f, 2)
@@ -250,18 +187,35 @@ class Table(object):
"""'root' is the full OS path to the directory of this table""" """'root' is the full OS path to the directory of this table"""
self.root = root self.root = root
# Load the format and build packer # Load the format
with open(os.path.join(self.root, "_format"), "rb") as f: with open(os.path.join(self.root, "_format"), "rb") as f:
fmt = pickle.load(f) fmt = pickle.load(f)
if fmt["version"] != 1: # pragma: no cover (just future proofing) if fmt["version"] == 1: # pragma: no cover
raise NotImplementedError("version " + fmt["version"] + # We can handle this old version by converting from
# struct_fmt back to layout name.
compat = { "<dHHHHHH": "uint16_6",
"<dHHHHHHHHH": "uint16_9",
"<dffffffff": "float32_8" }
if fmt["struct_fmt"] in compat:
fmt["version"] = 2
fmt["layout"] = compat[fmt["struct_fmt"]]
else:
raise NotImplementedError("old version 1 data with format "
+ fmt["struct_fmt"] + " is no good")
elif fmt["version"] != 2: # pragma: no cover (just future proofing)
raise NotImplementedError("version " + str(fmt["version"]) +
" bulk data store not supported") " bulk data store not supported")
self.rows_per_file = fmt["rows_per_file"] self.rows_per_file = fmt["rows_per_file"]
self.files_per_dir = fmt["files_per_dir"] self.files_per_dir = fmt["files_per_dir"]
self.packer = struct.Struct(fmt["struct_fmt"]) self.layout = fmt["layout"]
self.file_size = self.packer.size * self.rows_per_file
# Use rocket to get row size and file size
rkt = rocket.Rocket(self.layout, None)
self.row_size = rkt.binary_size
self.file_size = rkt.binary_size * self.rows_per_file
rkt.close()
# Find nrows # Find nrows
self.nrows = self._get_nrows() self.nrows = self._get_nrows()
@@ -316,26 +270,53 @@ class Table(object):
# will just get longer but will still sort correctly. # will just get longer but will still sort correctly.
dirname = sprintf("%04x", filenum // self.files_per_dir) dirname = sprintf("%04x", filenum // self.files_per_dir)
filename = sprintf("%04x", filenum % self.files_per_dir) filename = sprintf("%04x", filenum % self.files_per_dir)
offset = (row % self.rows_per_file) * self.packer.size offset = (row % self.rows_per_file) * self.row_size
count = self.rows_per_file - (row % self.rows_per_file) count = self.rows_per_file - (row % self.rows_per_file)
return (dirname, filename, offset, count) return (dirname, filename, offset, count)
def _row_from_offset(self, subdir, filename, offset): def _row_from_offset(self, subdir, filename, offset):
"""Return the row number that corresponds to the given """Return the row number that corresponds to the given
'subdir/filename' and byte-offset within that file.""" 'subdir/filename' and byte-offset within that file."""
if (offset % self.packer.size) != 0: # pragma: no cover; shouldn't occur if (offset % self.row_size) != 0: # pragma: no cover
# this shouldn't occur, unless there is some corruption somewhere
raise ValueError("file offset is not a multiple of data size") raise ValueError("file offset is not a multiple of data size")
filenum = int(subdir, 16) * self.files_per_dir + int(filename, 16) filenum = int(subdir, 16) * self.files_per_dir + int(filename, 16)
row = (filenum * self.rows_per_file) + (offset // self.packer.size) row = (filenum * self.rows_per_file) + (offset // self.row_size)
return row return row
def _remove_or_truncate_file(self, subdir, filename, offset = 0):
"""Remove the given file, and remove the subdirectory too
if it's empty. If offset is nonzero, truncate the file
to that size instead."""
# Close potentially open file in file_open LRU cache
self.file_open.cache_remove(self, subdir, filename)
if offset:
# Truncate it
with open(os.path.join(self.root, subdir, filename), "r+b") as f:
f.truncate(offset)
else:
# Remove file
os.remove(os.path.join(self.root, subdir, filename))
# Try deleting subdir, too
try:
os.rmdir(os.path.join(self.root, subdir))
except:
pass
# Cache open files # Cache open files
@nilmdb.utils.lru_cache(size = fd_cache_size, @nilmdb.utils.lru_cache(size = fd_cache_size,
onremove = lambda f: f.close()) onremove = lambda f: f.close())
def file_open(self, subdir, filename): def file_open(self, subdir, filename):
"""Open and map a given 'subdir/filename' (relative to self.root). """Open and map a given 'subdir/filename' (relative to self.root).
Will be automatically closed when evicted from the cache.""" Will be automatically closed when evicted from the cache."""
return File(self.root, subdir, filename) # Create path if it doesn't exist
try:
os.mkdir(os.path.join(self.root, subdir))
except OSError:
pass
# Return a rocket.Rocket object, which contains the open file
return rocket.Rocket(self.layout,
os.path.join(self.root, subdir, filename))
def append(self, data): def append(self, data):
"""Append the data and flush it to disk. """Append the data and flush it to disk.
@@ -351,12 +332,106 @@ class Table(object):
f = self.file_open(subdir, fname) f = self.file_open(subdir, fname)
# Write the data # Write the data
for i in xrange(count): written = f.append_iter(count, dataiter)
row = dataiter.next() if written != count: # pragma: no cover
f.append(self.packer.pack(*row)) raise Exception("Didn't write the expected number of rows: "
+ str(written) + " != " + str(count))
remaining -= count remaining -= count
self.nrows += count self.nrows += count
def append_string(self, data, start, end):
"""Parse the formatted string in 'data', according to the
current layout, and append it to the table. If any timestamps
are non-monotonic, or don't fall between 'start' and 'end',
a ValueError is raised.
If this function succeeds, it returns normally. Otherwise,
the table is reverted back to its original state by truncating
or deleting files as necessary."""
data_offset = 0
last_timestamp = -1e12
tot_rows = self.nrows
count = 0
linenum = 0
try:
while data_offset < len(data):
# See how many rows we can fit into the current file,
# and open it
(subdir, fname, offset, count) = self._offset_from_row(tot_rows)
f = self.file_open(subdir, fname)
# Ask the rocket object to parse and append up to "count"
# rows of data, verifying things along the way.
try:
(added_rows, data_offset, last_timestamp, linenum
) = f.append_string(count, data, data_offset, linenum,
start, end, last_timestamp)
except rocket.ParseError as e:
(linenum, errtype, obj) = e.args
if errtype == rocket.ERR_NON_MONOTONIC:
err = sprintf("line %d: timestamp is not monotonically "
"increasing", linenum)
elif errtype == rocket.ERR_OUT_OF_INTERVAL:
if obj < start:
err = sprintf("line %d: Data timestamp %s < "
"start time %s", linenum,
ftts(obj), ftts(start))
else:
err = sprintf("line %d: Data timestamp %s >= "
"end time %s", linenum,
ftts(obj), ftts(end))
else:
err = sprintf("line %d: %s", linenum, str(obj))
raise ValueError("error parsing input data: " + err)
tot_rows += added_rows
except Exception:
# Some failure, so try to roll things back by truncating or
# deleting files that we may have appended data to.
cleanpos = self.nrows
while cleanpos <= tot_rows:
(subdir, fname, offset, count) = self._offset_from_row(cleanpos)
self._remove_or_truncate_file(subdir, fname, offset)
cleanpos += count
# Re-raise original exception
raise
else:
# Success, so update self.nrows accordingly
self.nrows = tot_rows
def _get_data(self, start, stop, as_string):
"""Extract data corresponding to Python range [n:m],
and returns a numeric list or formatted string,
depending on as_string."""
if (start is None or
stop is None or
start > stop or
start < 0 or
stop > self.nrows):
raise IndexError("Index out of range")
ret = []
row = start
remaining = stop - start
while remaining > 0:
(subdir, filename, offset, count) = self._offset_from_row(row)
if count > remaining:
count = remaining
f = self.file_open(subdir, filename)
if as_string:
ret.append(f.extract_string(offset, count))
else:
ret.extend(f.extract_list(offset, count))
remaining -= count
row += count
if as_string:
return "".join(ret)
return ret
def get_as_text(self, start, stop):
"""Extract data corresponding to Python range [n:m],
and returns a formatted string"""
return self._get_data(start, stop, True)
def __getitem__(self, key): def __getitem__(self, key):
"""Extract data and return it. Supports simple indexing """Extract data and return it. Supports simple indexing
(table[n]) and range slices (table[n:m]). Returns a nested (table[n]) and range slices (table[n:m]). Returns a nested
@@ -365,41 +440,32 @@ class Table(object):
# Handle simple slices # Handle simple slices
if isinstance(key, slice): if isinstance(key, slice):
# Fall back to brute force if the slice isn't simple # Fall back to brute force if the slice isn't simple
if ((key.step is not None and key.step != 1) or try:
key.start is None or if (key.step is not None and key.step != 1):
key.stop is None or raise IndexError
key.start >= key.stop or return self._get_data(key.start, key.stop, False)
key.start < 0 or except IndexError:
key.stop > self.nrows):
return [ self[x] for x in xrange(*key.indices(self.nrows)) ] return [ self[x] for x in xrange(*key.indices(self.nrows)) ]
ret = [] # Handle single points (inefficiently!)
row = key.start
remaining = key.stop - key.start
while remaining:
(subdir, filename, offset, count) = self._offset_from_row(row)
if count > remaining:
count = remaining
mm = self.file_open(subdir, filename).mmap
for i in xrange(count):
ret.append(list(self.packer.unpack_from(mm, offset)))
offset += self.packer.size
remaining -= count
row += count
return ret
# Handle single points
if key < 0 or key >= self.nrows: if key < 0 or key >= self.nrows:
raise IndexError("Index out of range") raise IndexError("Index out of range")
(subdir, filename, offset, count) = self._offset_from_row(key) (subdir, filename, offset, count) = self._offset_from_row(key)
mm = self.file_open(subdir, filename).mmap f = self.file_open(subdir, filename)
# unpack_from ignores the mmap object's current seek position return f.extract_list(offset, 1)[0]
return list(self.packer.unpack_from(mm, offset))
def _remove_rows(self, subdir, filename, start, stop): def _remove_rows(self, subdir, filename, start, stop):
"""Helper to mark specific rows as being removed from a """Helper to mark specific rows as being removed from a
file, and potentially removing or truncating the file itself.""" file, and potentially remove or truncate the file itself."""
# Import an existing list of deleted rows for this file # Close potentially open file in file_open LRU cache
self.file_open.cache_remove(self, subdir, filename)
# We keep a file like 0000.removed that contains a list of
# which rows have been "removed". Note that we never have to
# remove entries from this list, because we never decrease
# self.nrows, and so we will never overwrite those locations in the
# file. Only when the list covers the entire extent of the
# file will that file be removed.
datafile = os.path.join(self.root, subdir, filename) datafile = os.path.join(self.root, subdir, filename)
cachefile = datafile + ".removed" cachefile = datafile + ".removed"
try: try:
@@ -439,20 +505,19 @@ class Table(object):
# are generally easier if we don't have to special-case that. # are generally easier if we don't have to special-case that.
if (len(merged) == 1 and if (len(merged) == 1 and
merged[0][0] == 0 and merged[0][1] == self.rows_per_file): merged[0][0] == 0 and merged[0][1] == self.rows_per_file):
# Close potentially open file in file_open LRU cache
self.file_open.cache_remove(self, subdir, filename)
# Delete files # Delete files
os.remove(datafile)
if cachefile_present: if cachefile_present:
os.remove(cachefile) os.remove(cachefile)
self._remove_or_truncate_file(subdir, filename, 0)
# Try deleting subdir, too
try:
os.rmdir(os.path.join(self.root, subdir))
except:
pass
else: else:
# File needs to stick around. This means we can get
# degenerate cases where we have large files containing as
# little as one row. Try to punch a hole in the file,
# so that this region doesn't take up filesystem space.
offset = start * self.row_size
count = (stop - start) * self.row_size
nilmdb.utils.fallocate.punch_hole(datafile, offset, count)
# Update cache. Try to do it atomically. # Update cache. Try to do it atomically.
nilmdb.utils.atomic.replace_file(cachefile, nilmdb.utils.atomic.replace_file(cachefile,
pickle.dumps(merged, 2)) pickle.dumps(merged, 2))
@@ -473,7 +538,7 @@ class Table(object):
(subdir, filename, offset, count) = self._offset_from_row(row) (subdir, filename, offset, count) = self._offset_from_row(row)
if count > remaining: if count > remaining:
count = remaining count = remaining
row_offset = offset // self.packer.size row_offset = offset // self.row_size
# Mark the rows as being removed # Mark the rows as being removed
self._remove_rows(subdir, filename, row_offset, row_offset + count) self._remove_rows(subdir, filename, row_offset, row_offset + count)
remaining -= count remaining -= count

View File

@@ -19,6 +19,8 @@ Intervals are half-open, ie. they include data points with timestamps
# Fourth version is an optimized rb-tree that stores interval starts # Fourth version is an optimized rb-tree that stores interval starts
# and ends directly in the tree, like bxinterval did. # and ends directly in the tree, like bxinterval did.
from ..utils.time import float_time_to_string as ftts
cimport rbtree cimport rbtree
cdef extern from "stdint.h": cdef extern from "stdint.h":
ctypedef unsigned long long uint64_t ctypedef unsigned long long uint64_t
@@ -47,7 +49,7 @@ cdef class Interval:
return self.__class__.__name__ + "(" + s + ")" return self.__class__.__name__ + "(" + s + ")"
def __str__(self): def __str__(self):
return "[" + repr(self.start) + " -> " + repr(self.end) + ")" return "[" + ftts(self.start) + " -> " + ftts(self.end) + ")"
def __cmp__(self, Interval other): def __cmp__(self, Interval other):
"""Compare two intervals. If non-equal, order by start then end""" """Compare two intervals. If non-equal, order by start then end"""

View File

@@ -4,7 +4,6 @@ import time
import sys import sys
import inspect import inspect
import cStringIO import cStringIO
import numpy as np
cdef enum: cdef enum:
max_value_count = 64 max_value_count = 64
@@ -42,10 +41,16 @@ class Layout:
if datatype == 'uint16': if datatype == 'uint16':
self.parse = self.parse_uint16 self.parse = self.parse_uint16
self.format = self.format_uint16 self.format_str = "%.6f" + " %d" * self.count
elif datatype == 'float32' or datatype == 'float64': self.format = self.format_generic
elif datatype == 'float32':
self.parse = self.parse_float64 self.parse = self.parse_float64
self.format = self.format_float64 self.format_str = "%.6f" + " %.6e" * self.count
self.format = self.format_generic
elif datatype == 'float64':
self.parse = self.parse_float64
self.format_str = "%.6f" + " %.16e" * self.count
self.format = self.format_generic
else: else:
raise KeyError("invalid type") raise KeyError("invalid type")
@@ -57,15 +62,15 @@ class Layout:
cdef double ts cdef double ts
# Return doubles even in float32 case, since they're going into # Return doubles even in float32 case, since they're going into
# a Python array which would upconvert to double anyway. # a Python array which would upconvert to double anyway.
result = [] result = [0] * (self.count + 1)
cdef char *end cdef char *end
ts = libc.stdlib.strtod(text, &end) ts = libc.stdlib.strtod(text, &end)
if end == text: if end == text:
raise ValueError("bad timestamp") raise ValueError("bad timestamp")
result.append(ts) result[0] = ts
for n in range(self.count): for n in range(self.count):
text = end text = end
result.append(libc.stdlib.strtod(text, &end)) result[n+1] = libc.stdlib.strtod(text, &end)
if end == text: if end == text:
raise ValueError("wrong number of values") raise ValueError("wrong number of values")
n = 0 n = 0
@@ -79,18 +84,18 @@ class Layout:
cdef int n cdef int n
cdef double ts cdef double ts
cdef int v cdef int v
result = []
cdef char *end cdef char *end
result = [0] * (self.count + 1)
ts = libc.stdlib.strtod(text, &end) ts = libc.stdlib.strtod(text, &end)
if end == text: if end == text:
raise ValueError("bad timestamp") raise ValueError("bad timestamp")
result.append(ts) result[0] = ts
for n in range(self.count): for n in range(self.count):
text = end text = end
v = libc.stdlib.strtol(text, &end, 10) v = libc.stdlib.strtol(text, &end, 10)
if v < 0 or v > 65535: if v < 0 or v > 65535:
raise ValueError("value out of range") raise ValueError("value out of range")
result.append(v) result[n+1] = v
if end == text: if end == text:
raise ValueError("wrong number of values") raise ValueError("wrong number of values")
n = 0 n = 0
@@ -101,25 +106,12 @@ class Layout:
return (ts, result) return (ts, result)
# Formatters # Formatters
def format_float64(self, d): def format_generic(self, d):
n = len(d) - 1 n = len(d) - 1
if n != self.count: if n != self.count:
raise ValueError("wrong number of values for layout type: " raise ValueError("wrong number of values for layout type: "
"got %d, wanted %d" % (n, self.count)) "got %d, wanted %d" % (n, self.count))
s = "%.6f" % d[0] return (self.format_str % tuple(d)) + "\n"
for i in range(n):
s += " %f" % d[i+1]
return s + "\n"
def format_uint16(self, d):
n = len(d) - 1
if n != self.count:
raise ValueError("wrong number of values for layout type: "
"got %d, wanted %d" % (n, self.count))
s = "%.6f" % d[0]
for i in range(n):
s += " %d" % d[i+1]
return s + "\n"
# Get a layout by name # Get a layout by name
def get_named(typestring): def get_named(typestring):

View File

@@ -10,7 +10,7 @@ Manages both the SQL database and the table storage backend.
# Need absolute_import so that "import nilmdb" won't pull in # Need absolute_import so that "import nilmdb" won't pull in
# nilmdb.py, but will pull the parent nilmdb module instead. # nilmdb.py, but will pull the parent nilmdb module instead.
from __future__ import absolute_import from __future__ import absolute_import
import nilmdb import nilmdb.utils
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.server.interval import (Interval, DBInterval, from nilmdb.server.interval import (Interval, DBInterval,
IntervalSet, IntervalError) IntervalSet, IntervalError)
@@ -31,11 +31,9 @@ import bisect
# after a series of INSERT, SELECT, but before a CREATE TABLE or PRAGMA. # after a series of INSERT, SELECT, but before a CREATE TABLE or PRAGMA.
# 3: at the end of an explicit transaction, e.g. "with self.con as con:" # 3: at the end of an explicit transaction, e.g. "with self.con as con:"
# #
# To speed up testing, or if this transaction speed becomes an issue, # To speed things up, we can set 'PRAGMA synchronous=OFF'. Or, it
# the sync=False option to NilmDB.__init__ will set PRAGMA synchronous=OFF. # seems that 'PRAGMA synchronous=NORMAL' and 'PRAGMA journal_mode=WAL'
# give an equivalent speedup more safely. That is what is used here.
# Don't touch old entries -- just add new ones.
_sql_schema_updates = { _sql_schema_updates = {
0: """ 0: """
-- All streams -- All streams
@@ -77,7 +75,7 @@ _sql_schema_updates = {
class NilmDB(object): class NilmDB(object):
verbose = 0 verbose = 0
def __init__(self, basepath, sync=True, max_results=None, def __init__(self, basepath, max_results=None,
bulkdata_args=None): bulkdata_args=None):
if bulkdata_args is None: if bulkdata_args is None:
bulkdata_args = {} bulkdata_args = {}
@@ -101,10 +99,8 @@ class NilmDB(object):
self._sql_schema_update() self._sql_schema_update()
# See big comment at top about the performance implications of this # See big comment at top about the performance implications of this
if sync: self.con.execute("PRAGMA synchronous=NORMAL")
self.con.execute("PRAGMA synchronous=FULL") self.con.execute("PRAGMA journal_mode=WAL")
else:
self.con.execute("PRAGMA synchronous=OFF")
# Approximate largest number of elements that we want to send # Approximate largest number of elements that we want to send
# in a single reply (for stream_intervals, stream_extract) # in a single reply (for stream_intervals, stream_extract)
@@ -269,28 +265,46 @@ class NilmDB(object):
return return
def stream_list(self, path = None, layout = None): def stream_list(self, path = None, layout = None, extended = False):
"""Return list of [path, layout] lists of all streams """Return list of lists of all streams in the database.
in the database.
If path is specified, include only streams with a path that If path is specified, include only streams with a path that
matches the given string. matches the given string.
If layout is specified, include only streams with a layout If layout is specified, include only streams with a layout
that matches the given string. that matches the given string.
"""
where = "WHERE 1=1"
params = ()
if layout:
where += " AND layout=?"
params += (layout,)
if path:
where += " AND path=?"
params += (path,)
result = self.con.execute("SELECT path, layout "
"FROM streams " + where, params).fetchall()
return sorted(list(x) for x in result) If extended = False, returns a list of lists containing
the path and layout: [ path, layout ]
If extended = True, returns a list of lists containing
more information:
path
layout
interval_min (earliest interval start)
interval_max (latest interval end)
rows (total number of rows of data)
seconds (total time covered by this stream)
"""
params = ()
query = "SELECT streams.path, streams.layout"
if extended:
query += ", min(ranges.start_time), max(ranges.end_time) "
query += ", sum(ranges.end_pos - ranges.start_pos) "
query += ", sum(ranges.end_time - ranges.start_time) "
query += " FROM streams"
if extended:
query += " LEFT JOIN ranges ON streams.id = ranges.stream_id"
query += " WHERE 1=1"
if layout is not None:
query += " AND streams.layout=?"
params += (layout,)
if path is not None:
query += " AND streams.path=?"
params += (path,)
query += " GROUP BY streams.id ORDER BY streams.path"
result = self.con.execute(query, params).fetchall()
return [ list(x) for x in result ]
def stream_intervals(self, path, start = None, end = None): def stream_intervals(self, path, start = None, end = None):
""" """
@@ -401,8 +415,7 @@ class NilmDB(object):
path: Path at which to add the data path: Path at which to add the data
start: Starting timestamp start: Starting timestamp
end: Ending timestamp end: Ending timestamp
data: Rows of data, to be passed to bulkdata table.append data: Textual data, formatted according to the layout of path
method. E.g. nilmdb.layout.Parser.data
""" """
# First check for basic overlap using timestamp info given. # First check for basic overlap using timestamp info given.
stream_id = self._stream_id(path) stream_id = self._stream_id(path)
@@ -412,10 +425,11 @@ class NilmDB(object):
raise OverlapError("new data overlaps existing data at range: " raise OverlapError("new data overlaps existing data at range: "
+ str(iset & interval)) + str(iset & interval))
# Insert the data # Tenatively append the data. This will raise a ValueError if
# there are any parse errors.
table = self.data.getnode(path) table = self.data.getnode(path)
row_start = table.nrows row_start = table.nrows
table.append(data) table.append_string(data, start, end)
row_end = table.nrows row_end = table.nrows
# Insert the record into the sql database. # Insert the record into the sql database.
@@ -462,9 +476,8 @@ class NilmDB(object):
""" """
Returns (data, restart) tuple. Returns (data, restart) tuple.
data is a list of raw data from the database, suitable for data is ASCII-formatted data from the database, formatted
passing to e.g. nilmdb.layout.Formatter to translate into according to the layout of the stream.
textual form.
restart, if nonzero, means that there were too many results to restart, if nonzero, means that there were too many results to
return in a single request. The data is complete from the return in a single request. The data is complete from the
@@ -505,7 +518,7 @@ class NilmDB(object):
restart = table[row_max][0] restart = table[row_max][0]
# Gather these results up # Gather these results up
result.extend(table[row_start:row_end]) result.append(table.get_as_text(row_start, row_end))
# Count them # Count them
remaining -= row_end - row_start remaining -= row_end - row_start
@@ -515,7 +528,7 @@ class NilmDB(object):
if count: if count:
return matched return matched
return (result, restart) return ("".join(result), restart)
def stream_remove(self, path, start = None, end = None): def stream_remove(self, path, start = None, end = None):
""" """

143
nilmdb/server/pyrocket.py Normal file
View File

@@ -0,0 +1,143 @@
# Python implementation of the "rocket" data parsing interface.
# This interface translates between the binary format on disk
# and the ASCII format used when communicating with clients.
# This is slow! Use the C version instead.
from __future__ import absolute_import
import struct
import cStringIO
import itertools
from . import layout as _layout
import nilmdb.utils
from nilmdb.utils.time import float_time_to_string as ftts
ERR_UNKNOWN = 0
ERR_NON_MONOTONIC = 1
ERR_OUT_OF_INTERVAL = 2
class ParseError(Exception):
pass
@nilmdb.utils.must_close(wrap_verify = False)
class Rocket(object):
def __init__(self, layout, filename):
self.layout = layout
if filename:
self.file = open(filename, "a+b")
else:
self.file = None
# For packing/unpacking into a binary file.
# This will change in the C version
try:
(self.ltype, lcount) = layout.split('_', 2)
self.lcount = int(lcount)
except:
raise ValueError("no such layout: badly formatted string")
if self.lcount < 1:
raise ValueError("no such layout: bad count")
try:
struct_fmt = '<d' # Little endian, double timestamp
struct_mapping = {
"int8": 'b',
"uint8": 'B',
"int16": 'h',
"uint16": 'H',
"int32": 'i',
"uint32": 'I',
"int64": 'q',
"uint64": 'Q',
"float32": 'f',
"float64": 'd',
}
struct_fmt += struct_mapping[self.ltype] * self.lcount
except KeyError:
raise ValueError("no such layout: bad data type")
self.packer = struct.Struct(struct_fmt)
# For packing/unpacking from strings.
self.layoutparser = _layout.Layout(self.layout)
self.formatter = _layout.Formatter(self.layout)
def close(self):
if self.file:
self.file.close()
@property
def binary_size(self):
"""Return size of one row of data in the binary file, in bytes"""
return self.packer.size
def append_iter(self, maxrows, data):
"""Append the list data to the file"""
# We assume the file is opened in append mode,
# so all writes go to the end.
written = 0
for row in itertools.islice(data, maxrows):
self.file.write(self.packer.pack(*row))
written += 1
self.file.flush()
return written
def append_string(self, count, data, data_offset, linenum,
start, end, last_timestamp):
"""Parse string and append data.
count: maximum number of rows to add
data: string data
data_offset: byte offset into data to start parsing
linenum: current line number of data
start: starting timestamp for interval
end: end timestamp for interval
last_timestamp: last timestamp that was previously parsed
Raises ParseError if timestamps are non-monotonic, outside the
start/end interval, etc.
On success, return a tuple with three values:
added_rows: how many rows were added from the file
data_offset: current offset into the data string
last_timestamp: last timestamp we parsed
"""
# Parse the input data
indata = cStringIO.StringIO(data)
indata.seek(data_offset)
written = 0
while written < count:
line = indata.readline()
linenum += 1
if line == "":
break
comment = line.find('#')
if comment >= 0:
line = line.split('#', 1)[0]
line = line.strip()
if line == "":
continue
try:
(ts, row) = self.layoutparser.parse(line)
except ValueError as e:
raise ParseError(linenum, ERR_UNKNOWN, e)
if ts <= last_timestamp:
raise ParseError(linenum, ERR_NON_MONOTONIC, ts)
last_timestamp = ts
if ts < start or ts >= end:
raise ParseError(linenum, ERR_OUT_OF_INTERVAL, ts)
self.append_iter(1, [row])
written += 1
return (written, indata.tell(), last_timestamp, linenum)
def extract_list(self, offset, count):
"""Extract count rows of data from the file at offset offset.
Return a list of lists [[row],[row],...]"""
ret = []
self.file.seek(offset)
for i in xrange(count):
data = self.file.read(self.binary_size)
ret.append(list(self.packer.unpack(data)))
return ret
def extract_string(self, offset, count):
"""Extract count rows of data from the file at offset offset.
Return an ascii formatted string according to the layout"""
return self.formatter.format(self.extract_list(offset, count))

789
nilmdb/server/rocket.c Normal file
View File

@@ -0,0 +1,789 @@
#include <Python.h>
#include <structmember.h>
#include <endian.h>
#include <stdint.h>
/* Values missing from stdint.h */
#define UINT8_MIN 0
#define UINT16_MIN 0
#define UINT32_MIN 0
#define UINT64_MIN 0
/* Marker values (if min == max, skip range check) */
#define FLOAT32_MIN 0
#define FLOAT32_MAX 0
#define FLOAT64_MIN 0
#define FLOAT64_MAX 0
/* Somewhat arbitrary, just so we can use fixed sizes for strings
etc. */
static const int MAX_LAYOUT_COUNT = 64;
/* Error object and constants */
static PyObject *ParseError;
typedef enum {
ERR_OTHER,
ERR_NON_MONOTONIC,
ERR_OUT_OF_INTERVAL,
} parseerror_code_t;
static void add_parseerror_codes(PyObject *module)
{
PyModule_AddIntMacro(module, ERR_OTHER);
PyModule_AddIntMacro(module, ERR_NON_MONOTONIC);
PyModule_AddIntMacro(module, ERR_OUT_OF_INTERVAL);
}
/* Helpers to raise ParseErrors. Use "return raise_str(...)" etc. */
static PyObject *raise_str(int linenum, int code, const char *string)
{
PyObject *o;
o = Py_BuildValue("(iis)", linenum, code, string);
if (o != NULL) {
PyErr_SetObject(ParseError, o);
Py_DECREF(o);
}
return NULL;
}
static PyObject *raise_num(int linenum, int code, double num)
{
PyObject *o;
o = Py_BuildValue("(iid)", linenum, code, num);
if (o != NULL) {
PyErr_SetObject(ParseError, o);
Py_DECREF(o);
}
return NULL;
}
/****
* Layout and type helpers
*/
typedef union {
int8_t i;
uint8_t u;
} union8_t;
typedef union {
int16_t i;
uint16_t u;
} union16_t;
typedef union {
int32_t i;
uint32_t u;
float f;
} union32_t;
typedef union {
int64_t i;
uint64_t u;
double d;
} union64_t;
typedef enum {
LAYOUT_TYPE_NONE,
LAYOUT_TYPE_INT8,
LAYOUT_TYPE_UINT8,
LAYOUT_TYPE_INT16,
LAYOUT_TYPE_UINT16,
LAYOUT_TYPE_INT32,
LAYOUT_TYPE_UINT32,
LAYOUT_TYPE_INT64,
LAYOUT_TYPE_UINT64,
LAYOUT_TYPE_FLOAT32,
LAYOUT_TYPE_FLOAT64,
} layout_type_t;
struct {
char *string;
layout_type_t layout;
int size;
} type_lookup[] = {
{ "int8", LAYOUT_TYPE_INT8, 1 },
{ "uint8", LAYOUT_TYPE_UINT8, 1 },
{ "int16", LAYOUT_TYPE_INT16, 2 },
{ "uint16", LAYOUT_TYPE_UINT16, 2 },
{ "int32", LAYOUT_TYPE_INT32, 4 },
{ "uint32", LAYOUT_TYPE_UINT32, 4 },
{ "int64", LAYOUT_TYPE_INT64, 8 },
{ "uint64", LAYOUT_TYPE_UINT64, 8 },
{ "float32", LAYOUT_TYPE_FLOAT32, 4 },
{ "float64", LAYOUT_TYPE_FLOAT64, 8 },
{ NULL }
};
/****
* Object definition, init, etc
*/
/* Rocket object */
typedef struct {
PyObject_HEAD
layout_type_t layout_type;
int layout_count;
int binary_size;
FILE *file;
int file_size;
} Rocket;
/* Dealloc / new */
static void Rocket_dealloc(Rocket *self)
{
if (self->file) {
fprintf(stderr, "rocket: file wasn't closed\n");
fclose(self->file);
self->file = NULL;
}
self->ob_type->tp_free((PyObject *)self);
}
static PyObject *Rocket_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Rocket *self;
self = (Rocket *)type->tp_alloc(type, 0);
if (!self)
return NULL;
self->layout_type = LAYOUT_TYPE_NONE;
self->layout_count = 0;
self->binary_size = 0;
self->file = NULL;
self->file_size = -1;
return (PyObject *)self;
}
/* .__init__(layout, file) */
static int Rocket_init(Rocket *self, PyObject *args, PyObject *kwds)
{
const char *layout, *path;
static char *kwlist[] = { "layout", "file", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sz", kwlist,
&layout, &path))
return -1;
if (!layout)
return -1;
if (path) {
if ((self->file = fopen(path, "a+b")) == NULL) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
self->file_size = -1;
} else {
self->file = NULL;
}
const char *under;
char *tmp;
under = strchr(layout, '_');
if (!under) {
PyErr_SetString(PyExc_ValueError, "no such layout: "
"badly formatted string");
return -1;
}
self->layout_count = strtoul(under+1, &tmp, 10);
if (self->layout_count < 1 || *tmp != '\0') {
PyErr_SetString(PyExc_ValueError, "no such layout: "
"bad count");
return -1;
}
if (self->layout_count >= MAX_LAYOUT_COUNT) {
PyErr_SetString(PyExc_ValueError, "no such layout: "
"count too high");
return -1;
}
int i;
for (i = 0; type_lookup[i].string; i++)
if (strncmp(layout, type_lookup[i].string, under-layout) == 0)
break;
if (!type_lookup[i].string) {
PyErr_SetString(PyExc_ValueError, "no such layout: "
"bad data type");
return -1;
}
self->layout_type = type_lookup[i].layout;
self->binary_size = 8 + (type_lookup[i].size * self->layout_count);
return 0;
}
/* .close() */
static PyObject *Rocket_close(Rocket *self)
{
if (self->file) {
fclose(self->file);
self->file = NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* .file_size property */
static PyObject *Rocket_get_file_size(Rocket *self)
{
if (!self->file) {
PyErr_SetString(PyExc_AttributeError, "no file");
return NULL;
}
if (self->file_size < 0) {
int oldpos;
if (((oldpos = ftell(self->file)) < 0) ||
(fseek(self->file, 0, SEEK_END) < 0) ||
((self->file_size = ftell(self->file)) < 0) ||
(fseek(self->file, oldpos, SEEK_SET) < 0)) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
}
return PyInt_FromLong(self->file_size);
}
/****
* Append from iterator
*/
/* Helper for writing Python objects to the file */
static inline void append_pyobject(FILE *out, PyObject *val, layout_type_t type)
{
union8_t t8;
union16_t t16;
union32_t t32;
union64_t t64;
int ret = 0;
switch (type) {
#define CASE(type, pyconvert, pytype, disktype, htole, bytes) \
case LAYOUT_TYPE_##type: \
pytype = pyconvert(val); \
if (PyErr_Occurred()) \
return; \
disktype = htole(disktype); \
ret = fwrite(&disktype, bytes, 1, out); \
break
CASE(INT8, PyInt_AsLong, t8.i, t8.u, , 1);
CASE(UINT8, PyInt_AsLong, t8.u, t8.u, , 1);
CASE(INT16, PyInt_AsLong, t16.i, t16.u, htole16, 2);
CASE(UINT16, PyInt_AsLong, t16.u, t16.u, htole16, 2);
CASE(INT32, PyInt_AsLong, t32.i, t32.u, htole32, 4);
CASE(UINT32, PyInt_AsLong, t32.u, t32.u, htole32, 4);
CASE(INT64, PyInt_AsLong, t64.i, t64.u, htole64, 8);
CASE(UINT64, PyInt_AsLong, t64.u, t64.u, htole64, 8);
CASE(FLOAT32, PyFloat_AsDouble, t32.f, t32.u, htole32, 4);
CASE(FLOAT64, PyFloat_AsDouble, t64.d, t64.u, htole64, 8);
#undef CASE
default:
PyErr_SetString(PyExc_TypeError, "unknown type");
return;
}
if (ret <= 0) {
PyErr_SetFromErrno(PyExc_OSError);
}
}
/* .append_iter(maxrows, dataiter) */
static PyObject *Rocket_append_iter(Rocket *self, PyObject *args)
{
int maxrows;
PyObject *iter;
PyObject *rowlist;
if (!PyArg_ParseTuple(args, "iO:append_iter", &maxrows, &iter))
return NULL;
if (!PyIter_Check(iter)) {
PyErr_SetString(PyExc_TypeError, "need an iterable");
return NULL;
}
if (!self->file) {
PyErr_SetString(PyExc_Exception, "no file");
return NULL;
}
/* Mark file size so that it will get updated next time it's read */
self->file_size = -1;
int row;
for (row = 0; row < maxrows; row++) {
rowlist = PyIter_Next(iter);
if (!rowlist)
break;
if (!PyList_Check(rowlist)) {
PyErr_SetString(PyExc_TypeError, "rows must be lists");
goto row_err;
}
if (PyList_Size(rowlist) != self->layout_count + 1) {
PyErr_SetString(PyExc_TypeError, "short row");
goto row_err;
}
/* Extract and write timestamp */
append_pyobject(self->file, PyList_GetItem(rowlist, 0),
LAYOUT_TYPE_FLOAT64);
if (PyErr_Occurred())
goto row_err;
/* Extract and write values */
int i;
for (i = 0; i < self->layout_count; i++) {
append_pyobject(self->file,
PyList_GetItem(rowlist, i+1),
self->layout_type);
if (PyErr_Occurred())
goto row_err;
}
}
fflush(self->file);
/* All done */
return PyLong_FromLong(row);
row_err:
fflush(self->file);
Py_DECREF(rowlist);
return NULL;
}
/****
* Append from string
*/
static inline long int strtol10(const char *nptr, char **endptr) {
return strtol(nptr, endptr, 10);
}
static inline long int strtoul10(const char *nptr, char **endptr) {
return strtoul(nptr, endptr, 10);
}
/* .append_string(count, data, offset, linenum, start, end, last_timestamp) */
static PyObject *Rocket_append_string(Rocket *self, PyObject *args)
{
int count;
const char *data;
int offset;
int linenum;
double start;
double end;
double last_timestamp;
int written = 0;
char *endptr;
union8_t t8;
union16_t t16;
union32_t t32;
union64_t t64;
int i;
/* It would be nice to use 't#' instead of 's' for data,
but we need the null termination for strto*. If we had
strnto* that took a length, we could use t# and not require
a copy. */
if (!PyArg_ParseTuple(args, "isiiddd:append_string", &count,
&data, &offset, &linenum,
&start, &end, &last_timestamp))
return NULL;
const char *buf = &data[offset];
while (written < count && *buf)
{
linenum++;
/* Skip leading whitespace and commented lines */
while (*buf == ' ' || *buf == '\t')
buf++;
if (*buf == '#') {
while (*buf && *buf != '\n')
buf++;
if (*buf)
buf++;
continue;
}
/* Extract timestamp */
t64.d = strtod(buf, &endptr);
if (endptr == buf)
return raise_str(linenum, ERR_OTHER, "bad timestamp");
if (t64.d <= last_timestamp)
return raise_num(linenum, ERR_NON_MONOTONIC, t64.d);
last_timestamp = t64.d;
if (t64.d < start || t64.d >= end)
return raise_num(linenum, ERR_OUT_OF_INTERVAL, t64.d);
t64.u = le64toh(t64.u);
if (fwrite(&t64.u, 8, 1, self->file) != 1)
goto err;
buf = endptr;
/* Parse all values in the line */
switch (self->layout_type) {
#define CS(type, parsefunc, parsetype, realtype, disktype, letoh, bytes) \
case LAYOUT_TYPE_##type: \
/* parse and write in a loop */ \
for (i = 0; i < self->layout_count; i++) { \
parsetype = parsefunc(buf, &endptr); \
if (endptr == buf) \
goto wrong_number_of_values; \
if (type##_MIN != type##_MAX && \
(parsetype < type##_MIN || \
parsetype > type##_MAX)) \
goto value_out_of_range; \
realtype = parsetype; \
disktype = letoh(disktype); \
if (fwrite(&disktype, bytes, \
1, self->file) != 1) \
goto err; \
buf = endptr; \
} \
/* Skip trailing whitespace and comments */ \
while (*buf == ' ' || *buf == '\t') \
buf++; \
if (*buf == '#') \
while (*buf && *buf != '\n') \
buf++; \
if (*buf == '\n') \
buf++; \
else if (*buf != '\0') \
goto extra_data_on_line; \
break
CS(INT8, strtol10, t64.i, t8.i, t8.u, , 1);
CS(UINT8, strtoul10, t64.u, t8.u, t8.u, , 1);
CS(INT16, strtol10, t64.i, t16.i, t16.u, le16toh, 2);
CS(UINT16, strtoul10, t64.u, t16.u, t16.u, le16toh, 2);
CS(INT32, strtol10, t64.i, t32.i, t32.u, le32toh, 4);
CS(UINT32, strtoul10, t64.u, t32.u, t32.u, le32toh, 4);
CS(INT64, strtol10, t64.i, t64.i, t64.u, le64toh, 8);
CS(UINT64, strtoul10, t64.u, t64.u, t64.u, le64toh, 8);
CS(FLOAT32, strtod, t64.d, t32.f, t32.u, le32toh, 4);
CS(FLOAT64, strtod, t64.d, t64.d, t64.u, le64toh, 8);
#undef CS
default:
PyErr_SetString(PyExc_TypeError, "unknown type");
return NULL;
}
/* Done this line */
written++;
}
fflush(self->file);
/* Build return value and return*/
offset = buf - data;
PyObject *o;
o = Py_BuildValue("(iidi)", written, offset, last_timestamp, linenum);
return o;
err:
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
wrong_number_of_values:
return raise_str(linenum, ERR_OTHER, "wrong number of values");
value_out_of_range:
return raise_str(linenum, ERR_OTHER, "value out of range");
extra_data_on_line:
return raise_str(linenum, ERR_OTHER, "extra data on line");
}
/****
* Extract to Python list
*/
static int _extract_handle_params(Rocket *self, PyObject *args, long *count)
{
long offset;
if (!PyArg_ParseTuple(args, "ll", &offset, count))
return -1;
if (!self->file) {
PyErr_SetString(PyExc_Exception, "no file");
return -1;
}
/* Seek to target location */
if (fseek(self->file, offset, SEEK_SET) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
return 0;
}
/* Helper for extracting data from a file as a Python object */
static inline void *extract_pyobject(FILE *in, layout_type_t type)
{
union8_t t8;
union16_t t16;
union32_t t32;
union64_t t64;
switch (type) {
#define CASE(type, pyconvert, pytype, disktype, letoh, bytes) \
case LAYOUT_TYPE_##type: \
if (fread(&disktype, bytes, 1, in) <= 0) \
break; \
disktype = letoh(disktype); \
return pyconvert(pytype); \
break
CASE(INT8, PyInt_FromLong, t8.i, t8.u, , 1);
CASE(UINT8, PyInt_FromLong, t8.u, t8.u, , 1);
CASE(INT16, PyInt_FromLong, t16.i, t16.u, le16toh, 2);
CASE(UINT16, PyInt_FromLong, t16.u, t16.u, le16toh, 2);
CASE(INT32, PyInt_FromLong, t32.i, t32.u, le32toh, 4);
CASE(UINT32, PyInt_FromLong, t32.u, t32.u, le32toh, 4);
CASE(INT64, PyInt_FromLong, t64.i, t64.u, le64toh, 8);
CASE(UINT64, PyInt_FromLong, t64.u, t64.u, le64toh, 8);
CASE(FLOAT32, PyFloat_FromDouble, t32.f, t32.u, le32toh, 4);
CASE(FLOAT64, PyFloat_FromDouble, t64.d, t64.u, le64toh, 8);
#undef CASE
default:
PyErr_SetString(PyExc_TypeError, "unknown type");
return NULL;
}
PyErr_SetString(PyExc_OSError, "failed to read from file");
return NULL;
}
static PyObject *Rocket_extract_list(Rocket *self, PyObject *args)
{
long count;
if (_extract_handle_params(self, args, &count) < 0)
return NULL;
/* Make a list to return */
PyObject *retlist = PyList_New(0);
if (!retlist)
return NULL;
/* Read data into new Python lists */
int row;
for (row = 0; row < count; row++)
{
PyObject *rowlist = PyList_New(self->layout_count + 1);
if (!rowlist) {
Py_DECREF(retlist);
return NULL;
}
/* Timestamp */
PyObject *entry = extract_pyobject(self->file,
LAYOUT_TYPE_FLOAT64);
if (!entry || (PyList_SetItem(rowlist, 0, entry) < 0)) {
Py_DECREF(rowlist);
Py_DECREF(retlist);
return NULL;
}
/* Data */
int i;
for (i = 0; i < self->layout_count; i++) {
PyObject *ent = extract_pyobject(self->file,
self->layout_type);
if (!ent || (PyList_SetItem(rowlist, i+1, ent) < 0)) {
Py_DECREF(rowlist);
Py_DECREF(retlist);
return NULL;
}
}
/* Add row to return value */
if (PyList_Append(retlist, rowlist) < 0) {
Py_DECREF(rowlist);
Py_DECREF(retlist);
return NULL;
}
Py_DECREF(rowlist);
}
return retlist;
}
/****
* Extract to string
*/
static PyObject *Rocket_extract_string(Rocket *self, PyObject *args)
{
long count;
if (_extract_handle_params(self, args, &count) < 0)
return NULL;
char *str = NULL, *new;
long len_alloc = 0;
long len = 0;
int ret;
/* min space free in string (and the maximum length of one
line); this is generous */
const int min_free = 32 * MAX_LAYOUT_COUNT;
/* how much to allocate at once */
const int alloc_size = 1048576;
int row, i;
union8_t t8;
union16_t t16;
union32_t t32;
union64_t t64;
for (row = 0; row < count; row++) {
/* Make sure there's space for a line */
if ((len_alloc - len) < min_free) {
/* grow by 1 meg at a time */
len_alloc += alloc_size;
new = realloc(str, len_alloc);
if (new == NULL)
goto err;
str = new;
}
/* Read and print timestamp */
if (fread(&t64.u, 8, 1, self->file) != 1)
goto err;
t64.u = le64toh(t64.u);
/* Timestamps are always printed to the microsecond */
ret = sprintf(&str[len], "%.6f", t64.d);
if (ret <= 0)
goto err;
len += ret;
/* Read and print values */
switch (self->layout_type) {
#define CASE(type, fmt, fmttype, disktype, letoh, bytes) \
case LAYOUT_TYPE_##type: \
/* read and format in a loop */ \
for (i = 0; i < self->layout_count; i++) { \
if (fread(&disktype, bytes, \
1, self->file) < 0) \
goto err; \
disktype = letoh(disktype); \
ret = sprintf(&str[len], " " fmt, \
fmttype); \
if (ret <= 0) \
goto err; \
len += ret; \
} \
break
CASE(INT8, "%hhd", t8.i, t8.u, , 1);
CASE(UINT8, "%hhu", t8.u, t8.u, , 1);
CASE(INT16, "%hd", t16.i, t16.u, le16toh, 2);
CASE(UINT16, "%hu", t16.u, t16.u, le16toh, 2);
CASE(INT32, "%d", t32.i, t32.u, le32toh, 4);
CASE(UINT32, "%u", t32.u, t32.u, le32toh, 4);
CASE(INT64, "%ld", t64.i, t64.u, le64toh, 8);
CASE(UINT64, "%lu", t64.u, t64.u, le64toh, 8);
/* These next two are a bit debatable. floats
are 6-9 significant figures, so we print 7.
Doubles are 15-19, so we print 17. This is
similar to the old prep format for float32.
*/
CASE(FLOAT32, "%.6e", t32.f, t32.u, le32toh, 4);
CASE(FLOAT64, "%.16e", t64.d, t64.u, le64toh, 8);
#undef CASE
default:
PyErr_SetString(PyExc_TypeError, "unknown type");
if (str) free(str);
return NULL;
}
str[len++] = '\n';
}
PyObject *pystr = PyString_FromStringAndSize(str, len);
free(str);
return pystr;
err:
if (str) free(str);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
/****
* Module and type setup
*/
static PyGetSetDef Rocket_getsetters[] = {
{ "file_size", (getter)Rocket_get_file_size, NULL,
"file size in bytes", NULL },
{ NULL },
};
static PyMemberDef Rocket_members[] = {
{ "binary_size", T_INT, offsetof(Rocket, binary_size), 0,
"binary size per row" },
{ NULL },
};
static PyMethodDef Rocket_methods[] = {
{ "close", (PyCFunction)Rocket_close, METH_NOARGS,
"close(self)\n\n"
"Close file handle" },
{ "append_iter", (PyCFunction)Rocket_append_iter, METH_VARARGS,
"append_iter(self, maxrows, iterable)\n\n"
"Append up to maxrows of data from iter to the file" },
{ "append_string", (PyCFunction)Rocket_append_string, METH_VARARGS,
"append_string(self, count, data, offset, line, start, end, ts)\n\n"
"Parse string and append data.\n"
"\n"
" count: maximum number of rows to add\n"
" data: string data\n"
" offset: byte offset into data to start parsing\n"
" line: current line number of data\n"
" start: starting timestamp for interval\n"
" end: end timestamp for interval\n"
" ts: last timestamp that was previously parsed\n"
"\n"
"Raises ParseError if timestamps are non-monotonic, outside\n"
"the start/end interval etc.\n"
"\n"
"On success, return a tuple with three values:\n"
" added_rows: how many rows were added from the file\n"
" data_offset: current offset into the data string\n"
" last_timestamp: last timestamp we parsed" },
{ "extract_list", (PyCFunction)Rocket_extract_list, METH_VARARGS,
"extract_list(self, offset, count)\n\n"
"Extract count rows of data from the file at offset offset.\n"
"Return a list of lists [[row],[row],...]" },
{ "extract_string", (PyCFunction)Rocket_extract_string, METH_VARARGS,
"extract_string(self, offset, count)\n\n"
"Extract count rows of data from the file at offset offset.\n"
"Return an ascii formatted string according to the layout" },
{ NULL },
};
static PyTypeObject RocketType = {
PyObject_HEAD_INIT(NULL)
.tp_name = "rocket.Rocket",
.tp_basicsize = sizeof(Rocket),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Rocket_new,
.tp_dealloc = (destructor)Rocket_dealloc,
.tp_init = (initproc)Rocket_init,
.tp_methods = Rocket_methods,
.tp_members = Rocket_members,
.tp_getset = Rocket_getsetters,
.tp_doc = ("rocket.Rocket(layout, file)\n\n"
"C implementation of the \"rocket\" data parsing\n"
"interface, which translates between the binary\n"
"format on disk and the ASCII or Python list\n"
"format used when communicating with the rest of\n"
"the system.")
};
static PyMethodDef module_methods[] = {
{ NULL },
};
PyMODINIT_FUNC
initrocket(void)
{
PyObject *module;
RocketType.tp_new = PyType_GenericNew;
if (PyType_Ready(&RocketType) < 0)
return;
module = Py_InitModule3("rocket", module_methods,
"Rocket data parsing and formatting module");
Py_INCREF(&RocketType);
PyModule_AddObject(module, "Rocket", (PyObject *)&RocketType);
ParseError = PyErr_NewException("rocket.ParseError", NULL, NULL);
Py_INCREF(ParseError);
PyModule_AddObject(module, "ParseError", ParseError);
add_parseerror_codes(module);
return;
}

View File

@@ -3,7 +3,7 @@
# Need absolute_import so that "import nilmdb" won't pull in # Need absolute_import so that "import nilmdb" won't pull in
# nilmdb.py, but will pull the nilmdb module instead. # nilmdb.py, but will pull the nilmdb module instead.
from __future__ import absolute_import from __future__ import absolute_import
import nilmdb import nilmdb.server
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.server.errors import NilmDBError from nilmdb.server.errors import NilmDBError
@@ -12,7 +12,6 @@ import sys
import os import os
import simplejson as json import simplejson as json
import decorator import decorator
import traceback
import psutil import psutil
class NilmApp(object): class NilmApp(object):
@@ -45,12 +44,17 @@ def workaround_cp_bug_1200(func, *args, **kwargs): # pragma: no cover
bug #1200. This throws them as generic Exceptions instead so that bug #1200. This throws them as generic Exceptions instead so that
they make it through. they make it through.
""" """
exc_info = None
try: try:
for val in func(*args, **kwargs): for val in func(*args, **kwargs):
yield val yield val
except (LookupError, UnicodeError): except (LookupError, UnicodeError):
raise Exception("bug workaround; real exception is:\n" + # Re-raise it, but maintain the original traceback
traceback.format_exc()) exc_info = sys.exc_info()
new_exc = Exception(exc_info[0].__name__ + ": " + str(exc_info[1]))
raise new_exc, None, exc_info[2]
finally:
del exc_info
def exception_to_httperror(*expected): def exception_to_httperror(*expected):
"""Return a decorator-generating function that catches expected """Return a decorator-generating function that catches expected
@@ -61,26 +65,74 @@ def exception_to_httperror(*expected):
pass pass
""" """
def wrapper(func, *args, **kwargs): def wrapper(func, *args, **kwargs):
exc_info = None
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except expected as e: except expected:
message = sprintf("%s", str(e)) # Re-raise it, but maintain the original traceback
raise cherrypy.HTTPError("400 Bad Request", message) exc_info = sys.exc_info()
new_exc = cherrypy.HTTPError("400 Bad Request", str(exc_info[1]))
raise new_exc, None, exc_info[2]
finally:
del exc_info
# We need to preserve the function's argspecs for CherryPy to # We need to preserve the function's argspecs for CherryPy to
# handle argument errors correctly. Decorator.decorator takes # handle argument errors correctly. Decorator.decorator takes
# care of that. # care of that.
return decorator.decorator(wrapper) return decorator.decorator(wrapper)
# Custom Cherrypy tools # Custom CherryPy tools
def allow_methods(methods):
method = cherrypy.request.method.upper() def CORS_allow(methods):
if method not in methods: """This does several things:
if method in cherrypy.request.methods_with_bodies:
cherrypy.request.body.read() Handles CORS preflight requests.
allowed = ', '.join(methods) Adds Allow: header to all requests.
cherrypy.response.headers['Allow'] = allowed Raise 405 if request.method not in method.
raise cherrypy.HTTPError(405, method + " not allowed; use " + allowed)
cherrypy.tools.allow_methods = cherrypy.Tool('before_handler', allow_methods) It is similar to cherrypy.tools.allow, with the CORS stuff added.
"""
request = cherrypy.request.headers
response = cherrypy.response.headers
if not isinstance(methods, (tuple, list)): # pragma: no cover
methods = [ methods ]
methods = [ m.upper() for m in methods if m ]
if not methods: # pragma: no cover
methods = [ 'GET', 'HEAD' ]
elif 'GET' in methods and 'HEAD' not in methods: # pragma: no cover
methods.append('HEAD')
response['Allow'] = ', '.join(methods)
# Allow all origins
if 'Origin' in request:
response['Access-Control-Allow-Origin'] = request['Origin']
# If it's a CORS request, send response.
request_method = request.get("Access-Control-Request-Method", None)
request_headers = request.get("Access-Control-Request-Headers", None)
if (cherrypy.request.method == "OPTIONS" and
request_method and request_headers):
response['Access-Control-Allow-Headers'] = request_headers
response['Access-Control-Allow-Methods'] = ', '.join(methods)
# Try to stop further processing and return a 200 OK
cherrypy.response.status = "200 OK"
cherrypy.response.body = ""
cherrypy.request.handler = lambda: ""
return
# Reject methods that were not explicitly allowed
if cherrypy.request.method not in methods:
raise cherrypy.HTTPError(405)
cherrypy.tools.CORS_allow = cherrypy.Tool('on_start_resource', CORS_allow)
# Helper for json_in tool to process JSON data into normal request
# parameters.
def json_to_request_params(body):
cherrypy.lib.jsontools.json_processor(body)
if not isinstance(cherrypy.request.json, dict):
raise cherrypy.HTTPError(415)
cherrypy.request.params.update(cherrypy.request.json)
# CherryPy apps # CherryPy apps
class Root(NilmApp): class Root(NilmApp):
@@ -120,21 +172,30 @@ class Stream(NilmApp):
"""Stream-specific operations""" """Stream-specific operations"""
# /stream/list # /stream/list
# /stream/list?layout=PrepData # /stream/list?layout=float32_8
# /stream/list?path=/newton/prep # /stream/list?path=/newton/prep&extended=1
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
def list(self, path = None, layout = None): def list(self, path = None, layout = None, extended = None):
"""List all streams in the database. With optional path or """List all streams in the database. With optional path or
layout parameter, just list streams that match the given path layout parameter, just list streams that match the given path
or layout""" or layout.
return self.db.stream_list(path, layout)
# /stream/create?path=/newton/prep&layout=PrepData If extent is not given, returns a list of lists containing
the path and layout: [ path, layout ]
If extended is provided, returns a list of lists containing
extended info: [ path, layout, extent_min, extent_max,
total_rows, total_seconds ]. More data may be added.
"""
return self.db.stream_list(path, layout, bool(extended))
# /stream/create?path=/newton/prep&layout=float32_8
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@exception_to_httperror(NilmDBError, ValueError) @exception_to_httperror(NilmDBError, ValueError)
@cherrypy.tools.allow_methods(methods = ["POST"]) @cherrypy.tools.CORS_allow(methods = ["POST"])
def create(self, path, layout): def create(self, path, layout):
"""Create a new stream in the database. Provide path """Create a new stream in the database. Provide path
and one of the nilmdb.layout.layouts keys. and one of the nilmdb.layout.layouts keys.
@@ -143,9 +204,10 @@ class Stream(NilmApp):
# /stream/destroy?path=/newton/prep # /stream/destroy?path=/newton/prep
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@exception_to_httperror(NilmDBError) @exception_to_httperror(NilmDBError)
@cherrypy.tools.allow_methods(methods = ["POST"]) @cherrypy.tools.CORS_allow(methods = ["POST"])
def destroy(self, path): def destroy(self, path):
"""Delete a stream and its associated data.""" """Delete a stream and its associated data."""
return self.db.stream_destroy(path) return self.db.stream_destroy(path)
@@ -174,33 +236,47 @@ class Stream(NilmApp):
result[k] = None result[k] = None
return result return result
# Helper for set_metadata and get_metadata
def _metadata_helper(self, function, path, data):
if not isinstance(data, dict):
try:
data = dict(json.loads(data))
except TypeError as e:
raise NilmDBError("can't parse 'data' parameter: " + e.message)
for key in data:
if not (isinstance(data[key], basestring) or
isinstance(data[key], float) or
isinstance(data[key], int)):
raise NilmDBError("metadata values must be a string or number")
function(path, data)
# /stream/set_metadata?path=/newton/prep&data=<json> # /stream/set_metadata?path=/newton/prep&data=<json>
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@exception_to_httperror(NilmDBError, LookupError, TypeError) @exception_to_httperror(NilmDBError, LookupError)
@cherrypy.tools.allow_methods(methods = ["POST"]) @cherrypy.tools.CORS_allow(methods = ["POST"])
def set_metadata(self, path, data): def set_metadata(self, path, data):
"""Set metadata for the named stream, replacing any """Set metadata for the named stream, replacing any existing
existing metadata. Data should be a json-encoded metadata. Data can be json-encoded or a plain dictionary."""
dictionary""" self._metadata_helper(self.db.stream_set_metadata, path, data)
data_dict = json.loads(data)
self.db.stream_set_metadata(path, data_dict)
# /stream/update_metadata?path=/newton/prep&data=<json> # /stream/update_metadata?path=/newton/prep&data=<json>
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@exception_to_httperror(NilmDBError, LookupError, TypeError) @exception_to_httperror(NilmDBError, LookupError, ValueError)
@cherrypy.tools.allow_methods(methods = ["POST"]) @cherrypy.tools.CORS_allow(methods = ["POST"])
def update_metadata(self, path, data): def update_metadata(self, path, data):
"""Update metadata for the named stream. Data """Set metadata for the named stream, replacing any existing
should be a json-encoded dictionary""" metadata. Data can be json-encoded or a plain dictionary."""
data_dict = json.loads(data) self._metadata_helper(self.db.stream_update_metadata, path, data)
self.db.stream_update_metadata(path, data_dict)
# /stream/insert?path=/newton/prep # /stream/insert?path=/newton/prep
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@cherrypy.tools.allow_methods(methods = ["PUT"]) @exception_to_httperror(NilmDBError, ValueError)
@cherrypy.tools.CORS_allow(methods = ["PUT"])
def insert(self, path, start, end): def insert(self, path, start, end):
""" """
Insert new data into the database. Provide textual data Insert new data into the database. Provide textual data
@@ -216,16 +292,6 @@ class Stream(NilmApp):
streams = self.db.stream_list(path = path) streams = self.db.stream_list(path = path)
if len(streams) != 1: if len(streams) != 1:
raise cherrypy.HTTPError("404 Not Found", "No such stream") raise cherrypy.HTTPError("404 Not Found", "No such stream")
layout = streams[0][1]
# Parse the input data
try:
parser = nilmdb.server.layout.Parser(layout)
parser.parse(body)
except nilmdb.server.layout.ParserError as e:
raise cherrypy.HTTPError("400 Bad Request",
"error parsing input data: " +
e.message)
# Check limits # Check limits
start = float(start) start = float(start)
@@ -233,20 +299,10 @@ class Stream(NilmApp):
if start >= end: if start >= end:
raise cherrypy.HTTPError("400 Bad Request", raise cherrypy.HTTPError("400 Bad Request",
"start must precede end") "start must precede end")
if parser.min_timestamp is not None and parser.min_timestamp < start:
raise cherrypy.HTTPError("400 Bad Request", "Data timestamp " +
repr(parser.min_timestamp) +
" < start time " + repr(start))
if parser.max_timestamp is not None and parser.max_timestamp >= end:
raise cherrypy.HTTPError("400 Bad Request", "Data timestamp " +
repr(parser.max_timestamp) +
" >= end time " + repr(end))
# Now do the nilmdb insert, passing it the parser full of data. # Pass the data directly to nilmdb, which will parse it and
try: # raise a ValueError if there are any problems.
self.db.stream_insert(path, start, end, parser.data) self.db.stream_insert(path, start, end, body)
except NilmDBError as e:
raise cherrypy.HTTPError("400 Bad Request", e.message)
# Done # Done
return return
@@ -254,9 +310,10 @@ class Stream(NilmApp):
# /stream/remove?path=/newton/prep # /stream/remove?path=/newton/prep
# /stream/remove?path=/newton/prep&start=1234567890.0&end=1234567899.0 # /stream/remove?path=/newton/prep&start=1234567890.0&end=1234567899.0
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@exception_to_httperror(NilmDBError) @exception_to_httperror(NilmDBError)
@cherrypy.tools.allow_methods(methods = ["POST"]) @cherrypy.tools.CORS_allow(methods = ["POST"])
def remove(self, path, start = None, end = None): def remove(self, path, start = None, end = None):
""" """
Remove data from the backend database. Removes all data in Remove data from the backend database. Removes all data in
@@ -342,10 +399,6 @@ class Stream(NilmApp):
streams = self.db.stream_list(path = path) streams = self.db.stream_list(path = path)
if len(streams) != 1: if len(streams) != 1:
raise cherrypy.HTTPError("404 Not Found", "No such stream") raise cherrypy.HTTPError("404 Not Found", "No such stream")
layout = streams[0][1]
# Get formatter
formatter = nilmdb.server.layout.Formatter(layout)
@workaround_cp_bug_1200 @workaround_cp_bug_1200
def content(start, end, count): def content(start, end, count):
@@ -357,9 +410,7 @@ class Stream(NilmApp):
while True: while True:
(data, restart) = self.db.stream_extract(path, start, end) (data, restart) = self.db.stream_extract(path, start, end)
yield data
# Format the data and yield it
yield formatter.format(data)
if restart == 0: if restart == 0:
return return
@@ -400,7 +451,7 @@ class Server(object):
'server.socket_host': host, 'server.socket_host': host,
'server.socket_port': port, 'server.socket_port': port,
'engine.autoreload_on': False, 'engine.autoreload_on': False,
'server.max_request_body_size': 4*1024*1024, 'server.max_request_body_size': 8*1024*1024,
}) })
if self.embedded: if self.embedded:
cherrypy.config.update({ 'environment': 'embedded' }) cherrypy.config.update({ 'environment': 'embedded' })
@@ -411,16 +462,20 @@ class Server(object):
'error_page.default': self.json_error_page, 'error_page.default': self.json_error_page,
}) })
# Send a permissive Access-Control-Allow-Origin (CORS) header # Some default headers to just help identify that things are working
# with all responses so that browsers can send cross-domain app_config.update({ 'response.headers.X-Jim-Is-Awesome': 'yeah' })
# requests to this server.
app_config.update({ 'response.headers.Access-Control-Allow-Origin':
'*' })
# Only allow GET and HEAD by default. Individual handlers # Set up Cross-Origin Resource Sharing (CORS) handler so we
# can override. # can correctly respond to browsers' CORS preflight requests.
app_config.update({ 'tools.allow_methods.on': True, # This also limits verbs to GET and HEAD by default.
'tools.allow_methods.methods': ['GET', 'HEAD'] }) app_config.update({ 'tools.CORS_allow.on': True,
'tools.CORS_allow.methods': ['GET', 'HEAD'] })
# Configure the 'json_in' tool to also allow other content-types
# (like x-www-form-urlencoded), and to treat JSON as a dict that
# fills requests.param.
app_config.update({ 'tools.json_in.force': False,
'tools.json_in.processor': json_to_request_params })
# Send tracebacks in error responses. They're hidden by the # Send tracebacks in error responses. They're hidden by the
# error_page function for client errors (code 400-499). # error_page function for client errors (code 400-499).

View File

@@ -8,3 +8,5 @@ from nilmdb.utils.diskusage import du, human_size
from nilmdb.utils.mustclose import must_close from nilmdb.utils.mustclose import must_close
from nilmdb.utils import atomic from nilmdb.utils import atomic
import nilmdb.utils.threadsafety import nilmdb.utils.threadsafety
import nilmdb.utils.fallocate
import nilmdb.utils.time

49
nilmdb/utils/fallocate.py Normal file
View File

@@ -0,0 +1,49 @@
# Implementation of hole punching via fallocate, if the OS
# and filesystem support it.
try:
import os
import ctypes
import ctypes.util
def make_fallocate():
libc_name = ctypes.util.find_library('c')
libc = ctypes.CDLL(libc_name, use_errno=True)
_fallocate = libc.fallocate
_fallocate.restype = ctypes.c_int
_fallocate.argtypes = [ ctypes.c_int, ctypes.c_int,
ctypes.c_int64, ctypes.c_int64 ]
del libc
del libc_name
def fallocate(fd, mode, offset, len_):
res = _fallocate(fd, mode, offset, len_)
if res != 0: # pragma: no cover
errno = ctypes.get_errno()
raise IOError(errno, os.strerror(errno))
return fallocate
fallocate = make_fallocate()
del make_fallocate
except Exception: # pragma: no cover
fallocate = None
FALLOC_FL_KEEP_SIZE = 0x01
FALLOC_FL_PUNCH_HOLE = 0x02
def punch_hole(filename, offset, length, ignore_errors = True):
"""Punch a hole in the file. This isn't well supported, so errors
are ignored by default."""
try:
if fallocate is None: # pragma: no cover
raise IOError("fallocate not available")
with open(filename, "r+") as f:
fallocate(f.fileno(),
FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
offset, length)
except IOError: # pragma: no cover
if ignore_errors:
return
raise

View File

@@ -19,6 +19,16 @@ def parse_time(toparse):
except ValueError: except ValueError:
pass pass
# Try to treat it as a single double
try:
timestamp = float(toparse)
# range is from about year 2001 - 2065
if timestamp < 1e9 or timestamp > 3e9:
raise ValueError
return datetime_tz.datetime_tz.fromtimestamp(timestamp)
except ValueError:
pass
# Try to extract a substring in a condensed format that we expect # Try to extract a substring in a condensed format that we expect
# to see in a filename or header comment # to see in a filename or header comment
res = re.search(r"(^|[^\d])(" # non-numeric or SOL res = re.search(r"(^|[^\d])(" # non-numeric or SOL
@@ -52,3 +62,8 @@ def format_time(timestamp):
""" """
dt = datetime_tz.datetime_tz.fromtimestamp(timestamp) dt = datetime_tz.datetime_tz.fromtimestamp(timestamp)
return dt.strftime("%a, %d %b %Y %H:%M:%S.%f %z") return dt.strftime("%a, %d %b %Y %H:%M:%S.%f %z")
def float_time_to_string(timestamp):
"""Convert a floating-point Unix timestamp to a string,
like '1234567890.000000'"""
return "%.6f" % timestamp

View File

@@ -70,9 +70,6 @@ class TimestamperRate(Timestamper):
raise StopIteration raise StopIteration
yield sprintf("%.6f ", start + n / rate) yield sprintf("%.6f ", start + n / rate)
n += 1 n += 1
# Handle case where we're passed a datetime or datetime_tz object
if "totimestamp" in dir(start):
start = start.totimestamp()
Timestamper.__init__(self, infile, iterator(start, rate, end)) Timestamper.__init__(self, infile, iterator(start, rate, end))
self.start = start self.start = start
self.rate = rate self.rate = rate
@@ -92,13 +89,3 @@ class TimestamperNow(Timestamper):
Timestamper.__init__(self, infile, iterator()) Timestamper.__init__(self, infile, iterator())
def __str__(self): def __str__(self):
return "TimestamperNow(...)" return "TimestamperNow(...)"
class TimestamperNull(Timestamper):
"""Timestamper that adds nothing to each line"""
def __init__(self, infile):
def iterator():
while True:
yield ""
Timestamper.__init__(self, infile, iterator())
def __str__(self):
return "TimestamperNull(...)"

View File

@@ -56,7 +56,7 @@ try:
except ImportError: except ImportError:
use_cython = False use_cython = False
ext_modules = [] ext_modules = [ Extension('nilmdb.server.rocket', ['nilmdb/server/rocket.c' ]) ]
for modulename in cython_modules: for modulename in cython_modules:
filename = modulename.replace('.','/') filename = modulename.replace('.','/')
if use_cython: if use_cython:

View File

@@ -1,124 +1,124 @@
# path: /newton/prep # path: /newton/prep
# layout: PrepData # layout: float32_8
# start: Fri, 23 Mar 2012 10:00:30.000000 +0000 # start: Fri, 23 Mar 2012 10:00:30.000000 +0000
# end: Fri, 23 Mar 2012 10:00:31.000000 +0000 # end: Fri, 23 Mar 2012 10:00:31.000000 +0000
1332496830.000000 251774.000000 224241.000000 5688.100098 1915.530029 9329.219727 4183.709961 1212.349976 2641.790039 1332496830.000000 2.517740e+05 2.242410e+05 5.688100e+03 1.915530e+03 9.329220e+03 4.183710e+03 1.212350e+03 2.641790e+03
1332496830.008333 259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 1332496830.008333 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
1332496830.016667 263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 1332496830.016667 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03
1332496830.025000 257614.000000 223323.000000 5003.660156 3525.139893 7165.310059 4685.620117 1715.380005 3440.479980 1332496830.025000 2.576140e+05 2.233230e+05 5.003660e+03 3.525140e+03 7.165310e+03 4.685620e+03 1.715380e+03 3.440480e+03
1332496830.033333 255780.000000 221915.000000 6357.310059 2145.290039 8426.969727 3775.350098 1475.390015 3797.239990 1332496830.033333 2.557800e+05 2.219150e+05 6.357310e+03 2.145290e+03 8.426970e+03 3.775350e+03 1.475390e+03 3.797240e+03
1332496830.041667 260166.000000 223008.000000 6702.589844 1484.959961 9288.099609 3330.830078 1228.500000 3214.320068 1332496830.041667 2.601660e+05 2.230080e+05 6.702590e+03 1.484960e+03 9.288100e+03 3.330830e+03 1.228500e+03 3.214320e+03
1332496830.050000 261231.000000 226426.000000 4980.060059 2982.379883 8499.629883 4267.669922 994.088989 2292.889893 1332496830.050000 2.612310e+05 2.264260e+05 4.980060e+03 2.982380e+03 8.499630e+03 4.267670e+03 9.940890e+02 2.292890e+03
1332496830.058333 255117.000000 226642.000000 4584.410156 4656.439941 7860.149902 5317.310059 1473.599976 2111.689941 1332496830.058333 2.551170e+05 2.266420e+05 4.584410e+03 4.656440e+03 7.860150e+03 5.317310e+03 1.473600e+03 2.111690e+03
1332496830.066667 253300.000000 223554.000000 6455.089844 3036.649902 8869.750000 4986.310059 2607.360107 2839.590088 1332496830.066667 2.533000e+05 2.235540e+05 6.455090e+03 3.036650e+03 8.869750e+03 4.986310e+03 2.607360e+03 2.839590e+03
1332496830.075000 261061.000000 221263.000000 6951.979980 1500.239990 9386.099609 3791.679932 2677.010010 3980.629883 1332496830.075000 2.610610e+05 2.212630e+05 6.951980e+03 1.500240e+03 9.386100e+03 3.791680e+03 2.677010e+03 3.980630e+03
1332496830.083333 266503.000000 223198.000000 5189.609863 2594.560059 8571.530273 3175.000000 919.840027 3792.010010 1332496830.083333 2.665030e+05 2.231980e+05 5.189610e+03 2.594560e+03 8.571530e+03 3.175000e+03 9.198400e+02 3.792010e+03
1332496830.091667 260692.000000 225184.000000 3782.479980 4642.879883 7662.959961 3917.790039 -251.097000 2907.060059 1332496830.091667 2.606920e+05 2.251840e+05 3.782480e+03 4.642880e+03 7.662960e+03 3.917790e+03 -2.510970e+02 2.907060e+03
1332496830.100000 253963.000000 225081.000000 5123.529785 3839.550049 8669.030273 4877.819824 943.723999 2527.449951 1332496830.100000 2.539630e+05 2.250810e+05 5.123530e+03 3.839550e+03 8.669030e+03 4.877820e+03 9.437240e+02 2.527450e+03
1332496830.108333 256555.000000 224169.000000 5930.600098 2298.540039 8906.709961 5331.680176 2549.909912 3053.560059 1332496830.108333 2.565550e+05 2.241690e+05 5.930600e+03 2.298540e+03 8.906710e+03 5.331680e+03 2.549910e+03 3.053560e+03
1332496830.116667 260889.000000 225010.000000 4681.129883 2971.870117 7900.040039 4874.080078 2322.429932 3649.120117 1332496830.116667 2.608890e+05 2.250100e+05 4.681130e+03 2.971870e+03 7.900040e+03 4.874080e+03 2.322430e+03 3.649120e+03
1332496830.125000 257944.000000 224923.000000 3291.139893 4357.089844 7131.589844 4385.560059 1077.050049 3664.040039 1332496830.125000 2.579440e+05 2.249230e+05 3.291140e+03 4.357090e+03 7.131590e+03 4.385560e+03 1.077050e+03 3.664040e+03
1332496830.133333 255009.000000 223018.000000 4584.819824 2864.000000 8469.490234 3625.580078 985.557007 3504.229980 1332496830.133333 2.550090e+05 2.230180e+05 4.584820e+03 2.864000e+03 8.469490e+03 3.625580e+03 9.855570e+02 3.504230e+03
1332496830.141667 260114.000000 221947.000000 5676.189941 1210.339966 9393.780273 3390.239990 1654.020020 3018.699951 1332496830.141667 2.601140e+05 2.219470e+05 5.676190e+03 1.210340e+03 9.393780e+03 3.390240e+03 1.654020e+03 3.018700e+03
1332496830.150000 264277.000000 224438.000000 4446.620117 2176.719971 8142.089844 4584.879883 2327.830078 2615.800049 1332496830.150000 2.642770e+05 2.244380e+05 4.446620e+03 2.176720e+03 8.142090e+03 4.584880e+03 2.327830e+03 2.615800e+03
1332496830.158333 259221.000000 226471.000000 2734.439941 4182.759766 6389.549805 5540.520020 1958.880005 2720.120117 1332496830.158333 2.592210e+05 2.264710e+05 2.734440e+03 4.182760e+03 6.389550e+03 5.540520e+03 1.958880e+03 2.720120e+03
1332496830.166667 252650.000000 224831.000000 4163.640137 2989.989990 7179.200195 5213.060059 1929.550049 3457.659912 1332496830.166667 2.526500e+05 2.248310e+05 4.163640e+03 2.989990e+03 7.179200e+03 5.213060e+03 1.929550e+03 3.457660e+03
1332496830.175000 257083.000000 222048.000000 5759.040039 702.440979 8566.549805 3552.020020 1832.939941 3956.189941 1332496830.175000 2.570830e+05 2.220480e+05 5.759040e+03 7.024410e+02 8.566550e+03 3.552020e+03 1.832940e+03 3.956190e+03
1332496830.183333 263130.000000 222967.000000 5141.140137 1166.119995 8666.959961 2720.370117 971.374023 3479.729980 1332496830.183333 2.631300e+05 2.229670e+05 5.141140e+03 1.166120e+03 8.666960e+03 2.720370e+03 9.713740e+02 3.479730e+03
1332496830.191667 260236.000000 225265.000000 3425.139893 3339.080078 7853.609863 3674.949951 525.908020 2443.310059 1332496830.191667 2.602360e+05 2.252650e+05 3.425140e+03 3.339080e+03 7.853610e+03 3.674950e+03 5.259080e+02 2.443310e+03
1332496830.200000 253503.000000 224527.000000 4398.129883 2927.429932 8110.279785 4842.470215 1513.869995 2467.100098 1332496830.200000 2.535030e+05 2.245270e+05 4.398130e+03 2.927430e+03 8.110280e+03 4.842470e+03 1.513870e+03 2.467100e+03
1332496830.208333 256126.000000 222693.000000 6043.529785 656.223999 8797.559570 4832.410156 2832.370117 3426.139893 1332496830.208333 2.561260e+05 2.226930e+05 6.043530e+03 6.562240e+02 8.797560e+03 4.832410e+03 2.832370e+03 3.426140e+03
1332496830.216667 261677.000000 223608.000000 5830.459961 1033.910034 8123.939941 3980.689941 1927.959961 4092.719971 1332496830.216667 2.616770e+05 2.236080e+05 5.830460e+03 1.033910e+03 8.123940e+03 3.980690e+03 1.927960e+03 4.092720e+03
1332496830.225000 259457.000000 225536.000000 4015.570068 2995.989990 7135.439941 3713.550049 307.220001 3849.429932 1332496830.225000 2.594570e+05 2.255360e+05 4.015570e+03 2.995990e+03 7.135440e+03 3.713550e+03 3.072200e+02 3.849430e+03
1332496830.233333 253352.000000 224216.000000 4650.560059 3196.620117 8131.279785 3586.159912 70.832298 3074.179932 1332496830.233333 2.533520e+05 2.242160e+05 4.650560e+03 3.196620e+03 8.131280e+03 3.586160e+03 7.083230e+01 3.074180e+03
1332496830.241667 256124.000000 221513.000000 6100.479980 821.979980 9757.540039 3474.510010 1647.520020 2559.860107 1332496830.241667 2.561240e+05 2.215130e+05 6.100480e+03 8.219800e+02 9.757540e+03 3.474510e+03 1.647520e+03 2.559860e+03
1332496830.250000 263024.000000 221559.000000 5789.959961 699.416992 9129.740234 4153.080078 2829.250000 2677.270020 1332496830.250000 2.630240e+05 2.215590e+05 5.789960e+03 6.994170e+02 9.129740e+03 4.153080e+03 2.829250e+03 2.677270e+03
1332496830.258333 261720.000000 224015.000000 4358.500000 2645.360107 7414.109863 4810.669922 2225.989990 3185.989990 1332496830.258333 2.617200e+05 2.240150e+05 4.358500e+03 2.645360e+03 7.414110e+03 4.810670e+03 2.225990e+03 3.185990e+03
1332496830.266667 254756.000000 224240.000000 4857.379883 3229.679932 7539.310059 4769.140137 1507.130005 3668.260010 1332496830.266667 2.547560e+05 2.242400e+05 4.857380e+03 3.229680e+03 7.539310e+03 4.769140e+03 1.507130e+03 3.668260e+03
1332496830.275000 256889.000000 222658.000000 6473.419922 1214.109985 9010.759766 3848.729980 1303.839966 3778.500000 1332496830.275000 2.568890e+05 2.226580e+05 6.473420e+03 1.214110e+03 9.010760e+03 3.848730e+03 1.303840e+03 3.778500e+03
1332496830.283333 264208.000000 223316.000000 5700.450195 1116.560059 9087.610352 3846.679932 1293.589966 2891.560059 1332496830.283333 2.642080e+05 2.233160e+05 5.700450e+03 1.116560e+03 9.087610e+03 3.846680e+03 1.293590e+03 2.891560e+03
1332496830.291667 263310.000000 225719.000000 3936.120117 3252.360107 7552.850098 4897.859863 1156.630005 2037.160034 1332496830.291667 2.633100e+05 2.257190e+05 3.936120e+03 3.252360e+03 7.552850e+03 4.897860e+03 1.156630e+03 2.037160e+03
1332496830.300000 255079.000000 225086.000000 4536.450195 3960.110107 7454.589844 5479.069824 1596.359985 2190.800049 1332496830.300000 2.550790e+05 2.250860e+05 4.536450e+03 3.960110e+03 7.454590e+03 5.479070e+03 1.596360e+03 2.190800e+03
1332496830.308333 254487.000000 222508.000000 6635.859863 1758.849976 8732.969727 4466.970215 2650.360107 3139.310059 1332496830.308333 2.544870e+05 2.225080e+05 6.635860e+03 1.758850e+03 8.732970e+03 4.466970e+03 2.650360e+03 3.139310e+03
1332496830.316667 261241.000000 222432.000000 6702.270020 1085.130005 8989.230469 3112.989990 1933.560059 3828.409912 1332496830.316667 2.612410e+05 2.224320e+05 6.702270e+03 1.085130e+03 8.989230e+03 3.112990e+03 1.933560e+03 3.828410e+03
1332496830.325000 262119.000000 225587.000000 4714.950195 2892.360107 8107.819824 2961.310059 239.977997 3273.719971 1332496830.325000 2.621190e+05 2.255870e+05 4.714950e+03 2.892360e+03 8.107820e+03 2.961310e+03 2.399780e+02 3.273720e+03
1332496830.333333 254999.000000 226514.000000 4532.089844 4126.899902 8200.129883 3872.590088 56.089001 2370.580078 1332496830.333333 2.549990e+05 2.265140e+05 4.532090e+03 4.126900e+03 8.200130e+03 3.872590e+03 5.608900e+01 2.370580e+03
1332496830.341667 254289.000000 224033.000000 6538.810059 2251.439941 9419.429688 4564.450195 2077.810059 2508.169922 1332496830.341667 2.542890e+05 2.240330e+05 6.538810e+03 2.251440e+03 9.419430e+03 4.564450e+03 2.077810e+03 2.508170e+03
1332496830.350000 261890.000000 221960.000000 6846.089844 1475.270020 9125.589844 4598.290039 3299.219971 3475.419922 1332496830.350000 2.618900e+05 2.219600e+05 6.846090e+03 1.475270e+03 9.125590e+03 4.598290e+03 3.299220e+03 3.475420e+03
1332496830.358333 264502.000000 223085.000000 5066.379883 3270.560059 7933.169922 4173.709961 1908.910034 3867.459961 1332496830.358333 2.645020e+05 2.230850e+05 5.066380e+03 3.270560e+03 7.933170e+03 4.173710e+03 1.908910e+03 3.867460e+03
1332496830.366667 257889.000000 223656.000000 4201.660156 4473.640137 7688.339844 4161.580078 687.578979 3653.689941 1332496830.366667 2.578890e+05 2.236560e+05 4.201660e+03 4.473640e+03 7.688340e+03 4.161580e+03 6.875790e+02 3.653690e+03
1332496830.375000 254270.000000 223151.000000 5715.140137 2752.139893 9273.320312 3772.949951 896.403992 3256.060059 1332496830.375000 2.542700e+05 2.231510e+05 5.715140e+03 2.752140e+03 9.273320e+03 3.772950e+03 8.964040e+02 3.256060e+03
1332496830.383333 258257.000000 224217.000000 6114.310059 1856.859985 9604.320312 4200.490234 1764.380005 2939.219971 1332496830.383333 2.582570e+05 2.242170e+05 6.114310e+03 1.856860e+03 9.604320e+03 4.200490e+03 1.764380e+03 2.939220e+03
1332496830.391667 260020.000000 226868.000000 4237.529785 3605.879883 8066.220215 5430.250000 2138.580078 2696.709961 1332496830.391667 2.600200e+05 2.268680e+05 4.237530e+03 3.605880e+03 8.066220e+03 5.430250e+03 2.138580e+03 2.696710e+03
1332496830.400000 255083.000000 225924.000000 3350.310059 4853.069824 7045.819824 5925.200195 1893.609985 2897.340088 1332496830.400000 2.550830e+05 2.259240e+05 3.350310e+03 4.853070e+03 7.045820e+03 5.925200e+03 1.893610e+03 2.897340e+03
1332496830.408333 254453.000000 222127.000000 5271.330078 2491.500000 8436.679688 5032.080078 2436.050049 3724.590088 1332496830.408333 2.544530e+05 2.221270e+05 5.271330e+03 2.491500e+03 8.436680e+03 5.032080e+03 2.436050e+03 3.724590e+03
1332496830.416667 262588.000000 219950.000000 5994.620117 789.273987 9029.650391 3515.739990 1953.569946 4014.520020 1332496830.416667 2.625880e+05 2.199500e+05 5.994620e+03 7.892740e+02 9.029650e+03 3.515740e+03 1.953570e+03 4.014520e+03
1332496830.425000 265610.000000 223333.000000 4391.410156 2400.959961 8146.459961 3536.959961 530.231995 3133.919922 1332496830.425000 2.656100e+05 2.233330e+05 4.391410e+03 2.400960e+03 8.146460e+03 3.536960e+03 5.302320e+02 3.133920e+03
1332496830.433333 257470.000000 226977.000000 2975.320068 4633.529785 7278.560059 4640.100098 -50.150200 2024.959961 1332496830.433333 2.574700e+05 2.269770e+05 2.975320e+03 4.633530e+03 7.278560e+03 4.640100e+03 -5.015020e+01 2.024960e+03
1332496830.441667 250687.000000 226331.000000 4517.859863 3183.800049 8072.600098 5281.660156 1605.140015 2335.139893 1332496830.441667 2.506870e+05 2.263310e+05 4.517860e+03 3.183800e+03 8.072600e+03 5.281660e+03 1.605140e+03 2.335140e+03
1332496830.450000 255563.000000 224495.000000 5551.000000 1101.300049 8461.490234 4725.700195 2726.669922 3480.540039 1332496830.450000 2.555630e+05 2.244950e+05 5.551000e+03 1.101300e+03 8.461490e+03 4.725700e+03 2.726670e+03 3.480540e+03
1332496830.458333 261335.000000 224645.000000 4764.680176 1557.020020 7833.350098 3524.810059 1577.410034 4038.620117 1332496830.458333 2.613350e+05 2.246450e+05 4.764680e+03 1.557020e+03 7.833350e+03 3.524810e+03 1.577410e+03 4.038620e+03
1332496830.466667 260269.000000 224008.000000 3558.030029 2987.610107 7362.439941 3279.229980 562.442017 3786.550049 1332496830.466667 2.602690e+05 2.240080e+05 3.558030e+03 2.987610e+03 7.362440e+03 3.279230e+03 5.624420e+02 3.786550e+03
1332496830.475000 257435.000000 221777.000000 4972.600098 2166.879883 8481.440430 3328.719971 1037.130005 3271.370117 1332496830.475000 2.574350e+05 2.217770e+05 4.972600e+03 2.166880e+03 8.481440e+03 3.328720e+03 1.037130e+03 3.271370e+03
1332496830.483333 261046.000000 221550.000000 5816.180176 590.216980 9120.929688 3895.399902 2382.669922 2824.169922 1332496830.483333 2.610460e+05 2.215500e+05 5.816180e+03 5.902170e+02 9.120930e+03 3.895400e+03 2.382670e+03 2.824170e+03
1332496830.491667 262766.000000 224473.000000 4835.049805 1785.770020 7880.759766 4745.620117 2443.659912 3229.550049 1332496830.491667 2.627660e+05 2.244730e+05 4.835050e+03 1.785770e+03 7.880760e+03 4.745620e+03 2.443660e+03 3.229550e+03
1332496830.500000 256509.000000 226413.000000 3758.870117 3461.199951 6743.770020 4928.959961 1536.619995 3546.689941 1332496830.500000 2.565090e+05 2.264130e+05 3.758870e+03 3.461200e+03 6.743770e+03 4.928960e+03 1.536620e+03 3.546690e+03
1332496830.508333 250793.000000 224372.000000 5218.490234 2865.260010 7803.959961 4351.089844 1333.819946 3680.489990 1332496830.508333 2.507930e+05 2.243720e+05 5.218490e+03 2.865260e+03 7.803960e+03 4.351090e+03 1.333820e+03 3.680490e+03
1332496830.516667 256319.000000 222066.000000 6403.970215 732.344971 9627.759766 3089.300049 1516.780029 3653.689941 1332496830.516667 2.563190e+05 2.220660e+05 6.403970e+03 7.323450e+02 9.627760e+03 3.089300e+03 1.516780e+03 3.653690e+03
1332496830.525000 263343.000000 223235.000000 5200.430176 1388.579956 9372.849609 3371.229980 1450.390015 2678.909912 1332496830.525000 2.633430e+05 2.232350e+05 5.200430e+03 1.388580e+03 9.372850e+03 3.371230e+03 1.450390e+03 2.678910e+03
1332496830.533333 260903.000000 225110.000000 3722.580078 3246.659912 7876.540039 4716.810059 1498.439941 2116.520020 1332496830.533333 2.609030e+05 2.251100e+05 3.722580e+03 3.246660e+03 7.876540e+03 4.716810e+03 1.498440e+03 2.116520e+03
1332496830.541667 254416.000000 223769.000000 4841.649902 2956.399902 8115.919922 5392.359863 2142.810059 2652.320068 1332496830.541667 2.544160e+05 2.237690e+05 4.841650e+03 2.956400e+03 8.115920e+03 5.392360e+03 2.142810e+03 2.652320e+03
1332496830.550000 256698.000000 222172.000000 6471.229980 970.395996 8834.980469 4816.839844 2376.629883 3605.860107 1332496830.550000 2.566980e+05 2.221720e+05 6.471230e+03 9.703960e+02 8.834980e+03 4.816840e+03 2.376630e+03 3.605860e+03
1332496830.558333 261841.000000 223537.000000 5500.740234 1189.660034 8365.730469 4016.469971 1042.270020 3821.199951 1332496830.558333 2.618410e+05 2.235370e+05 5.500740e+03 1.189660e+03 8.365730e+03 4.016470e+03 1.042270e+03 3.821200e+03
1332496830.566667 259503.000000 225840.000000 3827.929932 3088.840088 7676.140137 3978.310059 -357.006989 3016.419922 1332496830.566667 2.595030e+05 2.258400e+05 3.827930e+03 3.088840e+03 7.676140e+03 3.978310e+03 -3.570070e+02 3.016420e+03
1332496830.575000 253457.000000 224636.000000 4914.609863 3097.449951 8224.900391 4321.439941 171.373993 2412.360107 1332496830.575000 2.534570e+05 2.246360e+05 4.914610e+03 3.097450e+03 8.224900e+03 4.321440e+03 1.713740e+02 2.412360e+03
1332496830.583333 256029.000000 222221.000000 6841.799805 1028.500000 9252.299805 4387.569824 2418.139893 2510.100098 1332496830.583333 2.560290e+05 2.222210e+05 6.841800e+03 1.028500e+03 9.252300e+03 4.387570e+03 2.418140e+03 2.510100e+03
1332496830.591667 262840.000000 222550.000000 6210.250000 1410.729980 8538.900391 4152.580078 3009.300049 3219.760010 1332496830.591667 2.628400e+05 2.225500e+05 6.210250e+03 1.410730e+03 8.538900e+03 4.152580e+03 3.009300e+03 3.219760e+03
1332496830.600000 261633.000000 225065.000000 4284.529785 3357.209961 7282.169922 3823.590088 1402.839966 3644.669922 1332496830.600000 2.616330e+05 2.250650e+05 4.284530e+03 3.357210e+03 7.282170e+03 3.823590e+03 1.402840e+03 3.644670e+03
1332496830.608333 254591.000000 225109.000000 4693.160156 3647.739990 7745.160156 3686.379883 490.161011 3448.860107 1332496830.608333 2.545910e+05 2.251090e+05 4.693160e+03 3.647740e+03 7.745160e+03 3.686380e+03 4.901610e+02 3.448860e+03
1332496830.616667 254780.000000 223599.000000 6527.379883 1569.869995 9438.429688 3456.580078 1162.520020 3252.010010 1332496830.616667 2.547800e+05 2.235990e+05 6.527380e+03 1.569870e+03 9.438430e+03 3.456580e+03 1.162520e+03 3.252010e+03
1332496830.625000 260639.000000 224107.000000 6531.049805 1633.050049 9283.719727 4174.020020 2089.550049 2775.750000 1332496830.625000 2.606390e+05 2.241070e+05 6.531050e+03 1.633050e+03 9.283720e+03 4.174020e+03 2.089550e+03 2.775750e+03
1332496830.633333 261108.000000 225472.000000 4968.259766 3527.850098 7692.870117 5137.100098 2207.389893 2436.659912 1332496830.633333 2.611080e+05 2.254720e+05 4.968260e+03 3.527850e+03 7.692870e+03 5.137100e+03 2.207390e+03 2.436660e+03
1332496830.641667 255775.000000 223708.000000 4963.450195 4017.370117 7701.419922 5269.649902 2284.399902 2842.080078 1332496830.641667 2.557750e+05 2.237080e+05 4.963450e+03 4.017370e+03 7.701420e+03 5.269650e+03 2.284400e+03 2.842080e+03
1332496830.650000 257398.000000 220947.000000 6767.500000 1645.709961 9107.070312 4000.179932 2548.860107 3624.770020 1332496830.650000 2.573980e+05 2.209470e+05 6.767500e+03 1.645710e+03 9.107070e+03 4.000180e+03 2.548860e+03 3.624770e+03
1332496830.658333 264924.000000 221559.000000 6471.459961 1110.329956 9459.650391 3108.169922 1696.969971 3893.439941 1332496830.658333 2.649240e+05 2.215590e+05 6.471460e+03 1.110330e+03 9.459650e+03 3.108170e+03 1.696970e+03 3.893440e+03
1332496830.666667 265339.000000 225733.000000 4348.799805 3459.510010 8475.299805 4031.239990 573.346985 2910.270020 1332496830.666667 2.653390e+05 2.257330e+05 4.348800e+03 3.459510e+03 8.475300e+03 4.031240e+03 5.733470e+02 2.910270e+03
1332496830.675000 256814.000000 226995.000000 3479.540039 4949.790039 7499.910156 5624.709961 751.656006 2347.709961 1332496830.675000 2.568140e+05 2.269950e+05 3.479540e+03 4.949790e+03 7.499910e+03 5.624710e+03 7.516560e+02 2.347710e+03
1332496830.683333 253316.000000 225161.000000 5147.060059 3218.429932 8460.160156 5869.299805 2336.320068 2987.959961 1332496830.683333 2.533160e+05 2.251610e+05 5.147060e+03 3.218430e+03 8.460160e+03 5.869300e+03 2.336320e+03 2.987960e+03
1332496830.691667 259360.000000 223101.000000 5549.120117 1869.949951 8740.759766 4668.939941 2457.909912 3758.820068 1332496830.691667 2.593600e+05 2.231010e+05 5.549120e+03 1.869950e+03 8.740760e+03 4.668940e+03 2.457910e+03 3.758820e+03
1332496830.700000 262012.000000 224016.000000 4173.609863 3004.129883 8157.040039 3704.729980 987.963989 3652.750000 1332496830.700000 2.620120e+05 2.240160e+05 4.173610e+03 3.004130e+03 8.157040e+03 3.704730e+03 9.879640e+02 3.652750e+03
1332496830.708333 257176.000000 224420.000000 3517.300049 4118.750000 7822.240234 3718.229980 37.264900 2953.679932 1332496830.708333 2.571760e+05 2.244200e+05 3.517300e+03 4.118750e+03 7.822240e+03 3.718230e+03 3.726490e+01 2.953680e+03
1332496830.716667 255146.000000 223322.000000 4923.979980 2330.679932 9095.910156 3792.399902 1013.070007 2711.239990 1332496830.716667 2.551460e+05 2.233220e+05 4.923980e+03 2.330680e+03 9.095910e+03 3.792400e+03 1.013070e+03 2.711240e+03
1332496830.725000 260524.000000 223651.000000 5413.629883 1146.209961 8817.169922 4419.649902 2446.649902 2832.050049 1332496830.725000 2.605240e+05 2.236510e+05 5.413630e+03 1.146210e+03 8.817170e+03 4.419650e+03 2.446650e+03 2.832050e+03
1332496830.733333 262098.000000 225752.000000 4262.979980 2270.969971 7135.479980 5067.120117 2294.679932 3376.620117 1332496830.733333 2.620980e+05 2.257520e+05 4.262980e+03 2.270970e+03 7.135480e+03 5.067120e+03 2.294680e+03 3.376620e+03
1332496830.741667 256889.000000 225379.000000 3606.459961 3568.189941 6552.649902 4970.270020 1516.380005 3662.570068 1332496830.741667 2.568890e+05 2.253790e+05 3.606460e+03 3.568190e+03 6.552650e+03 4.970270e+03 1.516380e+03 3.662570e+03
1332496830.750000 253948.000000 222631.000000 5511.700195 2066.300049 7952.660156 4019.909912 1513.140015 3752.629883 1332496830.750000 2.539480e+05 2.226310e+05 5.511700e+03 2.066300e+03 7.952660e+03 4.019910e+03 1.513140e+03 3.752630e+03
1332496830.758333 259799.000000 222067.000000 5873.500000 608.583984 9253.780273 2870.739990 1348.239990 3344.199951 1332496830.758333 2.597990e+05 2.220670e+05 5.873500e+03 6.085840e+02 9.253780e+03 2.870740e+03 1.348240e+03 3.344200e+03
1332496830.766667 262547.000000 224901.000000 4346.080078 1928.099976 8590.969727 3455.459961 904.390991 2379.270020 1332496830.766667 2.625470e+05 2.249010e+05 4.346080e+03 1.928100e+03 8.590970e+03 3.455460e+03 9.043910e+02 2.379270e+03
1332496830.775000 256137.000000 226761.000000 3423.560059 3379.080078 7471.149902 4894.169922 1153.540039 2031.410034 1332496830.775000 2.561370e+05 2.267610e+05 3.423560e+03 3.379080e+03 7.471150e+03 4.894170e+03 1.153540e+03 2.031410e+03
1332496830.783333 250326.000000 225013.000000 5519.979980 2423.969971 7991.759766 5117.950195 2098.790039 3099.239990 1332496830.783333 2.503260e+05 2.250130e+05 5.519980e+03 2.423970e+03 7.991760e+03 5.117950e+03 2.098790e+03 3.099240e+03
1332496830.791667 255454.000000 222992.000000 6547.950195 496.496002 8751.339844 3900.560059 2132.290039 4076.810059 1332496830.791667 2.554540e+05 2.229920e+05 6.547950e+03 4.964960e+02 8.751340e+03 3.900560e+03 2.132290e+03 4.076810e+03
1332496830.800000 261286.000000 223489.000000 5152.850098 1501.510010 8425.610352 2888.030029 776.114014 3786.360107 1332496830.800000 2.612860e+05 2.234890e+05 5.152850e+03 1.501510e+03 8.425610e+03 2.888030e+03 7.761140e+02 3.786360e+03
1332496830.808333 258969.000000 224069.000000 3832.610107 3001.979980 7979.259766 3182.310059 52.716000 2874.800049 1332496830.808333 2.589690e+05 2.240690e+05 3.832610e+03 3.001980e+03 7.979260e+03 3.182310e+03 5.271600e+01 2.874800e+03
1332496830.816667 254946.000000 222035.000000 5317.879883 2139.800049 9103.139648 3955.610107 1235.170044 2394.149902 1332496830.816667 2.549460e+05 2.220350e+05 5.317880e+03 2.139800e+03 9.103140e+03 3.955610e+03 1.235170e+03 2.394150e+03
1332496830.825000 258676.000000 221205.000000 6594.910156 505.343994 9423.360352 4562.470215 2913.739990 2892.350098 1332496830.825000 2.586760e+05 2.212050e+05 6.594910e+03 5.053440e+02 9.423360e+03 4.562470e+03 2.913740e+03 2.892350e+03
1332496830.833333 262125.000000 223566.000000 5116.750000 1773.599976 8082.200195 4776.370117 2386.389893 3659.729980 1332496830.833333 2.621250e+05 2.235660e+05 5.116750e+03 1.773600e+03 8.082200e+03 4.776370e+03 2.386390e+03 3.659730e+03
1332496830.841667 257835.000000 225918.000000 3714.300049 3477.080078 7205.370117 4554.609863 711.539001 3878.419922 1332496830.841667 2.578350e+05 2.259180e+05 3.714300e+03 3.477080e+03 7.205370e+03 4.554610e+03 7.115390e+02 3.878420e+03
1332496830.850000 253660.000000 224371.000000 5022.450195 2592.429932 8277.200195 4119.370117 486.507996 3666.739990 1332496830.850000 2.536600e+05 2.243710e+05 5.022450e+03 2.592430e+03 8.277200e+03 4.119370e+03 4.865080e+02 3.666740e+03
1332496830.858333 259503.000000 222061.000000 6589.950195 659.935974 9596.919922 3598.100098 1702.489990 3036.600098 1332496830.858333 2.595030e+05 2.220610e+05 6.589950e+03 6.599360e+02 9.596920e+03 3.598100e+03 1.702490e+03 3.036600e+03
1332496830.866667 265495.000000 222843.000000 5541.850098 1728.430054 8459.959961 4492.000000 2231.969971 2430.620117 1332496830.866667 2.654950e+05 2.228430e+05 5.541850e+03 1.728430e+03 8.459960e+03 4.492000e+03 2.231970e+03 2.430620e+03
1332496830.875000 260929.000000 224996.000000 4000.949951 3745.989990 6983.790039 5430.859863 1855.260010 2533.379883 1332496830.875000 2.609290e+05 2.249960e+05 4.000950e+03 3.745990e+03 6.983790e+03 5.430860e+03 1.855260e+03 2.533380e+03
1332496830.883333 252716.000000 224335.000000 5086.560059 3401.149902 7597.970215 5196.120117 1755.719971 3079.760010 1332496830.883333 2.527160e+05 2.243350e+05 5.086560e+03 3.401150e+03 7.597970e+03 5.196120e+03 1.755720e+03 3.079760e+03
1332496830.891667 254110.000000 223111.000000 6822.189941 1229.079956 9164.339844 3761.229980 1679.390015 3584.879883 1332496830.891667 2.541100e+05 2.231110e+05 6.822190e+03 1.229080e+03 9.164340e+03 3.761230e+03 1.679390e+03 3.584880e+03
1332496830.900000 259969.000000 224693.000000 6183.950195 1538.500000 9222.080078 3139.169922 949.901978 3180.800049 1332496830.900000 2.599690e+05 2.246930e+05 6.183950e+03 1.538500e+03 9.222080e+03 3.139170e+03 9.499020e+02 3.180800e+03
1332496830.908333 259078.000000 226913.000000 4388.890137 3694.820068 8195.019531 3933.000000 426.079987 2388.449951 1332496830.908333 2.590780e+05 2.269130e+05 4.388890e+03 3.694820e+03 8.195020e+03 3.933000e+03 4.260800e+02 2.388450e+03
1332496830.916667 254563.000000 224760.000000 5168.439941 4020.939941 8450.269531 4758.910156 1458.900024 2286.429932 1332496830.916667 2.545630e+05 2.247600e+05 5.168440e+03 4.020940e+03 8.450270e+03 4.758910e+03 1.458900e+03 2.286430e+03
1332496830.925000 258059.000000 221217.000000 6883.459961 1649.530029 9232.780273 4457.649902 3057.820068 3031.949951 1332496830.925000 2.580590e+05 2.212170e+05 6.883460e+03 1.649530e+03 9.232780e+03 4.457650e+03 3.057820e+03 3.031950e+03
1332496830.933333 264667.000000 221177.000000 6218.509766 1645.729980 8657.179688 3663.500000 2528.280029 3978.340088 1332496830.933333 2.646670e+05 2.211770e+05 6.218510e+03 1.645730e+03 8.657180e+03 3.663500e+03 2.528280e+03 3.978340e+03
1332496830.941667 262925.000000 224382.000000 4627.500000 3635.929932 7892.799805 3431.320068 604.508972 3901.370117 1332496830.941667 2.629250e+05 2.243820e+05 4.627500e+03 3.635930e+03 7.892800e+03 3.431320e+03 6.045090e+02 3.901370e+03
1332496830.950000 254708.000000 225448.000000 4408.250000 4461.040039 8197.169922 3953.750000 -44.534599 3154.870117 1332496830.950000 2.547080e+05 2.254480e+05 4.408250e+03 4.461040e+03 8.197170e+03 3.953750e+03 -4.453460e+01 3.154870e+03
1332496830.958333 253702.000000 224635.000000 5825.770020 2577.050049 9590.049805 4569.250000 1460.270020 2785.169922 1332496830.958333 2.537020e+05 2.246350e+05 5.825770e+03 2.577050e+03 9.590050e+03 4.569250e+03 1.460270e+03 2.785170e+03
1332496830.966667 260206.000000 224140.000000 5387.979980 1951.160034 8789.509766 5131.660156 2706.379883 2972.479980 1332496830.966667 2.602060e+05 2.241400e+05 5.387980e+03 1.951160e+03 8.789510e+03 5.131660e+03 2.706380e+03 2.972480e+03
1332496830.975000 261240.000000 224737.000000 3860.810059 3418.310059 7414.529785 5284.520020 2271.379883 3183.149902 1332496830.975000 2.612400e+05 2.247370e+05 3.860810e+03 3.418310e+03 7.414530e+03 5.284520e+03 2.271380e+03 3.183150e+03
1332496830.983333 256140.000000 223252.000000 3850.010010 3957.139893 7262.649902 4964.640137 1499.510010 3453.129883 1332496830.983333 2.561400e+05 2.232520e+05 3.850010e+03 3.957140e+03 7.262650e+03 4.964640e+03 1.499510e+03 3.453130e+03
1332496830.991667 256116.000000 221349.000000 5594.479980 2054.399902 8835.129883 3662.010010 1485.510010 3613.010010 1332496830.991667 2.561160e+05 2.213490e+05 5.594480e+03 2.054400e+03 8.835130e+03 3.662010e+03 1.485510e+03 3.613010e+03

View File

@@ -1,119 +1,119 @@
1332496830.008333 259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 1332496830.008333 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
1332496830.016667 263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 1332496830.016667 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03
1332496830.025000 257614.000000 223323.000000 5003.660156 3525.139893 7165.310059 4685.620117 1715.380005 3440.479980 1332496830.025000 2.576140e+05 2.233230e+05 5.003660e+03 3.525140e+03 7.165310e+03 4.685620e+03 1.715380e+03 3.440480e+03
1332496830.033333 255780.000000 221915.000000 6357.310059 2145.290039 8426.969727 3775.350098 1475.390015 3797.239990 1332496830.033333 2.557800e+05 2.219150e+05 6.357310e+03 2.145290e+03 8.426970e+03 3.775350e+03 1.475390e+03 3.797240e+03
1332496830.041667 260166.000000 223008.000000 6702.589844 1484.959961 9288.099609 3330.830078 1228.500000 3214.320068 1332496830.041667 2.601660e+05 2.230080e+05 6.702590e+03 1.484960e+03 9.288100e+03 3.330830e+03 1.228500e+03 3.214320e+03
1332496830.050000 261231.000000 226426.000000 4980.060059 2982.379883 8499.629883 4267.669922 994.088989 2292.889893 1332496830.050000 2.612310e+05 2.264260e+05 4.980060e+03 2.982380e+03 8.499630e+03 4.267670e+03 9.940890e+02 2.292890e+03
1332496830.058333 255117.000000 226642.000000 4584.410156 4656.439941 7860.149902 5317.310059 1473.599976 2111.689941 1332496830.058333 2.551170e+05 2.266420e+05 4.584410e+03 4.656440e+03 7.860150e+03 5.317310e+03 1.473600e+03 2.111690e+03
1332496830.066667 253300.000000 223554.000000 6455.089844 3036.649902 8869.750000 4986.310059 2607.360107 2839.590088 1332496830.066667 2.533000e+05 2.235540e+05 6.455090e+03 3.036650e+03 8.869750e+03 4.986310e+03 2.607360e+03 2.839590e+03
1332496830.075000 261061.000000 221263.000000 6951.979980 1500.239990 9386.099609 3791.679932 2677.010010 3980.629883 1332496830.075000 2.610610e+05 2.212630e+05 6.951980e+03 1.500240e+03 9.386100e+03 3.791680e+03 2.677010e+03 3.980630e+03
1332496830.083333 266503.000000 223198.000000 5189.609863 2594.560059 8571.530273 3175.000000 919.840027 3792.010010 1332496830.083333 2.665030e+05 2.231980e+05 5.189610e+03 2.594560e+03 8.571530e+03 3.175000e+03 9.198400e+02 3.792010e+03
1332496830.091667 260692.000000 225184.000000 3782.479980 4642.879883 7662.959961 3917.790039 -251.097000 2907.060059 1332496830.091667 2.606920e+05 2.251840e+05 3.782480e+03 4.642880e+03 7.662960e+03 3.917790e+03 -2.510970e+02 2.907060e+03
1332496830.100000 253963.000000 225081.000000 5123.529785 3839.550049 8669.030273 4877.819824 943.723999 2527.449951 1332496830.100000 2.539630e+05 2.250810e+05 5.123530e+03 3.839550e+03 8.669030e+03 4.877820e+03 9.437240e+02 2.527450e+03
1332496830.108333 256555.000000 224169.000000 5930.600098 2298.540039 8906.709961 5331.680176 2549.909912 3053.560059 1332496830.108333 2.565550e+05 2.241690e+05 5.930600e+03 2.298540e+03 8.906710e+03 5.331680e+03 2.549910e+03 3.053560e+03
1332496830.116667 260889.000000 225010.000000 4681.129883 2971.870117 7900.040039 4874.080078 2322.429932 3649.120117 1332496830.116667 2.608890e+05 2.250100e+05 4.681130e+03 2.971870e+03 7.900040e+03 4.874080e+03 2.322430e+03 3.649120e+03
1332496830.125000 257944.000000 224923.000000 3291.139893 4357.089844 7131.589844 4385.560059 1077.050049 3664.040039 1332496830.125000 2.579440e+05 2.249230e+05 3.291140e+03 4.357090e+03 7.131590e+03 4.385560e+03 1.077050e+03 3.664040e+03
1332496830.133333 255009.000000 223018.000000 4584.819824 2864.000000 8469.490234 3625.580078 985.557007 3504.229980 1332496830.133333 2.550090e+05 2.230180e+05 4.584820e+03 2.864000e+03 8.469490e+03 3.625580e+03 9.855570e+02 3.504230e+03
1332496830.141667 260114.000000 221947.000000 5676.189941 1210.339966 9393.780273 3390.239990 1654.020020 3018.699951 1332496830.141667 2.601140e+05 2.219470e+05 5.676190e+03 1.210340e+03 9.393780e+03 3.390240e+03 1.654020e+03 3.018700e+03
1332496830.150000 264277.000000 224438.000000 4446.620117 2176.719971 8142.089844 4584.879883 2327.830078 2615.800049 1332496830.150000 2.642770e+05 2.244380e+05 4.446620e+03 2.176720e+03 8.142090e+03 4.584880e+03 2.327830e+03 2.615800e+03
1332496830.158333 259221.000000 226471.000000 2734.439941 4182.759766 6389.549805 5540.520020 1958.880005 2720.120117 1332496830.158333 2.592210e+05 2.264710e+05 2.734440e+03 4.182760e+03 6.389550e+03 5.540520e+03 1.958880e+03 2.720120e+03
1332496830.166667 252650.000000 224831.000000 4163.640137 2989.989990 7179.200195 5213.060059 1929.550049 3457.659912 1332496830.166667 2.526500e+05 2.248310e+05 4.163640e+03 2.989990e+03 7.179200e+03 5.213060e+03 1.929550e+03 3.457660e+03
1332496830.175000 257083.000000 222048.000000 5759.040039 702.440979 8566.549805 3552.020020 1832.939941 3956.189941 1332496830.175000 2.570830e+05 2.220480e+05 5.759040e+03 7.024410e+02 8.566550e+03 3.552020e+03 1.832940e+03 3.956190e+03
1332496830.183333 263130.000000 222967.000000 5141.140137 1166.119995 8666.959961 2720.370117 971.374023 3479.729980 1332496830.183333 2.631300e+05 2.229670e+05 5.141140e+03 1.166120e+03 8.666960e+03 2.720370e+03 9.713740e+02 3.479730e+03
1332496830.191667 260236.000000 225265.000000 3425.139893 3339.080078 7853.609863 3674.949951 525.908020 2443.310059 1332496830.191667 2.602360e+05 2.252650e+05 3.425140e+03 3.339080e+03 7.853610e+03 3.674950e+03 5.259080e+02 2.443310e+03
1332496830.200000 253503.000000 224527.000000 4398.129883 2927.429932 8110.279785 4842.470215 1513.869995 2467.100098 1332496830.200000 2.535030e+05 2.245270e+05 4.398130e+03 2.927430e+03 8.110280e+03 4.842470e+03 1.513870e+03 2.467100e+03
1332496830.208333 256126.000000 222693.000000 6043.529785 656.223999 8797.559570 4832.410156 2832.370117 3426.139893 1332496830.208333 2.561260e+05 2.226930e+05 6.043530e+03 6.562240e+02 8.797560e+03 4.832410e+03 2.832370e+03 3.426140e+03
1332496830.216667 261677.000000 223608.000000 5830.459961 1033.910034 8123.939941 3980.689941 1927.959961 4092.719971 1332496830.216667 2.616770e+05 2.236080e+05 5.830460e+03 1.033910e+03 8.123940e+03 3.980690e+03 1.927960e+03 4.092720e+03
1332496830.225000 259457.000000 225536.000000 4015.570068 2995.989990 7135.439941 3713.550049 307.220001 3849.429932 1332496830.225000 2.594570e+05 2.255360e+05 4.015570e+03 2.995990e+03 7.135440e+03 3.713550e+03 3.072200e+02 3.849430e+03
1332496830.233333 253352.000000 224216.000000 4650.560059 3196.620117 8131.279785 3586.159912 70.832298 3074.179932 1332496830.233333 2.533520e+05 2.242160e+05 4.650560e+03 3.196620e+03 8.131280e+03 3.586160e+03 7.083230e+01 3.074180e+03
1332496830.241667 256124.000000 221513.000000 6100.479980 821.979980 9757.540039 3474.510010 1647.520020 2559.860107 1332496830.241667 2.561240e+05 2.215130e+05 6.100480e+03 8.219800e+02 9.757540e+03 3.474510e+03 1.647520e+03 2.559860e+03
1332496830.250000 263024.000000 221559.000000 5789.959961 699.416992 9129.740234 4153.080078 2829.250000 2677.270020 1332496830.250000 2.630240e+05 2.215590e+05 5.789960e+03 6.994170e+02 9.129740e+03 4.153080e+03 2.829250e+03 2.677270e+03
1332496830.258333 261720.000000 224015.000000 4358.500000 2645.360107 7414.109863 4810.669922 2225.989990 3185.989990 1332496830.258333 2.617200e+05 2.240150e+05 4.358500e+03 2.645360e+03 7.414110e+03 4.810670e+03 2.225990e+03 3.185990e+03
1332496830.266667 254756.000000 224240.000000 4857.379883 3229.679932 7539.310059 4769.140137 1507.130005 3668.260010 1332496830.266667 2.547560e+05 2.242400e+05 4.857380e+03 3.229680e+03 7.539310e+03 4.769140e+03 1.507130e+03 3.668260e+03
1332496830.275000 256889.000000 222658.000000 6473.419922 1214.109985 9010.759766 3848.729980 1303.839966 3778.500000 1332496830.275000 2.568890e+05 2.226580e+05 6.473420e+03 1.214110e+03 9.010760e+03 3.848730e+03 1.303840e+03 3.778500e+03
1332496830.283333 264208.000000 223316.000000 5700.450195 1116.560059 9087.610352 3846.679932 1293.589966 2891.560059 1332496830.283333 2.642080e+05 2.233160e+05 5.700450e+03 1.116560e+03 9.087610e+03 3.846680e+03 1.293590e+03 2.891560e+03
1332496830.291667 263310.000000 225719.000000 3936.120117 3252.360107 7552.850098 4897.859863 1156.630005 2037.160034 1332496830.291667 2.633100e+05 2.257190e+05 3.936120e+03 3.252360e+03 7.552850e+03 4.897860e+03 1.156630e+03 2.037160e+03
1332496830.300000 255079.000000 225086.000000 4536.450195 3960.110107 7454.589844 5479.069824 1596.359985 2190.800049 1332496830.300000 2.550790e+05 2.250860e+05 4.536450e+03 3.960110e+03 7.454590e+03 5.479070e+03 1.596360e+03 2.190800e+03
1332496830.308333 254487.000000 222508.000000 6635.859863 1758.849976 8732.969727 4466.970215 2650.360107 3139.310059 1332496830.308333 2.544870e+05 2.225080e+05 6.635860e+03 1.758850e+03 8.732970e+03 4.466970e+03 2.650360e+03 3.139310e+03
1332496830.316667 261241.000000 222432.000000 6702.270020 1085.130005 8989.230469 3112.989990 1933.560059 3828.409912 1332496830.316667 2.612410e+05 2.224320e+05 6.702270e+03 1.085130e+03 8.989230e+03 3.112990e+03 1.933560e+03 3.828410e+03
1332496830.325000 262119.000000 225587.000000 4714.950195 2892.360107 8107.819824 2961.310059 239.977997 3273.719971 1332496830.325000 2.621190e+05 2.255870e+05 4.714950e+03 2.892360e+03 8.107820e+03 2.961310e+03 2.399780e+02 3.273720e+03
1332496830.333333 254999.000000 226514.000000 4532.089844 4126.899902 8200.129883 3872.590088 56.089001 2370.580078 1332496830.333333 2.549990e+05 2.265140e+05 4.532090e+03 4.126900e+03 8.200130e+03 3.872590e+03 5.608900e+01 2.370580e+03
1332496830.341667 254289.000000 224033.000000 6538.810059 2251.439941 9419.429688 4564.450195 2077.810059 2508.169922 1332496830.341667 2.542890e+05 2.240330e+05 6.538810e+03 2.251440e+03 9.419430e+03 4.564450e+03 2.077810e+03 2.508170e+03
1332496830.350000 261890.000000 221960.000000 6846.089844 1475.270020 9125.589844 4598.290039 3299.219971 3475.419922 1332496830.350000 2.618900e+05 2.219600e+05 6.846090e+03 1.475270e+03 9.125590e+03 4.598290e+03 3.299220e+03 3.475420e+03
1332496830.358333 264502.000000 223085.000000 5066.379883 3270.560059 7933.169922 4173.709961 1908.910034 3867.459961 1332496830.358333 2.645020e+05 2.230850e+05 5.066380e+03 3.270560e+03 7.933170e+03 4.173710e+03 1.908910e+03 3.867460e+03
1332496830.366667 257889.000000 223656.000000 4201.660156 4473.640137 7688.339844 4161.580078 687.578979 3653.689941 1332496830.366667 2.578890e+05 2.236560e+05 4.201660e+03 4.473640e+03 7.688340e+03 4.161580e+03 6.875790e+02 3.653690e+03
1332496830.375000 254270.000000 223151.000000 5715.140137 2752.139893 9273.320312 3772.949951 896.403992 3256.060059 1332496830.375000 2.542700e+05 2.231510e+05 5.715140e+03 2.752140e+03 9.273320e+03 3.772950e+03 8.964040e+02 3.256060e+03
1332496830.383333 258257.000000 224217.000000 6114.310059 1856.859985 9604.320312 4200.490234 1764.380005 2939.219971 1332496830.383333 2.582570e+05 2.242170e+05 6.114310e+03 1.856860e+03 9.604320e+03 4.200490e+03 1.764380e+03 2.939220e+03
1332496830.391667 260020.000000 226868.000000 4237.529785 3605.879883 8066.220215 5430.250000 2138.580078 2696.709961 1332496830.391667 2.600200e+05 2.268680e+05 4.237530e+03 3.605880e+03 8.066220e+03 5.430250e+03 2.138580e+03 2.696710e+03
1332496830.400000 255083.000000 225924.000000 3350.310059 4853.069824 7045.819824 5925.200195 1893.609985 2897.340088 1332496830.400000 2.550830e+05 2.259240e+05 3.350310e+03 4.853070e+03 7.045820e+03 5.925200e+03 1.893610e+03 2.897340e+03
1332496830.408333 254453.000000 222127.000000 5271.330078 2491.500000 8436.679688 5032.080078 2436.050049 3724.590088 1332496830.408333 2.544530e+05 2.221270e+05 5.271330e+03 2.491500e+03 8.436680e+03 5.032080e+03 2.436050e+03 3.724590e+03
1332496830.416667 262588.000000 219950.000000 5994.620117 789.273987 9029.650391 3515.739990 1953.569946 4014.520020 1332496830.416667 2.625880e+05 2.199500e+05 5.994620e+03 7.892740e+02 9.029650e+03 3.515740e+03 1.953570e+03 4.014520e+03
1332496830.425000 265610.000000 223333.000000 4391.410156 2400.959961 8146.459961 3536.959961 530.231995 3133.919922 1332496830.425000 2.656100e+05 2.233330e+05 4.391410e+03 2.400960e+03 8.146460e+03 3.536960e+03 5.302320e+02 3.133920e+03
1332496830.433333 257470.000000 226977.000000 2975.320068 4633.529785 7278.560059 4640.100098 -50.150200 2024.959961 1332496830.433333 2.574700e+05 2.269770e+05 2.975320e+03 4.633530e+03 7.278560e+03 4.640100e+03 -5.015020e+01 2.024960e+03
1332496830.441667 250687.000000 226331.000000 4517.859863 3183.800049 8072.600098 5281.660156 1605.140015 2335.139893 1332496830.441667 2.506870e+05 2.263310e+05 4.517860e+03 3.183800e+03 8.072600e+03 5.281660e+03 1.605140e+03 2.335140e+03
1332496830.450000 255563.000000 224495.000000 5551.000000 1101.300049 8461.490234 4725.700195 2726.669922 3480.540039 1332496830.450000 2.555630e+05 2.244950e+05 5.551000e+03 1.101300e+03 8.461490e+03 4.725700e+03 2.726670e+03 3.480540e+03
1332496830.458333 261335.000000 224645.000000 4764.680176 1557.020020 7833.350098 3524.810059 1577.410034 4038.620117 1332496830.458333 2.613350e+05 2.246450e+05 4.764680e+03 1.557020e+03 7.833350e+03 3.524810e+03 1.577410e+03 4.038620e+03
1332496830.466667 260269.000000 224008.000000 3558.030029 2987.610107 7362.439941 3279.229980 562.442017 3786.550049 1332496830.466667 2.602690e+05 2.240080e+05 3.558030e+03 2.987610e+03 7.362440e+03 3.279230e+03 5.624420e+02 3.786550e+03
1332496830.475000 257435.000000 221777.000000 4972.600098 2166.879883 8481.440430 3328.719971 1037.130005 3271.370117 1332496830.475000 2.574350e+05 2.217770e+05 4.972600e+03 2.166880e+03 8.481440e+03 3.328720e+03 1.037130e+03 3.271370e+03
1332496830.483333 261046.000000 221550.000000 5816.180176 590.216980 9120.929688 3895.399902 2382.669922 2824.169922 1332496830.483333 2.610460e+05 2.215500e+05 5.816180e+03 5.902170e+02 9.120930e+03 3.895400e+03 2.382670e+03 2.824170e+03
1332496830.491667 262766.000000 224473.000000 4835.049805 1785.770020 7880.759766 4745.620117 2443.659912 3229.550049 1332496830.491667 2.627660e+05 2.244730e+05 4.835050e+03 1.785770e+03 7.880760e+03 4.745620e+03 2.443660e+03 3.229550e+03
1332496830.500000 256509.000000 226413.000000 3758.870117 3461.199951 6743.770020 4928.959961 1536.619995 3546.689941 1332496830.500000 2.565090e+05 2.264130e+05 3.758870e+03 3.461200e+03 6.743770e+03 4.928960e+03 1.536620e+03 3.546690e+03
1332496830.508333 250793.000000 224372.000000 5218.490234 2865.260010 7803.959961 4351.089844 1333.819946 3680.489990 1332496830.508333 2.507930e+05 2.243720e+05 5.218490e+03 2.865260e+03 7.803960e+03 4.351090e+03 1.333820e+03 3.680490e+03
1332496830.516667 256319.000000 222066.000000 6403.970215 732.344971 9627.759766 3089.300049 1516.780029 3653.689941 1332496830.516667 2.563190e+05 2.220660e+05 6.403970e+03 7.323450e+02 9.627760e+03 3.089300e+03 1.516780e+03 3.653690e+03
1332496830.525000 263343.000000 223235.000000 5200.430176 1388.579956 9372.849609 3371.229980 1450.390015 2678.909912 1332496830.525000 2.633430e+05 2.232350e+05 5.200430e+03 1.388580e+03 9.372850e+03 3.371230e+03 1.450390e+03 2.678910e+03
1332496830.533333 260903.000000 225110.000000 3722.580078 3246.659912 7876.540039 4716.810059 1498.439941 2116.520020 1332496830.533333 2.609030e+05 2.251100e+05 3.722580e+03 3.246660e+03 7.876540e+03 4.716810e+03 1.498440e+03 2.116520e+03
1332496830.541667 254416.000000 223769.000000 4841.649902 2956.399902 8115.919922 5392.359863 2142.810059 2652.320068 1332496830.541667 2.544160e+05 2.237690e+05 4.841650e+03 2.956400e+03 8.115920e+03 5.392360e+03 2.142810e+03 2.652320e+03
1332496830.550000 256698.000000 222172.000000 6471.229980 970.395996 8834.980469 4816.839844 2376.629883 3605.860107 1332496830.550000 2.566980e+05 2.221720e+05 6.471230e+03 9.703960e+02 8.834980e+03 4.816840e+03 2.376630e+03 3.605860e+03
1332496830.558333 261841.000000 223537.000000 5500.740234 1189.660034 8365.730469 4016.469971 1042.270020 3821.199951 1332496830.558333 2.618410e+05 2.235370e+05 5.500740e+03 1.189660e+03 8.365730e+03 4.016470e+03 1.042270e+03 3.821200e+03
1332496830.566667 259503.000000 225840.000000 3827.929932 3088.840088 7676.140137 3978.310059 -357.006989 3016.419922 1332496830.566667 2.595030e+05 2.258400e+05 3.827930e+03 3.088840e+03 7.676140e+03 3.978310e+03 -3.570070e+02 3.016420e+03
1332496830.575000 253457.000000 224636.000000 4914.609863 3097.449951 8224.900391 4321.439941 171.373993 2412.360107 1332496830.575000 2.534570e+05 2.246360e+05 4.914610e+03 3.097450e+03 8.224900e+03 4.321440e+03 1.713740e+02 2.412360e+03
1332496830.583333 256029.000000 222221.000000 6841.799805 1028.500000 9252.299805 4387.569824 2418.139893 2510.100098 1332496830.583333 2.560290e+05 2.222210e+05 6.841800e+03 1.028500e+03 9.252300e+03 4.387570e+03 2.418140e+03 2.510100e+03
1332496830.591667 262840.000000 222550.000000 6210.250000 1410.729980 8538.900391 4152.580078 3009.300049 3219.760010 1332496830.591667 2.628400e+05 2.225500e+05 6.210250e+03 1.410730e+03 8.538900e+03 4.152580e+03 3.009300e+03 3.219760e+03
1332496830.600000 261633.000000 225065.000000 4284.529785 3357.209961 7282.169922 3823.590088 1402.839966 3644.669922 1332496830.600000 2.616330e+05 2.250650e+05 4.284530e+03 3.357210e+03 7.282170e+03 3.823590e+03 1.402840e+03 3.644670e+03
1332496830.608333 254591.000000 225109.000000 4693.160156 3647.739990 7745.160156 3686.379883 490.161011 3448.860107 1332496830.608333 2.545910e+05 2.251090e+05 4.693160e+03 3.647740e+03 7.745160e+03 3.686380e+03 4.901610e+02 3.448860e+03
1332496830.616667 254780.000000 223599.000000 6527.379883 1569.869995 9438.429688 3456.580078 1162.520020 3252.010010 1332496830.616667 2.547800e+05 2.235990e+05 6.527380e+03 1.569870e+03 9.438430e+03 3.456580e+03 1.162520e+03 3.252010e+03
1332496830.625000 260639.000000 224107.000000 6531.049805 1633.050049 9283.719727 4174.020020 2089.550049 2775.750000 1332496830.625000 2.606390e+05 2.241070e+05 6.531050e+03 1.633050e+03 9.283720e+03 4.174020e+03 2.089550e+03 2.775750e+03
1332496830.633333 261108.000000 225472.000000 4968.259766 3527.850098 7692.870117 5137.100098 2207.389893 2436.659912 1332496830.633333 2.611080e+05 2.254720e+05 4.968260e+03 3.527850e+03 7.692870e+03 5.137100e+03 2.207390e+03 2.436660e+03
1332496830.641667 255775.000000 223708.000000 4963.450195 4017.370117 7701.419922 5269.649902 2284.399902 2842.080078 1332496830.641667 2.557750e+05 2.237080e+05 4.963450e+03 4.017370e+03 7.701420e+03 5.269650e+03 2.284400e+03 2.842080e+03
1332496830.650000 257398.000000 220947.000000 6767.500000 1645.709961 9107.070312 4000.179932 2548.860107 3624.770020 1332496830.650000 2.573980e+05 2.209470e+05 6.767500e+03 1.645710e+03 9.107070e+03 4.000180e+03 2.548860e+03 3.624770e+03
1332496830.658333 264924.000000 221559.000000 6471.459961 1110.329956 9459.650391 3108.169922 1696.969971 3893.439941 1332496830.658333 2.649240e+05 2.215590e+05 6.471460e+03 1.110330e+03 9.459650e+03 3.108170e+03 1.696970e+03 3.893440e+03
1332496830.666667 265339.000000 225733.000000 4348.799805 3459.510010 8475.299805 4031.239990 573.346985 2910.270020 1332496830.666667 2.653390e+05 2.257330e+05 4.348800e+03 3.459510e+03 8.475300e+03 4.031240e+03 5.733470e+02 2.910270e+03
1332496830.675000 256814.000000 226995.000000 3479.540039 4949.790039 7499.910156 5624.709961 751.656006 2347.709961 1332496830.675000 2.568140e+05 2.269950e+05 3.479540e+03 4.949790e+03 7.499910e+03 5.624710e+03 7.516560e+02 2.347710e+03
1332496830.683333 253316.000000 225161.000000 5147.060059 3218.429932 8460.160156 5869.299805 2336.320068 2987.959961 1332496830.683333 2.533160e+05 2.251610e+05 5.147060e+03 3.218430e+03 8.460160e+03 5.869300e+03 2.336320e+03 2.987960e+03
1332496830.691667 259360.000000 223101.000000 5549.120117 1869.949951 8740.759766 4668.939941 2457.909912 3758.820068 1332496830.691667 2.593600e+05 2.231010e+05 5.549120e+03 1.869950e+03 8.740760e+03 4.668940e+03 2.457910e+03 3.758820e+03
1332496830.700000 262012.000000 224016.000000 4173.609863 3004.129883 8157.040039 3704.729980 987.963989 3652.750000 1332496830.700000 2.620120e+05 2.240160e+05 4.173610e+03 3.004130e+03 8.157040e+03 3.704730e+03 9.879640e+02 3.652750e+03
1332496830.708333 257176.000000 224420.000000 3517.300049 4118.750000 7822.240234 3718.229980 37.264900 2953.679932 1332496830.708333 2.571760e+05 2.244200e+05 3.517300e+03 4.118750e+03 7.822240e+03 3.718230e+03 3.726490e+01 2.953680e+03
1332496830.716667 255146.000000 223322.000000 4923.979980 2330.679932 9095.910156 3792.399902 1013.070007 2711.239990 1332496830.716667 2.551460e+05 2.233220e+05 4.923980e+03 2.330680e+03 9.095910e+03 3.792400e+03 1.013070e+03 2.711240e+03
1332496830.725000 260524.000000 223651.000000 5413.629883 1146.209961 8817.169922 4419.649902 2446.649902 2832.050049 1332496830.725000 2.605240e+05 2.236510e+05 5.413630e+03 1.146210e+03 8.817170e+03 4.419650e+03 2.446650e+03 2.832050e+03
1332496830.733333 262098.000000 225752.000000 4262.979980 2270.969971 7135.479980 5067.120117 2294.679932 3376.620117 1332496830.733333 2.620980e+05 2.257520e+05 4.262980e+03 2.270970e+03 7.135480e+03 5.067120e+03 2.294680e+03 3.376620e+03
1332496830.741667 256889.000000 225379.000000 3606.459961 3568.189941 6552.649902 4970.270020 1516.380005 3662.570068 1332496830.741667 2.568890e+05 2.253790e+05 3.606460e+03 3.568190e+03 6.552650e+03 4.970270e+03 1.516380e+03 3.662570e+03
1332496830.750000 253948.000000 222631.000000 5511.700195 2066.300049 7952.660156 4019.909912 1513.140015 3752.629883 1332496830.750000 2.539480e+05 2.226310e+05 5.511700e+03 2.066300e+03 7.952660e+03 4.019910e+03 1.513140e+03 3.752630e+03
1332496830.758333 259799.000000 222067.000000 5873.500000 608.583984 9253.780273 2870.739990 1348.239990 3344.199951 1332496830.758333 2.597990e+05 2.220670e+05 5.873500e+03 6.085840e+02 9.253780e+03 2.870740e+03 1.348240e+03 3.344200e+03
1332496830.766667 262547.000000 224901.000000 4346.080078 1928.099976 8590.969727 3455.459961 904.390991 2379.270020 1332496830.766667 2.625470e+05 2.249010e+05 4.346080e+03 1.928100e+03 8.590970e+03 3.455460e+03 9.043910e+02 2.379270e+03
1332496830.775000 256137.000000 226761.000000 3423.560059 3379.080078 7471.149902 4894.169922 1153.540039 2031.410034 1332496830.775000 2.561370e+05 2.267610e+05 3.423560e+03 3.379080e+03 7.471150e+03 4.894170e+03 1.153540e+03 2.031410e+03
1332496830.783333 250326.000000 225013.000000 5519.979980 2423.969971 7991.759766 5117.950195 2098.790039 3099.239990 1332496830.783333 2.503260e+05 2.250130e+05 5.519980e+03 2.423970e+03 7.991760e+03 5.117950e+03 2.098790e+03 3.099240e+03
1332496830.791667 255454.000000 222992.000000 6547.950195 496.496002 8751.339844 3900.560059 2132.290039 4076.810059 1332496830.791667 2.554540e+05 2.229920e+05 6.547950e+03 4.964960e+02 8.751340e+03 3.900560e+03 2.132290e+03 4.076810e+03
1332496830.800000 261286.000000 223489.000000 5152.850098 1501.510010 8425.610352 2888.030029 776.114014 3786.360107 1332496830.800000 2.612860e+05 2.234890e+05 5.152850e+03 1.501510e+03 8.425610e+03 2.888030e+03 7.761140e+02 3.786360e+03
1332496830.808333 258969.000000 224069.000000 3832.610107 3001.979980 7979.259766 3182.310059 52.716000 2874.800049 1332496830.808333 2.589690e+05 2.240690e+05 3.832610e+03 3.001980e+03 7.979260e+03 3.182310e+03 5.271600e+01 2.874800e+03
1332496830.816667 254946.000000 222035.000000 5317.879883 2139.800049 9103.139648 3955.610107 1235.170044 2394.149902 1332496830.816667 2.549460e+05 2.220350e+05 5.317880e+03 2.139800e+03 9.103140e+03 3.955610e+03 1.235170e+03 2.394150e+03
1332496830.825000 258676.000000 221205.000000 6594.910156 505.343994 9423.360352 4562.470215 2913.739990 2892.350098 1332496830.825000 2.586760e+05 2.212050e+05 6.594910e+03 5.053440e+02 9.423360e+03 4.562470e+03 2.913740e+03 2.892350e+03
1332496830.833333 262125.000000 223566.000000 5116.750000 1773.599976 8082.200195 4776.370117 2386.389893 3659.729980 1332496830.833333 2.621250e+05 2.235660e+05 5.116750e+03 1.773600e+03 8.082200e+03 4.776370e+03 2.386390e+03 3.659730e+03
1332496830.841667 257835.000000 225918.000000 3714.300049 3477.080078 7205.370117 4554.609863 711.539001 3878.419922 1332496830.841667 2.578350e+05 2.259180e+05 3.714300e+03 3.477080e+03 7.205370e+03 4.554610e+03 7.115390e+02 3.878420e+03
1332496830.850000 253660.000000 224371.000000 5022.450195 2592.429932 8277.200195 4119.370117 486.507996 3666.739990 1332496830.850000 2.536600e+05 2.243710e+05 5.022450e+03 2.592430e+03 8.277200e+03 4.119370e+03 4.865080e+02 3.666740e+03
1332496830.858333 259503.000000 222061.000000 6589.950195 659.935974 9596.919922 3598.100098 1702.489990 3036.600098 1332496830.858333 2.595030e+05 2.220610e+05 6.589950e+03 6.599360e+02 9.596920e+03 3.598100e+03 1.702490e+03 3.036600e+03
1332496830.866667 265495.000000 222843.000000 5541.850098 1728.430054 8459.959961 4492.000000 2231.969971 2430.620117 1332496830.866667 2.654950e+05 2.228430e+05 5.541850e+03 1.728430e+03 8.459960e+03 4.492000e+03 2.231970e+03 2.430620e+03
1332496830.875000 260929.000000 224996.000000 4000.949951 3745.989990 6983.790039 5430.859863 1855.260010 2533.379883 1332496830.875000 2.609290e+05 2.249960e+05 4.000950e+03 3.745990e+03 6.983790e+03 5.430860e+03 1.855260e+03 2.533380e+03
1332496830.883333 252716.000000 224335.000000 5086.560059 3401.149902 7597.970215 5196.120117 1755.719971 3079.760010 1332496830.883333 2.527160e+05 2.243350e+05 5.086560e+03 3.401150e+03 7.597970e+03 5.196120e+03 1.755720e+03 3.079760e+03
1332496830.891667 254110.000000 223111.000000 6822.189941 1229.079956 9164.339844 3761.229980 1679.390015 3584.879883 1332496830.891667 2.541100e+05 2.231110e+05 6.822190e+03 1.229080e+03 9.164340e+03 3.761230e+03 1.679390e+03 3.584880e+03
1332496830.900000 259969.000000 224693.000000 6183.950195 1538.500000 9222.080078 3139.169922 949.901978 3180.800049 1332496830.900000 2.599690e+05 2.246930e+05 6.183950e+03 1.538500e+03 9.222080e+03 3.139170e+03 9.499020e+02 3.180800e+03
1332496830.908333 259078.000000 226913.000000 4388.890137 3694.820068 8195.019531 3933.000000 426.079987 2388.449951 1332496830.908333 2.590780e+05 2.269130e+05 4.388890e+03 3.694820e+03 8.195020e+03 3.933000e+03 4.260800e+02 2.388450e+03
1332496830.916667 254563.000000 224760.000000 5168.439941 4020.939941 8450.269531 4758.910156 1458.900024 2286.429932 1332496830.916667 2.545630e+05 2.247600e+05 5.168440e+03 4.020940e+03 8.450270e+03 4.758910e+03 1.458900e+03 2.286430e+03
1332496830.925000 258059.000000 221217.000000 6883.459961 1649.530029 9232.780273 4457.649902 3057.820068 3031.949951 1332496830.925000 2.580590e+05 2.212170e+05 6.883460e+03 1.649530e+03 9.232780e+03 4.457650e+03 3.057820e+03 3.031950e+03
1332496830.933333 264667.000000 221177.000000 6218.509766 1645.729980 8657.179688 3663.500000 2528.280029 3978.340088 1332496830.933333 2.646670e+05 2.211770e+05 6.218510e+03 1.645730e+03 8.657180e+03 3.663500e+03 2.528280e+03 3.978340e+03
1332496830.941667 262925.000000 224382.000000 4627.500000 3635.929932 7892.799805 3431.320068 604.508972 3901.370117 1332496830.941667 2.629250e+05 2.243820e+05 4.627500e+03 3.635930e+03 7.892800e+03 3.431320e+03 6.045090e+02 3.901370e+03
1332496830.950000 254708.000000 225448.000000 4408.250000 4461.040039 8197.169922 3953.750000 -44.534599 3154.870117 1332496830.950000 2.547080e+05 2.254480e+05 4.408250e+03 4.461040e+03 8.197170e+03 3.953750e+03 -4.453460e+01 3.154870e+03
1332496830.958333 253702.000000 224635.000000 5825.770020 2577.050049 9590.049805 4569.250000 1460.270020 2785.169922 1332496830.958333 2.537020e+05 2.246350e+05 5.825770e+03 2.577050e+03 9.590050e+03 4.569250e+03 1.460270e+03 2.785170e+03
1332496830.966667 260206.000000 224140.000000 5387.979980 1951.160034 8789.509766 5131.660156 2706.379883 2972.479980 1332496830.966667 2.602060e+05 2.241400e+05 5.387980e+03 1.951160e+03 8.789510e+03 5.131660e+03 2.706380e+03 2.972480e+03
1332496830.975000 261240.000000 224737.000000 3860.810059 3418.310059 7414.529785 5284.520020 2271.379883 3183.149902 1332496830.975000 2.612400e+05 2.247370e+05 3.860810e+03 3.418310e+03 7.414530e+03 5.284520e+03 2.271380e+03 3.183150e+03
1332496830.983333 256140.000000 223252.000000 3850.010010 3957.139893 7262.649902 4964.640137 1499.510010 3453.129883 1332496830.983333 2.561400e+05 2.232520e+05 3.850010e+03 3.957140e+03 7.262650e+03 4.964640e+03 1.499510e+03 3.453130e+03
1332496830.991667 256116.000000 221349.000000 5594.479980 2054.399902 8835.129883 3662.010010 1485.510010 3613.010010 1332496830.991667 2.561160e+05 2.213490e+05 5.594480e+03 2.054400e+03 8.835130e+03 3.662010e+03 1.485510e+03 3.613010e+03

View File

@@ -1 +1 @@
1332496830.008333 259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 1332496830.008333 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03

View File

@@ -1,2 +1,2 @@
1332496830.008333 259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 1332496830.008333 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
1332496830.016667 263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 1332496830.016667 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03

View File

@@ -1,124 +1,124 @@
# path: /newton/prep # path: /newton/prep
# layout: PrepData # layout: float32_8
# start: Fri, 23 Mar 2012 10:00:30.000000 +0000 # start: Fri, 23 Mar 2012 10:00:30.000000 +0000
# end: Fri, 23 Mar 2012 10:00:31.000000 +0000 # end: Fri, 23 Mar 2012 10:00:31.000000 +0000
251774.000000 224241.000000 5688.100098 1915.530029 9329.219727 4183.709961 1212.349976 2641.790039 2.517740e+05 2.242410e+05 5.688100e+03 1.915530e+03 9.329220e+03 4.183710e+03 1.212350e+03 2.641790e+03
259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03
257614.000000 223323.000000 5003.660156 3525.139893 7165.310059 4685.620117 1715.380005 3440.479980 2.576140e+05 2.233230e+05 5.003660e+03 3.525140e+03 7.165310e+03 4.685620e+03 1.715380e+03 3.440480e+03
255780.000000 221915.000000 6357.310059 2145.290039 8426.969727 3775.350098 1475.390015 3797.239990 2.557800e+05 2.219150e+05 6.357310e+03 2.145290e+03 8.426970e+03 3.775350e+03 1.475390e+03 3.797240e+03
260166.000000 223008.000000 6702.589844 1484.959961 9288.099609 3330.830078 1228.500000 3214.320068 2.601660e+05 2.230080e+05 6.702590e+03 1.484960e+03 9.288100e+03 3.330830e+03 1.228500e+03 3.214320e+03
261231.000000 226426.000000 4980.060059 2982.379883 8499.629883 4267.669922 994.088989 2292.889893 2.612310e+05 2.264260e+05 4.980060e+03 2.982380e+03 8.499630e+03 4.267670e+03 9.940890e+02 2.292890e+03
255117.000000 226642.000000 4584.410156 4656.439941 7860.149902 5317.310059 1473.599976 2111.689941 2.551170e+05 2.266420e+05 4.584410e+03 4.656440e+03 7.860150e+03 5.317310e+03 1.473600e+03 2.111690e+03
253300.000000 223554.000000 6455.089844 3036.649902 8869.750000 4986.310059 2607.360107 2839.590088 2.533000e+05 2.235540e+05 6.455090e+03 3.036650e+03 8.869750e+03 4.986310e+03 2.607360e+03 2.839590e+03
261061.000000 221263.000000 6951.979980 1500.239990 9386.099609 3791.679932 2677.010010 3980.629883 2.610610e+05 2.212630e+05 6.951980e+03 1.500240e+03 9.386100e+03 3.791680e+03 2.677010e+03 3.980630e+03
266503.000000 223198.000000 5189.609863 2594.560059 8571.530273 3175.000000 919.840027 3792.010010 2.665030e+05 2.231980e+05 5.189610e+03 2.594560e+03 8.571530e+03 3.175000e+03 9.198400e+02 3.792010e+03
260692.000000 225184.000000 3782.479980 4642.879883 7662.959961 3917.790039 -251.097000 2907.060059 2.606920e+05 2.251840e+05 3.782480e+03 4.642880e+03 7.662960e+03 3.917790e+03 -2.510970e+02 2.907060e+03
253963.000000 225081.000000 5123.529785 3839.550049 8669.030273 4877.819824 943.723999 2527.449951 2.539630e+05 2.250810e+05 5.123530e+03 3.839550e+03 8.669030e+03 4.877820e+03 9.437240e+02 2.527450e+03
256555.000000 224169.000000 5930.600098 2298.540039 8906.709961 5331.680176 2549.909912 3053.560059 2.565550e+05 2.241690e+05 5.930600e+03 2.298540e+03 8.906710e+03 5.331680e+03 2.549910e+03 3.053560e+03
260889.000000 225010.000000 4681.129883 2971.870117 7900.040039 4874.080078 2322.429932 3649.120117 2.608890e+05 2.250100e+05 4.681130e+03 2.971870e+03 7.900040e+03 4.874080e+03 2.322430e+03 3.649120e+03
257944.000000 224923.000000 3291.139893 4357.089844 7131.589844 4385.560059 1077.050049 3664.040039 2.579440e+05 2.249230e+05 3.291140e+03 4.357090e+03 7.131590e+03 4.385560e+03 1.077050e+03 3.664040e+03
255009.000000 223018.000000 4584.819824 2864.000000 8469.490234 3625.580078 985.557007 3504.229980 2.550090e+05 2.230180e+05 4.584820e+03 2.864000e+03 8.469490e+03 3.625580e+03 9.855570e+02 3.504230e+03
260114.000000 221947.000000 5676.189941 1210.339966 9393.780273 3390.239990 1654.020020 3018.699951 2.601140e+05 2.219470e+05 5.676190e+03 1.210340e+03 9.393780e+03 3.390240e+03 1.654020e+03 3.018700e+03
264277.000000 224438.000000 4446.620117 2176.719971 8142.089844 4584.879883 2327.830078 2615.800049 2.642770e+05 2.244380e+05 4.446620e+03 2.176720e+03 8.142090e+03 4.584880e+03 2.327830e+03 2.615800e+03
259221.000000 226471.000000 2734.439941 4182.759766 6389.549805 5540.520020 1958.880005 2720.120117 2.592210e+05 2.264710e+05 2.734440e+03 4.182760e+03 6.389550e+03 5.540520e+03 1.958880e+03 2.720120e+03
252650.000000 224831.000000 4163.640137 2989.989990 7179.200195 5213.060059 1929.550049 3457.659912 2.526500e+05 2.248310e+05 4.163640e+03 2.989990e+03 7.179200e+03 5.213060e+03 1.929550e+03 3.457660e+03
257083.000000 222048.000000 5759.040039 702.440979 8566.549805 3552.020020 1832.939941 3956.189941 2.570830e+05 2.220480e+05 5.759040e+03 7.024410e+02 8.566550e+03 3.552020e+03 1.832940e+03 3.956190e+03
263130.000000 222967.000000 5141.140137 1166.119995 8666.959961 2720.370117 971.374023 3479.729980 2.631300e+05 2.229670e+05 5.141140e+03 1.166120e+03 8.666960e+03 2.720370e+03 9.713740e+02 3.479730e+03
260236.000000 225265.000000 3425.139893 3339.080078 7853.609863 3674.949951 525.908020 2443.310059 2.602360e+05 2.252650e+05 3.425140e+03 3.339080e+03 7.853610e+03 3.674950e+03 5.259080e+02 2.443310e+03
253503.000000 224527.000000 4398.129883 2927.429932 8110.279785 4842.470215 1513.869995 2467.100098 2.535030e+05 2.245270e+05 4.398130e+03 2.927430e+03 8.110280e+03 4.842470e+03 1.513870e+03 2.467100e+03
256126.000000 222693.000000 6043.529785 656.223999 8797.559570 4832.410156 2832.370117 3426.139893 2.561260e+05 2.226930e+05 6.043530e+03 6.562240e+02 8.797560e+03 4.832410e+03 2.832370e+03 3.426140e+03
261677.000000 223608.000000 5830.459961 1033.910034 8123.939941 3980.689941 1927.959961 4092.719971 2.616770e+05 2.236080e+05 5.830460e+03 1.033910e+03 8.123940e+03 3.980690e+03 1.927960e+03 4.092720e+03
259457.000000 225536.000000 4015.570068 2995.989990 7135.439941 3713.550049 307.220001 3849.429932 2.594570e+05 2.255360e+05 4.015570e+03 2.995990e+03 7.135440e+03 3.713550e+03 3.072200e+02 3.849430e+03
253352.000000 224216.000000 4650.560059 3196.620117 8131.279785 3586.159912 70.832298 3074.179932 2.533520e+05 2.242160e+05 4.650560e+03 3.196620e+03 8.131280e+03 3.586160e+03 7.083230e+01 3.074180e+03
256124.000000 221513.000000 6100.479980 821.979980 9757.540039 3474.510010 1647.520020 2559.860107 2.561240e+05 2.215130e+05 6.100480e+03 8.219800e+02 9.757540e+03 3.474510e+03 1.647520e+03 2.559860e+03
263024.000000 221559.000000 5789.959961 699.416992 9129.740234 4153.080078 2829.250000 2677.270020 2.630240e+05 2.215590e+05 5.789960e+03 6.994170e+02 9.129740e+03 4.153080e+03 2.829250e+03 2.677270e+03
261720.000000 224015.000000 4358.500000 2645.360107 7414.109863 4810.669922 2225.989990 3185.989990 2.617200e+05 2.240150e+05 4.358500e+03 2.645360e+03 7.414110e+03 4.810670e+03 2.225990e+03 3.185990e+03
254756.000000 224240.000000 4857.379883 3229.679932 7539.310059 4769.140137 1507.130005 3668.260010 2.547560e+05 2.242400e+05 4.857380e+03 3.229680e+03 7.539310e+03 4.769140e+03 1.507130e+03 3.668260e+03
256889.000000 222658.000000 6473.419922 1214.109985 9010.759766 3848.729980 1303.839966 3778.500000 2.568890e+05 2.226580e+05 6.473420e+03 1.214110e+03 9.010760e+03 3.848730e+03 1.303840e+03 3.778500e+03
264208.000000 223316.000000 5700.450195 1116.560059 9087.610352 3846.679932 1293.589966 2891.560059 2.642080e+05 2.233160e+05 5.700450e+03 1.116560e+03 9.087610e+03 3.846680e+03 1.293590e+03 2.891560e+03
263310.000000 225719.000000 3936.120117 3252.360107 7552.850098 4897.859863 1156.630005 2037.160034 2.633100e+05 2.257190e+05 3.936120e+03 3.252360e+03 7.552850e+03 4.897860e+03 1.156630e+03 2.037160e+03
255079.000000 225086.000000 4536.450195 3960.110107 7454.589844 5479.069824 1596.359985 2190.800049 2.550790e+05 2.250860e+05 4.536450e+03 3.960110e+03 7.454590e+03 5.479070e+03 1.596360e+03 2.190800e+03
254487.000000 222508.000000 6635.859863 1758.849976 8732.969727 4466.970215 2650.360107 3139.310059 2.544870e+05 2.225080e+05 6.635860e+03 1.758850e+03 8.732970e+03 4.466970e+03 2.650360e+03 3.139310e+03
261241.000000 222432.000000 6702.270020 1085.130005 8989.230469 3112.989990 1933.560059 3828.409912 2.612410e+05 2.224320e+05 6.702270e+03 1.085130e+03 8.989230e+03 3.112990e+03 1.933560e+03 3.828410e+03
262119.000000 225587.000000 4714.950195 2892.360107 8107.819824 2961.310059 239.977997 3273.719971 2.621190e+05 2.255870e+05 4.714950e+03 2.892360e+03 8.107820e+03 2.961310e+03 2.399780e+02 3.273720e+03
254999.000000 226514.000000 4532.089844 4126.899902 8200.129883 3872.590088 56.089001 2370.580078 2.549990e+05 2.265140e+05 4.532090e+03 4.126900e+03 8.200130e+03 3.872590e+03 5.608900e+01 2.370580e+03
254289.000000 224033.000000 6538.810059 2251.439941 9419.429688 4564.450195 2077.810059 2508.169922 2.542890e+05 2.240330e+05 6.538810e+03 2.251440e+03 9.419430e+03 4.564450e+03 2.077810e+03 2.508170e+03
261890.000000 221960.000000 6846.089844 1475.270020 9125.589844 4598.290039 3299.219971 3475.419922 2.618900e+05 2.219600e+05 6.846090e+03 1.475270e+03 9.125590e+03 4.598290e+03 3.299220e+03 3.475420e+03
264502.000000 223085.000000 5066.379883 3270.560059 7933.169922 4173.709961 1908.910034 3867.459961 2.645020e+05 2.230850e+05 5.066380e+03 3.270560e+03 7.933170e+03 4.173710e+03 1.908910e+03 3.867460e+03
257889.000000 223656.000000 4201.660156 4473.640137 7688.339844 4161.580078 687.578979 3653.689941 2.578890e+05 2.236560e+05 4.201660e+03 4.473640e+03 7.688340e+03 4.161580e+03 6.875790e+02 3.653690e+03
254270.000000 223151.000000 5715.140137 2752.139893 9273.320312 3772.949951 896.403992 3256.060059 2.542700e+05 2.231510e+05 5.715140e+03 2.752140e+03 9.273320e+03 3.772950e+03 8.964040e+02 3.256060e+03
258257.000000 224217.000000 6114.310059 1856.859985 9604.320312 4200.490234 1764.380005 2939.219971 2.582570e+05 2.242170e+05 6.114310e+03 1.856860e+03 9.604320e+03 4.200490e+03 1.764380e+03 2.939220e+03
260020.000000 226868.000000 4237.529785 3605.879883 8066.220215 5430.250000 2138.580078 2696.709961 2.600200e+05 2.268680e+05 4.237530e+03 3.605880e+03 8.066220e+03 5.430250e+03 2.138580e+03 2.696710e+03
255083.000000 225924.000000 3350.310059 4853.069824 7045.819824 5925.200195 1893.609985 2897.340088 2.550830e+05 2.259240e+05 3.350310e+03 4.853070e+03 7.045820e+03 5.925200e+03 1.893610e+03 2.897340e+03
254453.000000 222127.000000 5271.330078 2491.500000 8436.679688 5032.080078 2436.050049 3724.590088 2.544530e+05 2.221270e+05 5.271330e+03 2.491500e+03 8.436680e+03 5.032080e+03 2.436050e+03 3.724590e+03
262588.000000 219950.000000 5994.620117 789.273987 9029.650391 3515.739990 1953.569946 4014.520020 2.625880e+05 2.199500e+05 5.994620e+03 7.892740e+02 9.029650e+03 3.515740e+03 1.953570e+03 4.014520e+03
265610.000000 223333.000000 4391.410156 2400.959961 8146.459961 3536.959961 530.231995 3133.919922 2.656100e+05 2.233330e+05 4.391410e+03 2.400960e+03 8.146460e+03 3.536960e+03 5.302320e+02 3.133920e+03
257470.000000 226977.000000 2975.320068 4633.529785 7278.560059 4640.100098 -50.150200 2024.959961 2.574700e+05 2.269770e+05 2.975320e+03 4.633530e+03 7.278560e+03 4.640100e+03 -5.015020e+01 2.024960e+03
250687.000000 226331.000000 4517.859863 3183.800049 8072.600098 5281.660156 1605.140015 2335.139893 2.506870e+05 2.263310e+05 4.517860e+03 3.183800e+03 8.072600e+03 5.281660e+03 1.605140e+03 2.335140e+03
255563.000000 224495.000000 5551.000000 1101.300049 8461.490234 4725.700195 2726.669922 3480.540039 2.555630e+05 2.244950e+05 5.551000e+03 1.101300e+03 8.461490e+03 4.725700e+03 2.726670e+03 3.480540e+03
261335.000000 224645.000000 4764.680176 1557.020020 7833.350098 3524.810059 1577.410034 4038.620117 2.613350e+05 2.246450e+05 4.764680e+03 1.557020e+03 7.833350e+03 3.524810e+03 1.577410e+03 4.038620e+03
260269.000000 224008.000000 3558.030029 2987.610107 7362.439941 3279.229980 562.442017 3786.550049 2.602690e+05 2.240080e+05 3.558030e+03 2.987610e+03 7.362440e+03 3.279230e+03 5.624420e+02 3.786550e+03
257435.000000 221777.000000 4972.600098 2166.879883 8481.440430 3328.719971 1037.130005 3271.370117 2.574350e+05 2.217770e+05 4.972600e+03 2.166880e+03 8.481440e+03 3.328720e+03 1.037130e+03 3.271370e+03
261046.000000 221550.000000 5816.180176 590.216980 9120.929688 3895.399902 2382.669922 2824.169922 2.610460e+05 2.215500e+05 5.816180e+03 5.902170e+02 9.120930e+03 3.895400e+03 2.382670e+03 2.824170e+03
262766.000000 224473.000000 4835.049805 1785.770020 7880.759766 4745.620117 2443.659912 3229.550049 2.627660e+05 2.244730e+05 4.835050e+03 1.785770e+03 7.880760e+03 4.745620e+03 2.443660e+03 3.229550e+03
256509.000000 226413.000000 3758.870117 3461.199951 6743.770020 4928.959961 1536.619995 3546.689941 2.565090e+05 2.264130e+05 3.758870e+03 3.461200e+03 6.743770e+03 4.928960e+03 1.536620e+03 3.546690e+03
250793.000000 224372.000000 5218.490234 2865.260010 7803.959961 4351.089844 1333.819946 3680.489990 2.507930e+05 2.243720e+05 5.218490e+03 2.865260e+03 7.803960e+03 4.351090e+03 1.333820e+03 3.680490e+03
256319.000000 222066.000000 6403.970215 732.344971 9627.759766 3089.300049 1516.780029 3653.689941 2.563190e+05 2.220660e+05 6.403970e+03 7.323450e+02 9.627760e+03 3.089300e+03 1.516780e+03 3.653690e+03
263343.000000 223235.000000 5200.430176 1388.579956 9372.849609 3371.229980 1450.390015 2678.909912 2.633430e+05 2.232350e+05 5.200430e+03 1.388580e+03 9.372850e+03 3.371230e+03 1.450390e+03 2.678910e+03
260903.000000 225110.000000 3722.580078 3246.659912 7876.540039 4716.810059 1498.439941 2116.520020 2.609030e+05 2.251100e+05 3.722580e+03 3.246660e+03 7.876540e+03 4.716810e+03 1.498440e+03 2.116520e+03
254416.000000 223769.000000 4841.649902 2956.399902 8115.919922 5392.359863 2142.810059 2652.320068 2.544160e+05 2.237690e+05 4.841650e+03 2.956400e+03 8.115920e+03 5.392360e+03 2.142810e+03 2.652320e+03
256698.000000 222172.000000 6471.229980 970.395996 8834.980469 4816.839844 2376.629883 3605.860107 2.566980e+05 2.221720e+05 6.471230e+03 9.703960e+02 8.834980e+03 4.816840e+03 2.376630e+03 3.605860e+03
261841.000000 223537.000000 5500.740234 1189.660034 8365.730469 4016.469971 1042.270020 3821.199951 2.618410e+05 2.235370e+05 5.500740e+03 1.189660e+03 8.365730e+03 4.016470e+03 1.042270e+03 3.821200e+03
259503.000000 225840.000000 3827.929932 3088.840088 7676.140137 3978.310059 -357.006989 3016.419922 2.595030e+05 2.258400e+05 3.827930e+03 3.088840e+03 7.676140e+03 3.978310e+03 -3.570070e+02 3.016420e+03
253457.000000 224636.000000 4914.609863 3097.449951 8224.900391 4321.439941 171.373993 2412.360107 2.534570e+05 2.246360e+05 4.914610e+03 3.097450e+03 8.224900e+03 4.321440e+03 1.713740e+02 2.412360e+03
256029.000000 222221.000000 6841.799805 1028.500000 9252.299805 4387.569824 2418.139893 2510.100098 2.560290e+05 2.222210e+05 6.841800e+03 1.028500e+03 9.252300e+03 4.387570e+03 2.418140e+03 2.510100e+03
262840.000000 222550.000000 6210.250000 1410.729980 8538.900391 4152.580078 3009.300049 3219.760010 2.628400e+05 2.225500e+05 6.210250e+03 1.410730e+03 8.538900e+03 4.152580e+03 3.009300e+03 3.219760e+03
261633.000000 225065.000000 4284.529785 3357.209961 7282.169922 3823.590088 1402.839966 3644.669922 2.616330e+05 2.250650e+05 4.284530e+03 3.357210e+03 7.282170e+03 3.823590e+03 1.402840e+03 3.644670e+03
254591.000000 225109.000000 4693.160156 3647.739990 7745.160156 3686.379883 490.161011 3448.860107 2.545910e+05 2.251090e+05 4.693160e+03 3.647740e+03 7.745160e+03 3.686380e+03 4.901610e+02 3.448860e+03
254780.000000 223599.000000 6527.379883 1569.869995 9438.429688 3456.580078 1162.520020 3252.010010 2.547800e+05 2.235990e+05 6.527380e+03 1.569870e+03 9.438430e+03 3.456580e+03 1.162520e+03 3.252010e+03
260639.000000 224107.000000 6531.049805 1633.050049 9283.719727 4174.020020 2089.550049 2775.750000 2.606390e+05 2.241070e+05 6.531050e+03 1.633050e+03 9.283720e+03 4.174020e+03 2.089550e+03 2.775750e+03
261108.000000 225472.000000 4968.259766 3527.850098 7692.870117 5137.100098 2207.389893 2436.659912 2.611080e+05 2.254720e+05 4.968260e+03 3.527850e+03 7.692870e+03 5.137100e+03 2.207390e+03 2.436660e+03
255775.000000 223708.000000 4963.450195 4017.370117 7701.419922 5269.649902 2284.399902 2842.080078 2.557750e+05 2.237080e+05 4.963450e+03 4.017370e+03 7.701420e+03 5.269650e+03 2.284400e+03 2.842080e+03
257398.000000 220947.000000 6767.500000 1645.709961 9107.070312 4000.179932 2548.860107 3624.770020 2.573980e+05 2.209470e+05 6.767500e+03 1.645710e+03 9.107070e+03 4.000180e+03 2.548860e+03 3.624770e+03
264924.000000 221559.000000 6471.459961 1110.329956 9459.650391 3108.169922 1696.969971 3893.439941 2.649240e+05 2.215590e+05 6.471460e+03 1.110330e+03 9.459650e+03 3.108170e+03 1.696970e+03 3.893440e+03
265339.000000 225733.000000 4348.799805 3459.510010 8475.299805 4031.239990 573.346985 2910.270020 2.653390e+05 2.257330e+05 4.348800e+03 3.459510e+03 8.475300e+03 4.031240e+03 5.733470e+02 2.910270e+03
256814.000000 226995.000000 3479.540039 4949.790039 7499.910156 5624.709961 751.656006 2347.709961 2.568140e+05 2.269950e+05 3.479540e+03 4.949790e+03 7.499910e+03 5.624710e+03 7.516560e+02 2.347710e+03
253316.000000 225161.000000 5147.060059 3218.429932 8460.160156 5869.299805 2336.320068 2987.959961 2.533160e+05 2.251610e+05 5.147060e+03 3.218430e+03 8.460160e+03 5.869300e+03 2.336320e+03 2.987960e+03
259360.000000 223101.000000 5549.120117 1869.949951 8740.759766 4668.939941 2457.909912 3758.820068 2.593600e+05 2.231010e+05 5.549120e+03 1.869950e+03 8.740760e+03 4.668940e+03 2.457910e+03 3.758820e+03
262012.000000 224016.000000 4173.609863 3004.129883 8157.040039 3704.729980 987.963989 3652.750000 2.620120e+05 2.240160e+05 4.173610e+03 3.004130e+03 8.157040e+03 3.704730e+03 9.879640e+02 3.652750e+03
257176.000000 224420.000000 3517.300049 4118.750000 7822.240234 3718.229980 37.264900 2953.679932 2.571760e+05 2.244200e+05 3.517300e+03 4.118750e+03 7.822240e+03 3.718230e+03 3.726490e+01 2.953680e+03
255146.000000 223322.000000 4923.979980 2330.679932 9095.910156 3792.399902 1013.070007 2711.239990 2.551460e+05 2.233220e+05 4.923980e+03 2.330680e+03 9.095910e+03 3.792400e+03 1.013070e+03 2.711240e+03
260524.000000 223651.000000 5413.629883 1146.209961 8817.169922 4419.649902 2446.649902 2832.050049 2.605240e+05 2.236510e+05 5.413630e+03 1.146210e+03 8.817170e+03 4.419650e+03 2.446650e+03 2.832050e+03
262098.000000 225752.000000 4262.979980 2270.969971 7135.479980 5067.120117 2294.679932 3376.620117 2.620980e+05 2.257520e+05 4.262980e+03 2.270970e+03 7.135480e+03 5.067120e+03 2.294680e+03 3.376620e+03
256889.000000 225379.000000 3606.459961 3568.189941 6552.649902 4970.270020 1516.380005 3662.570068 2.568890e+05 2.253790e+05 3.606460e+03 3.568190e+03 6.552650e+03 4.970270e+03 1.516380e+03 3.662570e+03
253948.000000 222631.000000 5511.700195 2066.300049 7952.660156 4019.909912 1513.140015 3752.629883 2.539480e+05 2.226310e+05 5.511700e+03 2.066300e+03 7.952660e+03 4.019910e+03 1.513140e+03 3.752630e+03
259799.000000 222067.000000 5873.500000 608.583984 9253.780273 2870.739990 1348.239990 3344.199951 2.597990e+05 2.220670e+05 5.873500e+03 6.085840e+02 9.253780e+03 2.870740e+03 1.348240e+03 3.344200e+03
262547.000000 224901.000000 4346.080078 1928.099976 8590.969727 3455.459961 904.390991 2379.270020 2.625470e+05 2.249010e+05 4.346080e+03 1.928100e+03 8.590970e+03 3.455460e+03 9.043910e+02 2.379270e+03
256137.000000 226761.000000 3423.560059 3379.080078 7471.149902 4894.169922 1153.540039 2031.410034 2.561370e+05 2.267610e+05 3.423560e+03 3.379080e+03 7.471150e+03 4.894170e+03 1.153540e+03 2.031410e+03
250326.000000 225013.000000 5519.979980 2423.969971 7991.759766 5117.950195 2098.790039 3099.239990 2.503260e+05 2.250130e+05 5.519980e+03 2.423970e+03 7.991760e+03 5.117950e+03 2.098790e+03 3.099240e+03
255454.000000 222992.000000 6547.950195 496.496002 8751.339844 3900.560059 2132.290039 4076.810059 2.554540e+05 2.229920e+05 6.547950e+03 4.964960e+02 8.751340e+03 3.900560e+03 2.132290e+03 4.076810e+03
261286.000000 223489.000000 5152.850098 1501.510010 8425.610352 2888.030029 776.114014 3786.360107 2.612860e+05 2.234890e+05 5.152850e+03 1.501510e+03 8.425610e+03 2.888030e+03 7.761140e+02 3.786360e+03
258969.000000 224069.000000 3832.610107 3001.979980 7979.259766 3182.310059 52.716000 2874.800049 2.589690e+05 2.240690e+05 3.832610e+03 3.001980e+03 7.979260e+03 3.182310e+03 5.271600e+01 2.874800e+03
254946.000000 222035.000000 5317.879883 2139.800049 9103.139648 3955.610107 1235.170044 2394.149902 2.549460e+05 2.220350e+05 5.317880e+03 2.139800e+03 9.103140e+03 3.955610e+03 1.235170e+03 2.394150e+03
258676.000000 221205.000000 6594.910156 505.343994 9423.360352 4562.470215 2913.739990 2892.350098 2.586760e+05 2.212050e+05 6.594910e+03 5.053440e+02 9.423360e+03 4.562470e+03 2.913740e+03 2.892350e+03
262125.000000 223566.000000 5116.750000 1773.599976 8082.200195 4776.370117 2386.389893 3659.729980 2.621250e+05 2.235660e+05 5.116750e+03 1.773600e+03 8.082200e+03 4.776370e+03 2.386390e+03 3.659730e+03
257835.000000 225918.000000 3714.300049 3477.080078 7205.370117 4554.609863 711.539001 3878.419922 2.578350e+05 2.259180e+05 3.714300e+03 3.477080e+03 7.205370e+03 4.554610e+03 7.115390e+02 3.878420e+03
253660.000000 224371.000000 5022.450195 2592.429932 8277.200195 4119.370117 486.507996 3666.739990 2.536600e+05 2.243710e+05 5.022450e+03 2.592430e+03 8.277200e+03 4.119370e+03 4.865080e+02 3.666740e+03
259503.000000 222061.000000 6589.950195 659.935974 9596.919922 3598.100098 1702.489990 3036.600098 2.595030e+05 2.220610e+05 6.589950e+03 6.599360e+02 9.596920e+03 3.598100e+03 1.702490e+03 3.036600e+03
265495.000000 222843.000000 5541.850098 1728.430054 8459.959961 4492.000000 2231.969971 2430.620117 2.654950e+05 2.228430e+05 5.541850e+03 1.728430e+03 8.459960e+03 4.492000e+03 2.231970e+03 2.430620e+03
260929.000000 224996.000000 4000.949951 3745.989990 6983.790039 5430.859863 1855.260010 2533.379883 2.609290e+05 2.249960e+05 4.000950e+03 3.745990e+03 6.983790e+03 5.430860e+03 1.855260e+03 2.533380e+03
252716.000000 224335.000000 5086.560059 3401.149902 7597.970215 5196.120117 1755.719971 3079.760010 2.527160e+05 2.243350e+05 5.086560e+03 3.401150e+03 7.597970e+03 5.196120e+03 1.755720e+03 3.079760e+03
254110.000000 223111.000000 6822.189941 1229.079956 9164.339844 3761.229980 1679.390015 3584.879883 2.541100e+05 2.231110e+05 6.822190e+03 1.229080e+03 9.164340e+03 3.761230e+03 1.679390e+03 3.584880e+03
259969.000000 224693.000000 6183.950195 1538.500000 9222.080078 3139.169922 949.901978 3180.800049 2.599690e+05 2.246930e+05 6.183950e+03 1.538500e+03 9.222080e+03 3.139170e+03 9.499020e+02 3.180800e+03
259078.000000 226913.000000 4388.890137 3694.820068 8195.019531 3933.000000 426.079987 2388.449951 2.590780e+05 2.269130e+05 4.388890e+03 3.694820e+03 8.195020e+03 3.933000e+03 4.260800e+02 2.388450e+03
254563.000000 224760.000000 5168.439941 4020.939941 8450.269531 4758.910156 1458.900024 2286.429932 2.545630e+05 2.247600e+05 5.168440e+03 4.020940e+03 8.450270e+03 4.758910e+03 1.458900e+03 2.286430e+03
258059.000000 221217.000000 6883.459961 1649.530029 9232.780273 4457.649902 3057.820068 3031.949951 2.580590e+05 2.212170e+05 6.883460e+03 1.649530e+03 9.232780e+03 4.457650e+03 3.057820e+03 3.031950e+03
264667.000000 221177.000000 6218.509766 1645.729980 8657.179688 3663.500000 2528.280029 3978.340088 2.646670e+05 2.211770e+05 6.218510e+03 1.645730e+03 8.657180e+03 3.663500e+03 2.528280e+03 3.978340e+03
262925.000000 224382.000000 4627.500000 3635.929932 7892.799805 3431.320068 604.508972 3901.370117 2.629250e+05 2.243820e+05 4.627500e+03 3.635930e+03 7.892800e+03 3.431320e+03 6.045090e+02 3.901370e+03
254708.000000 225448.000000 4408.250000 4461.040039 8197.169922 3953.750000 -44.534599 3154.870117 2.547080e+05 2.254480e+05 4.408250e+03 4.461040e+03 8.197170e+03 3.953750e+03 -4.453460e+01 3.154870e+03
253702.000000 224635.000000 5825.770020 2577.050049 9590.049805 4569.250000 1460.270020 2785.169922 2.537020e+05 2.246350e+05 5.825770e+03 2.577050e+03 9.590050e+03 4.569250e+03 1.460270e+03 2.785170e+03
260206.000000 224140.000000 5387.979980 1951.160034 8789.509766 5131.660156 2706.379883 2972.479980 2.602060e+05 2.241400e+05 5.387980e+03 1.951160e+03 8.789510e+03 5.131660e+03 2.706380e+03 2.972480e+03
261240.000000 224737.000000 3860.810059 3418.310059 7414.529785 5284.520020 2271.379883 3183.149902 2.612400e+05 2.247370e+05 3.860810e+03 3.418310e+03 7.414530e+03 5.284520e+03 2.271380e+03 3.183150e+03
256140.000000 223252.000000 3850.010010 3957.139893 7262.649902 4964.640137 1499.510010 3453.129883 2.561400e+05 2.232520e+05 3.850010e+03 3.957140e+03 7.262650e+03 4.964640e+03 1.499510e+03 3.453130e+03
256116.000000 221349.000000 5594.479980 2054.399902 8835.129883 3662.010010 1485.510010 3613.010010 2.561160e+05 2.213490e+05 5.594480e+03 2.054400e+03 8.835130e+03 3.662010e+03 1.485510e+03 3.613010e+03

View File

@@ -1,120 +1,120 @@
251774.000000 224241.000000 5688.100098 1915.530029 9329.219727 4183.709961 1212.349976 2641.790039 2.517740e+05 2.242410e+05 5.688100e+03 1.915530e+03 9.329220e+03 4.183710e+03 1.212350e+03 2.641790e+03
259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03
257614.000000 223323.000000 5003.660156 3525.139893 7165.310059 4685.620117 1715.380005 3440.479980 2.576140e+05 2.233230e+05 5.003660e+03 3.525140e+03 7.165310e+03 4.685620e+03 1.715380e+03 3.440480e+03
255780.000000 221915.000000 6357.310059 2145.290039 8426.969727 3775.350098 1475.390015 3797.239990 2.557800e+05 2.219150e+05 6.357310e+03 2.145290e+03 8.426970e+03 3.775350e+03 1.475390e+03 3.797240e+03
260166.000000 223008.000000 6702.589844 1484.959961 9288.099609 3330.830078 1228.500000 3214.320068 2.601660e+05 2.230080e+05 6.702590e+03 1.484960e+03 9.288100e+03 3.330830e+03 1.228500e+03 3.214320e+03
261231.000000 226426.000000 4980.060059 2982.379883 8499.629883 4267.669922 994.088989 2292.889893 2.612310e+05 2.264260e+05 4.980060e+03 2.982380e+03 8.499630e+03 4.267670e+03 9.940890e+02 2.292890e+03
255117.000000 226642.000000 4584.410156 4656.439941 7860.149902 5317.310059 1473.599976 2111.689941 2.551170e+05 2.266420e+05 4.584410e+03 4.656440e+03 7.860150e+03 5.317310e+03 1.473600e+03 2.111690e+03
253300.000000 223554.000000 6455.089844 3036.649902 8869.750000 4986.310059 2607.360107 2839.590088 2.533000e+05 2.235540e+05 6.455090e+03 3.036650e+03 8.869750e+03 4.986310e+03 2.607360e+03 2.839590e+03
261061.000000 221263.000000 6951.979980 1500.239990 9386.099609 3791.679932 2677.010010 3980.629883 2.610610e+05 2.212630e+05 6.951980e+03 1.500240e+03 9.386100e+03 3.791680e+03 2.677010e+03 3.980630e+03
266503.000000 223198.000000 5189.609863 2594.560059 8571.530273 3175.000000 919.840027 3792.010010 2.665030e+05 2.231980e+05 5.189610e+03 2.594560e+03 8.571530e+03 3.175000e+03 9.198400e+02 3.792010e+03
260692.000000 225184.000000 3782.479980 4642.879883 7662.959961 3917.790039 -251.097000 2907.060059 2.606920e+05 2.251840e+05 3.782480e+03 4.642880e+03 7.662960e+03 3.917790e+03 -2.510970e+02 2.907060e+03
253963.000000 225081.000000 5123.529785 3839.550049 8669.030273 4877.819824 943.723999 2527.449951 2.539630e+05 2.250810e+05 5.123530e+03 3.839550e+03 8.669030e+03 4.877820e+03 9.437240e+02 2.527450e+03
256555.000000 224169.000000 5930.600098 2298.540039 8906.709961 5331.680176 2549.909912 3053.560059 2.565550e+05 2.241690e+05 5.930600e+03 2.298540e+03 8.906710e+03 5.331680e+03 2.549910e+03 3.053560e+03
260889.000000 225010.000000 4681.129883 2971.870117 7900.040039 4874.080078 2322.429932 3649.120117 2.608890e+05 2.250100e+05 4.681130e+03 2.971870e+03 7.900040e+03 4.874080e+03 2.322430e+03 3.649120e+03
257944.000000 224923.000000 3291.139893 4357.089844 7131.589844 4385.560059 1077.050049 3664.040039 2.579440e+05 2.249230e+05 3.291140e+03 4.357090e+03 7.131590e+03 4.385560e+03 1.077050e+03 3.664040e+03
255009.000000 223018.000000 4584.819824 2864.000000 8469.490234 3625.580078 985.557007 3504.229980 2.550090e+05 2.230180e+05 4.584820e+03 2.864000e+03 8.469490e+03 3.625580e+03 9.855570e+02 3.504230e+03
260114.000000 221947.000000 5676.189941 1210.339966 9393.780273 3390.239990 1654.020020 3018.699951 2.601140e+05 2.219470e+05 5.676190e+03 1.210340e+03 9.393780e+03 3.390240e+03 1.654020e+03 3.018700e+03
264277.000000 224438.000000 4446.620117 2176.719971 8142.089844 4584.879883 2327.830078 2615.800049 2.642770e+05 2.244380e+05 4.446620e+03 2.176720e+03 8.142090e+03 4.584880e+03 2.327830e+03 2.615800e+03
259221.000000 226471.000000 2734.439941 4182.759766 6389.549805 5540.520020 1958.880005 2720.120117 2.592210e+05 2.264710e+05 2.734440e+03 4.182760e+03 6.389550e+03 5.540520e+03 1.958880e+03 2.720120e+03
252650.000000 224831.000000 4163.640137 2989.989990 7179.200195 5213.060059 1929.550049 3457.659912 2.526500e+05 2.248310e+05 4.163640e+03 2.989990e+03 7.179200e+03 5.213060e+03 1.929550e+03 3.457660e+03
257083.000000 222048.000000 5759.040039 702.440979 8566.549805 3552.020020 1832.939941 3956.189941 2.570830e+05 2.220480e+05 5.759040e+03 7.024410e+02 8.566550e+03 3.552020e+03 1.832940e+03 3.956190e+03
263130.000000 222967.000000 5141.140137 1166.119995 8666.959961 2720.370117 971.374023 3479.729980 2.631300e+05 2.229670e+05 5.141140e+03 1.166120e+03 8.666960e+03 2.720370e+03 9.713740e+02 3.479730e+03
260236.000000 225265.000000 3425.139893 3339.080078 7853.609863 3674.949951 525.908020 2443.310059 2.602360e+05 2.252650e+05 3.425140e+03 3.339080e+03 7.853610e+03 3.674950e+03 5.259080e+02 2.443310e+03
253503.000000 224527.000000 4398.129883 2927.429932 8110.279785 4842.470215 1513.869995 2467.100098 2.535030e+05 2.245270e+05 4.398130e+03 2.927430e+03 8.110280e+03 4.842470e+03 1.513870e+03 2.467100e+03
256126.000000 222693.000000 6043.529785 656.223999 8797.559570 4832.410156 2832.370117 3426.139893 2.561260e+05 2.226930e+05 6.043530e+03 6.562240e+02 8.797560e+03 4.832410e+03 2.832370e+03 3.426140e+03
261677.000000 223608.000000 5830.459961 1033.910034 8123.939941 3980.689941 1927.959961 4092.719971 2.616770e+05 2.236080e+05 5.830460e+03 1.033910e+03 8.123940e+03 3.980690e+03 1.927960e+03 4.092720e+03
259457.000000 225536.000000 4015.570068 2995.989990 7135.439941 3713.550049 307.220001 3849.429932 2.594570e+05 2.255360e+05 4.015570e+03 2.995990e+03 7.135440e+03 3.713550e+03 3.072200e+02 3.849430e+03
253352.000000 224216.000000 4650.560059 3196.620117 8131.279785 3586.159912 70.832298 3074.179932 2.533520e+05 2.242160e+05 4.650560e+03 3.196620e+03 8.131280e+03 3.586160e+03 7.083230e+01 3.074180e+03
256124.000000 221513.000000 6100.479980 821.979980 9757.540039 3474.510010 1647.520020 2559.860107 2.561240e+05 2.215130e+05 6.100480e+03 8.219800e+02 9.757540e+03 3.474510e+03 1.647520e+03 2.559860e+03
263024.000000 221559.000000 5789.959961 699.416992 9129.740234 4153.080078 2829.250000 2677.270020 2.630240e+05 2.215590e+05 5.789960e+03 6.994170e+02 9.129740e+03 4.153080e+03 2.829250e+03 2.677270e+03
261720.000000 224015.000000 4358.500000 2645.360107 7414.109863 4810.669922 2225.989990 3185.989990 2.617200e+05 2.240150e+05 4.358500e+03 2.645360e+03 7.414110e+03 4.810670e+03 2.225990e+03 3.185990e+03
254756.000000 224240.000000 4857.379883 3229.679932 7539.310059 4769.140137 1507.130005 3668.260010 2.547560e+05 2.242400e+05 4.857380e+03 3.229680e+03 7.539310e+03 4.769140e+03 1.507130e+03 3.668260e+03
256889.000000 222658.000000 6473.419922 1214.109985 9010.759766 3848.729980 1303.839966 3778.500000 2.568890e+05 2.226580e+05 6.473420e+03 1.214110e+03 9.010760e+03 3.848730e+03 1.303840e+03 3.778500e+03
264208.000000 223316.000000 5700.450195 1116.560059 9087.610352 3846.679932 1293.589966 2891.560059 2.642080e+05 2.233160e+05 5.700450e+03 1.116560e+03 9.087610e+03 3.846680e+03 1.293590e+03 2.891560e+03
263310.000000 225719.000000 3936.120117 3252.360107 7552.850098 4897.859863 1156.630005 2037.160034 2.633100e+05 2.257190e+05 3.936120e+03 3.252360e+03 7.552850e+03 4.897860e+03 1.156630e+03 2.037160e+03
255079.000000 225086.000000 4536.450195 3960.110107 7454.589844 5479.069824 1596.359985 2190.800049 2.550790e+05 2.250860e+05 4.536450e+03 3.960110e+03 7.454590e+03 5.479070e+03 1.596360e+03 2.190800e+03
254487.000000 222508.000000 6635.859863 1758.849976 8732.969727 4466.970215 2650.360107 3139.310059 2.544870e+05 2.225080e+05 6.635860e+03 1.758850e+03 8.732970e+03 4.466970e+03 2.650360e+03 3.139310e+03
261241.000000 222432.000000 6702.270020 1085.130005 8989.230469 3112.989990 1933.560059 3828.409912 2.612410e+05 2.224320e+05 6.702270e+03 1.085130e+03 8.989230e+03 3.112990e+03 1.933560e+03 3.828410e+03
262119.000000 225587.000000 4714.950195 2892.360107 8107.819824 2961.310059 239.977997 3273.719971 2.621190e+05 2.255870e+05 4.714950e+03 2.892360e+03 8.107820e+03 2.961310e+03 2.399780e+02 3.273720e+03
254999.000000 226514.000000 4532.089844 4126.899902 8200.129883 3872.590088 56.089001 2370.580078 2.549990e+05 2.265140e+05 4.532090e+03 4.126900e+03 8.200130e+03 3.872590e+03 5.608900e+01 2.370580e+03
254289.000000 224033.000000 6538.810059 2251.439941 9419.429688 4564.450195 2077.810059 2508.169922 2.542890e+05 2.240330e+05 6.538810e+03 2.251440e+03 9.419430e+03 4.564450e+03 2.077810e+03 2.508170e+03
261890.000000 221960.000000 6846.089844 1475.270020 9125.589844 4598.290039 3299.219971 3475.419922 2.618900e+05 2.219600e+05 6.846090e+03 1.475270e+03 9.125590e+03 4.598290e+03 3.299220e+03 3.475420e+03
264502.000000 223085.000000 5066.379883 3270.560059 7933.169922 4173.709961 1908.910034 3867.459961 2.645020e+05 2.230850e+05 5.066380e+03 3.270560e+03 7.933170e+03 4.173710e+03 1.908910e+03 3.867460e+03
257889.000000 223656.000000 4201.660156 4473.640137 7688.339844 4161.580078 687.578979 3653.689941 2.578890e+05 2.236560e+05 4.201660e+03 4.473640e+03 7.688340e+03 4.161580e+03 6.875790e+02 3.653690e+03
254270.000000 223151.000000 5715.140137 2752.139893 9273.320312 3772.949951 896.403992 3256.060059 2.542700e+05 2.231510e+05 5.715140e+03 2.752140e+03 9.273320e+03 3.772950e+03 8.964040e+02 3.256060e+03
258257.000000 224217.000000 6114.310059 1856.859985 9604.320312 4200.490234 1764.380005 2939.219971 2.582570e+05 2.242170e+05 6.114310e+03 1.856860e+03 9.604320e+03 4.200490e+03 1.764380e+03 2.939220e+03
260020.000000 226868.000000 4237.529785 3605.879883 8066.220215 5430.250000 2138.580078 2696.709961 2.600200e+05 2.268680e+05 4.237530e+03 3.605880e+03 8.066220e+03 5.430250e+03 2.138580e+03 2.696710e+03
255083.000000 225924.000000 3350.310059 4853.069824 7045.819824 5925.200195 1893.609985 2897.340088 2.550830e+05 2.259240e+05 3.350310e+03 4.853070e+03 7.045820e+03 5.925200e+03 1.893610e+03 2.897340e+03
254453.000000 222127.000000 5271.330078 2491.500000 8436.679688 5032.080078 2436.050049 3724.590088 2.544530e+05 2.221270e+05 5.271330e+03 2.491500e+03 8.436680e+03 5.032080e+03 2.436050e+03 3.724590e+03
262588.000000 219950.000000 5994.620117 789.273987 9029.650391 3515.739990 1953.569946 4014.520020 2.625880e+05 2.199500e+05 5.994620e+03 7.892740e+02 9.029650e+03 3.515740e+03 1.953570e+03 4.014520e+03
265610.000000 223333.000000 4391.410156 2400.959961 8146.459961 3536.959961 530.231995 3133.919922 2.656100e+05 2.233330e+05 4.391410e+03 2.400960e+03 8.146460e+03 3.536960e+03 5.302320e+02 3.133920e+03
257470.000000 226977.000000 2975.320068 4633.529785 7278.560059 4640.100098 -50.150200 2024.959961 2.574700e+05 2.269770e+05 2.975320e+03 4.633530e+03 7.278560e+03 4.640100e+03 -5.015020e+01 2.024960e+03
250687.000000 226331.000000 4517.859863 3183.800049 8072.600098 5281.660156 1605.140015 2335.139893 2.506870e+05 2.263310e+05 4.517860e+03 3.183800e+03 8.072600e+03 5.281660e+03 1.605140e+03 2.335140e+03
255563.000000 224495.000000 5551.000000 1101.300049 8461.490234 4725.700195 2726.669922 3480.540039 2.555630e+05 2.244950e+05 5.551000e+03 1.101300e+03 8.461490e+03 4.725700e+03 2.726670e+03 3.480540e+03
261335.000000 224645.000000 4764.680176 1557.020020 7833.350098 3524.810059 1577.410034 4038.620117 2.613350e+05 2.246450e+05 4.764680e+03 1.557020e+03 7.833350e+03 3.524810e+03 1.577410e+03 4.038620e+03
260269.000000 224008.000000 3558.030029 2987.610107 7362.439941 3279.229980 562.442017 3786.550049 2.602690e+05 2.240080e+05 3.558030e+03 2.987610e+03 7.362440e+03 3.279230e+03 5.624420e+02 3.786550e+03
257435.000000 221777.000000 4972.600098 2166.879883 8481.440430 3328.719971 1037.130005 3271.370117 2.574350e+05 2.217770e+05 4.972600e+03 2.166880e+03 8.481440e+03 3.328720e+03 1.037130e+03 3.271370e+03
261046.000000 221550.000000 5816.180176 590.216980 9120.929688 3895.399902 2382.669922 2824.169922 2.610460e+05 2.215500e+05 5.816180e+03 5.902170e+02 9.120930e+03 3.895400e+03 2.382670e+03 2.824170e+03
262766.000000 224473.000000 4835.049805 1785.770020 7880.759766 4745.620117 2443.659912 3229.550049 2.627660e+05 2.244730e+05 4.835050e+03 1.785770e+03 7.880760e+03 4.745620e+03 2.443660e+03 3.229550e+03
256509.000000 226413.000000 3758.870117 3461.199951 6743.770020 4928.959961 1536.619995 3546.689941 2.565090e+05 2.264130e+05 3.758870e+03 3.461200e+03 6.743770e+03 4.928960e+03 1.536620e+03 3.546690e+03
250793.000000 224372.000000 5218.490234 2865.260010 7803.959961 4351.089844 1333.819946 3680.489990 2.507930e+05 2.243720e+05 5.218490e+03 2.865260e+03 7.803960e+03 4.351090e+03 1.333820e+03 3.680490e+03
256319.000000 222066.000000 6403.970215 732.344971 9627.759766 3089.300049 1516.780029 3653.689941 2.563190e+05 2.220660e+05 6.403970e+03 7.323450e+02 9.627760e+03 3.089300e+03 1.516780e+03 3.653690e+03
263343.000000 223235.000000 5200.430176 1388.579956 9372.849609 3371.229980 1450.390015 2678.909912 2.633430e+05 2.232350e+05 5.200430e+03 1.388580e+03 9.372850e+03 3.371230e+03 1.450390e+03 2.678910e+03
260903.000000 225110.000000 3722.580078 3246.659912 7876.540039 4716.810059 1498.439941 2116.520020 2.609030e+05 2.251100e+05 3.722580e+03 3.246660e+03 7.876540e+03 4.716810e+03 1.498440e+03 2.116520e+03
254416.000000 223769.000000 4841.649902 2956.399902 8115.919922 5392.359863 2142.810059 2652.320068 2.544160e+05 2.237690e+05 4.841650e+03 2.956400e+03 8.115920e+03 5.392360e+03 2.142810e+03 2.652320e+03
256698.000000 222172.000000 6471.229980 970.395996 8834.980469 4816.839844 2376.629883 3605.860107 2.566980e+05 2.221720e+05 6.471230e+03 9.703960e+02 8.834980e+03 4.816840e+03 2.376630e+03 3.605860e+03
261841.000000 223537.000000 5500.740234 1189.660034 8365.730469 4016.469971 1042.270020 3821.199951 2.618410e+05 2.235370e+05 5.500740e+03 1.189660e+03 8.365730e+03 4.016470e+03 1.042270e+03 3.821200e+03
259503.000000 225840.000000 3827.929932 3088.840088 7676.140137 3978.310059 -357.006989 3016.419922 2.595030e+05 2.258400e+05 3.827930e+03 3.088840e+03 7.676140e+03 3.978310e+03 -3.570070e+02 3.016420e+03
253457.000000 224636.000000 4914.609863 3097.449951 8224.900391 4321.439941 171.373993 2412.360107 2.534570e+05 2.246360e+05 4.914610e+03 3.097450e+03 8.224900e+03 4.321440e+03 1.713740e+02 2.412360e+03
256029.000000 222221.000000 6841.799805 1028.500000 9252.299805 4387.569824 2418.139893 2510.100098 2.560290e+05 2.222210e+05 6.841800e+03 1.028500e+03 9.252300e+03 4.387570e+03 2.418140e+03 2.510100e+03
262840.000000 222550.000000 6210.250000 1410.729980 8538.900391 4152.580078 3009.300049 3219.760010 2.628400e+05 2.225500e+05 6.210250e+03 1.410730e+03 8.538900e+03 4.152580e+03 3.009300e+03 3.219760e+03
261633.000000 225065.000000 4284.529785 3357.209961 7282.169922 3823.590088 1402.839966 3644.669922 2.616330e+05 2.250650e+05 4.284530e+03 3.357210e+03 7.282170e+03 3.823590e+03 1.402840e+03 3.644670e+03
254591.000000 225109.000000 4693.160156 3647.739990 7745.160156 3686.379883 490.161011 3448.860107 2.545910e+05 2.251090e+05 4.693160e+03 3.647740e+03 7.745160e+03 3.686380e+03 4.901610e+02 3.448860e+03
254780.000000 223599.000000 6527.379883 1569.869995 9438.429688 3456.580078 1162.520020 3252.010010 2.547800e+05 2.235990e+05 6.527380e+03 1.569870e+03 9.438430e+03 3.456580e+03 1.162520e+03 3.252010e+03
260639.000000 224107.000000 6531.049805 1633.050049 9283.719727 4174.020020 2089.550049 2775.750000 2.606390e+05 2.241070e+05 6.531050e+03 1.633050e+03 9.283720e+03 4.174020e+03 2.089550e+03 2.775750e+03
261108.000000 225472.000000 4968.259766 3527.850098 7692.870117 5137.100098 2207.389893 2436.659912 2.611080e+05 2.254720e+05 4.968260e+03 3.527850e+03 7.692870e+03 5.137100e+03 2.207390e+03 2.436660e+03
255775.000000 223708.000000 4963.450195 4017.370117 7701.419922 5269.649902 2284.399902 2842.080078 2.557750e+05 2.237080e+05 4.963450e+03 4.017370e+03 7.701420e+03 5.269650e+03 2.284400e+03 2.842080e+03
257398.000000 220947.000000 6767.500000 1645.709961 9107.070312 4000.179932 2548.860107 3624.770020 2.573980e+05 2.209470e+05 6.767500e+03 1.645710e+03 9.107070e+03 4.000180e+03 2.548860e+03 3.624770e+03
264924.000000 221559.000000 6471.459961 1110.329956 9459.650391 3108.169922 1696.969971 3893.439941 2.649240e+05 2.215590e+05 6.471460e+03 1.110330e+03 9.459650e+03 3.108170e+03 1.696970e+03 3.893440e+03
265339.000000 225733.000000 4348.799805 3459.510010 8475.299805 4031.239990 573.346985 2910.270020 2.653390e+05 2.257330e+05 4.348800e+03 3.459510e+03 8.475300e+03 4.031240e+03 5.733470e+02 2.910270e+03
256814.000000 226995.000000 3479.540039 4949.790039 7499.910156 5624.709961 751.656006 2347.709961 2.568140e+05 2.269950e+05 3.479540e+03 4.949790e+03 7.499910e+03 5.624710e+03 7.516560e+02 2.347710e+03
253316.000000 225161.000000 5147.060059 3218.429932 8460.160156 5869.299805 2336.320068 2987.959961 2.533160e+05 2.251610e+05 5.147060e+03 3.218430e+03 8.460160e+03 5.869300e+03 2.336320e+03 2.987960e+03
259360.000000 223101.000000 5549.120117 1869.949951 8740.759766 4668.939941 2457.909912 3758.820068 2.593600e+05 2.231010e+05 5.549120e+03 1.869950e+03 8.740760e+03 4.668940e+03 2.457910e+03 3.758820e+03
262012.000000 224016.000000 4173.609863 3004.129883 8157.040039 3704.729980 987.963989 3652.750000 2.620120e+05 2.240160e+05 4.173610e+03 3.004130e+03 8.157040e+03 3.704730e+03 9.879640e+02 3.652750e+03
257176.000000 224420.000000 3517.300049 4118.750000 7822.240234 3718.229980 37.264900 2953.679932 2.571760e+05 2.244200e+05 3.517300e+03 4.118750e+03 7.822240e+03 3.718230e+03 3.726490e+01 2.953680e+03
255146.000000 223322.000000 4923.979980 2330.679932 9095.910156 3792.399902 1013.070007 2711.239990 2.551460e+05 2.233220e+05 4.923980e+03 2.330680e+03 9.095910e+03 3.792400e+03 1.013070e+03 2.711240e+03
260524.000000 223651.000000 5413.629883 1146.209961 8817.169922 4419.649902 2446.649902 2832.050049 2.605240e+05 2.236510e+05 5.413630e+03 1.146210e+03 8.817170e+03 4.419650e+03 2.446650e+03 2.832050e+03
262098.000000 225752.000000 4262.979980 2270.969971 7135.479980 5067.120117 2294.679932 3376.620117 2.620980e+05 2.257520e+05 4.262980e+03 2.270970e+03 7.135480e+03 5.067120e+03 2.294680e+03 3.376620e+03
256889.000000 225379.000000 3606.459961 3568.189941 6552.649902 4970.270020 1516.380005 3662.570068 2.568890e+05 2.253790e+05 3.606460e+03 3.568190e+03 6.552650e+03 4.970270e+03 1.516380e+03 3.662570e+03
253948.000000 222631.000000 5511.700195 2066.300049 7952.660156 4019.909912 1513.140015 3752.629883 2.539480e+05 2.226310e+05 5.511700e+03 2.066300e+03 7.952660e+03 4.019910e+03 1.513140e+03 3.752630e+03
259799.000000 222067.000000 5873.500000 608.583984 9253.780273 2870.739990 1348.239990 3344.199951 2.597990e+05 2.220670e+05 5.873500e+03 6.085840e+02 9.253780e+03 2.870740e+03 1.348240e+03 3.344200e+03
262547.000000 224901.000000 4346.080078 1928.099976 8590.969727 3455.459961 904.390991 2379.270020 2.625470e+05 2.249010e+05 4.346080e+03 1.928100e+03 8.590970e+03 3.455460e+03 9.043910e+02 2.379270e+03
256137.000000 226761.000000 3423.560059 3379.080078 7471.149902 4894.169922 1153.540039 2031.410034 2.561370e+05 2.267610e+05 3.423560e+03 3.379080e+03 7.471150e+03 4.894170e+03 1.153540e+03 2.031410e+03
250326.000000 225013.000000 5519.979980 2423.969971 7991.759766 5117.950195 2098.790039 3099.239990 2.503260e+05 2.250130e+05 5.519980e+03 2.423970e+03 7.991760e+03 5.117950e+03 2.098790e+03 3.099240e+03
255454.000000 222992.000000 6547.950195 496.496002 8751.339844 3900.560059 2132.290039 4076.810059 2.554540e+05 2.229920e+05 6.547950e+03 4.964960e+02 8.751340e+03 3.900560e+03 2.132290e+03 4.076810e+03
261286.000000 223489.000000 5152.850098 1501.510010 8425.610352 2888.030029 776.114014 3786.360107 2.612860e+05 2.234890e+05 5.152850e+03 1.501510e+03 8.425610e+03 2.888030e+03 7.761140e+02 3.786360e+03
258969.000000 224069.000000 3832.610107 3001.979980 7979.259766 3182.310059 52.716000 2874.800049 2.589690e+05 2.240690e+05 3.832610e+03 3.001980e+03 7.979260e+03 3.182310e+03 5.271600e+01 2.874800e+03
254946.000000 222035.000000 5317.879883 2139.800049 9103.139648 3955.610107 1235.170044 2394.149902 2.549460e+05 2.220350e+05 5.317880e+03 2.139800e+03 9.103140e+03 3.955610e+03 1.235170e+03 2.394150e+03
258676.000000 221205.000000 6594.910156 505.343994 9423.360352 4562.470215 2913.739990 2892.350098 2.586760e+05 2.212050e+05 6.594910e+03 5.053440e+02 9.423360e+03 4.562470e+03 2.913740e+03 2.892350e+03
262125.000000 223566.000000 5116.750000 1773.599976 8082.200195 4776.370117 2386.389893 3659.729980 2.621250e+05 2.235660e+05 5.116750e+03 1.773600e+03 8.082200e+03 4.776370e+03 2.386390e+03 3.659730e+03
257835.000000 225918.000000 3714.300049 3477.080078 7205.370117 4554.609863 711.539001 3878.419922 2.578350e+05 2.259180e+05 3.714300e+03 3.477080e+03 7.205370e+03 4.554610e+03 7.115390e+02 3.878420e+03
253660.000000 224371.000000 5022.450195 2592.429932 8277.200195 4119.370117 486.507996 3666.739990 2.536600e+05 2.243710e+05 5.022450e+03 2.592430e+03 8.277200e+03 4.119370e+03 4.865080e+02 3.666740e+03
259503.000000 222061.000000 6589.950195 659.935974 9596.919922 3598.100098 1702.489990 3036.600098 2.595030e+05 2.220610e+05 6.589950e+03 6.599360e+02 9.596920e+03 3.598100e+03 1.702490e+03 3.036600e+03
265495.000000 222843.000000 5541.850098 1728.430054 8459.959961 4492.000000 2231.969971 2430.620117 2.654950e+05 2.228430e+05 5.541850e+03 1.728430e+03 8.459960e+03 4.492000e+03 2.231970e+03 2.430620e+03
260929.000000 224996.000000 4000.949951 3745.989990 6983.790039 5430.859863 1855.260010 2533.379883 2.609290e+05 2.249960e+05 4.000950e+03 3.745990e+03 6.983790e+03 5.430860e+03 1.855260e+03 2.533380e+03
252716.000000 224335.000000 5086.560059 3401.149902 7597.970215 5196.120117 1755.719971 3079.760010 2.527160e+05 2.243350e+05 5.086560e+03 3.401150e+03 7.597970e+03 5.196120e+03 1.755720e+03 3.079760e+03
254110.000000 223111.000000 6822.189941 1229.079956 9164.339844 3761.229980 1679.390015 3584.879883 2.541100e+05 2.231110e+05 6.822190e+03 1.229080e+03 9.164340e+03 3.761230e+03 1.679390e+03 3.584880e+03
259969.000000 224693.000000 6183.950195 1538.500000 9222.080078 3139.169922 949.901978 3180.800049 2.599690e+05 2.246930e+05 6.183950e+03 1.538500e+03 9.222080e+03 3.139170e+03 9.499020e+02 3.180800e+03
259078.000000 226913.000000 4388.890137 3694.820068 8195.019531 3933.000000 426.079987 2388.449951 2.590780e+05 2.269130e+05 4.388890e+03 3.694820e+03 8.195020e+03 3.933000e+03 4.260800e+02 2.388450e+03
254563.000000 224760.000000 5168.439941 4020.939941 8450.269531 4758.910156 1458.900024 2286.429932 2.545630e+05 2.247600e+05 5.168440e+03 4.020940e+03 8.450270e+03 4.758910e+03 1.458900e+03 2.286430e+03
258059.000000 221217.000000 6883.459961 1649.530029 9232.780273 4457.649902 3057.820068 3031.949951 2.580590e+05 2.212170e+05 6.883460e+03 1.649530e+03 9.232780e+03 4.457650e+03 3.057820e+03 3.031950e+03
264667.000000 221177.000000 6218.509766 1645.729980 8657.179688 3663.500000 2528.280029 3978.340088 2.646670e+05 2.211770e+05 6.218510e+03 1.645730e+03 8.657180e+03 3.663500e+03 2.528280e+03 3.978340e+03
262925.000000 224382.000000 4627.500000 3635.929932 7892.799805 3431.320068 604.508972 3901.370117 2.629250e+05 2.243820e+05 4.627500e+03 3.635930e+03 7.892800e+03 3.431320e+03 6.045090e+02 3.901370e+03
254708.000000 225448.000000 4408.250000 4461.040039 8197.169922 3953.750000 -44.534599 3154.870117 2.547080e+05 2.254480e+05 4.408250e+03 4.461040e+03 8.197170e+03 3.953750e+03 -4.453460e+01 3.154870e+03
253702.000000 224635.000000 5825.770020 2577.050049 9590.049805 4569.250000 1460.270020 2785.169922 2.537020e+05 2.246350e+05 5.825770e+03 2.577050e+03 9.590050e+03 4.569250e+03 1.460270e+03 2.785170e+03
260206.000000 224140.000000 5387.979980 1951.160034 8789.509766 5131.660156 2706.379883 2972.479980 2.602060e+05 2.241400e+05 5.387980e+03 1.951160e+03 8.789510e+03 5.131660e+03 2.706380e+03 2.972480e+03
261240.000000 224737.000000 3860.810059 3418.310059 7414.529785 5284.520020 2271.379883 3183.149902 2.612400e+05 2.247370e+05 3.860810e+03 3.418310e+03 7.414530e+03 5.284520e+03 2.271380e+03 3.183150e+03
256140.000000 223252.000000 3850.010010 3957.139893 7262.649902 4964.640137 1499.510010 3453.129883 2.561400e+05 2.232520e+05 3.850010e+03 3.957140e+03 7.262650e+03 4.964640e+03 1.499510e+03 3.453130e+03
256116.000000 221349.000000 5594.479980 2054.399902 8835.129883 3662.010010 1485.510010 3613.010010 2.561160e+05 2.213490e+05 5.594480e+03 2.054400e+03 8.835130e+03 3.662010e+03 1.485510e+03 3.613010e+03

View File

@@ -1,124 +1,124 @@
# path: /newton/prep # path: /newton/prep
# layout: PrepData # layout: float32_8
# start: 1332496830.0 # start: 1332496830.000000
# end: 1332496830.999 # end: 1332496830.999000
1332496830.000000 251774.000000 224241.000000 5688.100098 1915.530029 9329.219727 4183.709961 1212.349976 2641.790039 1332496830.000000 2.517740e+05 2.242410e+05 5.688100e+03 1.915530e+03 9.329220e+03 4.183710e+03 1.212350e+03 2.641790e+03
1332496830.008333 259567.000000 222698.000000 6207.600098 678.671997 9380.230469 4575.580078 2830.610107 2688.629883 1332496830.008333 2.595670e+05 2.226980e+05 6.207600e+03 6.786720e+02 9.380230e+03 4.575580e+03 2.830610e+03 2.688630e+03
1332496830.016667 263073.000000 223304.000000 4961.640137 2197.120117 7687.310059 4861.859863 2732.780029 3008.540039 1332496830.016667 2.630730e+05 2.233040e+05 4.961640e+03 2.197120e+03 7.687310e+03 4.861860e+03 2.732780e+03 3.008540e+03
1332496830.025000 257614.000000 223323.000000 5003.660156 3525.139893 7165.310059 4685.620117 1715.380005 3440.479980 1332496830.025000 2.576140e+05 2.233230e+05 5.003660e+03 3.525140e+03 7.165310e+03 4.685620e+03 1.715380e+03 3.440480e+03
1332496830.033333 255780.000000 221915.000000 6357.310059 2145.290039 8426.969727 3775.350098 1475.390015 3797.239990 1332496830.033333 2.557800e+05 2.219150e+05 6.357310e+03 2.145290e+03 8.426970e+03 3.775350e+03 1.475390e+03 3.797240e+03
1332496830.041667 260166.000000 223008.000000 6702.589844 1484.959961 9288.099609 3330.830078 1228.500000 3214.320068 1332496830.041667 2.601660e+05 2.230080e+05 6.702590e+03 1.484960e+03 9.288100e+03 3.330830e+03 1.228500e+03 3.214320e+03
1332496830.050000 261231.000000 226426.000000 4980.060059 2982.379883 8499.629883 4267.669922 994.088989 2292.889893 1332496830.050000 2.612310e+05 2.264260e+05 4.980060e+03 2.982380e+03 8.499630e+03 4.267670e+03 9.940890e+02 2.292890e+03
1332496830.058333 255117.000000 226642.000000 4584.410156 4656.439941 7860.149902 5317.310059 1473.599976 2111.689941 1332496830.058333 2.551170e+05 2.266420e+05 4.584410e+03 4.656440e+03 7.860150e+03 5.317310e+03 1.473600e+03 2.111690e+03
1332496830.066667 253300.000000 223554.000000 6455.089844 3036.649902 8869.750000 4986.310059 2607.360107 2839.590088 1332496830.066667 2.533000e+05 2.235540e+05 6.455090e+03 3.036650e+03 8.869750e+03 4.986310e+03 2.607360e+03 2.839590e+03
1332496830.075000 261061.000000 221263.000000 6951.979980 1500.239990 9386.099609 3791.679932 2677.010010 3980.629883 1332496830.075000 2.610610e+05 2.212630e+05 6.951980e+03 1.500240e+03 9.386100e+03 3.791680e+03 2.677010e+03 3.980630e+03
1332496830.083333 266503.000000 223198.000000 5189.609863 2594.560059 8571.530273 3175.000000 919.840027 3792.010010 1332496830.083333 2.665030e+05 2.231980e+05 5.189610e+03 2.594560e+03 8.571530e+03 3.175000e+03 9.198400e+02 3.792010e+03
1332496830.091667 260692.000000 225184.000000 3782.479980 4642.879883 7662.959961 3917.790039 -251.097000 2907.060059 1332496830.091667 2.606920e+05 2.251840e+05 3.782480e+03 4.642880e+03 7.662960e+03 3.917790e+03 -2.510970e+02 2.907060e+03
1332496830.100000 253963.000000 225081.000000 5123.529785 3839.550049 8669.030273 4877.819824 943.723999 2527.449951 1332496830.100000 2.539630e+05 2.250810e+05 5.123530e+03 3.839550e+03 8.669030e+03 4.877820e+03 9.437240e+02 2.527450e+03
1332496830.108333 256555.000000 224169.000000 5930.600098 2298.540039 8906.709961 5331.680176 2549.909912 3053.560059 1332496830.108333 2.565550e+05 2.241690e+05 5.930600e+03 2.298540e+03 8.906710e+03 5.331680e+03 2.549910e+03 3.053560e+03
1332496830.116667 260889.000000 225010.000000 4681.129883 2971.870117 7900.040039 4874.080078 2322.429932 3649.120117 1332496830.116667 2.608890e+05 2.250100e+05 4.681130e+03 2.971870e+03 7.900040e+03 4.874080e+03 2.322430e+03 3.649120e+03
1332496830.125000 257944.000000 224923.000000 3291.139893 4357.089844 7131.589844 4385.560059 1077.050049 3664.040039 1332496830.125000 2.579440e+05 2.249230e+05 3.291140e+03 4.357090e+03 7.131590e+03 4.385560e+03 1.077050e+03 3.664040e+03
1332496830.133333 255009.000000 223018.000000 4584.819824 2864.000000 8469.490234 3625.580078 985.557007 3504.229980 1332496830.133333 2.550090e+05 2.230180e+05 4.584820e+03 2.864000e+03 8.469490e+03 3.625580e+03 9.855570e+02 3.504230e+03
1332496830.141667 260114.000000 221947.000000 5676.189941 1210.339966 9393.780273 3390.239990 1654.020020 3018.699951 1332496830.141667 2.601140e+05 2.219470e+05 5.676190e+03 1.210340e+03 9.393780e+03 3.390240e+03 1.654020e+03 3.018700e+03
1332496830.150000 264277.000000 224438.000000 4446.620117 2176.719971 8142.089844 4584.879883 2327.830078 2615.800049 1332496830.150000 2.642770e+05 2.244380e+05 4.446620e+03 2.176720e+03 8.142090e+03 4.584880e+03 2.327830e+03 2.615800e+03
1332496830.158333 259221.000000 226471.000000 2734.439941 4182.759766 6389.549805 5540.520020 1958.880005 2720.120117 1332496830.158333 2.592210e+05 2.264710e+05 2.734440e+03 4.182760e+03 6.389550e+03 5.540520e+03 1.958880e+03 2.720120e+03
1332496830.166667 252650.000000 224831.000000 4163.640137 2989.989990 7179.200195 5213.060059 1929.550049 3457.659912 1332496830.166667 2.526500e+05 2.248310e+05 4.163640e+03 2.989990e+03 7.179200e+03 5.213060e+03 1.929550e+03 3.457660e+03
1332496830.175000 257083.000000 222048.000000 5759.040039 702.440979 8566.549805 3552.020020 1832.939941 3956.189941 1332496830.175000 2.570830e+05 2.220480e+05 5.759040e+03 7.024410e+02 8.566550e+03 3.552020e+03 1.832940e+03 3.956190e+03
1332496830.183333 263130.000000 222967.000000 5141.140137 1166.119995 8666.959961 2720.370117 971.374023 3479.729980 1332496830.183333 2.631300e+05 2.229670e+05 5.141140e+03 1.166120e+03 8.666960e+03 2.720370e+03 9.713740e+02 3.479730e+03
1332496830.191667 260236.000000 225265.000000 3425.139893 3339.080078 7853.609863 3674.949951 525.908020 2443.310059 1332496830.191667 2.602360e+05 2.252650e+05 3.425140e+03 3.339080e+03 7.853610e+03 3.674950e+03 5.259080e+02 2.443310e+03
1332496830.200000 253503.000000 224527.000000 4398.129883 2927.429932 8110.279785 4842.470215 1513.869995 2467.100098 1332496830.200000 2.535030e+05 2.245270e+05 4.398130e+03 2.927430e+03 8.110280e+03 4.842470e+03 1.513870e+03 2.467100e+03
1332496830.208333 256126.000000 222693.000000 6043.529785 656.223999 8797.559570 4832.410156 2832.370117 3426.139893 1332496830.208333 2.561260e+05 2.226930e+05 6.043530e+03 6.562240e+02 8.797560e+03 4.832410e+03 2.832370e+03 3.426140e+03
1332496830.216667 261677.000000 223608.000000 5830.459961 1033.910034 8123.939941 3980.689941 1927.959961 4092.719971 1332496830.216667 2.616770e+05 2.236080e+05 5.830460e+03 1.033910e+03 8.123940e+03 3.980690e+03 1.927960e+03 4.092720e+03
1332496830.225000 259457.000000 225536.000000 4015.570068 2995.989990 7135.439941 3713.550049 307.220001 3849.429932 1332496830.225000 2.594570e+05 2.255360e+05 4.015570e+03 2.995990e+03 7.135440e+03 3.713550e+03 3.072200e+02 3.849430e+03
1332496830.233333 253352.000000 224216.000000 4650.560059 3196.620117 8131.279785 3586.159912 70.832298 3074.179932 1332496830.233333 2.533520e+05 2.242160e+05 4.650560e+03 3.196620e+03 8.131280e+03 3.586160e+03 7.083230e+01 3.074180e+03
1332496830.241667 256124.000000 221513.000000 6100.479980 821.979980 9757.540039 3474.510010 1647.520020 2559.860107 1332496830.241667 2.561240e+05 2.215130e+05 6.100480e+03 8.219800e+02 9.757540e+03 3.474510e+03 1.647520e+03 2.559860e+03
1332496830.250000 263024.000000 221559.000000 5789.959961 699.416992 9129.740234 4153.080078 2829.250000 2677.270020 1332496830.250000 2.630240e+05 2.215590e+05 5.789960e+03 6.994170e+02 9.129740e+03 4.153080e+03 2.829250e+03 2.677270e+03
1332496830.258333 261720.000000 224015.000000 4358.500000 2645.360107 7414.109863 4810.669922 2225.989990 3185.989990 1332496830.258333 2.617200e+05 2.240150e+05 4.358500e+03 2.645360e+03 7.414110e+03 4.810670e+03 2.225990e+03 3.185990e+03
1332496830.266667 254756.000000 224240.000000 4857.379883 3229.679932 7539.310059 4769.140137 1507.130005 3668.260010 1332496830.266667 2.547560e+05 2.242400e+05 4.857380e+03 3.229680e+03 7.539310e+03 4.769140e+03 1.507130e+03 3.668260e+03
1332496830.275000 256889.000000 222658.000000 6473.419922 1214.109985 9010.759766 3848.729980 1303.839966 3778.500000 1332496830.275000 2.568890e+05 2.226580e+05 6.473420e+03 1.214110e+03 9.010760e+03 3.848730e+03 1.303840e+03 3.778500e+03
1332496830.283333 264208.000000 223316.000000 5700.450195 1116.560059 9087.610352 3846.679932 1293.589966 2891.560059 1332496830.283333 2.642080e+05 2.233160e+05 5.700450e+03 1.116560e+03 9.087610e+03 3.846680e+03 1.293590e+03 2.891560e+03
1332496830.291667 263310.000000 225719.000000 3936.120117 3252.360107 7552.850098 4897.859863 1156.630005 2037.160034 1332496830.291667 2.633100e+05 2.257190e+05 3.936120e+03 3.252360e+03 7.552850e+03 4.897860e+03 1.156630e+03 2.037160e+03
1332496830.300000 255079.000000 225086.000000 4536.450195 3960.110107 7454.589844 5479.069824 1596.359985 2190.800049 1332496830.300000 2.550790e+05 2.250860e+05 4.536450e+03 3.960110e+03 7.454590e+03 5.479070e+03 1.596360e+03 2.190800e+03
1332496830.308333 254487.000000 222508.000000 6635.859863 1758.849976 8732.969727 4466.970215 2650.360107 3139.310059 1332496830.308333 2.544870e+05 2.225080e+05 6.635860e+03 1.758850e+03 8.732970e+03 4.466970e+03 2.650360e+03 3.139310e+03
1332496830.316667 261241.000000 222432.000000 6702.270020 1085.130005 8989.230469 3112.989990 1933.560059 3828.409912 1332496830.316667 2.612410e+05 2.224320e+05 6.702270e+03 1.085130e+03 8.989230e+03 3.112990e+03 1.933560e+03 3.828410e+03
1332496830.325000 262119.000000 225587.000000 4714.950195 2892.360107 8107.819824 2961.310059 239.977997 3273.719971 1332496830.325000 2.621190e+05 2.255870e+05 4.714950e+03 2.892360e+03 8.107820e+03 2.961310e+03 2.399780e+02 3.273720e+03
1332496830.333333 254999.000000 226514.000000 4532.089844 4126.899902 8200.129883 3872.590088 56.089001 2370.580078 1332496830.333333 2.549990e+05 2.265140e+05 4.532090e+03 4.126900e+03 8.200130e+03 3.872590e+03 5.608900e+01 2.370580e+03
1332496830.341667 254289.000000 224033.000000 6538.810059 2251.439941 9419.429688 4564.450195 2077.810059 2508.169922 1332496830.341667 2.542890e+05 2.240330e+05 6.538810e+03 2.251440e+03 9.419430e+03 4.564450e+03 2.077810e+03 2.508170e+03
1332496830.350000 261890.000000 221960.000000 6846.089844 1475.270020 9125.589844 4598.290039 3299.219971 3475.419922 1332496830.350000 2.618900e+05 2.219600e+05 6.846090e+03 1.475270e+03 9.125590e+03 4.598290e+03 3.299220e+03 3.475420e+03
1332496830.358333 264502.000000 223085.000000 5066.379883 3270.560059 7933.169922 4173.709961 1908.910034 3867.459961 1332496830.358333 2.645020e+05 2.230850e+05 5.066380e+03 3.270560e+03 7.933170e+03 4.173710e+03 1.908910e+03 3.867460e+03
1332496830.366667 257889.000000 223656.000000 4201.660156 4473.640137 7688.339844 4161.580078 687.578979 3653.689941 1332496830.366667 2.578890e+05 2.236560e+05 4.201660e+03 4.473640e+03 7.688340e+03 4.161580e+03 6.875790e+02 3.653690e+03
1332496830.375000 254270.000000 223151.000000 5715.140137 2752.139893 9273.320312 3772.949951 896.403992 3256.060059 1332496830.375000 2.542700e+05 2.231510e+05 5.715140e+03 2.752140e+03 9.273320e+03 3.772950e+03 8.964040e+02 3.256060e+03
1332496830.383333 258257.000000 224217.000000 6114.310059 1856.859985 9604.320312 4200.490234 1764.380005 2939.219971 1332496830.383333 2.582570e+05 2.242170e+05 6.114310e+03 1.856860e+03 9.604320e+03 4.200490e+03 1.764380e+03 2.939220e+03
1332496830.391667 260020.000000 226868.000000 4237.529785 3605.879883 8066.220215 5430.250000 2138.580078 2696.709961 1332496830.391667 2.600200e+05 2.268680e+05 4.237530e+03 3.605880e+03 8.066220e+03 5.430250e+03 2.138580e+03 2.696710e+03
1332496830.400000 255083.000000 225924.000000 3350.310059 4853.069824 7045.819824 5925.200195 1893.609985 2897.340088 1332496830.400000 2.550830e+05 2.259240e+05 3.350310e+03 4.853070e+03 7.045820e+03 5.925200e+03 1.893610e+03 2.897340e+03
1332496830.408333 254453.000000 222127.000000 5271.330078 2491.500000 8436.679688 5032.080078 2436.050049 3724.590088 1332496830.408333 2.544530e+05 2.221270e+05 5.271330e+03 2.491500e+03 8.436680e+03 5.032080e+03 2.436050e+03 3.724590e+03
1332496830.416667 262588.000000 219950.000000 5994.620117 789.273987 9029.650391 3515.739990 1953.569946 4014.520020 1332496830.416667 2.625880e+05 2.199500e+05 5.994620e+03 7.892740e+02 9.029650e+03 3.515740e+03 1.953570e+03 4.014520e+03
1332496830.425000 265610.000000 223333.000000 4391.410156 2400.959961 8146.459961 3536.959961 530.231995 3133.919922 1332496830.425000 2.656100e+05 2.233330e+05 4.391410e+03 2.400960e+03 8.146460e+03 3.536960e+03 5.302320e+02 3.133920e+03
1332496830.433333 257470.000000 226977.000000 2975.320068 4633.529785 7278.560059 4640.100098 -50.150200 2024.959961 1332496830.433333 2.574700e+05 2.269770e+05 2.975320e+03 4.633530e+03 7.278560e+03 4.640100e+03 -5.015020e+01 2.024960e+03
1332496830.441667 250687.000000 226331.000000 4517.859863 3183.800049 8072.600098 5281.660156 1605.140015 2335.139893 1332496830.441667 2.506870e+05 2.263310e+05 4.517860e+03 3.183800e+03 8.072600e+03 5.281660e+03 1.605140e+03 2.335140e+03
1332496830.450000 255563.000000 224495.000000 5551.000000 1101.300049 8461.490234 4725.700195 2726.669922 3480.540039 1332496830.450000 2.555630e+05 2.244950e+05 5.551000e+03 1.101300e+03 8.461490e+03 4.725700e+03 2.726670e+03 3.480540e+03
1332496830.458333 261335.000000 224645.000000 4764.680176 1557.020020 7833.350098 3524.810059 1577.410034 4038.620117 1332496830.458333 2.613350e+05 2.246450e+05 4.764680e+03 1.557020e+03 7.833350e+03 3.524810e+03 1.577410e+03 4.038620e+03
1332496830.466667 260269.000000 224008.000000 3558.030029 2987.610107 7362.439941 3279.229980 562.442017 3786.550049 1332496830.466667 2.602690e+05 2.240080e+05 3.558030e+03 2.987610e+03 7.362440e+03 3.279230e+03 5.624420e+02 3.786550e+03
1332496830.475000 257435.000000 221777.000000 4972.600098 2166.879883 8481.440430 3328.719971 1037.130005 3271.370117 1332496830.475000 2.574350e+05 2.217770e+05 4.972600e+03 2.166880e+03 8.481440e+03 3.328720e+03 1.037130e+03 3.271370e+03
1332496830.483333 261046.000000 221550.000000 5816.180176 590.216980 9120.929688 3895.399902 2382.669922 2824.169922 1332496830.483333 2.610460e+05 2.215500e+05 5.816180e+03 5.902170e+02 9.120930e+03 3.895400e+03 2.382670e+03 2.824170e+03
1332496830.491667 262766.000000 224473.000000 4835.049805 1785.770020 7880.759766 4745.620117 2443.659912 3229.550049 1332496830.491667 2.627660e+05 2.244730e+05 4.835050e+03 1.785770e+03 7.880760e+03 4.745620e+03 2.443660e+03 3.229550e+03
1332496830.500000 256509.000000 226413.000000 3758.870117 3461.199951 6743.770020 4928.959961 1536.619995 3546.689941 1332496830.500000 2.565090e+05 2.264130e+05 3.758870e+03 3.461200e+03 6.743770e+03 4.928960e+03 1.536620e+03 3.546690e+03
1332496830.508333 250793.000000 224372.000000 5218.490234 2865.260010 7803.959961 4351.089844 1333.819946 3680.489990 1332496830.508333 2.507930e+05 2.243720e+05 5.218490e+03 2.865260e+03 7.803960e+03 4.351090e+03 1.333820e+03 3.680490e+03
1332496830.516667 256319.000000 222066.000000 6403.970215 732.344971 9627.759766 3089.300049 1516.780029 3653.689941 1332496830.516667 2.563190e+05 2.220660e+05 6.403970e+03 7.323450e+02 9.627760e+03 3.089300e+03 1.516780e+03 3.653690e+03
1332496830.525000 263343.000000 223235.000000 5200.430176 1388.579956 9372.849609 3371.229980 1450.390015 2678.909912 1332496830.525000 2.633430e+05 2.232350e+05 5.200430e+03 1.388580e+03 9.372850e+03 3.371230e+03 1.450390e+03 2.678910e+03
1332496830.533333 260903.000000 225110.000000 3722.580078 3246.659912 7876.540039 4716.810059 1498.439941 2116.520020 1332496830.533333 2.609030e+05 2.251100e+05 3.722580e+03 3.246660e+03 7.876540e+03 4.716810e+03 1.498440e+03 2.116520e+03
1332496830.541667 254416.000000 223769.000000 4841.649902 2956.399902 8115.919922 5392.359863 2142.810059 2652.320068 1332496830.541667 2.544160e+05 2.237690e+05 4.841650e+03 2.956400e+03 8.115920e+03 5.392360e+03 2.142810e+03 2.652320e+03
1332496830.550000 256698.000000 222172.000000 6471.229980 970.395996 8834.980469 4816.839844 2376.629883 3605.860107 1332496830.550000 2.566980e+05 2.221720e+05 6.471230e+03 9.703960e+02 8.834980e+03 4.816840e+03 2.376630e+03 3.605860e+03
1332496830.558333 261841.000000 223537.000000 5500.740234 1189.660034 8365.730469 4016.469971 1042.270020 3821.199951 1332496830.558333 2.618410e+05 2.235370e+05 5.500740e+03 1.189660e+03 8.365730e+03 4.016470e+03 1.042270e+03 3.821200e+03
1332496830.566667 259503.000000 225840.000000 3827.929932 3088.840088 7676.140137 3978.310059 -357.006989 3016.419922 1332496830.566667 2.595030e+05 2.258400e+05 3.827930e+03 3.088840e+03 7.676140e+03 3.978310e+03 -3.570070e+02 3.016420e+03
1332496830.575000 253457.000000 224636.000000 4914.609863 3097.449951 8224.900391 4321.439941 171.373993 2412.360107 1332496830.575000 2.534570e+05 2.246360e+05 4.914610e+03 3.097450e+03 8.224900e+03 4.321440e+03 1.713740e+02 2.412360e+03
1332496830.583333 256029.000000 222221.000000 6841.799805 1028.500000 9252.299805 4387.569824 2418.139893 2510.100098 1332496830.583333 2.560290e+05 2.222210e+05 6.841800e+03 1.028500e+03 9.252300e+03 4.387570e+03 2.418140e+03 2.510100e+03
1332496830.591667 262840.000000 222550.000000 6210.250000 1410.729980 8538.900391 4152.580078 3009.300049 3219.760010 1332496830.591667 2.628400e+05 2.225500e+05 6.210250e+03 1.410730e+03 8.538900e+03 4.152580e+03 3.009300e+03 3.219760e+03
1332496830.600000 261633.000000 225065.000000 4284.529785 3357.209961 7282.169922 3823.590088 1402.839966 3644.669922 1332496830.600000 2.616330e+05 2.250650e+05 4.284530e+03 3.357210e+03 7.282170e+03 3.823590e+03 1.402840e+03 3.644670e+03
1332496830.608333 254591.000000 225109.000000 4693.160156 3647.739990 7745.160156 3686.379883 490.161011 3448.860107 1332496830.608333 2.545910e+05 2.251090e+05 4.693160e+03 3.647740e+03 7.745160e+03 3.686380e+03 4.901610e+02 3.448860e+03
1332496830.616667 254780.000000 223599.000000 6527.379883 1569.869995 9438.429688 3456.580078 1162.520020 3252.010010 1332496830.616667 2.547800e+05 2.235990e+05 6.527380e+03 1.569870e+03 9.438430e+03 3.456580e+03 1.162520e+03 3.252010e+03
1332496830.625000 260639.000000 224107.000000 6531.049805 1633.050049 9283.719727 4174.020020 2089.550049 2775.750000 1332496830.625000 2.606390e+05 2.241070e+05 6.531050e+03 1.633050e+03 9.283720e+03 4.174020e+03 2.089550e+03 2.775750e+03
1332496830.633333 261108.000000 225472.000000 4968.259766 3527.850098 7692.870117 5137.100098 2207.389893 2436.659912 1332496830.633333 2.611080e+05 2.254720e+05 4.968260e+03 3.527850e+03 7.692870e+03 5.137100e+03 2.207390e+03 2.436660e+03
1332496830.641667 255775.000000 223708.000000 4963.450195 4017.370117 7701.419922 5269.649902 2284.399902 2842.080078 1332496830.641667 2.557750e+05 2.237080e+05 4.963450e+03 4.017370e+03 7.701420e+03 5.269650e+03 2.284400e+03 2.842080e+03
1332496830.650000 257398.000000 220947.000000 6767.500000 1645.709961 9107.070312 4000.179932 2548.860107 3624.770020 1332496830.650000 2.573980e+05 2.209470e+05 6.767500e+03 1.645710e+03 9.107070e+03 4.000180e+03 2.548860e+03 3.624770e+03
1332496830.658333 264924.000000 221559.000000 6471.459961 1110.329956 9459.650391 3108.169922 1696.969971 3893.439941 1332496830.658333 2.649240e+05 2.215590e+05 6.471460e+03 1.110330e+03 9.459650e+03 3.108170e+03 1.696970e+03 3.893440e+03
1332496830.666667 265339.000000 225733.000000 4348.799805 3459.510010 8475.299805 4031.239990 573.346985 2910.270020 1332496830.666667 2.653390e+05 2.257330e+05 4.348800e+03 3.459510e+03 8.475300e+03 4.031240e+03 5.733470e+02 2.910270e+03
1332496830.675000 256814.000000 226995.000000 3479.540039 4949.790039 7499.910156 5624.709961 751.656006 2347.709961 1332496830.675000 2.568140e+05 2.269950e+05 3.479540e+03 4.949790e+03 7.499910e+03 5.624710e+03 7.516560e+02 2.347710e+03
1332496830.683333 253316.000000 225161.000000 5147.060059 3218.429932 8460.160156 5869.299805 2336.320068 2987.959961 1332496830.683333 2.533160e+05 2.251610e+05 5.147060e+03 3.218430e+03 8.460160e+03 5.869300e+03 2.336320e+03 2.987960e+03
1332496830.691667 259360.000000 223101.000000 5549.120117 1869.949951 8740.759766 4668.939941 2457.909912 3758.820068 1332496830.691667 2.593600e+05 2.231010e+05 5.549120e+03 1.869950e+03 8.740760e+03 4.668940e+03 2.457910e+03 3.758820e+03
1332496830.700000 262012.000000 224016.000000 4173.609863 3004.129883 8157.040039 3704.729980 987.963989 3652.750000 1332496830.700000 2.620120e+05 2.240160e+05 4.173610e+03 3.004130e+03 8.157040e+03 3.704730e+03 9.879640e+02 3.652750e+03
1332496830.708333 257176.000000 224420.000000 3517.300049 4118.750000 7822.240234 3718.229980 37.264900 2953.679932 1332496830.708333 2.571760e+05 2.244200e+05 3.517300e+03 4.118750e+03 7.822240e+03 3.718230e+03 3.726490e+01 2.953680e+03
1332496830.716667 255146.000000 223322.000000 4923.979980 2330.679932 9095.910156 3792.399902 1013.070007 2711.239990 1332496830.716667 2.551460e+05 2.233220e+05 4.923980e+03 2.330680e+03 9.095910e+03 3.792400e+03 1.013070e+03 2.711240e+03
1332496830.725000 260524.000000 223651.000000 5413.629883 1146.209961 8817.169922 4419.649902 2446.649902 2832.050049 1332496830.725000 2.605240e+05 2.236510e+05 5.413630e+03 1.146210e+03 8.817170e+03 4.419650e+03 2.446650e+03 2.832050e+03
1332496830.733333 262098.000000 225752.000000 4262.979980 2270.969971 7135.479980 5067.120117 2294.679932 3376.620117 1332496830.733333 2.620980e+05 2.257520e+05 4.262980e+03 2.270970e+03 7.135480e+03 5.067120e+03 2.294680e+03 3.376620e+03
1332496830.741667 256889.000000 225379.000000 3606.459961 3568.189941 6552.649902 4970.270020 1516.380005 3662.570068 1332496830.741667 2.568890e+05 2.253790e+05 3.606460e+03 3.568190e+03 6.552650e+03 4.970270e+03 1.516380e+03 3.662570e+03
1332496830.750000 253948.000000 222631.000000 5511.700195 2066.300049 7952.660156 4019.909912 1513.140015 3752.629883 1332496830.750000 2.539480e+05 2.226310e+05 5.511700e+03 2.066300e+03 7.952660e+03 4.019910e+03 1.513140e+03 3.752630e+03
1332496830.758333 259799.000000 222067.000000 5873.500000 608.583984 9253.780273 2870.739990 1348.239990 3344.199951 1332496830.758333 2.597990e+05 2.220670e+05 5.873500e+03 6.085840e+02 9.253780e+03 2.870740e+03 1.348240e+03 3.344200e+03
1332496830.766667 262547.000000 224901.000000 4346.080078 1928.099976 8590.969727 3455.459961 904.390991 2379.270020 1332496830.766667 2.625470e+05 2.249010e+05 4.346080e+03 1.928100e+03 8.590970e+03 3.455460e+03 9.043910e+02 2.379270e+03
1332496830.775000 256137.000000 226761.000000 3423.560059 3379.080078 7471.149902 4894.169922 1153.540039 2031.410034 1332496830.775000 2.561370e+05 2.267610e+05 3.423560e+03 3.379080e+03 7.471150e+03 4.894170e+03 1.153540e+03 2.031410e+03
1332496830.783333 250326.000000 225013.000000 5519.979980 2423.969971 7991.759766 5117.950195 2098.790039 3099.239990 1332496830.783333 2.503260e+05 2.250130e+05 5.519980e+03 2.423970e+03 7.991760e+03 5.117950e+03 2.098790e+03 3.099240e+03
1332496830.791667 255454.000000 222992.000000 6547.950195 496.496002 8751.339844 3900.560059 2132.290039 4076.810059 1332496830.791667 2.554540e+05 2.229920e+05 6.547950e+03 4.964960e+02 8.751340e+03 3.900560e+03 2.132290e+03 4.076810e+03
1332496830.800000 261286.000000 223489.000000 5152.850098 1501.510010 8425.610352 2888.030029 776.114014 3786.360107 1332496830.800000 2.612860e+05 2.234890e+05 5.152850e+03 1.501510e+03 8.425610e+03 2.888030e+03 7.761140e+02 3.786360e+03
1332496830.808333 258969.000000 224069.000000 3832.610107 3001.979980 7979.259766 3182.310059 52.716000 2874.800049 1332496830.808333 2.589690e+05 2.240690e+05 3.832610e+03 3.001980e+03 7.979260e+03 3.182310e+03 5.271600e+01 2.874800e+03
1332496830.816667 254946.000000 222035.000000 5317.879883 2139.800049 9103.139648 3955.610107 1235.170044 2394.149902 1332496830.816667 2.549460e+05 2.220350e+05 5.317880e+03 2.139800e+03 9.103140e+03 3.955610e+03 1.235170e+03 2.394150e+03
1332496830.825000 258676.000000 221205.000000 6594.910156 505.343994 9423.360352 4562.470215 2913.739990 2892.350098 1332496830.825000 2.586760e+05 2.212050e+05 6.594910e+03 5.053440e+02 9.423360e+03 4.562470e+03 2.913740e+03 2.892350e+03
1332496830.833333 262125.000000 223566.000000 5116.750000 1773.599976 8082.200195 4776.370117 2386.389893 3659.729980 1332496830.833333 2.621250e+05 2.235660e+05 5.116750e+03 1.773600e+03 8.082200e+03 4.776370e+03 2.386390e+03 3.659730e+03
1332496830.841667 257835.000000 225918.000000 3714.300049 3477.080078 7205.370117 4554.609863 711.539001 3878.419922 1332496830.841667 2.578350e+05 2.259180e+05 3.714300e+03 3.477080e+03 7.205370e+03 4.554610e+03 7.115390e+02 3.878420e+03
1332496830.850000 253660.000000 224371.000000 5022.450195 2592.429932 8277.200195 4119.370117 486.507996 3666.739990 1332496830.850000 2.536600e+05 2.243710e+05 5.022450e+03 2.592430e+03 8.277200e+03 4.119370e+03 4.865080e+02 3.666740e+03
1332496830.858333 259503.000000 222061.000000 6589.950195 659.935974 9596.919922 3598.100098 1702.489990 3036.600098 1332496830.858333 2.595030e+05 2.220610e+05 6.589950e+03 6.599360e+02 9.596920e+03 3.598100e+03 1.702490e+03 3.036600e+03
1332496830.866667 265495.000000 222843.000000 5541.850098 1728.430054 8459.959961 4492.000000 2231.969971 2430.620117 1332496830.866667 2.654950e+05 2.228430e+05 5.541850e+03 1.728430e+03 8.459960e+03 4.492000e+03 2.231970e+03 2.430620e+03
1332496830.875000 260929.000000 224996.000000 4000.949951 3745.989990 6983.790039 5430.859863 1855.260010 2533.379883 1332496830.875000 2.609290e+05 2.249960e+05 4.000950e+03 3.745990e+03 6.983790e+03 5.430860e+03 1.855260e+03 2.533380e+03
1332496830.883333 252716.000000 224335.000000 5086.560059 3401.149902 7597.970215 5196.120117 1755.719971 3079.760010 1332496830.883333 2.527160e+05 2.243350e+05 5.086560e+03 3.401150e+03 7.597970e+03 5.196120e+03 1.755720e+03 3.079760e+03
1332496830.891667 254110.000000 223111.000000 6822.189941 1229.079956 9164.339844 3761.229980 1679.390015 3584.879883 1332496830.891667 2.541100e+05 2.231110e+05 6.822190e+03 1.229080e+03 9.164340e+03 3.761230e+03 1.679390e+03 3.584880e+03
1332496830.900000 259969.000000 224693.000000 6183.950195 1538.500000 9222.080078 3139.169922 949.901978 3180.800049 1332496830.900000 2.599690e+05 2.246930e+05 6.183950e+03 1.538500e+03 9.222080e+03 3.139170e+03 9.499020e+02 3.180800e+03
1332496830.908333 259078.000000 226913.000000 4388.890137 3694.820068 8195.019531 3933.000000 426.079987 2388.449951 1332496830.908333 2.590780e+05 2.269130e+05 4.388890e+03 3.694820e+03 8.195020e+03 3.933000e+03 4.260800e+02 2.388450e+03
1332496830.916667 254563.000000 224760.000000 5168.439941 4020.939941 8450.269531 4758.910156 1458.900024 2286.429932 1332496830.916667 2.545630e+05 2.247600e+05 5.168440e+03 4.020940e+03 8.450270e+03 4.758910e+03 1.458900e+03 2.286430e+03
1332496830.925000 258059.000000 221217.000000 6883.459961 1649.530029 9232.780273 4457.649902 3057.820068 3031.949951 1332496830.925000 2.580590e+05 2.212170e+05 6.883460e+03 1.649530e+03 9.232780e+03 4.457650e+03 3.057820e+03 3.031950e+03
1332496830.933333 264667.000000 221177.000000 6218.509766 1645.729980 8657.179688 3663.500000 2528.280029 3978.340088 1332496830.933333 2.646670e+05 2.211770e+05 6.218510e+03 1.645730e+03 8.657180e+03 3.663500e+03 2.528280e+03 3.978340e+03
1332496830.941667 262925.000000 224382.000000 4627.500000 3635.929932 7892.799805 3431.320068 604.508972 3901.370117 1332496830.941667 2.629250e+05 2.243820e+05 4.627500e+03 3.635930e+03 7.892800e+03 3.431320e+03 6.045090e+02 3.901370e+03
1332496830.950000 254708.000000 225448.000000 4408.250000 4461.040039 8197.169922 3953.750000 -44.534599 3154.870117 1332496830.950000 2.547080e+05 2.254480e+05 4.408250e+03 4.461040e+03 8.197170e+03 3.953750e+03 -4.453460e+01 3.154870e+03
1332496830.958333 253702.000000 224635.000000 5825.770020 2577.050049 9590.049805 4569.250000 1460.270020 2785.169922 1332496830.958333 2.537020e+05 2.246350e+05 5.825770e+03 2.577050e+03 9.590050e+03 4.569250e+03 1.460270e+03 2.785170e+03
1332496830.966667 260206.000000 224140.000000 5387.979980 1951.160034 8789.509766 5131.660156 2706.379883 2972.479980 1332496830.966667 2.602060e+05 2.241400e+05 5.387980e+03 1.951160e+03 8.789510e+03 5.131660e+03 2.706380e+03 2.972480e+03
1332496830.975000 261240.000000 224737.000000 3860.810059 3418.310059 7414.529785 5284.520020 2271.379883 3183.149902 1332496830.975000 2.612400e+05 2.247370e+05 3.860810e+03 3.418310e+03 7.414530e+03 5.284520e+03 2.271380e+03 3.183150e+03
1332496830.983333 256140.000000 223252.000000 3850.010010 3957.139893 7262.649902 4964.640137 1499.510010 3453.129883 1332496830.983333 2.561400e+05 2.232520e+05 3.850010e+03 3.957140e+03 7.262650e+03 4.964640e+03 1.499510e+03 3.453130e+03
1332496830.991667 256116.000000 221349.000000 5594.479980 2054.399902 8835.129883 3662.010010 1485.510010 3613.010010 1332496830.991667 2.561160e+05 2.213490e+05 5.594480e+03 2.054400e+03 8.835130e+03 3.662010e+03 1.485510e+03 3.613010e+03

View File

@@ -1,3 +1,4 @@
# comments are cool?
2.66568e+05 2.24029e+05 5.16140e+03 2.52517e+03 8.35084e+03 3.72470e+03 1.35534e+03 2.03900e+03 2.66568e+05 2.24029e+05 5.16140e+03 2.52517e+03 8.35084e+03 3.72470e+03 1.35534e+03 2.03900e+03
2.57914e+05 2.27183e+05 4.30368e+03 4.13080e+03 7.25535e+03 4.89047e+03 1.63859e+03 1.93496e+03 2.57914e+05 2.27183e+05 4.30368e+03 4.13080e+03 7.25535e+03 4.89047e+03 1.63859e+03 1.93496e+03
2.51717e+05 2.26047e+05 5.99445e+03 3.49363e+03 8.07250e+03 5.08267e+03 2.26917e+03 2.86231e+03 2.51717e+05 2.26047e+05 5.99445e+03 3.49363e+03 8.07250e+03 5.08267e+03 2.26917e+03 2.86231e+03

View File

@@ -35,8 +35,6 @@ class TestBulkData(object):
data.create("/foo", "uint16_8") data.create("/foo", "uint16_8")
with assert_raises(ValueError): with assert_raises(ValueError):
data.create("foo/bar", "uint16_8") data.create("foo/bar", "uint16_8")
with assert_raises(ValueError):
data.create("/foo/bar", "uint8_8")
data.create("/foo/bar", "uint16_8") data.create("/foo/bar", "uint16_8")
data.create(u"/foo/baz/quux", "float64_16") data.create(u"/foo/baz/quux", "float64_16")
with assert_raises(ValueError): with assert_raises(ValueError):
@@ -70,6 +68,13 @@ class TestBulkData(object):
for s in misc_slices: for s in misc_slices:
eq_(node[s], raw[s]) eq_(node[s], raw[s])
# Extract misc slices while appending, to make sure the
# data isn't being added in the middle of the file
for s in [2, slice(1,5), 2, slice(1,5)]:
node.append([[0,0,0,0,0,0,0,0,0]])
raw.append([0,0,0,0,0,0,0,0,0])
eq_(node[s], raw[s])
# Get some coverage of remove; remove is more fully tested # Get some coverage of remove; remove is more fully tested
# in cmdline # in cmdline
with assert_raises(IndexError): with assert_raises(IndexError):

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import nilmdb import nilmdb.server
import nilmdb.client
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
from nilmdb.utils import timestamper from nilmdb.utils import timestamper
from nilmdb.client import ClientError, ServerError from nilmdb.client import ClientError, ServerError
@@ -20,11 +22,12 @@ import unittest
import warnings import warnings
import resource import resource
import time import time
import re
from testutil.helpers import * from testutil.helpers import *
testdb = "tests/client-testdb" testdb = "tests/client-testdb"
testurl = "http://localhost:12380/" testurl = "http://localhost:32180/"
def setup_module(): def setup_module():
global test_server, test_db global test_server, test_db
@@ -32,11 +35,11 @@ def setup_module():
recursive_unlink(testdb) recursive_unlink(testdb)
# Start web app on a custom port # Start web app on a custom port
test_db = nilmdb.utils.serializer_proxy(nilmdb.NilmDB)(testdb, sync = False) test_db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(testdb)
test_server = nilmdb.Server(test_db, host = "127.0.0.1", test_server = nilmdb.server.Server(test_db, host = "127.0.0.1",
port = 12380, stoppable = False, port = 32180, stoppable = False,
fast_shutdown = True, fast_shutdown = True,
force_traceback = False) force_traceback = True)
test_server.start(blocking = False) test_server.start(blocking = False)
def teardown_module(): def teardown_module():
@@ -49,30 +52,24 @@ class TestClient(object):
def test_client_01_basic(self): def test_client_01_basic(self):
# Test a fake host # Test a fake host
client = nilmdb.Client(url = "http://localhost:1/") client = nilmdb.client.Client(url = "http://localhost:1/")
with assert_raises(nilmdb.client.ServerError):
client.version()
client.close()
# Trigger same error with a PUT request
client = nilmdb.Client(url = "http://localhost:1/")
with assert_raises(nilmdb.client.ServerError): with assert_raises(nilmdb.client.ServerError):
client.version() client.version()
client.close() client.close()
# Then a fake URL on a real host # Then a fake URL on a real host
client = nilmdb.Client(url = "http://localhost:12380/fake/") client = nilmdb.client.Client(url = "http://localhost:32180/fake/")
with assert_raises(nilmdb.client.ClientError): with assert_raises(nilmdb.client.ClientError):
client.version() client.version()
client.close() client.close()
# Now a real URL with no http:// prefix # Now a real URL with no http:// prefix
client = nilmdb.Client(url = "localhost:12380") client = nilmdb.client.Client(url = "localhost:32180")
version = client.version() version = client.version()
client.close() client.close()
# Now use the real URL # Now use the real URL
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
version = client.version() version = client.version()
eq_(distutils.version.LooseVersion(version), eq_(distutils.version.LooseVersion(version),
distutils.version.LooseVersion(test_server.version)) distutils.version.LooseVersion(test_server.version))
@@ -84,16 +81,16 @@ class TestClient(object):
def test_client_02_createlist(self): def test_client_02_createlist(self):
# Basic stream tests, like those in test_nilmdb:test_stream # Basic stream tests, like those in test_nilmdb:test_stream
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
# Database starts empty # Database starts empty
eq_(client.stream_list(), []) eq_(client.stream_list(), [])
# Bad path # Bad path
with assert_raises(ClientError): with assert_raises(ClientError):
client.stream_create("foo/bar/baz", "PrepData") client.stream_create("foo/bar/baz", "float32_8")
with assert_raises(ClientError): with assert_raises(ClientError):
client.stream_create("/foo", "PrepData") client.stream_create("/foo", "float32_8")
# Bad layout type # Bad layout type
with assert_raises(ClientError): with assert_raises(ClientError):
client.stream_create("/newton/prep", "NoSuchLayout") client.stream_create("/newton/prep", "NoSuchLayout")
@@ -105,23 +102,23 @@ class TestClient(object):
for x in range(10): for x in range(10):
with assert_raises(ClientError): with assert_raises(ClientError):
client.http.post("/stream/list") client.http.post("/stream/list")
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
# Create three streams # Create three streams
client.stream_create("/newton/prep", "PrepData") client.stream_create("/newton/prep", "float32_8")
client.stream_create("/newton/raw", "RawData") client.stream_create("/newton/raw", "uint16_6")
client.stream_create("/newton/zzz/rawnotch", "RawNotchedData") client.stream_create("/newton/zzz/rawnotch", "uint16_9")
# Verify we got 3 streams # Verify we got 3 streams
eq_(client.stream_list(), [ ["/newton/prep", "PrepData"], eq_(client.stream_list(), [ ["/newton/prep", "float32_8"],
["/newton/raw", "RawData"], ["/newton/raw", "uint16_6"],
["/newton/zzz/rawnotch", "RawNotchedData"] ["/newton/zzz/rawnotch", "uint16_9"]
]) ])
# Match just one type or one path # Match just one type or one path
eq_(client.stream_list(layout="RawData"), eq_(client.stream_list(layout="uint16_6"),
[ ["/newton/raw", "RawData"] ]) [ ["/newton/raw", "uint16_6"] ])
eq_(client.stream_list(path="/newton/raw"), eq_(client.stream_list(path="/newton/raw"),
[ ["/newton/raw", "RawData"] ]) [ ["/newton/raw", "uint16_6"] ])
# Try messing with resource limits to trigger errors and get # Try messing with resource limits to trigger errors and get
# more coverage. Here, make it so we can only create files 1 # more coverage. Here, make it so we can only create files 1
@@ -130,13 +127,13 @@ class TestClient(object):
limit = resource.getrlimit(resource.RLIMIT_FSIZE) limit = resource.getrlimit(resource.RLIMIT_FSIZE)
resource.setrlimit(resource.RLIMIT_FSIZE, (1, limit[1])) resource.setrlimit(resource.RLIMIT_FSIZE, (1, limit[1]))
with assert_raises(ServerError) as e: with assert_raises(ServerError) as e:
client.stream_create("/newton/hello", "RawData") client.stream_create("/newton/hello", "uint16_6")
resource.setrlimit(resource.RLIMIT_FSIZE, limit) resource.setrlimit(resource.RLIMIT_FSIZE, limit)
client.close() client.close()
def test_client_03_metadata(self): def test_client_03_metadata(self):
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
# Set / get metadata # Set / get metadata
eq_(client.stream_get_metadata("/newton/prep"), {}) eq_(client.stream_get_metadata("/newton/prep"), {})
@@ -167,10 +164,24 @@ class TestClient(object):
client.stream_set_metadata("/newton/prep", [1,2,3]) client.stream_set_metadata("/newton/prep", [1,2,3])
with assert_raises(ClientError): with assert_raises(ClientError):
client.stream_update_metadata("/newton/prep", [1,2,3]) client.stream_update_metadata("/newton/prep", [1,2,3])
# test wrong types (dict of non-strings)
# numbers are OK; they'll get converted to strings
client.stream_set_metadata("/newton/prep", { "hello": 1234 })
# anything else is not
with assert_raises(ClientError):
client.stream_set_metadata("/newton/prep", { "world": { 1: 2 } })
with assert_raises(ClientError):
client.stream_set_metadata("/newton/prep", { "world": [ 1, 2 ] })
client.close() client.close()
def test_client_04_insert(self): def test_client_04_insert(self):
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
# Limit _max_data to 1 MB, since our test file is 1.5 MB
old_max_data = nilmdb.client.client.StreamInserter._max_data
nilmdb.client.client.StreamInserter._max_data = 1 * 1024 * 1024
datetime_tz.localtz_set("America/New_York") datetime_tz.localtz_set("America/New_York")
@@ -191,7 +202,8 @@ class TestClient(object):
with assert_raises(ClientError) as e: with assert_raises(ClientError) as e:
result = client.stream_insert("/newton/prep", data) result = client.stream_insert("/newton/prep", data)
in_("400 Bad Request", str(e.exception)) in_("400 Bad Request", str(e.exception))
in_("timestamp is not monotonically increasing", str(e.exception)) in2_("timestamp is not monotonically increasing",
"start must precede end", str(e.exception))
# Now try empty data (no server request made) # Now try empty data (no server request made)
empty = cStringIO.StringIO("") empty = cStringIO.StringIO("")
@@ -233,7 +245,7 @@ class TestClient(object):
result = client.stream_insert("/newton/prep", data, result = client.stream_insert("/newton/prep", data,
start + 5, start + 120) start + 5, start + 120)
in_("400 Bad Request", str(e.exception)) in_("400 Bad Request", str(e.exception))
in_("Data timestamp 1332511200.0 < start time 1332511205.0", in_("Data timestamp 1332511200.000000 < start time 1332511205.000000",
str(e.exception)) str(e.exception))
# Specify start/end (ends too early) # Specify start/end (ends too early)
@@ -244,8 +256,9 @@ class TestClient(object):
in_("400 Bad Request", str(e.exception)) in_("400 Bad Request", str(e.exception))
# Client chunks the input, so the exact timestamp here might change # Client chunks the input, so the exact timestamp here might change
# if the chunk positions change. # if the chunk positions change.
in_("Data timestamp 1332511271.016667 >= end time 1332511201.0", assert(re.search("Data timestamp 13325[0-9]+\.[0-9]+ "
str(e.exception)) ">= end time 1332511201.000000", str(e.exception))
is not None)
# Now do the real load # Now do the real load
data = timestamper.TimestamperRate(testfile, start, 120) data = timestamper.TimestamperRate(testfile, start, 120)
@@ -264,11 +277,12 @@ class TestClient(object):
in_("400 Bad Request", str(e.exception)) in_("400 Bad Request", str(e.exception))
in_("verlap", str(e.exception)) in_("verlap", str(e.exception))
nilmdb.client.client.StreamInserter._max_data = old_max_data
client.close() client.close()
def test_client_05_extractremove(self): def test_client_05_extractremove(self):
# Misc tests for extract and remove. Most of them are in test_cmdline. # Misc tests for extract and remove. Most of them are in test_cmdline.
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
for x in client.stream_extract("/newton/prep", 999123, 999124): for x in client.stream_extract("/newton/prep", 999123, 999124):
raise AssertionError("shouldn't be any data for this request") raise AssertionError("shouldn't be any data for this request")
@@ -284,7 +298,7 @@ class TestClient(object):
def test_client_06_generators(self): def test_client_06_generators(self):
# A lot of the client functionality is already tested by test_cmdline, # A lot of the client functionality is already tested by test_cmdline,
# but this gets a bit more coverage that cmdline misses. # but this gets a bit more coverage that cmdline misses.
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
# Trigger a client error in generator # Trigger a client error in generator
start = datetime_tz.datetime_tz.smartparse("20120323T2000") start = datetime_tz.datetime_tz.smartparse("20120323T2000")
@@ -320,7 +334,7 @@ class TestClient(object):
# Pokes around in client.http internals a bit to look at the # Pokes around in client.http internals a bit to look at the
# response headers. # response headers.
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
http = client.http http = client.http
# Use a warning rather than returning a test failure for the # Use a warning rather than returning a test failure for the
@@ -353,52 +367,48 @@ class TestClient(object):
raise AssertionError("/stream/extract is not text/plain:\n" + raise AssertionError("/stream/extract is not text/plain:\n" +
headers()) headers())
# Make sure Access-Control-Allow-Origin gets set
if "access-control-allow-origin: " not in headers():
raise AssertionError("No Access-Control-Allow-Origin (CORS) "
"header in /stream/extract response:\n" +
headers())
client.close() client.close()
def test_client_08_unicode(self): def test_client_08_unicode(self):
# Basic Unicode tests # Try both with and without posting JSON
client = nilmdb.Client(url = testurl) for post_json in (False, True):
# Basic Unicode tests
client = nilmdb.client.Client(url = testurl, post_json = post_json)
# Delete streams that exist # Delete streams that exist
for stream in client.stream_list(): for stream in client.stream_list():
client.stream_destroy(stream[0]) client.stream_destroy(stream[0])
# Database is empty # Database is empty
eq_(client.stream_list(), []) eq_(client.stream_list(), [])
# Create Unicode stream, match it # Create Unicode stream, match it
raw = [ u"/düsseldorf/raw", u"uint16_6" ] raw = [ u"/düsseldorf/raw", u"uint16_6" ]
prep = [ u"/düsseldorf/prep", u"uint16_6" ] prep = [ u"/düsseldorf/prep", u"uint16_6" ]
client.stream_create(*raw) client.stream_create(*raw)
eq_(client.stream_list(), [raw]) eq_(client.stream_list(), [raw])
eq_(client.stream_list(layout=raw[1]), [raw]) eq_(client.stream_list(layout=raw[1]), [raw])
eq_(client.stream_list(path=raw[0]), [raw]) eq_(client.stream_list(path=raw[0]), [raw])
client.stream_create(*prep) client.stream_create(*prep)
eq_(client.stream_list(), [prep, raw]) eq_(client.stream_list(), [prep, raw])
# Set / get metadata with Unicode keys and values # Set / get metadata with Unicode keys and values
eq_(client.stream_get_metadata(raw[0]), {}) eq_(client.stream_get_metadata(raw[0]), {})
eq_(client.stream_get_metadata(prep[0]), {}) eq_(client.stream_get_metadata(prep[0]), {})
meta1 = { u"alpha": u"α", meta1 = { u"alpha": u"α",
u"β": u"beta" } u"β": u"beta" }
meta2 = { u"alpha": u"α" } meta2 = { u"alpha": u"α" }
meta3 = { u"β": u"beta" } meta3 = { u"β": u"beta" }
client.stream_set_metadata(prep[0], meta1) client.stream_set_metadata(prep[0], meta1)
client.stream_update_metadata(prep[0], {}) client.stream_update_metadata(prep[0], {})
client.stream_update_metadata(raw[0], meta2) client.stream_update_metadata(raw[0], meta2)
client.stream_update_metadata(raw[0], meta3) client.stream_update_metadata(raw[0], meta3)
eq_(client.stream_get_metadata(prep[0]), meta1) eq_(client.stream_get_metadata(prep[0]), meta1)
eq_(client.stream_get_metadata(raw[0]), meta1) eq_(client.stream_get_metadata(raw[0]), meta1)
eq_(client.stream_get_metadata(raw[0], [ "alpha" ]), meta2) eq_(client.stream_get_metadata(raw[0], [ "alpha" ]), meta2)
eq_(client.stream_get_metadata(raw[0], [ "alpha", "β" ]), meta1) eq_(client.stream_get_metadata(raw[0], [ "alpha", "β" ]), meta1)
client.close() client.close()
def test_client_09_closing(self): def test_client_09_closing(self):
# Make sure we actually close sockets correctly. New # Make sure we actually close sockets correctly. New
@@ -412,68 +422,86 @@ class TestClient(object):
"probably not closing properly.") "probably not closing properly.")
if test == 1: if test == 1:
# explicit close # explicit close
client = nilmdb.Client(url = testurl) client = nilmdb.client.Client(url = testurl)
with assert_raises(ClientError) as e: with assert_raises(ClientError) as e:
client.stream_remove("/newton/prep", 123, 120) client.stream_remove("/newton/prep", 123, 120)
client.close() # remove this to see the failure client.close() # remove this to see the failure
elif test == 2: elif test == 2:
# use the context manager # use the context manager
with nilmdb.Client(url = testurl) as c: with nilmdb.client.Client(url = testurl) as c:
with assert_raises(ClientError) as e: with assert_raises(ClientError) as e:
c.stream_remove("/newton/prep", 123, 120) c.stream_remove("/newton/prep", 123, 120)
def test_client_10_context(self): def test_client_10_context(self):
# Test using the client's stream insertion context manager to # Test using the client's stream insertion context manager to
# insert data. # insert data.
client = nilmdb.Client(testurl) client = nilmdb.client.Client(testurl)
client.stream_create("/context/test", "uint16_1") client.stream_create("/context/test", "uint16_1")
with client.stream_insert_context("/context/test") as ctx: with client.stream_insert_context("/context/test") as ctx:
# override _max_data to trigger frequent server updates # override _max_data to trigger frequent server updates
ctx._max_data = 15 ctx._max_data = 15
with assert_raises(ValueError): ctx.insert("100 1\n")
ctx.insert_line("100 1")
ctx.insert_line("100 1\n") ctx.insert("101 ")
ctx.insert_iter([ "101 1\n", ctx.insert("1\n102 1")
"102 1\n", ctx.insert("")
"103 1\n" ]) ctx.insert("\n103 1\n")
ctx.insert_line("104 1\n")
ctx.insert_line("105 1\n") ctx.insert("104 1\n")
ctx.insert("# hello\n")
ctx.insert(" # hello\n")
ctx.insert(" 105 1\n")
ctx.finalize() ctx.finalize()
ctx.insert_line("106 1\n") ctx.insert("106 1\n")
ctx.update_end(106.5) ctx.update_end(106.5)
ctx.finalize() ctx.finalize()
ctx.update_start(106.8) ctx.update_start(106.8)
ctx.insert_line("107 1\n") ctx.insert("107 1\n")
ctx.insert_line("108 1\n") ctx.insert("108 1\n")
ctx.insert_line("109 1\n") ctx.insert("109 1\n")
ctx.insert_line("110 1\n") ctx.insert("110 1\n")
ctx.insert_line("111 1\n") ctx.insert("111 1\n")
ctx.update_end(113) ctx.update_end(113)
ctx.insert_line("112 1\n") ctx.insert("112 1\n")
ctx.update_end(114) ctx.update_end(114)
ctx.insert_line("113 1\n") ctx.insert("113 1\n")
ctx.update_end(115) ctx.update_end(115)
ctx.insert_line("114 1\n") ctx.insert("114 1" +
" # this is super long" * 100 +
"\n")
ctx.finalize() ctx.finalize()
ctx.insert("# this is super long" * 100)
with assert_raises(ClientError): with assert_raises(ClientError):
with client.stream_insert_context("/context/test", 100, 200) as ctx: with client.stream_insert_context("/context/test", 100, 200) as ctx:
ctx.insert_line("115 1\n") ctx.insert("115 1\n")
with assert_raises(ClientError): with assert_raises(ClientError):
with client.stream_insert_context("/context/test", 200, 300) as ctx: with client.stream_insert_context("/context/test", 200, 300) as ctx:
ctx.insert_line("115 1\n") ctx.insert("115 1\n")
with assert_raises(ClientError):
with client.stream_insert_context("/context/test") as ctx:
ctx.insert("bogus data\n")
with client.stream_insert_context("/context/test", 200, 300) as ctx: with client.stream_insert_context("/context/test", 200, 300) as ctx:
# make sure our override wasn't permanent # make sure our override wasn't permanent
ne_(ctx._max_data, 15) ne_(ctx._max_data, 15)
ctx.insert_line("225 1\n") ctx.insert("225 1\n")
ctx.finalize() ctx.finalize()
with assert_raises(ClientError):
with client.stream_insert_context("/context/test", 300, 400) as ctx:
ctx.insert("301 1\n")
ctx.insert("302 2\n")
ctx.insert("303 3\n")
ctx.insert("304 4\n")
ctx.insert("304 4\n") # non-monotonic after a few lines
ctx.finalize()
eq_(list(client.stream_intervals("/context/test")), eq_(list(client.stream_intervals("/context/test")),
[ [ 100, 105.000001 ], [ [ 100, 105.000001 ],
[ 106, 106.5 ], [ 106, 106.5 ],
@@ -487,7 +515,7 @@ class TestClient(object):
# Empty intervals are ok! If recording detection events # Empty intervals are ok! If recording detection events
# by inserting rows into the database, we want to be able to # by inserting rows into the database, we want to be able to
# have an interval where no events occurred. Test them here. # have an interval where no events occurred. Test them here.
client = nilmdb.Client(testurl) client = nilmdb.client.Client(testurl)
client.stream_create("/empty/test", "uint16_1") client.stream_create("/empty/test", "uint16_1")
def info(): def info():
@@ -502,9 +530,9 @@ class TestClient(object):
# Insert a region with just a few points # Insert a region with just a few points
with client.stream_insert_context("/empty/test") as ctx: with client.stream_insert_context("/empty/test") as ctx:
ctx.update_start(100) ctx.update_start(100)
ctx.insert_line("140 1\n") ctx.insert("140 1\n")
ctx.insert_line("150 1\n") ctx.insert("150 1\n")
ctx.insert_line("160 1\n") ctx.insert("160 1\n")
ctx.update_end(200) ctx.update_end(200)
ctx.finalize() ctx.finalize()
@@ -517,7 +545,7 @@ class TestClient(object):
# Try also creating a completely empty interval from scratch, # Try also creating a completely empty interval from scratch,
# in a few different ways. # in a few different ways.
client.stream_insert_block("/empty/test", "", 300, 350) client.stream_insert("/empty/test", "", 300, 350)
client.stream_insert("/empty/test", [], 400, 450) client.stream_insert("/empty/test", [], 400, 450)
with client.stream_insert_context("/empty/test", 500, 550): with client.stream_insert_context("/empty/test", 500, 550):
pass pass
@@ -538,10 +566,10 @@ class TestClient(object):
ctx.finalize() # inserts [1000, 1050] ctx.finalize() # inserts [1000, 1050]
ctx.finalize() # nothing ctx.finalize() # nothing
ctx.finalize() # nothing ctx.finalize() # nothing
ctx.insert_line("1100 1\n") ctx.insert("1100 1\n")
ctx.finalize() # inserts [1100, 1100.000001] ctx.finalize() # inserts [1100, 1100.000001]
ctx.update_start(1199) ctx.update_start(1199)
ctx.insert_line("1200 1\n") ctx.insert("1200 1\n")
ctx.update_end(1250) ctx.update_end(1250)
ctx.finalize() # inserts [1199, 1250] ctx.finalize() # inserts [1199, 1250]
ctx.update_start(1299) ctx.update_start(1299)
@@ -549,8 +577,15 @@ class TestClient(object):
ctx.update_end(1350) ctx.update_end(1350)
ctx.finalize() # nothing ctx.finalize() # nothing
ctx.update_start(1400) ctx.update_start(1400)
ctx.insert("# nothing!\n")
ctx.update_end(1450) ctx.update_end(1450)
ctx.finalize() ctx.finalize()
ctx.update_start(1500)
ctx.insert("# nothing!")
ctx.update_end(1550)
ctx.finalize()
ctx.insert("# nothing!\n" * 10)
ctx.finalize()
# implicit last finalize inserts [1400, 1450] # implicit last finalize inserts [1400, 1450]
# Check everything # Check everything
@@ -563,6 +598,7 @@ class TestClient(object):
(1, [1100, 1100.000001]), (1, [1100, 1100.000001]),
(1, [1199, 1250]), (1, [1199, 1250]),
(0, [1400, 1450]), (0, [1400, 1450]),
(0, [1500, 1550]),
]) ])
# Clean up # Clean up
@@ -573,11 +609,11 @@ class TestClient(object):
# Check that connections are persistent when they should be. # Check that connections are persistent when they should be.
# This is pretty hard to test; we have to poke deep into # This is pretty hard to test; we have to poke deep into
# the Requests library. # the Requests library.
with nilmdb.Client(url = testurl) as c: with nilmdb.client.Client(url = testurl) as c:
def connections(): def connections():
try: try:
poolmanager = c.http._last_response.connection.poolmanager poolmanager = c.http._last_response.connection.poolmanager
pool = poolmanager.pools[('http','localhost',12380)] pool = poolmanager.pools[('http','localhost',32180)]
return (pool.num_connections, pool.num_requests) return (pool.num_connections, pool.num_requests)
except: except:
raise SkipTest("can't get connection info") raise SkipTest("can't get connection info")

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import nilmdb import nilmdb.server
from nilmdb.utils.printf import * from nilmdb.utils.printf import *
import nilmdb.cmdline import nilmdb.cmdline
from nilmdb.utils import datetime_tz from nilmdb.utils import datetime_tz
@@ -11,12 +12,7 @@ from nose.tools import assert_raises
import itertools import itertools
import os import os
import re import re
import shutil
import sys import sys
import threading
import urllib2
from urllib2 import urlopen, HTTPError
import Queue
import StringIO import StringIO
import shlex import shlex
@@ -27,14 +23,14 @@ testdb = "tests/cmdline-testdb"
def server_start(max_results = None, bulkdata_args = {}): def server_start(max_results = None, bulkdata_args = {}):
global test_server, test_db global test_server, test_db
# Start web app on a custom port # Start web app on a custom port
test_db = nilmdb.utils.serializer_proxy(nilmdb.NilmDB)( test_db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(
testdb, sync = False, testdb,
max_results = max_results, max_results = max_results,
bulkdata_args = bulkdata_args) bulkdata_args = bulkdata_args)
test_server = nilmdb.Server(test_db, host = "127.0.0.1", test_server = nilmdb.server.Server(test_db, host = "127.0.0.1",
port = 12380, stoppable = False, port = 32180, stoppable = False,
fast_shutdown = True, fast_shutdown = True,
force_traceback = False) force_traceback = False)
test_server.start(blocking = False) test_server.start(blocking = False)
def server_stop(): def server_stop():
@@ -64,6 +60,7 @@ class TestCmdline(object):
passing the given input. Returns a tuple with the output and passing the given input. Returns a tuple with the output and
exit code""" exit code"""
# printf("TZ=UTC ./nilmtool.py %s\n", arg_string) # printf("TZ=UTC ./nilmtool.py %s\n", arg_string)
os.environ['NILMDB_URL'] = "http://localhost:32180/"
class stdio_wrapper: class stdio_wrapper:
def __init__(self, stdin, stdout, stderr): def __init__(self, stdin, stdout, stderr):
self.io = (stdin, stdout, stderr) self.io = (stdin, stdout, stderr)
@@ -129,8 +126,17 @@ class TestCmdline(object):
with open(file) as f: with open(file) as f:
contents = f.read() contents = f.read()
if contents != self.captured: if contents != self.captured:
print contents[1:1000] + "\n" print "--- reference file (first 1000 bytes):\n"
print self.captured[1:1000] + "\n" print contents[0:1000] + "\n"
print "--- captured data (first 1000 bytes):\n"
print self.captured[0:1000] + "\n"
zipped = itertools.izip_longest(contents, self.captured)
for (n, (a, b)) in enumerate(zipped):
if a != b:
print "--- first difference is at offset", n
print "--- reference:", repr(a)
print "--- captured:", repr(b)
break
raise AssertionError("captured data doesn't match " + file) raise AssertionError("captured data doesn't match " + file)
def matchfilecount(self, file): def matchfilecount(self, file):
@@ -174,7 +180,7 @@ class TestCmdline(object):
self.fail("-u localhost:1 info") self.fail("-u localhost:1 info")
self.contain("error connecting to server") self.contain("error connecting to server")
self.ok("-u localhost:12380 info") self.ok("-u localhost:32180 info")
self.ok("info") self.ok("info")
# Duplicated arguments should fail, but this isn't implemented # Duplicated arguments should fail, but this isn't implemented
@@ -192,6 +198,20 @@ class TestCmdline(object):
self.fail("extract --start 2000-01-01 --start 2001-01-02") self.fail("extract --start 2000-01-01 --start 2001-01-02")
self.contain("duplicated argument") self.contain("duplicated argument")
# Verify that "help command" and "command --help" are identical
# for all commands.
self.fail("")
m = re.search(r"{(.*)}", self.captured)
for command in [""] + m.group(1).split(','):
self.ok(command + " --help")
cap1 = self.captured
self.ok("help " + command)
cap2 = self.captured
self.ok("help " + command + " asdf --url --zxcv -")
cap3 = self.captured
eq_(cap1, cap2)
eq_(cap2, cap3)
def test_02_parsetime(self): def test_02_parsetime(self):
os.environ['TZ'] = "America/New_York" os.environ['TZ'] = "America/New_York"
test = datetime_tz.datetime_tz.now() test = datetime_tz.datetime_tz.now()
@@ -210,7 +230,7 @@ class TestCmdline(object):
def test_03_info(self): def test_03_info(self):
self.ok("info") self.ok("info")
self.contain("Server URL: http://localhost:12380/") self.contain("Server URL: http://localhost:32180/")
self.contain("Client version: " + nilmdb.__version__) self.contain("Client version: " + nilmdb.__version__)
self.contain("Server version: " + test_server.version) self.contain("Server version: " + test_server.version)
self.contain("Server database path") self.contain("Server database path")
@@ -225,10 +245,10 @@ class TestCmdline(object):
self.match("") self.match("")
# Bad paths # Bad paths
self.fail("create foo/bar/baz PrepData") self.fail("create foo/bar/baz float32_8")
self.contain("paths must start with /") self.contain("paths must start with /")
self.fail("create /foo PrepData") self.fail("create /foo float32_8")
self.contain("invalid path") self.contain("invalid path")
# Bad layout type # Bad layout type
@@ -240,53 +260,53 @@ class TestCmdline(object):
self.contain("no such layout") self.contain("no such layout")
# Create a few streams # Create a few streams
self.ok("create /newton/zzz/rawnotch RawNotchedData") self.ok("create /newton/zzz/rawnotch uint16_9")
self.ok("create /newton/prep PrepData") self.ok("create /newton/prep float32_8")
self.ok("create /newton/raw RawData") self.ok("create /newton/raw uint16_6")
# Should not be able to create a stream with another stream as # Should not be able to create a stream with another stream as
# its parent # its parent
self.fail("create /newton/prep/blah PrepData") self.fail("create /newton/prep/blah float32_8")
self.contain("path is subdir of existing node") self.contain("path is subdir of existing node")
# Should not be able to create a stream at a location that # Should not be able to create a stream at a location that
# has other nodes as children # has other nodes as children
self.fail("create /newton/zzz PrepData") self.fail("create /newton/zzz float32_8")
self.contain("subdirs of this path already exist") self.contain("subdirs of this path already exist")
# Verify we got those 3 streams and they're returned in # Verify we got those 3 streams and they're returned in
# alphabetical order. # alphabetical order.
self.ok("list") self.ok("list")
self.match("/newton/prep PrepData\n" self.match("/newton/prep float32_8\n"
"/newton/raw RawData\n" "/newton/raw uint16_6\n"
"/newton/zzz/rawnotch RawNotchedData\n") "/newton/zzz/rawnotch uint16_9\n")
# Match just one type or one path. Also check # Match just one type or one path. Also check
# that --path is optional # that --path is optional
self.ok("list --path /newton/raw") self.ok("list --path /newton/raw")
self.match("/newton/raw RawData\n") self.match("/newton/raw uint16_6\n")
self.ok("list /newton/raw") self.ok("list /newton/raw")
self.match("/newton/raw RawData\n") self.match("/newton/raw uint16_6\n")
self.fail("list -p /newton/raw /newton/raw") self.fail("list -p /newton/raw /newton/raw")
self.contain("too many paths") self.contain("too many paths")
self.ok("list --layout RawData") self.ok("list --layout uint16_6")
self.match("/newton/raw RawData\n") self.match("/newton/raw uint16_6\n")
# Wildcard matches # Wildcard matches
self.ok("list --layout Raw*") self.ok("list --layout uint16*")
self.match("/newton/raw RawData\n" self.match("/newton/raw uint16_6\n"
"/newton/zzz/rawnotch RawNotchedData\n") "/newton/zzz/rawnotch uint16_9\n")
self.ok("list --path *zzz* --layout Raw*") self.ok("list --path *zzz* --layout uint16*")
self.match("/newton/zzz/rawnotch RawNotchedData\n") self.match("/newton/zzz/rawnotch uint16_9\n")
self.ok("list *zzz* --layout Raw*") self.ok("list *zzz* --layout uint16*")
self.match("/newton/zzz/rawnotch RawNotchedData\n") self.match("/newton/zzz/rawnotch uint16_9\n")
self.ok("list --path *zzz* --layout Prep*") self.ok("list --path *zzz* --layout float32*")
self.match("") self.match("")
# reversed range # reversed range
@@ -353,43 +373,49 @@ class TestCmdline(object):
def test_06_insert(self): def test_06_insert(self):
self.ok("insert --help") self.ok("insert --help")
self.fail("insert /foo/bar baz qwer") self.fail("insert -s 2000 -e 2001 /foo/bar baz")
self.contain("error getting stream info") self.contain("error getting stream info")
self.fail("insert /newton/prep baz qwer") self.fail("insert -s 2000 -e 2001 /newton/prep baz")
self.match("error opening input file baz\n") self.match("error opening input file baz\n")
self.fail("insert /newton/prep") self.fail("insert /newton/prep --timestamp -f -r 120")
self.contain("error extracting time") self.contain("error extracting start time")
self.fail("insert --start 19801205 /newton/prep 1 2 3 4") self.fail("insert /newton/prep --timestamp -r 120")
self.contain("--start can only be used with one input file") self.contain("need --start or --filename")
self.fail("insert /newton/prep " self.fail("insert /newton/prep "
"tests/data/prep-20120323T1000") "tests/data/prep-20120323T1000")
# insert pre-timestamped data, from stdin
os.environ['TZ'] = "UTC"
with open("tests/data/prep-20120323T1004-timestamped") as input:
self.ok("insert --none /newton/prep", input)
# insert pre-timestamped data, with bad times (non-monotonic) # insert pre-timestamped data, with bad times (non-monotonic)
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
with open("tests/data/prep-20120323T1004-badtimes") as input: with open("tests/data/prep-20120323T1004-badtimes") as input:
self.fail("insert --none /newton/prep", input) self.fail("insert -s 20120323T1004 -e 20120323T1006 /newton/prep",
input)
self.contain("error parsing input data") self.contain("error parsing input data")
self.contain("line 7:") self.contain("line 7:")
self.contain("timestamp is not monotonically increasing") self.contain("timestamp is not monotonically increasing")
# insert pre-timestamped data, from stdin
os.environ['TZ'] = "UTC"
with open("tests/data/prep-20120323T1004-timestamped") as input:
self.ok("insert -s 20120323T1004 -e 20120323T1006 /newton/prep",
input)
# insert data with normal timestamper from filename # insert data with normal timestamper from filename
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
self.ok("insert --rate 120 /newton/prep " self.ok("insert --timestamp -f --rate 120 /newton/prep "
"tests/data/prep-20120323T1000 " "tests/data/prep-20120323T1000")
self.fail("insert -t --filename /newton/prep "
"tests/data/prep-20120323T1002")
self.contain("rate is needed")
self.ok("insert -t --filename --rate 120 /newton/prep "
"tests/data/prep-20120323T1002") "tests/data/prep-20120323T1002")
# overlap # overlap
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
self.fail("insert --rate 120 /newton/prep " self.fail("insert --timestamp -f --rate 120 /newton/prep "
"tests/data/prep-20120323T1004") "tests/data/prep-20120323T1004")
self.contain("overlap") self.contain("overlap")
@@ -401,24 +427,24 @@ class TestCmdline(object):
# still an overlap if we specify a different start # still an overlap if we specify a different start
os.environ['TZ'] = "America/New_York" os.environ['TZ'] = "America/New_York"
self.fail("insert --rate 120 --start '03/23/2012 06:05:00' /newton/prep" self.fail("insert -t -r 120 --start '03/23/2012 06:05:00' /newton/prep"
" tests/data/prep-20120323T1004") " tests/data/prep-20120323T1004")
self.contain("overlap") self.contain("overlap")
# wrong format # wrong format
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
self.fail("insert --rate 120 /newton/raw " self.fail("insert -t -r 120 -f /newton/raw "
"tests/data/prep-20120323T1004") "tests/data/prep-20120323T1004")
self.contain("error parsing input data") self.contain("error parsing input data")
# empty data does nothing # empty data does nothing
self.ok("insert --rate 120 --start '03/23/2012 06:05:00' /newton/prep " self.ok("insert -t -r 120 --start '03/23/2012 06:05:00' /newton/prep "
"/dev/null") "/dev/null")
# bad start time # bad start time
self.fail("insert --rate 120 --start 'whatever' /newton/prep /dev/null") self.fail("insert -t -r 120 --start 'whatever' /newton/prep /dev/null")
def test_07_detail(self): def test_07_detail_extended(self):
# Just count the number of lines, it's probably fine # Just count the number of lines, it's probably fine
self.ok("list --detail") self.ok("list --detail")
lines_(self.captured, 8) lines_(self.captured, 8)
@@ -456,12 +482,29 @@ class TestCmdline(object):
self.ok("list --detail --path *prep --timestamp-raw " self.ok("list --detail --path *prep --timestamp-raw "
"--start='23 Mar 2012 10:05:15.50'") "--start='23 Mar 2012 10:05:15.50'")
lines_(self.captured, 2) lines_(self.captured, 2)
self.contain("[ 1332497115.5 -> 1332497159.991668 ]") self.contain("[ 1332497115.500000 -> 1332497160.000000 ]")
self.ok("list --detail --path *prep -T " # bad time
"--start='23 Mar 2012 10:05:15.612'") self.fail("list --detail --path *prep -T --start='9332497115.612'")
# good time
self.ok("list --detail --path *prep -T --start='1332497115.612'")
lines_(self.captured, 2) lines_(self.captured, 2)
self.contain("[ 1332497115.612 -> 1332497159.991668 ]") self.contain("[ 1332497115.612000 -> 1332497160.000000 ]")
# Check --ext output
self.ok("list --ext")
lines_(self.captured, 9)
self.ok("list -E -T")
c = self.contain
c("\n interval extents: 1332496800.000000 -> 1332497160.000000\n")
c("\n total data: 43200 rows, 359.983336 seconds\n")
c("\n interval extents: (no data)\n")
c("\n total data: 0 rows, 0.000000 seconds\n")
# Misc
self.fail("list --ext --start='23 Mar 2012 10:05:15.50'")
self.contain("--start and --end only make sense with --detail")
def test_08_extract(self): def test_08_extract(self):
# nonexistent stream # nonexistent stream
@@ -572,13 +615,13 @@ class TestCmdline(object):
# Make sure we have the data we expect # Make sure we have the data we expect
self.ok("list --detail /newton/prep") self.ok("list --detail /newton/prep")
self.match("/newton/prep PrepData\n" + self.match("/newton/prep float32_8\n" +
" [ Fri, 23 Mar 2012 10:00:00.000000 +0000" " [ Fri, 23 Mar 2012 10:00:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:01:59.991668 +0000 ]\n" " -> Fri, 23 Mar 2012 10:01:59.991668 +0000 ]\n"
" [ Fri, 23 Mar 2012 10:02:00.000000 +0000" " [ Fri, 23 Mar 2012 10:02:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:03:59.991668 +0000 ]\n" " -> Fri, 23 Mar 2012 10:03:59.991668 +0000 ]\n"
" [ Fri, 23 Mar 2012 10:04:00.000000 +0000" " [ Fri, 23 Mar 2012 10:04:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:05:59.991668 +0000 ]\n") " -> Fri, 23 Mar 2012 10:06:00.000000 +0000 ]\n")
# Remove various chunks of prep data and make sure # Remove various chunks of prep data and make sure
# they're gone. # they're gone.
@@ -607,7 +650,7 @@ class TestCmdline(object):
# See the missing chunks in list output # See the missing chunks in list output
self.ok("list --detail /newton/prep") self.ok("list --detail /newton/prep")
self.match("/newton/prep PrepData\n" + self.match("/newton/prep float32_8\n" +
" [ Fri, 23 Mar 2012 10:00:00.000000 +0000" " [ Fri, 23 Mar 2012 10:00:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:00:05.000000 +0000 ]\n" " -> Fri, 23 Mar 2012 10:00:05.000000 +0000 ]\n"
" [ Fri, 23 Mar 2012 10:00:25.000000 +0000" " [ Fri, 23 Mar 2012 10:00:25.000000 +0000"
@@ -621,14 +664,15 @@ class TestCmdline(object):
self.ok("remove /newton/prep --start 2000-01-01 --end 2020-01-01") self.ok("remove /newton/prep --start 2000-01-01 --end 2020-01-01")
self.match("") # no count requested this time self.match("") # no count requested this time
self.ok("list --detail /newton/prep") self.ok("list --detail /newton/prep")
self.match("/newton/prep PrepData\n" + self.match("/newton/prep float32_8\n" +
" (no intervals)\n") " (no intervals)\n")
# Reinsert some data, to verify that no overlaps with deleted # Reinsert some data, to verify that no overlaps with deleted
# data are reported # data are reported
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
self.ok("insert --rate 120 /newton/prep " self.ok("insert --timestamp -f --rate 120 /newton/prep "
"tests/data/prep-20120323T1000 " "tests/data/prep-20120323T1000")
self.ok("insert -t --filename --rate 120 /newton/prep "
"tests/data/prep-20120323T1002") "tests/data/prep-20120323T1002")
def test_11_destroy(self): def test_11_destroy(self):
@@ -646,9 +690,9 @@ class TestCmdline(object):
# From previous tests, we have: # From previous tests, we have:
self.ok("list") self.ok("list")
self.match("/newton/prep PrepData\n" self.match("/newton/prep float32_8\n"
"/newton/raw RawData\n" "/newton/raw uint16_6\n"
"/newton/zzz/rawnotch RawNotchedData\n") "/newton/zzz/rawnotch uint16_9\n")
# Notice how they're not empty # Notice how they're not empty
self.ok("list --detail") self.ok("list --detail")
@@ -657,15 +701,15 @@ class TestCmdline(object):
# Delete some # Delete some
self.ok("destroy /newton/prep") self.ok("destroy /newton/prep")
self.ok("list") self.ok("list")
self.match("/newton/raw RawData\n" self.match("/newton/raw uint16_6\n"
"/newton/zzz/rawnotch RawNotchedData\n") "/newton/zzz/rawnotch uint16_9\n")
self.ok("destroy /newton/zzz/rawnotch") self.ok("destroy /newton/zzz/rawnotch")
self.ok("list") self.ok("list")
self.match("/newton/raw RawData\n") self.match("/newton/raw uint16_6\n")
self.ok("destroy /newton/raw") self.ok("destroy /newton/raw")
self.ok("create /newton/raw RawData") self.ok("create /newton/raw uint16_6")
self.ok("destroy /newton/raw") self.ok("destroy /newton/raw")
self.ok("list") self.ok("list")
self.match("") self.match("")
@@ -675,7 +719,7 @@ class TestCmdline(object):
"/newton/raw", "/newton/asdf/qwer" ] "/newton/raw", "/newton/asdf/qwer" ]
for path in rebuild: for path in rebuild:
# Create the path # Create the path
self.ok("create " + path + " PrepData") self.ok("create " + path + " float32_8")
self.ok("list") self.ok("list")
self.contain(path) self.contain(path)
# Make sure it was created empty # Make sure it was created empty
@@ -713,7 +757,8 @@ class TestCmdline(object):
self.ok("create /newton/prep float32_8") self.ok("create /newton/prep float32_8")
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
with open("tests/data/prep-20120323T1004-timestamped") as input: with open("tests/data/prep-20120323T1004-timestamped") as input:
self.ok("insert --none /newton/prep", input) self.ok("insert -s 20120323T1004 -e 20120323T1006 /newton/prep",
input)
# Extract it # Extract it
self.ok("extract /newton/prep --start '2000-01-01' " + self.ok("extract /newton/prep --start '2000-01-01' " +
@@ -745,7 +790,8 @@ class TestCmdline(object):
self.ok("create /newton/prep float32_8") self.ok("create /newton/prep float32_8")
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
with open("tests/data/prep-20120323T1004-timestamped") as input: with open("tests/data/prep-20120323T1004-timestamped") as input:
self.ok("insert --none /newton/prep", input) self.ok("insert -s 20120323T1004 -e 20120323T1006 /newton/prep",
input)
nfiles = 0 nfiles = 0
for (dirpath, dirnames, filenames) in os.walk(testdb): for (dirpath, dirnames, filenames) in os.walk(testdb):
nfiles += len(filenames) nfiles += len(filenames)
@@ -761,10 +807,11 @@ class TestCmdline(object):
"files_per_dir" : 3 }) "files_per_dir" : 3 })
# Insert data. Just for fun, insert out of order # Insert data. Just for fun, insert out of order
self.ok("create /newton/prep PrepData") self.ok("create /newton/prep float32_8")
os.environ['TZ'] = "UTC" os.environ['TZ'] = "UTC"
self.ok("insert --rate 120 /newton/prep " self.ok("insert -t --filename --rate 120 /newton/prep "
"tests/data/prep-20120323T1002 " "tests/data/prep-20120323T1002")
self.ok("insert -t --filename --rate 120 /newton/prep "
"tests/data/prep-20120323T1000") "tests/data/prep-20120323T1000")
# Should take up about 2.8 MB here (including directory entries) # Should take up about 2.8 MB here (including directory entries)
@@ -772,7 +819,7 @@ class TestCmdline(object):
# Make sure we have the data we expect # Make sure we have the data we expect
self.ok("list --detail") self.ok("list --detail")
self.match("/newton/prep PrepData\n" + self.match("/newton/prep float32_8\n" +
" [ Fri, 23 Mar 2012 10:00:00.000000 +0000" " [ Fri, 23 Mar 2012 10:00:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:01:59.991668 +0000 ]\n" " -> Fri, 23 Mar 2012 10:01:59.991668 +0000 ]\n"
" [ Fri, 23 Mar 2012 10:02:00.000000 +0000" " [ Fri, 23 Mar 2012 10:02:00.000000 +0000"
@@ -808,7 +855,7 @@ class TestCmdline(object):
# See the missing chunks in list output # See the missing chunks in list output
self.ok("list --detail") self.ok("list --detail")
self.match("/newton/prep PrepData\n" + self.match("/newton/prep float32_8\n" +
" [ Fri, 23 Mar 2012 10:00:00.000000 +0000" " [ Fri, 23 Mar 2012 10:00:00.000000 +0000"
" -> Fri, 23 Mar 2012 10:00:05.000000 +0000 ]\n" " -> Fri, 23 Mar 2012 10:00:05.000000 +0000 ]\n"
" [ Fri, 23 Mar 2012 10:00:25.000000 +0000" " [ Fri, 23 Mar 2012 10:00:25.000000 +0000"
@@ -829,7 +876,7 @@ class TestCmdline(object):
# With the specific file_size above, this will cause the last # With the specific file_size above, this will cause the last
# file in the bulk data storage to be exactly file_size large, # file in the bulk data storage to be exactly file_size large,
# so removing the data should also remove that last file. # so removing the data should also remove that last file.
self.ok("insert --rate 120 /newton/prep " + self.ok("insert --timestamp -f --rate 120 /newton/prep " +
"tests/data/prep-20120323T1002-first19lines") "tests/data/prep-20120323T1002-first19lines")
self.ok("remove /newton/prep " + self.ok("remove /newton/prep " +
"--start '23 Mar 2012 10:02:00' --end '2020-01-01'") "--start '23 Mar 2012 10:02:00' --end '2020-01-01'")
@@ -840,7 +887,8 @@ class TestCmdline(object):
# Re-add the full 10:02 data file. This tests adding new data once # Re-add the full 10:02 data file. This tests adding new data once
# we removed data near the end. # we removed data near the end.
self.ok("insert --rate 120 /newton/prep tests/data/prep-20120323T1002") self.ok("insert -t -f -r 120 /newton/prep "
"tests/data/prep-20120323T1002")
# See if we can extract it all # See if we can extract it all
self.ok("extract /newton/prep --start 2000-01-01 --end 2020-01-01") self.ok("extract /newton/prep --start 2000-01-01 --end 2020-01-01")

View File

@@ -89,14 +89,14 @@ class TestInterval:
# big integers and floats # big integers and floats
x = Interval(5000111222, 6000111222) x = Interval(5000111222, 6000111222)
eq_(str(x), "[5000111222.0 -> 6000111222.0)") eq_(str(x), "[5000111222.000000 -> 6000111222.000000)")
x = Interval(123.45, 234.56) x = Interval(123.45, 234.56)
eq_(str(x), "[123.45 -> 234.56)") eq_(str(x), "[123.450000 -> 234.560000)")
# misc # misc
i = Interval(d1, d2) i = Interval(d1, d2)
eq_(repr(i), repr(eval(repr(i)))) eq_(repr(i), repr(eval(repr(i))))
eq_(str(i), "[1332561600.0 -> 1332648000.0)") eq_(str(i), "[1332561600.000000 -> 1332648000.000000)")
def test_interval_intersect(self): def test_interval_intersect(self):
# Test Interval intersections # Test Interval intersections
@@ -192,7 +192,8 @@ class TestInterval:
# misc # misc
eq_(repr(iset), repr(eval(repr(iset)))) eq_(repr(iset), repr(eval(repr(iset))))
eq_(str(iset), "[[100.0 -> 200.0), [200.0 -> 300.0)]") eq_(str(iset),
"[[100.000000 -> 200.000000), [200.000000 -> 300.000000)]")
def test_intervalset_geniset(self): def test_intervalset_geniset(self):
# Test basic iset construction # Test basic iset construction

View File

@@ -9,14 +9,7 @@ from nose.tools import assert_raises
import distutils.version import distutils.version
import itertools import itertools
import os import os
import shutil
import sys import sys
import cherrypy
import threading
import urllib2
from urllib2 import urlopen, HTTPError
import Queue
import cStringIO
import random import random
import unittest import unittest
@@ -28,7 +21,7 @@ class TestLayouts(object):
# Some nilmdb.layout tests. Not complete, just fills in missing # Some nilmdb.layout tests. Not complete, just fills in missing
# coverage. # coverage.
def test_layouts(self): def test_layouts(self):
x = nilmdb.server.layout.get_named("PrepData") x = nilmdb.server.layout.get_named("float32_8")
y = nilmdb.server.layout.get_named("float32_8") y = nilmdb.server.layout.get_named("float32_8")
eq_(x.count, y.count) eq_(x.count, y.count)
eq_(x.datatype, y.datatype) eq_(x.datatype, y.datatype)
@@ -37,7 +30,7 @@ class TestLayouts(object):
eq_(x.datatype, y.datatype) eq_(x.datatype, y.datatype)
def test_parsing(self): def test_parsing(self):
self.real_t_parsing("PrepData", "RawData", "RawNotchedData") self.real_t_parsing("float32_8", "uint16_6", "uint16_9")
self.real_t_parsing("float32_8", "uint16_6", "uint16_9") self.real_t_parsing("float32_8", "uint16_6", "uint16_9")
def real_t_parsing(self, name_prep, name_raw, name_rawnotch): def real_t_parsing(self, name_prep, name_raw, name_rawnotch):
# invalid layouts # invalid layouts
@@ -72,7 +65,7 @@ class TestLayouts(object):
eq_(parser.data, [[1234567890.0,1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8], eq_(parser.data, [[1234567890.0,1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8],
[1234567890.1,1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8]]) [1234567890.1,1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8]])
# try RawData too, with clamping # try uint16_6 too, with clamping
parser = Parser(name_raw) parser = Parser(name_raw)
data = ( "1234567890.000000 1 2 3 4 5 6\n" + data = ( "1234567890.000000 1 2 3 4 5 6\n" +
"1234567890.100000 1 2 3 4 5 6\n" ) "1234567890.100000 1 2 3 4 5 6\n" )
@@ -106,7 +99,7 @@ class TestLayouts(object):
"1234567890.100001 1 2 3 4 5 6\n" ) "1234567890.100001 1 2 3 4 5 6\n" )
parser.parse(data) parser.parse(data)
# RawData with values out of bounds # uint16_6 with values out of bounds
parser = Parser(name_raw) parser = Parser(name_raw)
data = ( "1234567890.000000 1 2 3 4 500000 6\n" + data = ( "1234567890.000000 1 2 3 4 500000 6\n" +
"1234567890.100000 1 2 3 4 5 6\n" ) "1234567890.100000 1 2 3 4 5 6\n" )
@@ -122,7 +115,7 @@ class TestLayouts(object):
assert(parser.max_timestamp is None) assert(parser.max_timestamp is None)
def test_formatting(self): def test_formatting(self):
self.real_t_formatting("PrepData", "RawData", "RawNotchedData") self.real_t_formatting("float32_8", "uint16_6", "uint16_9")
self.real_t_formatting("float32_8", "uint16_6", "uint16_9") self.real_t_formatting("float32_8", "uint16_6", "uint16_9")
def real_t_formatting(self, name_prep, name_raw, name_rawnotch): def real_t_formatting(self, name_prep, name_raw, name_rawnotch):
# invalid layout # invalid layout
@@ -151,12 +144,14 @@ class TestLayouts(object):
[ 1234567890.100000, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8 ] ] [ 1234567890.100000, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8 ] ]
text = formatter.format(data) text = formatter.format(data)
eq_(text, eq_(text,
"1234567890.000000 1.100000 2.200000 3.300000 4.400000 " + "1234567890.000000 1.100000e+00 2.200000e+00 3.300000e+00 "
"5.500000 6.600000 7.700000 8.800000\n" + "4.400000e+00 5.500000e+00 6.600000e+00 7.700000e+00 "
"1234567890.100000 1.100000 2.200000 3.300000 4.400000 " + "8.800000e+00\n" +
"5.500000 6.600000 7.700000 8.800000\n") "1234567890.100000 1.100000e+00 2.200000e+00 3.300000e+00 "
"4.400000e+00 5.500000e+00 6.600000e+00 7.700000e+00 "
"8.800000e+00\n")
# try RawData too # try uint16_6 too
formatter = Formatter(name_raw) formatter = Formatter(name_raw)
data = [ [ 1234567890.000000, 1, 2, 3, 4, 5, 6 ], data = [ [ 1234567890.000000, 1, 2, 3, 4, 5, 6 ],
[ 1234567890.100000, 1, 2, 3, 4, 5, 6 ] ] [ 1234567890.100000, 1, 2, 3, 4, 5, 6 ] ]
@@ -181,7 +176,7 @@ class TestLayouts(object):
eq_(text, "") eq_(text, "")
def test_roundtrip(self): def test_roundtrip(self):
self.real_t_roundtrip("PrepData", "RawData", "RawNotchedData") self.real_t_roundtrip("float32_8", "uint16_6", "uint16_9")
self.real_t_roundtrip("float32_8", "uint16_6", "uint16_9") self.real_t_roundtrip("float32_8", "uint16_6", "uint16_9")
def real_t_roundtrip(self, name_prep, name_raw, name_rawnotch): def real_t_roundtrip(self, name_prep, name_raw, name_rawnotch):
# Verify that textual data passed into the Parser, and then # Verify that textual data passed into the Parser, and then
@@ -208,7 +203,7 @@ class TestLayouts(object):
eq_(parser1.data, parser2.data) eq_(parser1.data, parser2.data)
def datagen(): def datagen():
return [ sprintf("%f", random.uniform(-1000,1000)) return [ sprintf("%.6e", random.uniform(-1000,1000))
for x in range(8) ] for x in range(8) ]
do_roundtrip(name_prep, datagen) do_roundtrip(name_prep, datagen)
@@ -246,7 +241,7 @@ class TestLayoutSpeed:
parser = Parser(layout) parser = Parser(layout)
formatter = Formatter(layout) formatter = Formatter(layout)
parser.parse(data) parser.parse(data)
data = formatter.format(parser.data) formatter.format(parser.data)
elapsed = time.time() - start elapsed = time.time() - start
printf("roundtrip %s: %d ms, %.1f μs/row, %d rows/sec\n", printf("roundtrip %s: %d ms, %.1f μs/row, %d rows/sec\n",
layout, layout,
@@ -256,7 +251,7 @@ class TestLayoutSpeed:
print "" print ""
def datagen(): def datagen():
return [ sprintf("%f", random.uniform(-1000,1000)) return [ sprintf("%.6e", random.uniform(-1000,1000))
for x in range(10) ] for x in range(10) ]
do_speedtest("float32_10", datagen) do_speedtest("float32_10", datagen)
@@ -264,3 +259,8 @@ class TestLayoutSpeed:
return [ sprintf("%d", random.randint(0,65535)) return [ sprintf("%d", random.randint(0,65535))
for x in range(10) ] for x in range(10) ]
do_speedtest("uint16_10", datagen) do_speedtest("uint16_10", datagen)
def datagen():
return [ sprintf("%d", random.randint(0,65535))
for x in range(6) ]
do_speedtest("uint16_6", datagen)

View File

@@ -34,6 +34,10 @@ class Bar:
def __del__(self): def __del__(self):
fprintf(err, "Deleting\n") fprintf(err, "Deleting\n")
@classmethod
def baz(self):
fprintf(err, "Baz\n")
def close(self): def close(self):
fprintf(err, "Closing\n") fprintf(err, "Closing\n")

View File

@@ -1,4 +1,4 @@
import nilmdb import nilmdb.server
from nose.tools import * from nose.tools import *
from nose.tools import assert_raises from nose.tools import assert_raises
@@ -6,15 +6,13 @@ import distutils.version
import simplejson as json import simplejson as json
import itertools import itertools
import os import os
import shutil
import sys import sys
import cherrypy
import threading import threading
import urllib2 import urllib2
from urllib2 import urlopen, HTTPError from urllib2 import urlopen, HTTPError
import Queue
import cStringIO import cStringIO
import time import time
import requests
from nilmdb.utils import serializer_proxy from nilmdb.utils import serializer_proxy
@@ -31,11 +29,11 @@ class Test00Nilmdb(object): # named 00 so it runs first
recursive_unlink(testdb) recursive_unlink(testdb)
with assert_raises(IOError): with assert_raises(IOError):
nilmdb.NilmDB("/nonexistant-db/foo") nilmdb.server.NilmDB("/nonexistant-db/foo")
db = nilmdb.NilmDB(testdb) db = nilmdb.server.NilmDB(testdb)
db.close() db.close()
db = nilmdb.NilmDB(testdb, sync=False) db = nilmdb.server.NilmDB(testdb)
db.close() db.close()
# test timer, just to get coverage # test timer, just to get coverage
@@ -48,29 +46,29 @@ class Test00Nilmdb(object): # named 00 so it runs first
in_("test: ", capture.getvalue()) in_("test: ", capture.getvalue())
def test_stream(self): def test_stream(self):
db = nilmdb.NilmDB(testdb, sync=False) db = nilmdb.server.NilmDB(testdb)
eq_(db.stream_list(), []) eq_(db.stream_list(), [])
# Bad path # Bad path
with assert_raises(ValueError): with assert_raises(ValueError):
db.stream_create("foo/bar/baz", "PrepData") db.stream_create("foo/bar/baz", "float32_8")
with assert_raises(ValueError): with assert_raises(ValueError):
db.stream_create("/foo", "PrepData") db.stream_create("/foo", "float32_8")
# Bad layout type # Bad layout type
with assert_raises(ValueError): with assert_raises(ValueError):
db.stream_create("/newton/prep", "NoSuchLayout") db.stream_create("/newton/prep", "NoSuchLayout")
db.stream_create("/newton/prep", "PrepData") db.stream_create("/newton/prep", "float32_8")
db.stream_create("/newton/raw", "RawData") db.stream_create("/newton/raw", "uint16_6")
db.stream_create("/newton/zzz/rawnotch", "RawNotchedData") db.stream_create("/newton/zzz/rawnotch", "uint16_9")
# Verify we got 3 streams # Verify we got 3 streams
eq_(db.stream_list(), [ ["/newton/prep", "PrepData"], eq_(db.stream_list(), [ ["/newton/prep", "float32_8"],
["/newton/raw", "RawData"], ["/newton/raw", "uint16_6"],
["/newton/zzz/rawnotch", "RawNotchedData"] ["/newton/zzz/rawnotch", "uint16_9"]
]) ])
# Match just one type or one path # Match just one type or one path
eq_(db.stream_list(layout="RawData"), [ ["/newton/raw", "RawData"] ]) eq_(db.stream_list(layout="uint16_6"), [ ["/newton/raw", "uint16_6"] ])
eq_(db.stream_list(path="/newton/raw"), [ ["/newton/raw", "RawData"] ]) eq_(db.stream_list(path="/newton/raw"), [ ["/newton/raw", "uint16_6"] ])
# Verify that columns were made right (pytables specific) # Verify that columns were made right (pytables specific)
if "h5file" in db.data.__dict__: if "h5file" in db.data.__dict__:
@@ -106,7 +104,7 @@ class Test00Nilmdb(object): # named 00 so it runs first
class TestBlockingServer(object): class TestBlockingServer(object):
def setUp(self): def setUp(self):
self.db = serializer_proxy(nilmdb.NilmDB)(testdb, sync=False) self.db = serializer_proxy(nilmdb.server.NilmDB)(testdb)
def tearDown(self): def tearDown(self):
self.db.close() self.db.close()
@@ -115,11 +113,11 @@ class TestBlockingServer(object):
# Server should fail if the database doesn't have a "_thread_safe" # Server should fail if the database doesn't have a "_thread_safe"
# property. # property.
with assert_raises(KeyError): with assert_raises(KeyError):
nilmdb.Server(object()) nilmdb.server.Server(object())
# Start web app on a custom port # Start web app on a custom port
self.server = nilmdb.Server(self.db, host = "127.0.0.1", self.server = nilmdb.server.Server(self.db, host = "127.0.0.1",
port = 12380, stoppable = True) port = 32180, stoppable = True)
# Run it # Run it
event = threading.Event() event = threading.Event()
@@ -131,13 +129,13 @@ class TestBlockingServer(object):
raise AssertionError("server didn't start in 10 seconds") raise AssertionError("server didn't start in 10 seconds")
# Send request to exit. # Send request to exit.
req = urlopen("http://127.0.0.1:12380/exit/", timeout = 1) req = urlopen("http://127.0.0.1:32180/exit/", timeout = 1)
# Wait for it # Wait for it
thread.join() thread.join()
def geturl(path): def geturl(path):
req = urlopen("http://127.0.0.1:12380" + path, timeout = 10) req = urlopen("http://127.0.0.1:32180" + path, timeout = 10)
return req.read() return req.read()
def getjson(path): def getjson(path):
@@ -147,9 +145,9 @@ class TestServer(object):
def setUp(self): def setUp(self):
# Start web app on a custom port # Start web app on a custom port
self.db = serializer_proxy(nilmdb.NilmDB)(testdb, sync=False) self.db = serializer_proxy(nilmdb.server.NilmDB)(testdb)
self.server = nilmdb.Server(self.db, host = "127.0.0.1", self.server = nilmdb.server.Server(self.db, host = "127.0.0.1",
port = 12380, stoppable = False) port = 32180, stoppable = False)
self.server.start(blocking = False) self.server.start(blocking = False)
def tearDown(self): def tearDown(self):
@@ -173,13 +171,13 @@ class TestServer(object):
streams = getjson("/stream/list") streams = getjson("/stream/list")
eq_(streams, [ eq_(streams, [
['/newton/prep', 'PrepData'], ['/newton/prep', 'float32_8'],
['/newton/raw', 'RawData'], ['/newton/raw', 'uint16_6'],
['/newton/zzz/rawnotch', 'RawNotchedData'], ['/newton/zzz/rawnotch', 'uint16_9'],
]) ])
streams = getjson("/stream/list?layout=RawData") streams = getjson("/stream/list?layout=uint16_6")
eq_(streams, [['/newton/raw', 'RawData']]) eq_(streams, [['/newton/raw', 'uint16_6']])
streams = getjson("/stream/list?layout=NoSuchLayout") streams = getjson("/stream/list?layout=NoSuchLayout")
eq_(streams, []) eq_(streams, [])
@@ -208,3 +206,51 @@ class TestServer(object):
data = getjson("/stream/get_metadata?path=/newton/prep" data = getjson("/stream/get_metadata?path=/newton/prep"
"&key=foo") "&key=foo")
eq_(data, {'foo': None}) eq_(data, {'foo': None})
def test_cors_headers(self):
# Test that CORS headers are being set correctly
# Normal GET should send simple response
url = "http://127.0.0.1:32180/stream/list"
r = requests.get(url, headers = { "Origin": "http://google.com/" })
eq_(r.status_code, 200)
if "access-control-allow-origin" not in r.headers:
raise AssertionError("No Access-Control-Allow-Origin (CORS) "
"header in response:\n", r.headers)
eq_(r.headers["access-control-allow-origin"], "http://google.com/")
# OPTIONS without CORS preflight headers should result in 405
r = requests.options(url, headers = {
"Origin": "http://google.com/",
})
eq_(r.status_code, 405)
# OPTIONS with preflight headers should give preflight response
r = requests.options(url, headers = {
"Origin": "http://google.com/",
"Access-Control-Request-Method": "POST",
"Access-Control-Request-Headers": "X-Custom",
})
eq_(r.status_code, 200)
if "access-control-allow-origin" not in r.headers:
raise AssertionError("No Access-Control-Allow-Origin (CORS) "
"header in response:\n", r.headers)
eq_(r.headers["access-control-allow-methods"], "GET, HEAD")
eq_(r.headers["access-control-allow-headers"], "X-Custom")
def test_post_bodies(self):
# Test JSON post bodies
r = requests.post("http://127.0.0.1:32180/stream/set_metadata",
headers = { "Content-Type": "application/json" },
data = '{"hello": 1}')
eq_(r.status_code, 404) # wrong parameters
r = requests.post("http://127.0.0.1:32180/stream/set_metadata",
headers = { "Content-Type": "application/json" },
data = '["hello"]')
eq_(r.status_code, 415) # not a dict
r = requests.post("http://127.0.0.1:32180/stream/set_metadata",
headers = { "Content-Type": "application/json" },
data = '[hello]')
eq_(r.status_code, 400) # badly formatted JSON

View File

@@ -83,10 +83,3 @@ class TestTimestamper(object):
for line in ts: for line in ts:
raise AssertionError raise AssertionError
ts.close() ts.close()
# Test the null timestamper
input = cStringIO.StringIO(join(lines_out)) # note: lines_out
ts = timestamper.TimestamperNull(input)
foo = ts.readlines()
eq_(foo, join(lines_out))
eq_(str(ts), "TimestamperNull(...)")

View File

@@ -20,6 +20,11 @@ def in_(a, b):
if a not in b: if a not in b:
raise AssertionError("%s not in %s" % (myrepr(a), myrepr(b))) raise AssertionError("%s not in %s" % (myrepr(a), myrepr(b)))
def in2_(a1, a2, b):
if a1 not in b and a2 not in b:
raise AssertionError("(%s or %s) not in %s" % (myrepr(a1), myrepr(a2),
myrepr(b)))
def ne_(a, b): def ne_(a, b):
if not a != b: if not a != b:
raise AssertionError("unexpected %s == %s" % (myrepr(a), myrepr(b))) raise AssertionError("unexpected %s == %s" % (myrepr(a), myrepr(b)))