[schema-change] Prefix all columns that could cause conflicts

This commit is contained in:
Arturo Filastò 2018-09-17 17:30:38 +02:00
parent 52bfe5df6c
commit 18a89f4cbd
8 changed files with 185 additions and 207 deletions

View File

@ -12,13 +12,13 @@ DROP TABLE `networks`;
-- +migrate StatementBegin
CREATE TABLE `urls` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`url_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`url` VARCHAR(255) NOT NULL, -- XXX is this long enough?
`category_code` VARCHAR(5) NOT NULL, -- The citizenlab category code for the
-- site. We use the string NONE to denote
-- no known category code.
`country_code` VARCHAR(2) NOT NULL -- The two letter country code which this
`url_country_code` VARCHAR(2) NOT NULL -- The two letter country code which this
-- URL belongs to
);
@ -33,7 +33,7 @@ CREATE TABLE `urls` (
-- or add support for allowing the user to "correct" a misclassified measurement
-- or distinguishing between wifi and mobile.
CREATE TABLE `networks` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`network_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`network_name` VARCHAR(255) NOT NULL, -- String name representing the network_name which by default is populated based
-- on the ASN.
-- We use a separate key to reference the rows in
@ -46,11 +46,11 @@ CREATE TABLE `networks` (
-- 0000:0000:0000:0000:0000:0000:0000:0000,
-- which is 39 chars.
`asn` INT(4) NOT NULL,
`country_code` VARCHAR(2) NOT NULL -- The two letter country code
`network_country_code` VARCHAR(2) NOT NULL -- The two letter country code
);
CREATE TABLE `results` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`result_id` INTEGER PRIMARY KEY AUTOINCREMENT,
-- This can be one of "websites", "im", "performance", "middlebox".
`test_group_name` VARCHAR(16) NOT NULL,
-- We use a different start_time and runtime, because we want to also have
@ -58,26 +58,28 @@ CREATE TABLE `results` (
-- go into the test.
-- That is to say: `SUM(runtime) FROM measurements` will always be <=
-- `runtime FROM results` (most times <)
`start_time` DATETIME NOT NULL,
`runtime` REAL,
`result_start_time` DATETIME NOT NULL,
`result_runtime` REAL,
-- Used to indicate if the user has seen this result
`is_viewed` TINYINT(1) NOT NULL,
`result_is_viewed` TINYINT(1) NOT NULL,
-- This is a flag used to indicate if the result is done or is currently running.
`is_done` TINYINT(1) NOT NULL,
`data_usage_up` REAL NOT NULL,
`data_usage_down` REAL NOT NULL,
`result_is_done` TINYINT(1) NOT NULL,
`result_data_usage_up` REAL NOT NULL,
`result_data_usage_down` REAL NOT NULL,
-- It's probably reasonable to set the maximum length to 260 as this is the
-- maximum length of file paths on windows.
`measurement_dir` VARCHAR(260) NOT NULL,
`network_id` INTEGER NOT NULL,
FOREIGN KEY(`network_id`) REFERENCES `networks` (`id`)
CONSTRAINT `fk_network_id`
FOREIGN KEY(`network_id`)
REFERENCES `networks`(`network_id`)
);
CREATE TABLE `measurements` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`measurement_id` INTEGER PRIMARY KEY AUTOINCREMENT,
-- This can be one of:
-- facebook_messenger
-- telegram
@ -87,31 +89,31 @@ CREATE TABLE `measurements` (
-- dash
-- ndt
`test_name` VARCHAR(64) NOT NULL,
`start_time` DATETIME NOT NULL,
`runtime` REAL NOT NULL,
`measurement_start_time` DATETIME NOT NULL,
`measurement_runtime` REAL NOT NULL,
-- Note for golang: we used to have state be one of `done` and `active`, so
-- this is equivalent to done being true or false.
-- `state` TEXT,
`is_done` TINYINT(1) NOT NULL,
`measurement_is_done` TINYINT(1) NOT NULL,
-- The reason to have a dedicated is_uploaded flag, instead of just using
-- is_upload_failed, is that we may not have uploaded the measurement due
-- to a setting.
`is_uploaded` TINYINT(1) NOT NULL,
`measurement_is_uploaded` TINYINT(1) NOT NULL,
-- This is the measurement failed to run and the user should be offerred to
-- re-run it.
`is_failed` TINYINT(1) NOT NULL,
`failure_msg` VARCHAR(255),
`measurement_is_failed` TINYINT(1) NOT NULL,
`measurement_failure_msg` VARCHAR(255),
`is_upload_failed` TINYINT(1) NOT NULL,
`upload_failure_msg` VARCHAR(255),
`measurement_is_upload_failed` TINYINT(1) NOT NULL,
`measurement_upload_failure_msg` VARCHAR(255),
-- Is used to indicate that this particular measurement has been re-run and
-- therefore the UI can take this into account to either hide it from the
-- result view or at the very least disable the ability to re-run it.
-- XXX do we also want to have a reference to the re-run measurement?
`is_rerun` TINYINT(1) NOT NULL,
`measurement_is_rerun` TINYINT(1) NOT NULL,
-- This is the server-side report_id returned by the collector. By using
-- report_id & input, you can query the api to fetch this measurement.
@ -131,7 +133,7 @@ CREATE TABLE `measurements` (
-- this at some point in the near future.
-- See: https://github.com/ooni/pipeline/blob/master/docs/ooni-uuid.md &
-- https://github.com/ooni/pipeline/issues/48
`measurement_id` INT(64),
`collector_measurement_id` INT(64),
-- This indicates in the case of a websites test, that a site is likely
-- blocked, or for an IM test if the IM tests says the app is likely
@ -156,9 +158,11 @@ CREATE TABLE `measurements` (
-- have many measurements per file.
`report_file_path` VARCHAR(260) NOT NULL,
FOREIGN KEY (`result_id`) REFERENCES `results`(`id`)
ON DELETE CASCADE ON UPDATE CASCADE, -- If we delete a result we also want
-- all the measurements to be deleted as well.
FOREIGN KEY (`url_id`) REFERENCES `urls`(`id`)
CONSTRAINT `fk_result_id`
FOREIGN KEY (`result_id`)
REFERENCES `results`(`result_id`)
ON DELETE CASCADE, -- If we delete a result we also want
-- all the measurements to be deleted as well.
FOREIGN KEY (`url_id`) REFERENCES `urls`(`url_id`)
);
-- +migrate StatementEnd

View File

@ -130,100 +130,102 @@ func bindataDataDefaultconfigjson() (*asset, error) {
}
var _bindataDataMigrations1createmsmtresultssql = []byte(
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x6d\x73\xdb\x36\x12\xfe\xee\x5f\xb1\xe3\xe9\xf4\xec\x39\x49\x76" +
"\x72\x69\xe6\xce\xd7\x4e\xc7\xb5\x99\x9c\xda\x58\xce\xc8\xf2\x35\x99\x9b\x1b\x11\x22\x97\x12\x6a\x10\x60\x00\x50" +
"\x8c\xee\xd7\xdf\xec\x02\xa4\x48\xc5\x75\x9d\x99\xe6\x83\x23\x91\xc0\x62\x5f\x9f\x67\x17\x1a\x8f\xe1\xaf\xa5\x5c" +
"\x5b\xe1\x11\xae\x4d\xa3\x8f\xfa\x0f\xee\xbc\xf0\x58\xa2\xf6\x3f\xe1\x5a\xea\xa3\xa3\xeb\xf9\xed\x7b\x58\x5c\xfe" +
"\xf4\x2e\x81\xd4\xa2\xab\x95\x77\xe9\x3f\x07\x4f\x4b\x14\xae\xb6\xbc\xe7\xf0\x55\x6d\xd5\xe1\x23\x8d\xbe\x31\xf6" +
"\x81\x1e\x3f\x7e\x6e\xa2\xf3\xe1\x9b\xfb\xea\x49\x05\xaf\xe6\xc9\xe5\x22\x19\x9c\x08\x27\x47\x00\xa9\xcc\x53\x98" +
"\xce\x16\xc9\xdb\x64\x0e\xef\xe7\xd3\x9b\xcb\xf9\x47\xf8\x25\xf9\x08\x97\xf7\x8b\xdb\xe9\xec\x6a\x9e\xdc\x24\xb3" +
"\xc5\x88\x56\xd6\x56\xa5\xf0\xef\xcb\xf9\xd5\xbf\x2e\xe7\x27\x2f\xbf\xfb\xee\x14\x66\xb7\x0b\x98\xdd\xbf\x7b\x37" +
"\x82\xf1\x18\x3e\x7c\xf8\x00\xd2\x81\xdf\x48\x07\xca\xe8\x35\xa0\x36\xf5\x7a\xf3\x23\x6d\xcd\x84\xc7\xb5\xb1\xbb" +
"\x65\x66\x72\xdc\x0b\x39\x14\xb1\xd8\x20\x64\xd2\xcb\xff\xa1\x56\x62\x05\xed\x2e\xa0\x5d\x50\x18\x0b\x7e\x83\x47" +
"\xf0\xbc\x7f\xe3\x31\x38\xe9\x71\x02\xbf\x22\xd4\x0e\x69\x2b\x38\x6f\xa5\x5e\xc3\xec\x76\x96\x80\x37\x90\xa3\x36" +
"\xfe\x6b\x04\x6a\x03\x0f\xda\x34\x7a\xa8\xd9\xe4\x88\x4d\x34\xb5\xf6\x5f\x58\xf8\x72\x6f\x61\x6b\xa0\x6f\x0c\x28" +
"\xf4\x1e\x2d\xc4\x3d\xc1\xbe\x66\x23\xb3\x0d\xbb\xef\x79\x1a\x8d\xc7\x70\x3f\x7f\x07\x2b\x24\x67\x3b\xf0\xe6\xe8" +
"\x34\x24\xcb\xaf\x08\x99\x45\x4a\x02\x01\x0e\x2b\xc1\xf9\xe0\xc5\x4a\x05\x1f\xb6\xa9\xc5\x5f\x5e\x82\x45\xe1\x8c" +
"\x76\x17\xb4\xf3\xc5\x04\xde\x18\x0b\xce\x94\x08\xa6\x60\x97\x6d\x25\x36\x0e\x9a\x0d\x5a\x04\x8d\x98\xf3\x43\x6f" +
"\xbc\x50\xa0\xeb\x72\x85\x96\x16\xc6\xdc\xce\x3b\xd9\x23\x92\x26\xfd\x5f\x1c\xac\x0d\x79\xdc\x1b\x58\x21\x94\x75" +
"\xb6\x81\xd2\x58\x04\x2c\x0a\x99\x49\xd4\x9e\xde\xfc\x56\x3b\x0f\xca\x98\x87\xba\x62\xe9\xec\x15\x12\x6b\x4d\xe3" +
"\x40\xea\xe0\x93\xf1\x38\xd8\x30\xa1\x4f\x2f\x27\x70\x52\x1a\xe7\x41\x96\x95\xb1\x5e\x68\x7f\x4a\x66\x37\x22\x48" +
"\x14\x5b\x23\x73\xc8\xeb\x4a\xc9\x4c\x78\x52\x40\xc0\xaa\xd6\xd9\x86\xa4\x4a\x5d\x18\x5b\x0a\x2f\x0d\x49\x16\x9e" +
"\x55\x1d\x2a\x9a\x99\xb2\xa4\xb7\x06\x1c\x6e\xd1\x92\xad\xad\xd3\x48\xc1\xda\xa1\xa5\x2d\x46\xb3\x32\xc9\x67\x51" +
"\x56\x0a\x2f\xa2\xef\x4b\xb1\x83\x46\xba\x0d\x2b\x92\xe7\xf4\x1f\xd7\x44\x88\x00\xed\x57\x26\x0b\xc7\x17\xd6\x94" +
"\xad\xa3\x2b\x6b\x56\x18\x9e\xd0\xd7\xb7\xef\xef\x48\x9e\xb1\x2c\xc3\xd5\x15\xd9\xc9\x21\x13\x4a\x99\x86\x75\x6d" +
"\x55\xf1\x06\x8e\x33\x63\x2d\x66\xfe\x18\x04\x94\xd2\x65\x4a\x38\x27\x0b\x89\x39\xf4\x70\x27\x0a\xcc\xa5\x23\x9f" +
"\xd4\xd2\x6d\x48\xcc\x0a\x7d\x83\xa8\xa1\x91\x85\x04\xa1\x73\x28\xcd\x4a\x92\x9f\x87\x90\xd1\x21\xd2\xd7\xc2\x46" +
"\xdc\xb8\xd4\xa2\xc4\xa7\xf0\xe3\x2e\x14\x27\x2d\x03\x8b\x95\x45\x87\xda\xb7\x76\xf6\x85\xc4\x4a\x59\xed\x20\xc7" +
"\x42\xd4\xca\x53\x2c\x2a\x53\xd5\x4a\x78\xcc\x61\x25\x1c\xe6\x7f\x54\x42\xe4\x09\xcd\x92\x2f\xef\x66\x93\x67\xac" +
"\x8e\x28\xd2\xab\xa8\x07\xdc\x91\xe7\x2d\x16\x68\x51\x67\x21\xb4\x31\x65\x9f\x21\x70\x9f\x13\x6e\x04\x2b\xcc\x04" +
"\x89\x6f\x86\xe9\x73\x8c\xda\xca\x6c\x73\xfc\x5c\x71\x8d\xf4\xb1\xc0\x72\xe1\x45\x28\x1d\x84\xa2\xf6\xb5\xc5\x49" +
"\x3f\x16\x7e\x57\xf5\x62\xf1\xe2\xf5\x41\x28\x6e\x35\xd7\x3f\x65\xc4\x28\xa6\x03\x63\x9c\xac\xf6\x9b\x5e\x9d\xf7" +
"\x37\x85\x00\x1a\x8b\x8e\x5c\x14\x22\xd9\x05\x31\x24\xbb\x29\x40\x68\x90\xd5\xf6\x15\x25\xa1\xac\xb6\xaf\x29\xb5" +
"\x2d\x3a\xf7\x1c\xff\x2f\xb8\x6e\xf4\x1a\xa9\xe8\x2b\x8a\x78\x10\xd6\x09\x01\x25\x1f\xf0\xe2\x19\x92\xce\xcf\xcf" +
"\xcf\x2f\xfe\xf8\xcf\xe8\x19\xa2\x42\x22\x4a\x07\x7f\xfb\x07\x64\x1b\x61\xd9\x92\x54\x38\xcd\xb5\x71\xf2\xaa\xe7" +
"\xa1\x3f\x83\x22\x18\xe0\x87\x55\xd9\xf6\x1a\x5c\x94\x5f\x53\x96\xd1\xa9\xd2\x41\x26\x34\x61\x9e\x09\x31\x3f\x6e" +
"\x70\x45\xbc\xe9\x8e\x47\x70\x2c\x4b\xfa\x5b\xa1\x65\xc4\xd4\x19\xd2\xd7\x52\xe6\xb9\xc2\x95\xf9\x7c\x1c\xe2\x96" +
"\x7a\x74\x7e\xb9\xb6\xa6\xae\x0e\x6a\x7c\x90\x57\xed\x99\x5d\x21\xe5\xb2\xe0\xca\xf1\xe0\xbc\xb0\x7e\xe9\x65\x89" +
"\x8c\x3f\xb6\xd6\xf4\x79\x50\x15\x1d\xb2\x2b\x67\x60\x23\xb6\xd8\x8a\xe3\x44\xf7\xa6\x85\x39\x4e\x78\xb3\x45\xbb" +
"\x41\x91\x93\x3d\xcc\x84\x81\x01\x2c\x32\x86\xd2\x11\xc6\x6f\xd0\x42\x21\x32\x6f\xac\x0b\x2c\x10\xe5\xad\x0d\x48" +
"\xcd\x90\x8d\x40\x86\x4d\xf6\xbe\x12\x0c\x34\x44\x0a\x62\x77\x01\xe9\xdd\xfd\xcd\x49\x54\xf5\x14\xde\xcc\x6f\x6f" +
"\x60\xd0\xe2\x41\x23\x95\x02\xa1\x1a\xb1\x73\xe4\xdf\xef\x7f\x68\x25\xa5\x71\x57\xd8\xb4\x8f\x20\x13\x1a\xbd\x70" +
"\xf0\xfd\x69\x70\xed\xde\x33\x29\x5c\x5f\x2e\x92\xc5\xf4\x26\x39\x70\x69\x2b\x2d\x85\x79\x72\xf9\x6e\x74\xd4\x9e" +
"\x72\xef\x90\xb9\x47\xea\x9c\x48\x10\x41\x16\x7b\xc6\xd8\x08\x07\x8e\x40\x9f\x61\x23\xa8\x10\x13\xc8\x2d\x89\xf2" +
"\x31\x4f\x61\x31\x9d\x7d\xa4\x34\x7e\xd1\x8f\xe2\x20\x75\xa8\x0a\xa1\x50\x62\x4d\x52\x1f\x3d\x2d\x88\xa6\x85\x39" +
"\x27\x18\xf3\x66\x56\x5b\x8a\xbb\xda\x51\xa8\xb5\xd4\xeb\x49\x77\x36\xad\xfa\x9d\x93\x79\x09\x85\x7b\x59\x3b\xb1" +
"\xc6\x65\x5d\x05\x93\x9f\x58\x92\x9b\x46\x3f\xba\x68\x3c\x86\x29\x75\x27\x44\xba\x62\x45\x8a\x70\x17\x14\x18\x9a" +
"\x58\xdf\xb3\xf6\xa5\xf8\x2c\xcb\xba\x04\x85\x7a\xed\x19\x91\x5f\xbe\x3e\x07\x11\x9b\x5c\x6e\x76\xbb\x44\x3c\x58" +
"\x6b\x0a\x28\xa4\x42\xa8\x84\xdf\x50\xa7\x00\x8d\xd4\xb9\x69\x22\xd6\xf5\xa7\x81\x65\x2e\x6d\x0f\x0d\x5e\x9f\x7f" +
"\xe1\xee\x0e\xb6\xfb\xd5\x3d\x34\xe8\xcd\xed\x3c\x99\xbe\x9d\x51\xad\x9f\xf4\x97\x9f\xc2\x3c\x79\x93\xcc\x93\xd9" +
"\x55\x72\x37\xe0\x70\x42\x8a\xd3\x47\x00\x65\x98\xc3\x7f\x12\xaa\x5c\xb4\xaf\x0a\x91\xe1\xca\x98\x87\x65\x89\xce" +
"\xa1\x5e\xa3\x6d\xdf\x78\x54\xb8\xb6\xa2\x3c\xea\xa0\x55\x78\x27\xaa\xaa\xfd\xbe\xf1\xbe\x5a\x52\x51\xa3\x5d\x16" +
"\x12\x55\xbe\x2c\x85\x96\xcc\xf9\xd2\xe8\xc1\x2a\xa9\xb7\x42\xc9\x7c\x69\xf1\x53\x4d\xd0\xa4\xa4\xee\xc1\x85\xdb" +
"\xb4\x9f\x75\xee\x7b\x00\x36\x84\xae\xd7\xaf\xbe\x48\xbd\xaf\xae\xc5\x47\xaa\x66\x66\x7c\x68\xc2\xd7\x46\x09\xbd" +
"\xbe\x20\x68\x6b\x4b\x87\x50\x8d\xa0\xd0\x63\x0f\x8e\xd3\x50\x10\x84\x59\xa9\xc8\xbc\xdc\x62\x3a\x02\x67\x8e\xfa" +
"\xac\x2f\x1d\xe0\xa7\x5a\x6e\x85\x8a\x0d\x35\x97\xda\x0a\xb9\x77\xb2\x35\x57\x5d\x21\x94\xc3\x0e\xcb\x52\x3e\x26" +
"\x85\x45\xf2\x21\x86\xed\x19\xb5\x17\xb9\x29\x54\x4a\xa7\xb0\x80\x1c\x43\xc9\xe7\x20\xdd\xb2\xae\x94\x11\x39\xe6" +
"\x8c\x0a\x23\x90\xda\xf9\x08\xc4\xdc\xe5\xd7\x4e\xea\x75\x2b\xad\x5b\xbe\x2c\x84\x54\x98\x8f\x42\x45\x09\xdf\xb6" +
"\x41\xda\xf8\x70\x48\x27\x95\x8b\x72\x9f\xa1\x90\xd7\x5d\x64\x89\x1c\xa8\x70\xfd\x00\x4f\xda\x9d\xcf\x44\xb3\x43" +
"\xf9\x41\x31\x6e\xf3\x6a\xcd\x51\xe8\x20\xd4\x6d\x4c\xad\x72\x0e\x15\xf1\x98\xe5\x65\xad\x3c\x8b\x63\xda\x20\xfd" +
"\x5e\x93\x20\xea\x29\x6c\xa3\x15\xb5\xc5\x65\xe9\xd6\xc3\x3e\xb9\x85\x81\x43\x87\x3d\x25\xac\xb7\xf0\x29\x99\x04" +
"\x84\xee\x4b\xf4\xe6\x28\x70\x72\x55\xc2\x7a\x99\xd5\x4a\xd8\x81\x63\x88\x40\x56\x44\x20\xd1\x52\xa1\xf3\x7d\x4e" +
"\xa2\xc5\xc2\x44\x2e\xbe\x9f\x32\x14\x78\xf1\x80\x31\x5b\x89\x5d\x45\x16\x86\x3c\x6f\x00\x25\x73\xf1\x46\xe6\x08" +
"\xd2\x77\x03\xd0\xde\x93\x4c\x20\xc4\x49\x3c\x0c\x05\x60\xde\xa2\xdd\x81\x42\xe1\x3c\x4d\x33\xdd\x60\x25\x56\x52" +
"\x49\x1f\xdb\xf2\x41\x04\xe2\xfd\x44\x6e\x28\xb7\xb8\x89\x68\x3b\x8a\x98\xc5\xbd\x36\xde\x44\xe6\x62\x01\x3d\xa3" +
"\x7f\xec\xa2\x60\xd1\xd6\xfa\x2b\x52\xca\xa1\xdd\xa2\x1d\x3b\xb2\x31\x74\x21\x4b\x99\x83\x45\x5f\x5b\x4d\x13\xcb" +
"\x2e\xce\xbd\x4a\x21\x75\x24\x13\xf8\x69\x37\x2c\x95\xfd\xa6\x6f\x41\xea\xaa\xf6\x23\xd8\x99\x9a\x3d\xfb\xa9\x26" +
"\x5f\xb0\xf5\x95\x24\xe5\x0b\xf4\xf1\x1e\xa1\xaf\x7c\xe7\x86\xe4\x73\xf7\xf1\x6d\xb2\x60\xc4\x74\x17\x67\x67\xa2" +
"\x92\x13\x63\xb4\x9c\x48\x43\x9f\xcf\xb6\x2f\xce\xfa\x54\xf0\x23\x9f\xfa\xc3\x37\xd3\xd9\xfb\xfb\xc5\xb7\x9d\x3a" +
"\x3f\x7c\x33\x4f\xde\xdf\xce\x17\xcb\xe9\xf5\x5e\xbe\xb7\x22\x0b\x61\x2a\xa4\xa5\x76\xdd\x63\xb9\x1f\x6c\x63\xcb" +
"\xfa\x9f\xff\xa6\xa0\xa4\xf3\x6d\x51\xe9\xa0\x77\xc7\x14\x03\x86\xe4\x9b\x27\x6f\x60\x1d\x79\xf9\xe7\xbb\xdb\x59" +
"\x98\x9b\x87\x46\xd2\xf8\xd5\x6b\xd8\xd0\x85\x56\x7a\x2b\x54\x8d\x0e\x4e\xd2\x4e\xef\x74\x04\x29\x5b\x94\x9e\x82" +
"\xb0\x5c\xd1\x45\xad\xf6\xde\x13\x1d\xab\xf7\x84\x73\x51\x50\xe2\x0b\x65\x51\xe4\xbb\x50\x00\x95\x35\x19\x91\x59" +
"\x17\xc6\x4a\x56\x48\x94\x33\xea\xe1\x81\x2c\x2b\x15\x84\x64\x0a\x85\xae\x2b\x9e\x86\xa2\x98\x0e\xdd\xfa\x0e\x8f" +
"\xc0\xb1\xd7\x78\x58\xbd\x87\x3c\xcb\xd3\x43\x43\x6e\xd4\xa6\x6d\x74\xb9\xff\x68\x0b\xf5\x0f\xa6\x99\xf1\x38\xde" +
"\x19\xe5\x93\x08\x36\xb5\x55\xfd\x7e\xe3\xcb\xc4\x26\x74\xde\xa1\xa7\x0e\x10\x05\x4d\x98\xed\x4d\x46\x97\xc7\x23" +
"\x58\xd5\x0c\xe6\xe4\xe2\x4a\x09\xee\xf5\xe2\xb5\xc8\x80\xc1\x84\x0f\x77\x4e\x95\x91\xda\xb7\x63\xab\x46\x61\x7b" +
"\xb3\x6b\x18\x31\x11\x2f\xba\x94\x5d\x4b\xbf\xa9\x57\x93\xcc\x94\x67\x94\xb9\x67\xad\xe3\xcf\x56\xca\xac\xce\x4a" +
"\xe1\x3c\xda\xb3\xdc\x64\x8e\x5f\x8f\xeb\x5a\xe6\x93\x32\x87\x6f\xfb\xcd\xc2\x93\x72\xa4\x73\x35\xba\xb3\x57\x7f" +
"\xff\xb2\x67\x8b\x9e\xa1\x3e\xe1\xd0\x33\x11\x43\x5d\x6b\x47\x26\x1c\xbb\x46\x40\x3b\x5a\xf1\x60\x31\x0a\xf9\x24" +
"\xf8\x96\x92\xfc\x49\xf3\xab\xda\xb5\xb2\x56\xca\x64\x0f\xc4\x89\x44\xde\x04\x7c\x1a\xa6\x37\xbc\xb1\x6d\xad\xe3" +
"\x57\x47\xe3\x88\x8b\x00\x50\x3d\x2d\x48\x16\x7c\x3d\x14\xe7\x37\x68\x84\x83\x1c\x3d\x66\x1c\xf6\xb8\xfe\x63\xc4" +
"\x95\xf4\xe7\xdb\xe9\x2c\x05\x01\xe9\xd5\xed\xfd\x6c\x71\x72\x9a\x76\x15\xc7\xf5\xd4\x9a\x17\xe7\x97\x80\xd0\xb1" +
"\x46\x45\x77\x87\x77\xa0\x05\x04\xfb\x8d\xed\x1e\x4c\x6f\x48\x6d\xd7\x41\xab\xd0\xa6\x14\x6a\xd7\x07\xd7\x47\x86" +
"\x0e\x0d\xa6\x12\x9f\xea\x88\x04\xce\xdb\x3a\xa3\x3c\x19\xc5\x8b\xca\x86\x1a\x29\x62\xa0\xfe\x4d\x26\x77\x79\x0f" +
"\xb8\x73\x5d\x8b\x19\x6f\x34\xe3\xc5\xf2\xb0\xb1\x40\x2f\xa4\x72\xf1\xfa\x93\x30\x8a\x45\xf5\xd8\xc8\xc1\x09\x7e" +
"\x9e\xf4\xa9\x2a\xd4\xf1\x19\x0d\x1d\xf4\x01\x5c\x45\xd2\x4d\x01\xb3\xeb\xc5\x28\xfa\x8a\x7b\xa7\xa2\xb5\x9f\xca" +
"\x81\x33\x83\xdc\xd2\x75\x59\xe8\xb3\xc9\x69\xaf\x33\x25\x9d\xd3\x60\xe9\x63\x34\x83\x90\x59\xe3\xda\xfb\xc5\x01" +
"\x8f\x51\x08\x83\xed\x8d\x89\x77\x4d\xe0\xcd\x1a\x89\x71\x3b\x80\x21\x8b\x7e\x67\xb2\x78\x64\xda\xdb\x0a\x2b\xf9" +
"\x20\xee\x19\xa4\xf6\x68\xb5\x50\x8a\x39\x97\x80\xff\x21\x60\xa0\x08\xe3\x12\x4f\xe3\x7a\x9c\x4b\xf7\xf0\x08\xa2" +
"\xba\xc9\x6f\xce\xe8\x09\x4c\x3d\xb7\x7b\x25\xf5\x08\x0e\xb5\x63\xdd\x1b\x4b\x75\x41\x9d\x6c\x98\xa3\xd0\x02\xf2" +
"\x4d\xc8\xaa\x4b\xed\x8d\x31\xec\xc2\x9b\x5f\x38\x42\x95\xc5\x6d\xbc\x32\x6c\x1b\x09\x12\xd2\x62\x4e\x90\x63\x34" +
"\x75\x0c\x0f\xf1\xea\xa6\x14\x7b\x61\xd4\x07\x94\x42\xef\x06\x1a\xf2\xb9\x05\x5f\x87\xf6\xf1\x98\x9e\x2c\xc9\xc8" +
"\xa7\x07\xb7\xde\x54\xc6\xec\xd3\xba\x7a\x38\x95\xb5\x37\x00\x71\x26\x0b\x80\x7c\x3b\x83\xeb\xe4\x5d\xb2\x48\xe0" +
"\xea\xf2\xee\xea\xf2\x3a\xa1\x27\xf7\xef\x69\xf0\x68\x9f\x30\x09\x4c\x0b\xca\xe3\x1c\x15\xfa\xd0\xc6\x70\x82\xf6" +
"\x9b\x9c\xe7\xfe\xbe\x11\xfd\x20\x94\x3a\xac\x06\x17\xaf\xc5\xc3\x29\x39\x0d\xc0\x0d\x2a\x35\x79\xc4\xc6\xc8\x1a" +
"\x43\x03\xf9\xd7\xa6\xfd\xc4\xf9\xbb\xbf\x67\xfd\x3f\x00\x00\xff\xff\xc9\xf1\x5a\xc3\x72\x1b\x00\x00")
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x59\x6d\x73\xdb\x36\x12\xfe\xee\x5f\xb1\xe3\xe9\xf4\xec\x39\x49\x76" +
"\x72\x69\xe6\xce\xd7\x4e\xc7\xb5\x99\x9c\xda\x58\xca\xc8\xf2\x35\x99\x9b\x1b\x11\x22\x97\x12\x2a\x10\x60\xf0\x22" +
"\x46\xf7\xeb\x6f\x16\x00\x29\x52\x56\x1c\x67\xda\x0f\xa9\x48\x02\x8b\x7d\x7d\xf6\x59\x78\x38\x84\xbf\x96\x7c\xa5" +
"\x99\x45\xb8\x55\xb5\x3c\xe9\xbe\xb8\xb7\xcc\x62\x89\xd2\xfe\x82\x2b\x2e\x4f\x4e\x6e\x67\xd3\xf7\x30\xbf\xfe\xe5" +
"\x5d\x02\xa9\x46\xe3\x84\x35\xe9\x3f\x7b\x6f\x4b\x64\xc6\x69\xbf\xe7\xf0\x93\xd3\xe2\xf0\x95\x44\x5b\x2b\xbd\xa1" +
"\xd7\xc7\xcf\x4d\x64\xde\xff\xf2\x50\x3d\xa9\xe0\xcd\x2c\xb9\x9e\x27\xbd\x13\xe1\xec\x04\xfc\xcf\x05\xcf\x53\x18" +
"\x4f\xe6\xc9\xdb\x64\x06\xef\x67\xe3\xbb\xeb\xd9\x47\xf8\x2d\xf9\x08\xd7\x0f\xf3\xe9\x78\x72\x33\x4b\xee\x92\xc9" +
"\x7c\x10\x57\xa7\xf0\xef\xeb\xd9\xcd\xbf\xae\x67\x67\x2f\x7f\xf8\xe1\x1c\x26\xd3\x39\x4c\x1e\xde\xbd\x1b\xc0\x70" +
"\x08\x1f\x3e\x7c\x00\x6e\xc0\xae\xb9\x01\xa1\xe4\x0a\x50\x2a\xb7\x5a\xff\x4c\x5b\x33\x66\x71\xa5\xf4\x6e\x91\xa9" +
"\x1c\xf7\x42\x0e\x45\xcc\xd7\x08\x19\xb7\xfc\x7f\x28\x05\x5b\x42\xb3\x0b\x68\x17\x14\x4a\x83\x5d\xe3\x09\x3c\xef" +
"\xbf\xe1\x10\x0c\xb7\x38\x82\xdf\x11\x9c\x41\xda\x0a\xc6\x6a\x2e\x57\x30\x99\x4e\x12\xb0\x0a\x72\x94\xca\x7e\x8b" +
"\x40\xa9\x60\x23\x55\x2d\xfb\x9a\x8d\x4e\x1a\x5f\x66\xca\x49\xfb\xc8\xca\x97\x7b\x2b\x1b\x23\x6d\xad\x40\xa0\xb5" +
"\xa8\x21\xee\x09\x36\xd6\x6b\x9e\xad\xbd\x0b\x9f\xa7\xd5\x70\x08\x0f\xb3\x77\xb0\x44\x72\xb8\x01\xab\x4e\xce\x43" +
"\xd2\xfc\x8e\x90\x69\xa4\x64\x60\x60\xb0\x62\x3e\x2f\x2c\x5b\x8a\xe0\xc7\x26\xc5\xfc\xc3\x4b\xd0\xc8\x8c\x92\xe6" +
"\x8a\x76\xbe\x18\xc1\x1b\xa5\xc1\xa8\x12\x41\x15\xde\x6d\x5b\x8e\xb5\x81\x7a\x8d\x1a\x41\x22\xe6\xfe\xa5\x55\x96" +
"\x09\x90\xae\x5c\xa2\xa6\x85\x31\xc7\xf3\x56\xf6\x80\xa4\x71\xfb\x17\x03\x2b\x45\x5e\xb7\x0a\x96\x08\xa5\xcb\xd6" +
"\x50\x2a\x8d\x80\x45\xc1\x33\x8e\xd2\xd2\x97\x3f\x9c\xb1\x20\x94\xda\xb8\xca\x4b\xf7\x5e\x21\xb1\x5a\xd5\x06\xb8" +
"\x0c\x3e\x19\x0e\x83\x0d\x23\xfa\xf5\x72\x04\x67\xa5\x32\x16\x78\x59\x29\x6d\x99\xb4\xe7\x64\x76\xcd\x82\x44\xb6" +
"\x55\x3c\x87\xdc\x55\x82\x67\xcc\x92\x02\x0c\x96\x4e\x66\x6b\x92\xca\x65\xa1\x74\xc9\x2c\x57\x24\x99\x59\xaf\x6a" +
"\x5f\xd1\x4c\x95\x25\x7d\x55\x60\x70\x8b\x9a\x6c\x6d\x9c\x46\x0a\x3a\x83\x9a\xb6\x28\xe9\x95\x49\x3e\xb3\xb2\x12" +
"\x78\x15\x7d\x5f\xb2\x1d\xd4\xdc\xac\xbd\x22\x79\x4e\xff\xf3\x75\x11\x22\x40\xfb\x85\xca\xc2\xf1\x85\x56\x65\xe3" +
"\xe8\x4a\xab\x25\x86\x37\xf4\xf8\xf6\xfd\x3d\xc9\x53\xda\xcb\x30\xae\x22\x3b\x7d\xc8\x98\x10\xaa\xf6\xba\x36\xaa" +
"\x58\x05\xa7\x99\xd2\x1a\x33\x7b\x0a\x0c\x4a\x6e\x32\xc1\x8c\xe1\x05\xc7\x1c\x3a\xf8\x13\x05\xe6\xdc\x90\x4f\x1c" +
"\x37\x6b\x12\xb3\x44\x5b\x23\x4a\xa8\x79\xc1\x81\xc9\x1c\x4a\xb5\xe4\xe4\xe7\x3e\x74\xb4\xc8\x14\xe0\x23\x3e\x7e" +
"\x03\x84\x34\x3b\x24\x2b\xf1\x29\x2c\xb9\x0f\x85\x4a\xcb\x40\x63\xa5\xd1\xa0\xb4\x8d\xbd\x5d\x21\xb1\x62\x96\x3b" +
"\xc8\xb1\x60\x4e\x58\x8a\x49\xa5\x2a\x27\x98\xc5\x1c\x96\xcc\x60\xfe\xb5\x52\x22\x8f\x48\x2f\xf9\xfa\x7e\x32\x7a" +
"\xc6\xea\x88\x28\x9d\xca\xda\xe0\x8e\x22\xa0\xb1\x40\x8d\x32\x0b\x21\x8e\xa9\xfb\x0c\x81\xfb\xdc\x30\x03\x58\x62" +
"\xc6\x48\x7c\xdd\x4f\xa3\x53\x94\x9a\x67\xeb\xd3\xe7\x8a\xab\xb9\x8d\x85\x96\x33\xcb\x42\x09\x21\x14\xce\x3a\x8d" +
"\xa3\x6e\x2c\xec\xae\xea\xc4\xe2\xc5\xeb\x83\x50\x4c\xa5\xc7\x01\xca\x8c\x41\x4c\x0b\x8f\x77\xbc\xda\x6f\x7a\x75" +
"\xd9\xdd\x14\x02\xa8\x34\x1a\x72\x51\x88\x64\x1b\xc4\x90\xf4\xaa\x00\x26\x81\x57\xdb\x57\x94\x8c\xbc\xda\xbe\xa6" +
"\x14\xd7\x68\xcc\x73\xfc\x3f\xf7\xf5\x23\x57\x48\xc5\x5f\x51\xc4\x83\xb0\x56\x08\x08\xbe\xc1\xab\x67\x48\xba\xbc" +
"\xbc\xbc\xbc\xfa\xfa\x3f\x83\x67\x88\x0a\x89\xc8\x0d\xfc\xed\x1f\x90\xad\x99\xf6\x96\xa4\xcc\x48\x5f\x1b\x67\xaf" +
"\x3a\x1e\xea\x7a\xff\xcf\xb6\x0c\x0f\xf8\xfd\x2a\x6d\x38\x88\x2f\x52\x68\x9e\x9f\x5f\xa5\xd1\xc7\xdc\x40\xc6\x24" +
"\x41\xa1\x0a\x29\x70\x5a\xe3\x92\x5a\xaa\x39\x1d\xc0\x29\x2f\xe9\xdf\x0a\xb5\x07\x52\x99\x21\x3d\x96\x3c\xcf\x05" +
"\x2e\xd5\xe7\xd3\x10\xc6\xd4\xa2\xb1\x8b\x95\x56\xae\x3a\x28\xf9\x5e\x9a\x35\x67\xb6\x75\x95\xf3\xc2\x17\x92\x05" +
"\x63\x99\xb6\x0b\xcb\x4b\xf4\xb0\xa4\x9d\xa4\xdf\xbd\x22\x69\x01\x5f\x18\x05\x6b\xb6\xc5\x46\x9c\xcf\x7b\xab\x1a" +
"\xf4\xf3\xf9\xaf\xb6\xa8\xd7\xc8\x72\xb2\xc7\x37\xc8\xd0\x18\x34\x7a\x68\xa5\x23\x94\x5d\xa3\x86\x82\x65\x56\x69" +
"\x13\x9a\x43\x94\xb7\x52\xc0\xa5\x47\x72\x04\x32\x6c\xb4\xf7\x15\xf3\xb8\x43\xbd\x82\xed\xae\x20\xbd\x7f\xb8\x3b" +
"\x8b\xaa\x9e\xc3\x9b\xd9\xf4\x0e\x7a\x0c\x10\x6a\x2e\x04\x30\x51\xb3\x9d\x21\xff\xfe\xf8\x53\x23\x29\x8d\xbb\xc2" +
"\xa6\x7d\x20\x7d\x9f\xa3\x0f\x06\x7e\x3c\xef\x45\x75\xef\xa0\x14\x6e\xaf\xe7\xc9\x7c\x7c\x97\x1c\x78\xb6\x59\x1a" +
"\x65\xa7\x30\x4b\xae\xdf\x0d\x4e\x9a\x33\x1f\x0c\xfa\x06\xc5\x65\x4e\x9d\x12\x81\x17\xfb\xb6\xb2\x66\x06\x0c\x75" +
"\x06\x8f\x29\x41\x50\x3f\xab\xcc\x82\xe8\x01\xe6\x29\xcc\xc7\x93\x8f\x94\xea\x2f\xba\xa1\xed\xe5\x13\x55\x2a\x14" +
"\x82\xad\x48\xf8\xd1\x43\x83\x54\x5a\x98\xfb\xac\xf3\x3d\x36\x73\x9a\x92\x41\xec\x28\xfe\x92\xcb\xd5\xe8\x50\x05" +
"\x5a\xfc\x05\x05\xba\x2b\x29\x23\x16\xce\xb0\x15\x2e\x5c\x15\xfc\xf0\xf5\x95\xb9\xaa\xe5\xd1\xb5\xc3\x21\x8c\x89" +
"\xde\x50\xd7\x66\x4b\xd2\xce\xd3\xa8\xd0\xe2\x89\x36\x58\x6f\x52\xc9\x3e\xf3\xd2\x95\x20\x50\xae\xac\x87\xf2\x97" +
"\xaf\x2f\x81\x45\xa6\xec\x19\x73\x9b\xb2\x07\x6b\x55\x01\x05\x17\x08\x15\xb3\x6b\xa2\x1a\x50\x73\x99\xab\x3a\x82" +
"\x64\x77\xac\x58\xe4\x5c\x77\xe0\xe3\xf5\xe5\xa3\x18\x1c\xed\xd6\x7d\x83\x6e\xa6\x93\xfb\xf9\xec\x7a\x3c\x99\x43" +
"\x5a\x6c\x16\x9d\x0d\x11\xff\xde\x4c\x67\xc9\xf8\xed\x84\x60\xe3\xac\x2b\xef\x3c\x7e\x9f\x25\x6f\x92\x59\x32\xb9" +
"\x49\xee\x3b\x5c\xe1\x60\xe5\x63\xbc\xea\xd7\xc6\xd9\x63\xdb\xfe\x2c\x72\x5d\x35\x9f\x0a\x96\xe1\x52\xa9\xcd\xa2" +
"\x44\x63\x50\xae\x50\x37\x5f\x2c\x0a\x5c\x69\x56\x9e\xb4\x68\xce\xac\x61\x55\xd5\x3c\xaf\xad\xad\x16\x04\x1c\xa8" +
"\x17\x05\x47\x91\x2f\x4a\x26\xb9\xa7\x19\x5c\xc9\xde\x2a\x2e\xb7\x4c\xf0\x7c\xa1\xf1\x93\x23\xf8\x13\x5c\x76\x20" +
"\xc9\xac\x9b\xdf\x32\xb7\x1d\x90\xec\xc3\xe3\xeb\x57\x8f\x52\xb8\xeb\x90\xe7\x14\x7d\x77\x7d\xaf\xf2\x8f\x14\xe7" +
"\x44\xd9\x30\x17\xac\x94\x60\x72\x75\x45\xb0\xda\x54\x28\x21\x2a\xc1\xb0\xc5\x4e\x2b\x48\x43\xc1\x11\x5e\xa6\x2c" +
"\xb3\x7c\x8b\xe9\x00\x8c\x3a\xe9\x12\x10\x6e\x00\x3f\x39\xbe\x65\x22\x72\x7c\x5f\xd1\x4b\xf4\x34\x4e\x3b\x5f\xdc" +
"\x05\x13\x06\x5b\x1c\x4d\xfd\x31\x29\xcc\x93\x0f\xf3\x23\x56\x7c\xbd\xce\x63\xab\x0c\x75\xd8\x2a\xcf\x20\xc7\x80" +
"\x32\x39\x70\xb3\x70\x95\x50\x2c\xc7\xdc\x03\xd1\x00\xb8\x34\x36\x36\x04\x3f\x84\x38\xc3\xe5\xaa\x91\xd6\x2e\x5f" +
"\x14\x8c\x0b\xcc\x07\xa1\x5e\x99\x6d\xd8\x99\x54\x36\x1c\xd2\x4a\xf5\x25\xbf\xd7\x1a\x72\xd7\x46\x9f\x9a\x14\xc1" +
"\x82\xdd\x43\xd8\x81\x7d\x8d\x94\x67\x82\xe9\xe1\x59\x41\x49\xcf\x44\x9d\xf4\xd1\x69\x81\xdc\xac\x95\x13\xb9\x0f" +
"\x21\xf5\x56\xed\x97\x35\xf2\x34\x0e\x69\x03\xb7\xc7\xb5\x0a\x62\x9f\xc2\xd7\xee\x06\x5a\xed\x34\x2e\x4a\xb3\xea" +
"\x53\xfc\x06\x88\x8e\xda\xfc\x8d\x87\x74\x36\x3d\x75\x16\x41\xb4\x79\xdc\x6c\x7c\x04\x7d\x92\x56\x4c\x5b\x9e\x39" +
"\xc1\x74\xcf\x91\xd4\xf6\x96\xd4\xf6\xa2\x67\x98\xcc\xf7\xb9\x8d\x1a\x0b\x15\xf9\xc4\xc3\xd8\x43\x8d\x65\x1b\x8c" +
"\x59\x4f\x0c\x81\x65\x61\x7e\xb5\x0a\x90\x7b\x3e\xb1\xe6\x39\x02\xb7\xed\x6c\xb7\xf7\xbc\xef\x77\xd4\x42\xfd\x9c" +
"\x17\x5a\xc6\x16\xf5\x0e\x04\x32\x63\x69\x50\x6b\x67\x46\xb6\xe4\x82\xdb\x38\x69\xf4\x22\x16\xaf\x5f\x72\x45\x79" +
"\xe9\x89\x50\xc3\x8a\x62\x05\x74\x26\x13\x15\x1b\xad\x17\xd0\x31\xfa\xe7\xa3\xd1\xd1\xa8\x9d\xfc\x86\x74\x34\xa8" +
"\xb7\xa8\x87\x86\xec\x0d\xac\x6a\xc1\x73\xd0\x68\x9d\x96\x34\x90\xed\xe2\x78\x2f\x04\x12\xc3\x1a\xc1\x2f\xbb\x7e" +
"\xc9\xed\x37\x7d\x0f\x5c\x56\xce\x0e\x60\xa7\x9c\xf7\xf2\x27\x47\x7e\xf1\x9e\xa8\x38\x19\x52\xa0\x8d\xd7\x25\x5d" +
"\x43\x5a\x97\x24\x9f\xdb\x9f\x6f\x93\xb9\x47\x67\x73\x75\x71\xc1\x2a\x3e\x52\x4a\xf2\x11\x57\xf4\xfb\x62\xfb\xe2" +
"\xa2\xdb\x82\x7e\xf6\xa7\xfe\xf4\xdd\x78\xf2\xfe\x61\xfe\x7d\xab\xce\x4f\xdf\xcd\x92\xf7\xd3\xd9\x7c\x31\xbe\xdd" +
"\xcb\xb7\x9a\x65\x21\x64\x05\xd7\x34\x8d\x58\x2c\xf7\xf3\x7b\x24\x13\xff\xf9\x6f\x0a\x82\x1b\xdb\x14\xa4\x0c\x7a" +
"\xb7\x5d\xa9\x9f\xd8\x5a\xa4\x64\xda\x2a\xb2\x87\x5f\xef\xa7\x93\x70\x3d\xd0\x37\x92\xa6\xcb\x0e\x01\x45\x13\x26" +
"\x84\x2d\x13\x0e\x0d\x9c\xa5\xad\xde\xe9\x00\x52\x6f\x51\x7a\x0e\x4c\x7b\x34\x28\x9c\xd8\x7b\x8f\xb5\xdc\xa3\x23" +
"\xdc\x17\x08\x15\x01\x13\x1a\x59\xbe\x0b\xc5\x50\x69\x95\x51\xe3\x6c\xc3\x58\xf1\x0a\xa9\xbd\x0d\x3a\x58\xc2\xcb" +
"\x4a\x04\x21\x99\x40\x26\x5d\xe5\x87\xbd\x28\xa6\x45\xc9\xae\xc3\x5b\x36\xd7\x68\xdc\xaf\xe4\xc3\x9e\xee\x87\xa2" +
"\x9a\xdc\x28\x55\x43\xdc\x3d\x4b\x6a\x8a\xf6\x2b\xc3\xda\x70\x18\xaf\xc6\xf2\x51\x04\xa4\x83\x6b\xd0\xc7\x89\x4d" +
"\x28\xbf\x43\x4b\xe4\x15\x19\x0d\xd0\xcd\x85\x4d\x9b\xc7\x03\x58\x3a\xdf\x14\xc8\xc5\x95\x60\x9e\xa6\xc6\xdb\x9f" +
"\x5e\x57\x64\x36\x5c\xad\x55\x8a\x4b\xdb\x4c\xe5\x12\x99\xee\x8c\xe6\x61\x82\x46\xbc\x6a\x53\x76\xc5\xed\xda\x2d" +
"\x47\x99\x2a\x2f\x28\x73\x2f\x1a\xc7\x5f\x2c\x85\x5a\x5e\x94\xcc\x58\xd4\x17\xb9\xca\x8c\xff\x3c\x74\x8e\xe7\xa3" +
"\x32\x87\xef\xbb\xc4\xe4\x49\x39\xdc\x18\x87\xe6\xe2\xd5\xdf\x83\x47\x5a\xbb\x16\x47\x78\x18\xb1\x93\x43\x1f\x45" +
"\x64\x35\x8d\x45\x19\x33\xde\x49\x0c\x9a\xa1\xd1\x8f\x4c\x83\x90\x59\xcc\x5f\xcd\x92\x67\x69\x50\x17\xbb\x46\xd6" +
"\x52\xa8\x6c\x43\x5d\x96\xa8\x01\xc1\xa1\x84\xf1\x9d\xdf\xd8\xcc\x07\xf1\xd1\xd0\xa0\x65\x22\x14\x54\x4f\x0b\xe2" +
"\x85\xbf\x0f\x8b\x93\x29\xd4\xcc\x40\x8e\x16\x33\x9f\x00\x71\xfd\xc7\x88\x30\xe9\xaf\xd3\xf1\x24\x05\x06\xe9\xcd" +
"\xf4\x61\x32\x3f\x3b\x4f\xdb\xda\xf3\x95\xd5\x98\x17\x27\xb3\x80\xdb\xb1\x5a\x59\x7b\x69\x79\xa0\x05\x04\xfb\x95" +
"\x6e\x5f\x8c\xef\x48\xed\x70\xc7\x9b\x72\xb3\x60\x52\x95\x4c\xec\xba\x30\x7b\x64\x72\x92\xa0\x2a\xf6\xc9\x45\x4c" +
"\x30\x56\xbb\x8c\x32\x66\x10\x6f\x66\x6b\xa2\x69\xd4\x97\xba\x57\xb7\x9e\x5b\x6e\x70\x67\x5a\x62\x1b\xaf\x70\xe3" +
"\x6d\x7a\x9f\xaa\xa0\x65\x5c\x98\x78\xdf\x4b\x68\xe5\x45\x75\x7a\x94\x81\x33\xfc\x3c\xea\x36\xb0\x50\xd1\x17\x34" +
"\x24\xd1\x0f\x30\x15\x49\x57\x05\x4c\x6e\xe7\x83\xe8\x2b\xcf\xc6\x8a\xc6\x7e\x2a\x0c\x9f\x19\xe4\x96\x96\xb7\xa1" +
"\xcd\x46\xe7\x1d\x3e\x4c\x3a\xa7\xc1\xd2\x63\x0d\x07\x21\xd3\xca\x34\x17\xaa\xbd\xee\x46\x21\x0c\xb6\xd7\x2a\x5e" +
"\xaa\x81\x55\x2b\xa4\x3e\x3c\xfa\xe2\x8d\x48\xe7\x90\xc7\x23\xeb\x96\x69\xee\x0f\xf2\x4c\x82\x4b\x8b\x5a\x32\x21" +
"\x7c\x27\xa6\x16\xb0\x09\x68\xc8\xc2\x78\xe7\xef\x19\xe4\x30\xe7\x66\x73\x04\x5b\xcd\xe8\x0f\xa3\xe4\x08\xc6\xd6" +
"\x13\xc8\x92\x98\x83\x41\x69\xbc\xee\xb5\xa6\xba\x20\x9e\x1c\xe6\x3e\xd4\x80\xfe\xaa\x67\xd9\xa6\xf6\x5a\x29\xef" +
"\xc2\xbb\xdf\x7c\x84\x2a\x8d\xdb\x78\x37\xda\xd0\x0b\x12\xd2\xa0\x4f\x90\xa3\x24\xf1\x88\x4d\xbc\xa3\x2a\xd9\x5e" +
"\x18\xb1\x83\x92\xc9\x5d\x4f\x43\x7f\x6e\xe1\xef\x7f\xbb\xc8\x4c\x6f\x16\x64\xe4\xd3\x83\xe6\xc1\x14\xb9\xf7\xf5" +
"\xe3\x21\xd2\xf7\xa9\xe6\xf3\xb1\x21\xb2\xb9\x01\x39\xb6\x6e\x3a\x81\xdb\xe4\x5d\x32\x4f\xe0\xe6\xfa\xfe\xe6\xfa" +
"\x36\xf1\x9d\x62\x5c\x50\x8a\xe7\x28\xd0\x06\xde\xe3\x73\xb7\xcb\x8a\xbe\xdc\x1e\x86\x43\x60\x42\x1c\x96\x85\x89" +
"\x7f\x10\x08\x32\x73\x9a\xdc\x6b\x14\x22\xf8\xa6\x6f\x4c\x6c\x24\xe7\x3d\x1b\xfc\xdf\xdb\xf6\xdf\x68\x00\xfe\xe2" +
"\x5f\xf5\xfe\x1f\x00\x00\xff\xff\x38\xc6\x64\x22\x78\x1c\x00\x00")
func bindataDataMigrations1createmsmtresultssqlBytes() ([]byte, error) {
return bindataRead(

View File

@ -14,7 +14,7 @@ func Run() {
_, err := root.Cmd.Parse(os.Args[1:])
if err != nil {
log.WithError(err).Error("failure in main command")
os.Exit(1)
os.Exit(2)
}
return
}

View File

@ -49,13 +49,13 @@ func init() {
// We assume that since these are summary level information the first
// item will contain the information necessary.
if isFirst {
msmtSummary.TotalRuntime = msmt.ResultRuntime
msmtSummary.TotalRuntime = msmt.Result.Runtime
msmtSummary.DataUsageUp = msmt.DataUsageUp
msmtSummary.DataUsageDown = msmt.DataUsageDown
msmtSummary.NetworkName = msmt.NetworkName
msmtSummary.NetworkCountryCode = msmt.NetworkCountryCode
msmtSummary.NetworkCountryCode = msmt.Network.CountryCode
msmtSummary.ASN = msmt.ASN
msmtSummary.StartTime = msmt.MeasurementStartTime
msmtSummary.StartTime = msmt.Measurement.StartTime
}
if msmt.IsAnomaly.Bool == true {
msmtSummary.AnomalyCount++
@ -76,7 +76,7 @@ func init() {
}
for idx, result := range incompleteResults {
output.ResultItem(output.ResultItemData{
ID: result.ResultID,
ID: result.Result.ID,
Index: idx,
TotalCount: len(incompleteResults),
Name: result.TestGroupName,
@ -97,16 +97,16 @@ func init() {
netCount := make(map[uint]int)
output.SectionTitle("Results")
for idx, result := range doneResults {
totalCount, anmlyCount, err := database.GetMeasurementCounts(ctx.DB, result.ResultID)
totalCount, anmlyCount, err := database.GetMeasurementCounts(ctx.DB, result.Result.ID)
if err != nil {
log.WithError(err).Error("failed to list measurement counts")
}
testKeys, err := database.GetResultTestKeys(ctx.DB, result.ResultID)
testKeys, err := database.GetResultTestKeys(ctx.DB, result.Result.ID)
if err != nil {
log.WithError(err).Error("failed to get testKeys")
}
output.ResultItem(output.ResultItemData{
ID: result.ResultID,
ID: result.Result.ID,
Index: idx,
TotalCount: len(doneResults),
Name: result.TestGroupName,

View File

@ -19,29 +19,16 @@ func ListMeasurements(sess sqlbuilder.Database, resultID int64) ([]MeasurementUR
measurements := []MeasurementURLNetwork{}
req := sess.Select(
"measurements.id as msmt_tbl_id",
"measurements.is_done as measurement_is_done",
"measurements.start_time as measurement_start_time",
"measurements.runtime as measurement_runtime",
"networks.id as network_id",
"networks.country_code as network_country_code",
"results.id as result_id",
"results.start_time as result_start_time",
"results.is_done as result_is_done",
"results.runtime as result_runtime",
"results.test_group_name as test_group_name",
"urls.id as url_id",
"urls.country_code as url_country_code",
db.Raw("networks.*"),
db.Raw("urls.*"),
db.Raw("measurements.*"),
db.Raw("results.*"),
).From("results").
Join("measurements").On("results.id = measurements.result_id").
Join("networks").On("results.network_id = networks.id").
LeftJoin("urls").On("urls.id = measurements.url_id").
OrderBy("measurements.start_time").
Where("results.id = ?", resultID)
Join("measurements").On("results.result_id = measurements.result_id").
Join("networks").On("results.network_id = networks.network_id").
LeftJoin("urls").On("urls.url_id = measurements.url_id").
OrderBy("measurements.measurement_start_time").
Where("results.result_id = ?", resultID)
if err := req.All(&measurements); err != nil {
log.Errorf("failed to run query %s: %v", req.String(), err)
@ -228,7 +215,7 @@ func CreateOrUpdateURL(sess sqlbuilder.Database, urlStr string, categoryCode str
return 0, err
}
res := tx.Collection("urls").Find(
db.Cond{"url": urlStr, "country_code": countryCode},
db.Cond{"url": urlStr, "url_country_code": countryCode},
)
err = res.One(&url)
@ -285,7 +272,7 @@ func AddTestKeys(sess sqlbuilder.Database, msmt *Measurement, tk interface{}) er
msmt.TestKeys = string(tkBytes)
msmt.IsAnomaly = sql.NullBool{Bool: isAnomaly, Valid: isAnomalyValid}
err = sess.Collection("measurements").Find("id", msmt.ID).Update(msmt)
err = sess.Collection("measurements").Find("measurement_id", msmt.ID).Update(msmt)
if err != nil {
log.WithError(err).Error("failed to update measurement")
return errors.Wrap(err, "updating measurement")

View File

@ -3,6 +3,7 @@ package database
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
@ -55,7 +56,7 @@ func TestMeasurementWorkflow(t *testing.T) {
}
var m2 Measurement
err = sess.Collection("measurements").Find("id", m1.ID).One(&m2)
err = sess.Collection("measurements").Find("measurement_id", m1.ID).One(&m2)
if err != nil {
t.Fatal(err)
}

View File

@ -13,68 +13,52 @@ import (
// ResultNetwork is used to represent the structure made from the JOIN
// between the results and networks tables.
type ResultNetwork struct {
Result `db:",inline"`
ResultID int64 `db:"result_id"`
Network `db:",inline"`
NetworkID int64 `db:"network_id"`
Result `db:",inline"`
Network `db:",inline"`
}
// MeasurementURLNetwork is used for the JOIN between Measurement and URL
type MeasurementURLNetwork struct {
Measurement `db:",inline"`
MeasurementStartTime time.Time `db:"measurement_start_time"`
MeasurementIsDone bool `db:"measurement_is_done"`
MeasurementRuntime float64 `db:"measurement_runtime"`
MsmtTblID int64 `db:"msmt_tbl_id"`
Network `db:",inline"`
NetworkID int64 `db:"network_id"`
NetworkCountryCode string `db:"network_country_code"`
Result `db:",inline"`
ResultID int64 `db:"result_id"`
ResultRuntime float64 `db:"result_runtime"`
ResultStartTime time.Time `db:"result_start_time"`
ResultIsDone bool `db:"result_is_done"`
URL `db:",inline"`
URLCountryCode sql.NullString `db:"url_country_code"`
Measurement `db:",inline"`
Network `db:",inline"`
Result `db:",inline"`
URL `db:",inline"`
}
// Network represents a network tested by the user
type Network struct {
ID int64 `db:"id,omitempty"`
ID int64 `db:"network_id,omitempty"`
NetworkName string `db:"network_name"`
NetworkType string `db:"network_type"`
IP string `db:"ip"`
ASN uint `db:"asn"`
CountryCode string `db:"country_code"`
CountryCode string `db:"network_country_code"`
}
// URL represents URLs from the testing lists
type URL struct {
ID sql.NullInt64 `db:"id,omitempty"`
ID sql.NullInt64 `db:"url_id,omitempty"`
URL sql.NullString `db:"url"`
CategoryCode sql.NullString `db:"category_code"`
CountryCode sql.NullString `db:"country_code"`
CountryCode sql.NullString `db:"url_country_code"`
}
// Measurement model
type Measurement struct {
ID int64 `db:"id,omitempty"`
ID int64 `db:"measurement_id,omitempty"`
TestName string `db:"test_name"`
StartTime time.Time `db:"start_time"`
Runtime float64 `db:"runtime"` // Fractional number of seconds
IsDone bool `db:"is_done"`
IsUploaded bool `db:"is_uploaded"`
IsFailed bool `db:"is_failed"`
FailureMsg sql.NullString `db:"failure_msg,omitempty"`
IsUploadFailed bool `db:"is_upload_failed"`
UploadFailureMsg sql.NullString `db:"upload_failure_msg,omitempty"`
IsRerun bool `db:"is_rerun"`
StartTime time.Time `db:"measurement_start_time"`
Runtime float64 `db:"measurement_runtime"` // Fractional number of seconds
IsDone bool `db:"measurement_is_done"`
IsUploaded bool `db:"measurement_is_uploaded"`
IsFailed bool `db:"measurement_is_failed"`
FailureMsg sql.NullString `db:"measurement_failure_msg,omitempty"`
IsUploadFailed bool `db:"measurement_is_upload_failed"`
UploadFailureMsg sql.NullString `db:"measurement_upload_failure_msg,omitempty"`
IsRerun bool `db:"measurement_is_rerun"`
ReportID sql.NullString `db:"report_id,omitempty"`
URLID sql.NullInt64 `db:"url_id,omitempty"` // Used to reference URL
MeasurementID sql.NullInt64 `db:"measurement_id,omitempty"`
MeasurementID sql.NullInt64 `db:"collector_measurement_id,omitempty"`
IsAnomaly sql.NullBool `db:"is_anomaly,omitempty"`
// FIXME we likely want to support JSON. See: https://github.com/upper/db/issues/462
TestKeys string `db:"test_keys"`
@ -84,15 +68,15 @@ type Measurement struct {
// Result model
type Result struct {
ID int64 `db:"id,omitempty"`
ID int64 `db:"result_id,omitempty"`
TestGroupName string `db:"test_group_name"`
StartTime time.Time `db:"start_time"`
NetworkID int64 `db:"network_id"` // Used to include a Network
Runtime float64 `db:"runtime"` // Runtime is expressed in fractional seconds
IsViewed bool `db:"is_viewed"`
IsDone bool `db:"is_done"`
DataUsageUp float64 `db:"data_usage_up"`
DataUsageDown float64 `db:"data_usage_down"`
StartTime time.Time `db:"result_start_time"`
NetworkID int64 `db:"network_id"` // Used to include a Network
Runtime float64 `db:"result_runtime"` // Runtime is expressed in fractional seconds
IsViewed bool `db:"result_is_viewed"`
IsDone bool `db:"result_is_done"`
DataUsageUp float64 `db:"result_data_usage_up"`
DataUsageDown float64 `db:"result_data_usage_down"`
MeasurementDir string `db:"measurement_dir"`
}
@ -112,7 +96,7 @@ func (r *Result) Finished(sess sqlbuilder.Database) error {
r.Runtime = time.Now().UTC().Sub(r.StartTime).Seconds()
r.IsDone = true
err := sess.Collection("results").Find("id", r.ID).Update(r)
err := sess.Collection("results").Find("result_id", r.ID).Update(r)
if err != nil {
return errors.Wrap(err, "updating finished result")
}
@ -123,7 +107,7 @@ func (r *Result) Finished(sess sqlbuilder.Database) error {
func (m *Measurement) Failed(sess sqlbuilder.Database, failure string) error {
m.FailureMsg = sql.NullString{String: failure, Valid: true}
m.IsFailed = true
err := sess.Collection("measurements").Find("id", m.ID).Update(m)
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
if err != nil {
return errors.Wrap(err, "updating measurement")
}
@ -136,7 +120,7 @@ func (m *Measurement) Done(sess sqlbuilder.Database) error {
m.Runtime = runtime.Seconds()
m.IsDone = true
err := sess.Collection("measurements").Find("id", m.ID).Update(m)
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
if err != nil {
return errors.Wrap(err, "updating measurement")
}
@ -148,7 +132,7 @@ func (m *Measurement) UploadFailed(sess sqlbuilder.Database, failure string) err
m.UploadFailureMsg = sql.NullString{String: failure, Valid: true}
m.IsUploaded = false
err := sess.Collection("measurements").Find("id", m.ID).Update(m)
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
if err != nil {
return errors.Wrap(err, "updating measurement")
}
@ -159,7 +143,7 @@ func (m *Measurement) UploadFailed(sess sqlbuilder.Database, failure string) err
func (m *Measurement) UploadSucceeded(sess sqlbuilder.Database) error {
m.IsUploaded = true
err := sess.Collection("measurements").Find("id", m.ID).Update(m)
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
if err != nil {
return errors.Wrap(err, "updating measurement")
}
@ -184,7 +168,7 @@ func (m *Measurement) AddToResult(sess sqlbuilder.Database, result *Result) erro
}
m.ReportFilePath = finalPath
err = sess.Collection("measurements").Find("id", m.ID).Update(m)
err = sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
if err != nil {
return errors.Wrap(err, "updating measurement")
}

View File

@ -54,25 +54,25 @@ func MeasurementItem(msmt database.MeasurementURLNetwork, isFirst bool, isLast b
"is_first": isFirst,
"is_last": isLast,
"id": msmt.MsmtTblID,
"id": msmt.Measurement.ID,
"test_name": msmt.TestName,
"test_group_name": msmt.Result.TestGroupName,
"start_time": msmt.MeasurementStartTime,
"start_time": msmt.Measurement.StartTime,
"test_keys": msmt.TestKeys,
"network_country_code": msmt.NetworkCountryCode,
"network_country_code": msmt.Network.CountryCode,
"network_name": msmt.Network.NetworkName,
"asn": msmt.Network.ASN,
"runtime": msmt.MeasurementRuntime,
"runtime": msmt.Measurement.Runtime,
"url": msmt.URL.URL.String,
"url_category_code": msmt.URL.CategoryCode.String,
"url_country_code": msmt.URLCountryCode.String,
"url_country_code": msmt.URL.CountryCode.String,
"is_anomaly": msmt.IsAnomaly.Bool,
"is_uploaded": msmt.IsUploaded,
"is_upload_failed": msmt.IsUploadFailed,
"upload_failure_msg": msmt.UploadFailureMsg.String,
"is_failed": msmt.IsFailed,
"failure_msg": msmt.FailureMsg.String,
"is_done": msmt.MeasurementIsDone,
"is_done": msmt.Measurement.IsDone,
"report_file_path": msmt.ReportFilePath,
}).Info("measurement")
}