diff --git a/README.md b/README.md index 06bb328..2cff2e1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,38 @@ # Status -[![Deploy Status](https://delphi.midas.cs.cmu.edu/~automation/public/github_deploy_repo/badge.php?repo=cmu-delphi/www-crowdcast)](#) +[![Deploy Status](https://delphi.midas.cs.cmu.edu/~automation/public/github_deploy_repo/badge.php?repo=cmu-delphi/www-epicast)](#) # About -The Crowdcast website for collecting flu forecasts. +The Crowdcast website for collecting flu forecasts. (Previously known as +Epicast.) -The site is live at: -- https://delphi.cmu.edu/crowdcast +The site is live at https://delphi.cmu.edu/crowdcast. -A live demo is available at http://demo.epicast.net/ (User ID is `00000000`) +# Branches + +The website is deployed to two separate environments: `dev` and `prod`. The +code for those environments is kept in the +[`dev`](https://github.com/cmu-delphi/www-epicast/tree/dev) and +[`prod`](https://github.com/cmu-delphi/www-epicast/tree/prod) branches, +respectively. + +## `dev` branch + +The `dev` branch is deployed to a Delphi-internal development environment where +we can iterate quickly without worry of breaking the production site. + +## `prod` branch + +The `prod` branch is deployed to a public-facing production environment. It +should contain only tested and reliable code. + +## process + +Changes are selectively merged into `prod` from `dev` after testing. However, +**`prod` should not be updated while a forecasting round is active** (i.e. +Friday through Monday), except in case of a critical bugfix. + +In any case, all code commits to `prod` should only consist of merges from +`dev`, rather than direct commits. (An exception to this is configuration, +which differs between environments.) diff --git a/deploy.json b/deploy.json deleted file mode 100644 index ffdf95a..0000000 --- a/deploy.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "type": "delphi deploy config", - "version": 1, - "actions": [ - - "// .htaccess file", - { - "type": "move", - "src": "site/.htaccess", - "dst": "/var/www/html/crowdcast/.htaccess", - "add-header-comment": false - }, - "// service worker", - { - "type": "move", - "src": "site/sw.js", - "dst": "/var/www/html/crowdcast/sw.js", - "add-header-comment": true - }, - "// web sources", - { - "type": "move", - "src": "site/", - "dst": "/var/www/html/crowdcast/", - "match": "^.*\\.php$", - "add-header-comment": true - }, - { - "type": "move", - "src": "site/common/", - "dst": "/var/www/html/crowdcast/common/", - "match": "^.*\\.php$", - "add-header-comment": true - }, - { - "type": "move", - "src": "site/css/", - "dst": "/var/www/html/crowdcast/css/", - "match": "^.*\\.(css|php)$", - "add-header-comment": true - }, - { - "type": "move", - "src": "site/js/", - "dst": "/var/www/html/crowdcast/js/", - "match": "^.*\\.js$", - "add-header-comment": true - }, - - "// images", - { - "type": "move", - "src": "site/images/flags/", - "dst": "/var/www/html/crowdcast/images/flags/", - "match": "^.*\\.png$" - }, - "// tutorials", - { - "type": "move", - "src": "site/images/", - "dst": "/var/www/html/crowdcast/images/", - "match": "^.*\\.(gif|mp4)$" - }, - "// benchmark data", - { - "type":"move", - "src":"site/data/", - "dst":"/var/www/html/crowdcast/data/", - "match":"^.*\\.csv$" - } - ] -} diff --git a/site/.htaccess b/site/.htaccess deleted file mode 100644 index 61f4952..0000000 --- a/site/.htaccess +++ /dev/null @@ -1,9 +0,0 @@ -RewriteEngine On - -## Compress Files ## - - - SetOutputFilter DEFLATE - - -## Compress Files ## diff --git a/site/FAQ.php b/site/FAQ.php deleted file mode 100644 index 5892e5d..0000000 --- a/site/FAQ.php +++ /dev/null @@ -1,85 +0,0 @@ - -
-
-
- FAQ - -
-

- In this page we collect and answer some frequently asked - questions we receive. All questions, however simple or - complicated, are welcome, as are suggestions for - improvements. -

-
-
-
- -
- -

- - 1. What data I should be basing a forecast on, is - it the situation of people in my current state? - -

- -

- Answer: You should forecast whatever you think will actually - happen in the location you are forecasting. -

-
- -

- - 2. Why did you choose to forecast "% of doctor - visits that involve flu-like symptoms"? Is this the only measure - you are interested in? - -

- -

- Answer: This is the measure CDC asked us to forecast first. An - elaborate system for measuring it already exists, and is being - re-purposed to measure covid-19 levels. We will likely also be - asked to forecast measures related to covid-19 hospitalization. -

-
- -

- - 3. "This seems like the wrong measure - I think - many COVID-19 patients may be diagnosed over the phone, and many - routine visits may be cancelled during this period.” - -

- -

- Answer: In that case, you should factor these beliefs into your - forecasts. -

-
- -

- - 4. “I think the best thing to nowcast would be - the number of true cases; and the best thing to forecast would be - the number of COVID-19 deaths, or perhaps excess mortality, to - capture deaths from all causes that occur because the healthcare - system is overwhelmed." - -

- -

- Answer: There are indeed other valuable measures to forecast. In - another project (not crowdsourced) we are forecasting future - demand on hospitals. -

-
-
- diff --git a/site/admin.php b/site/admin.php deleted file mode 100644 index 9bfd797..0000000 --- a/site/admin.php +++ /dev/null @@ -1,277 +0,0 @@ -', $field); - printf(' ', $field); -} -function sortBool(&$a, &$b) { - global $sortDir, $sortKey; - $value = 0; - if($a[$sortKey] && !$b[$sortKey]) { - $value = 1; - } - if(!$a[$sortKey] && $b[$sortKey]) { - $value = -1; - } - return $value * ($sortDir === 'a' ? 1 : -1); -} -function sortInt(&$a, &$b) { - global $sortDir, $sortKey; - $value = $a[$sortKey] - $b[$sortKey]; - return $value * ($sortDir === 'a' ? 1 : -1); -} -if(isAdmin($output)) { -?> -
- 0) { - $numForecastusers++; - } - } - } - foreach($u['submissions_hosp'] as &$s) { - if($s[0] === $output['epiweek']['round_epiweek']) { - $numForecasts_hosp += $s[1]; - if($s[1] > 0) { - $numForecastusers_hosp++; - } - } - } - foreach($emailTypes as &$type) { - if(getPreference($u, 'email_' . $type, 'int') === 1) { - $u['emails']++; - } - } - foreach($u['submissions'] as &$s) { - $u['total_submissions'] += $s[1]; - } - foreach($u['submissions_hosp'] as &$s) { - $u['total_submissions_hosp'] += $s[1]; - } - } - //PHP sort - if($sortFunc !== null) { - usort($output['userbase'], $sortFunc); - } - ?> -
-
- User Stats -
-
-
-
-
Total Registered Users
-
-
-
-
New Users Last 7 Days
-
-
-
-
Users Active Last 7 Days
-
-
-
-
Users Online Now
-
-
-
- -
-
- Regions and States -
-
-
-
-
Most Recent Report
-
-
-
-
Forecasts Received This Round
-
-
-
-
Users Participated This Round
-
-
-
- - -
-
- Userbase -
- Hopefully some day this will be too long to display on a single page. -
-
-
- - - - - - - - - - - - - - - -
Name EmailFirst Seen Last Seen PreferencesPresence Communication Submissions
', explode(' ', $u['first_seen'])) ?>', explode(' ', $u['last_seen'])) ?>', $k, $u['user_preferences'][$k]); - } else { - printf('%s: %s
', $k, $output['default_preferences'][$k]); - } - } - foreach(array_keys($u['user_preferences']) as $k) { - if(!isset($output['default_preferences'][$k])) { - printf('%s: %s
', $k, $u['user_preferences'][$k]); - } - } - ?>
- Online Now - - Offline - - Missing - - All Emails - 0) { ?> - Some Emails - - Do Not Contact - '); - foreach($u['submissions'] as &$s) { - printf('%s: %d
', formatEpiweek($s[0]), $s[1]); - } - printf('Total: %d
', $u['total_submissions']); - ?>
-
-
-
-
- Control Interface -
- Update user and system settings. -
-
-

The control interface is here.

-
-
- diff --git a/site/api.php b/site/api.php deleted file mode 100644 index 3e1075e..0000000 --- a/site/api.php +++ /dev/null @@ -1,56 +0,0 @@ - 0); -if(!$dbh) { - //Couldn't connect to the database - $output['result'] = -100; -} else { - //Connected successfully - if($_REQUEST['action'] == 'forecast' || $_REQUEST['action'] == 'autosave') { - $output['action'] = $_REQUEST['action']; - $hash = mysqli_real_escape_string($dbh, $_REQUEST['hash']); - $temp = array(); - if(getUserByHash($dbh, $temp, $hash) == 1) { - $forecast = array(); - foreach($_REQUEST['f'] as $f) { - array_push($forecast, floatval(mysqli_real_escape_string($dbh, $f))); - } - if(getEpiweekInfo($dbh, $temp) == 1) { - if(count($forecast) >= 1 && count($forecast) <= 53) { - //Save the forecast - $regionID = intval(mysqli_real_escape_string($dbh, $_REQUEST['region_id'])); - $commit = ($_REQUEST['action'] == 'forecast'); - if(saveForecast($dbh, $temp, $temp['user_id'], $regionID, $forecast, $commit) == 1) { - //Success - $output['result'] = 1; - } else { - //Failed to save forecast - $output['result'] = -5; - } - } else { - //Size of forecast array is wrong - $output['result'] = -4; - } - } else { - //Failed to get round info - $output['result'] = -3; - } - } else { - //Invalid user - $output['result'] = -2; - } - } else { - //Unknown action - $output['result'] = -1; - } -} -echo json_encode($output); -?> diff --git a/site/api_hosp.php b/site/api_hosp.php deleted file mode 100644 index ae5fdf9..0000000 --- a/site/api_hosp.php +++ /dev/null @@ -1,54 +0,0 @@ - 0); -if(!$dbh) { - //Couldn't connect to the database - $output['result'] = -100; -} else { - //Connected successfully - if($_REQUEST['action'] == 'forecast' || $_REQUEST['action'] == 'autosave') { - $output['action'] = $_REQUEST['action']; - $hash = mysql_real_escape_string($_REQUEST['hash']); - $temp = array(); - if(getUserByHash($temp, $hash) == 1) { - $forecast = array(); - foreach($_REQUEST['f'] as $f) { - array_push($forecast, floatval(mysql_real_escape_string($f))); - } - if(getEpiweekInfo($temp) == 1) { - if(count($forecast) >= 1 && count($forecast) <= 53) { - //Save the forecast - $group_id = intval(mysql_real_escape_string($_REQUEST['group_id'])); - $commit = ($_REQUEST['action'] == 'forecast'); - if(saveForecast_hosp($temp, $temp['user_id'], $group_id, $forecast, $commit) == 1) { - //Success - $output['result'] = 1; - } else { - //Failed to save forecast - $output['result'] = -5; - } - } else { - //Size of forecast array is wrong - $output['result'] = -4; - } - } else { - //Failed to get round info - $output['result'] = -3; - } - } else { - //Invalid user - $output['result'] = -2; - } - } else { - //Unknown action - $output['result'] = -1; - } -} -echo json_encode($output); -?> diff --git a/site/api_mturk.php b/site/api_mturk.php deleted file mode 100644 index 2ddb283..0000000 --- a/site/api_mturk.php +++ /dev/null @@ -1,59 +0,0 @@ - 0); -if(!$dbh) { - //Couldn't connect to the database - $output['result'] = -100; -} else { - //Connected successfully - if($_REQUEST['action'] == 'forecast' || $_REQUEST['action'] == 'autosave') { - $output['action'] = $_REQUEST['action']; - $mturkID = mysql_real_escape_string($_REQUEST['mturkID']); - $id = $_REQUEST['userID']; - $temp = array(); - if(userAlreadyExist($mturkID) == 1) { - $forecast = array(); - foreach($_REQUEST['f'] as $f) { - array_push($forecast, floatval(mysql_real_escape_string($f))); - } - if(getEpiweekInfo($temp) == 1) { - if(count($forecast) >= 1 && count($forecast) <= 53) { - //Save the forecast - $regionID = intval(mysql_real_escape_string($_REQUEST['region_id'])); - $commit = ($_REQUEST['action'] == 'forecast'); - // $id = getUserIDByMturkID($mturkID); - if(saveForecast_mturk($temp, $id, $regionID, $forecast, $commit) == 1) { - //Success - $output['result'] = 1; - } else { - //Failed to save forecast - $output['result'] = -5; - } - } else { - //Size of forecast array is wrong - $output['result'] = -4; - } - } else { - //Failed to get round info - $output['result'] = -3; - } - } else { - //Invalid user - $output['result'] = -2; - } - } else { - //Unknown action - $output['result'] = -1; - } -} -echo json_encode($output); -?> diff --git a/site/common/database.php b/site/common/database.php deleted file mode 100644 index fa054a0..0000000 --- a/site/common/database.php +++ /dev/null @@ -1,1602 +0,0 @@ -connect_errno) { - echo "Failed to connect to MySQL: (" . $dbh->connect_errno . ") " . $dbh->connect_error; - } - return $dbh; -} - -function getTargetPreference($dbh, &$output, $hash){ - $userID = $output['user_id']; - $result = $dbh->query("SELECT `value` FROM ec_fluv_user_preferences WHERE `user_id` = '{$userID}' AND 'name' = 'targets'"); - if($row = $result->fetch_assoc()) { - $list = explode(",",$result); - return $list; - } else { - return null; - } -} - -/* -===== getUserByHash ===== -Purpose: - Finds a user by their (partial) hash -Input: - $output - The array of return values (array reference) - $hash - The user's hash (or at least the first 32 bits of it) -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - 3 - Failure - $output['user_id'] - The user's id - $output['user_hash'] - The user's hash - $output['user_name'] - The user's name - $output['user_email'] - The user's email -*/ -function getUserByHash($dbh, &$output, $hash) { - if(strlen($hash) >= 8) { - $result = $dbh->query("SELECT `id`, `hash`, `name`, `email` FROM ec_fluv_users WHERE `hash` LIKE '{$hash}%'"); - if($row = $result->fetch_assoc()) { - setResult($output, 1); - $output['user_id'] = intval($row['id']); - $output['user_hash'] = $row['hash']; - $output['user_name'] = $row['name']; - $output['user_email'] = $row['email']; - $dbh->query("UPDATE ec_fluv_users SET `last_seen` = now() WHERE `id` = {$row['id']}"); - } else { - setResult($output, 2); - } - } else { - setResult($output, 3); - } - return getResult($output); -} - -/* -===== getUserByEmail ===== -Purpose: - Finds a user by their email address -Input: - $output - The array of return values (array reference) - $email - The user's email -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - 3 - Failure - See getUserByHash -*/ -function getUserByEmail($dbh, &$output, $email) { - $result = $dbh->query("SELECT `hash` FROM ec_fluv_users WHERE `email` = '{$email}'"); - if($row = $result->fetch_assoc()) { - return getUserByHash($output, $row['hash']); - } else { - setResult($output, 2); - return getResult($output); - } -} - -function getUserIDByMturkID($dbh, $mturkID) { - $result = $dbh->query("SELECT `id` FROM ec_fluv_users_mturk_2019 WHERE `name` = '{$mturkID}'"); - if($row = $result->fetch_assoc()) { - return $row['id']; - } else { - return -1; - } - -} - -function userAlreadyExist($dbh, $mturkID) { - $result = $dbh->query("SELECT `name` FROM ec_fluv_users_mturk_2019 WHERE `name` = '{$mturkID}'"); - if($row = $result->fetch_assoc()) { - return 1; - } else { - return 0; - } -} - - -/* -===== getUserStats ===== -Purpose: - Looks up user stats -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $epiweek - The epiweek -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['stat_completed'] - The number of regions completed on the given epiweek -*/ -function getUserStats($dbh, &$output, $userID, $epiweek) { -// echo "in getUserStats"; - $result = $dbh->query("SELECT count(1) `completed` FROM ec_fluv_submissions WHERE `user_id` = {$userID} AND `epiweek_now` = {$epiweek}"); - if($row = $result->fetch_assoc()) { - $output['stat_completed'] = intval($row['completed']); -// echo $output['stat_completed']; - setResult($output, 1); - } else { - setResult($output, 2); - } - return getResult($output); -} - -/* -===== getUserStats_hosp ===== -Purpose: - Looks up user stats -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $epiweek - The epiweek -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['stat_completed'] - The number of regions completed on the given epiweek -*/ -function getUserStats_hosp($dbh, &$output, $userID, $epiweek) { - $result = $dbh->query("SELECT count(1) `completed` FROM ec_fluv_submissions_hosp WHERE `user_id` = {$userID} AND `epiweek_now` = {$epiweek}"); - if($row = $result->fetch_assoc()) { - $output['stat_completed'] = intval($row['completed']); - setResult($output, 1); - } else { - setResult($output, 2); - } - return getResult($output); -} - -/* -===== getEpiweekInfo ===== -Purpose: - Returns info for the current epiweek -Input: - $output - The array of return values (array reference) -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure (table ec_fluv_round) - 3 - Failure (table epidata.fluview) - $output['epiweek']['round_epiweek'] - This round's identifier (can be ahead of data_epiweek) - $output['epiweek']['data_epiweek'] - The most recently published issue (from epidata.fluview) - $output['epiweek']['deadline'] - Deadline timestamp as a string (YYYY-MM-DD HH:MM:SS) - $output['epiweek']['deadline_timestamp'] - Unix timestamp of deadline - $output['epiweek']['remaining'] - An array containing days/hours/minutes/seconds remaining -*/ -function getEpiweekInfo($dbh, &$output) { - $result = $dbh->query('SELECT yearweek(now(), 6) `current_epiweek`, x.`round_epiweek`, x.`deadline`, unix_timestamp(x.`deadline`) `deadline_timestamp`, unix_timestamp(x.`deadline`) - unix_timestamp(now()) `remaining` FROM (SELECT `round_epiweek`, date_sub(`deadline`, INTERVAL 12 HOUR) `deadline` FROM ec_fluv_round) x'); - if($row = $result->fetch_assoc()) { - $output['epiweek'] = array(); - $output['epiweek']['current_epiweek'] = intval($row['current_epiweek']); - $current_year = intval($output['epiweek']['current_epiweek'] / 100); - $current_week = intval($output['epiweek']['current_epiweek'] % 100); - if($current_week >= 30) { - $output['epiweek']['season'] = array( - 'year' => $current_year, - 'start' => $current_year * 100 + 40, - 'end' => ($current_year + 1) * 100 + 20, - ); - } else { - $output['epiweek']['season'] = array( - 'year' => $current_year - 1, - 'start' => ($current_year - 1) * 100 + 40, - 'end' => $current_year * 100 + 20, - ); - } - $output['epiweek']['round_epiweek'] = intval($row['round_epiweek']); - $output['epiweek']['deadline'] = $row['deadline']; - $output['epiweek']['deadline_timestamp'] = intval($row['deadline_timestamp']); - $seconds = intval($row['remaining']); - $days = 0; - $hours = 0; - $minutes = 0; - if($seconds < 0) { - $seconds = 0; - } else { - $days = intval($seconds / (60 * 60 * 24)); - $seconds -= $days * (60 * 60 * 24); - $hours = intval($seconds / (60 * 60)); - $seconds -= $hours * (60 * 60); - $minutes = intval($seconds / 60); - $seconds -= $minutes * 60; - } - $output['epiweek']['remaining'] = array( - 'days' => $days, - 'hours' => $hours, - 'minutes' => $minutes, - 'seconds' => $seconds, - ); - setResult($output, 1); - } else { - setResult($output, 2); - return getResult($output); - } - $result = $dbh->query('SELECT max(`issue`) AS `data_epiweek` FROM epidata.`fluview`'); - if($row = $result->fetch_assoc()) { - $output['epiweek']['data_epiweek'] = intval($row['data_epiweek']); - setResult($output, 1); - } else { - setResult($output, 3); - return getResult($output); - } - return getResult($output); -} - -function getEpiweekInfo_mturk($dbh, &$output) { - $result = $dbh->query('SELECT yearweek(now(), 6) `current_epiweek`, x.`round_epiweek`, x.`deadline`, unix_timestamp(x.`deadline`) `deadline_timestamp`, unix_timestamp(x.`deadline`) - unix_timestamp(now()) `remaining` FROM (SELECT `round_epiweek`, date_sub(`deadline`, INTERVAL 12 HOUR) `deadline` FROM ec_fluv_round) x'); - if($row = $result->fetch_assoc()) { - $output['epiweek'] = array(); - $output['epiweek']['current_epiweek'] = intval($row['current_epiweek']); - - $current_year = intval($output['epiweek']['current_epiweek'] / 100); - $current_week = intval($output['epiweek']['current_epiweek'] % 100); - if($current_week >= 30) { - $output['epiweek']['season'] = array( - 'year' => $current_year, - 'start' => $current_year * 100 + 40, - 'end' => ($current_year + 1) * 100 + 20, - ); - } else { - $output['epiweek']['season'] = array( - 'year' => $current_year - 1, - 'start' => ($current_year - 1) * 100 + 40, - 'end' => $current_year * 100 + 20, - ); - } - - $output['epiweek']['round_epiweek'] = intval($row['round_epiweek']); - $output['epiweek']['deadline'] = $row['deadline']; - $output['epiweek']['deadline_timestamp'] = intval($row['deadline_timestamp']); - $seconds = intval($row['remaining']); - $days = 0; - $hours = 0; - $minutes = 0; - if($seconds < 0) { - $seconds = 0; - } else { - $days = intval($seconds / (60 * 60 * 24)); - $seconds -= $days * (60 * 60 * 24); - $hours = intval($seconds / (60 * 60)); - $seconds -= $hours * (60 * 60); - $minutes = intval($seconds / 60); - $seconds -= $minutes * 60; - } - $output['epiweek']['remaining'] = array( - 'days' => $days, - 'hours' => $hours, - 'minutes' => $minutes, - 'seconds' => $seconds, - ); - setResult($output, 1); - } else { - setResult($output, 2); - return getResult($output); - } - $dbh = databaseConnect(null, null, null, null, 'epicast2'); - $result = $dbh->query('SELECT max(`issue`) AS `data_epiweek` FROM epidata.`fluview`'); - if($row = $result->fetch_assoc()) { - $output['epiweek']['data_epiweek'] = intval($row['data_epiweek']); - setResult($output, 1); - } else { - setResult($output, 3); - return getResult($output); - } - return getResult($output); -} - -/* -===== getRegions ===== -Purpose: - Returns all regions -Input: - $output - The array of return values (array reference) - $userID - The user's ID -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['regions'] - An array of regions, indexed by region ID -*/ -function getRegions($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - $result = $dbh->query("SELECT r.`id`, r.`fluview_name`, r.`name`, r.`states`, r.`population`, CASE WHEN s.`user_id` IS NULL THEN FALSE ELSE TRUE END `completed` FROM ec_fluv_regions r LEFT JOIN ec_fluv_submissions s ON s.`user_id` = {$userID} AND s.`region_id` = r.`id` AND s.`epiweek_now` = {$temp['epiweek']['round_epiweek']} ORDER BY r.`id` ASC"); - $regions = array(); - while($row = $result->fetch_assoc()) { - if ($row['name'] == "ny_minus_jfk") { - $region_name = 'NY (excluding NYC)'; - } else { - $region_name = $row['name']; - } - - $region = array( - 'id' => intval($row['id']), - 'fluview_name' => $row['fluview_name'], - 'name' => $region_name, - 'states' => $row['states'], - 'population' => intval($row['population']), - 'completed' => intval($row['completed']) === 1, - ); - $regions[$region['id']] = $region; - } - $output['regions'] = &$regions; - - setResult($output, count($regions) == NUM_REGIONS ? 1 : 2); - return getResult($output); -} - -function getRegions_mturk($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - $result = $dbh->query("SELECT r.`id`, r.`name`, r.`states`, r.`population`, CASE WHEN s.`user_id` IS NULL THEN FALSE ELSE TRUE END `completed` FROM ec_fluv_regions r LEFT JOIN ec_fluv_submissions_mturk s ON s.`user_id` = {$userID} AND s.`region_id` = r.`id` AND s.`epiweek_now` = {$temp['epiweek']['round_epiweek']} ORDER BY r.`id` ASC"); - $regions = array(); - while($row = $result->fetch_assoc()) { - $region = array( - 'id' => intval($row['id']), - 'name' => $row['name'], - 'states' => $row['states'], - 'population' => intval($row['population']), - 'completed' => intval($row['completed']) === 1, - ); - $regions[$region['id']] = $region; - } - $output['regions'] = &$regions; - setResult($output, count($regions) == NUM_REGIONS ? 1 : 2); - return getResult($output); -} - -/* -===== getAgeGroups ===== -Purpose: - Returns all age groups -Input: - $output - The array of return values (array reference) - $userID - The user's ID -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['ageGroups'] - An array of regions, indexed by age group ID -*/ -function getAgeGroups($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - $result = $dbh->query("SELECT r.`id`, r.`flusurv_name`, r.`name`, r.`ages`, CASE WHEN s.`user_id` IS NULL THEN FALSE ELSE TRUE END `completed` FROM ec_fluv_age_groups r LEFT JOIN ec_fluv_submissions_hosp s ON s.`user_id` = {$userID} AND s.`group_id` = r.`id` AND s.`epiweek_now` = {$temp['epiweek']['round_epiweek']} ORDER BY r.`id` ASC"); - $ageGroups = array(); - while($row = $result->fetch_assoc()) { - $ageGroup = array( - 'id' => intval($row['id']), - 'flusurv_name' => $row['flusurv_name'], - 'name' => $row['name'], - 'ages' => $row['ages'], - 'completed' => intval($row['completed']) === 1, - ); - $ageGroups[$ageGroup['id']] = $ageGroup; - } - $output['ageGroups'] = &$ageGroups; - setResult($output, count($ageGroups) == NUM_AGEGROUPS ? 1 : 2); - return getResult($output); -} - -/* -===== getRegionsExtended ===== -Purpose: - Returns all regions, including historical counts and user forecasts for each region -Input: - $output - The array of return values (array reference) - $userID - The user's ID -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure (other) - 3 - Failure (history) - 4 - Failure (forecast) - $output['regions'] - An array of regions -*/ -function getRegionsExtended($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - //Basic region information - if(getRegions($dbh, $output, $userID) !== 1) { - return getResult($output); - } - - //History and forecast for every region - foreach($output['regions'] as &$r) { - if(getPreference($output, 'advanced_prior', 'int') === 1) { - $firstWeek = 199730; - } else { - $firstWeek = 200430; - } - - if(getHistory($dbh, $output, $r['id'], $firstWeek) !== 1) { - return getResult($output); - } - - $r['history'] = $output['history']; - if(loadForecast($dbh, $output, $userID, $r['id']) !== 1) { - return getResult($output); - } - - $r['forecast'] = $output['forecast']; - } - setResult($output, 1); - return getResult($output); -} - - -function getRegionsExtended_mturk($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - //Basic region information - if(getRegions_mturk($output, $userID) !== 1) { - return getResult($output); - } - //History and forecast for every region - foreach($output['regions'] as &$r) { - if(getPreference($output, 'advanced_prior', 'int') === 1) { - $firstWeek = 199730; - } else { - $firstWeek = 200430; - } - if(getHistory_mturk($output, $r['id'], $firstWeek) !== 1) { - return getResult($output); - } - $r['history'] = $output['history']; - if(loadForecast_mturk($output, $userID, $r['id']) !== 1) { - return getResult($output); - } - $r['forecast'] = $output['forecast']; - } - setResult($output, 1); - return getResult($output); -} - - -function getRegionsExtended_mturk_pastSeason($dbh, &$output, $userID, $epiweek) { - echo("inside getRegionsExtended_mturk_pastSeason"); - - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - //Basic region information - if(getRegions_mturk($output, $userID) !== 1) { - return getResult($output); - } - - //History and forecast for every region - foreach($output['regions'] as &$r) { - if(getPreference($output, 'advanced_prior', 'int') === 1) { - $firstWeek = 199730; - } else { - $firstWeek = 200430; - } - - echo("before getHistory_mturk_pastSeason"); - - if(getHistory_mturk_pastSeason($output, $r['id'], $firstWeek, $epiweek) !== 1) { - return getResult($output); - } - - echo("after getHistory_mturk_pastSeason"); - - $r['history'] = $output['history']; - if(loadForecast_mturk_pastSeason($output, $userID, $r['id'], $epiweek) !== 1) { - return getResult($output); - } - - echo("after loadForecast_mturk_pastSeason"); - - $r['forecast'] = $output['forecast']; - } - setResult($output, 1); - return getResult($output); -} - - -/* -===== getAgeGroupsExtended ===== -Purpose: - Returns all age groups, including historical counts and user forecasts for each age group -Input: - $output - The array of return values (array reference) - $userID - The user's ID -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure (other) - 3 - Failure (history) - 4 - Failure (forecast) - $output['ageGroups'] - An array of age groups -*/ -function getAgeGroupsExtended($dbh, &$output, $userID) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - //Basic region information - if(getAgeGroups($output, $userID) !== 1) { - return getResult($output); - } - $firstWeek = 200940; - //History and forecast for every region - foreach($output['ageGroups'] as &$g) { - - if(getHistory_Hosp($output, $g['flusurv_name'], $firstWeek) !== 1) { - return getResult($output); - } - $g['history'] = $output['history']; - if(loadForecast_hosp($output, $userID, $g['id']) !== 1) { - return getResult($output); - } - $g['forecast'] = $output['forecast']; - } - setResult($output, 1); - return getResult($output); -} - - -/* -===== getHistory ===== -Purpose: - Returns history for a region -Input: - $output - The array of return values (array reference) - $regionID - The region's ID - $firstWeek - The first epiweek -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['history'] - Arrays of epiweeks and historical incidence (wILI) for the region -*/ -function getHistory($dbh, &$output, $regionID, $firstWeek) { - $result = $dbh->query("SELECT fv.`epiweek`, fv.`wili` FROM epidata.`fluview` AS fv JOIN ( SELECT `epiweek`, max(`issue`) AS `latest` FROM epidata.`fluview` AS fv JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} GROUP BY fv.`epiweek` ) AS issues ON fv.`epiweek` = issues.`epiweek` AND fv.`issue` = issues.`latest` JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} ORDER BY fv.`epiweek` ASC"); - $date = array(); - $wili = array(); - while($row = $result->fetch_assoc()) { - $ew = intval($row['epiweek']); - while($firstWeek < $ew) { - array_push($date, $firstWeek); - array_push($wili, -1); - $firstWeek = addEpiweeks($firstWeek, 1); - } - array_push($date, $ew); - array_push($wili, floatval($row['wili'])); - $firstWeek = addEpiweeks($firstWeek, 1); - } - $output['history'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - -/* -===== getHistory_Hosp ===== -Purpose: - Returns history for an ageGroup -Input: - $ageGroup - The age group's ID - $firstWeek - The first epiweek -Output: - $output['history'] - Arrays of epiweeks and historical incidence (wILI) for the region -*/ -function getHistory_Hosp($dbh, &$output, $flusurv_name, $firstWeek) { - $result = $dbh->query("SELECT `epidata`.`flusurv`.`issue`, `epidata`.`flusurv`.`epiweek`, `epidata`.`flusurv`.`{$flusurv_name}` AS `rate` " . - "FROM (SELECT `epiweek`, max(`issue`) AS `latest` " . - "FROM `epidata`.`flusurv` WHERE `location` = 'network_all' AND `epiweek` >= {$firstWeek} GROUP BY `epiweek`) AS `issues` " . - "JOIN `epidata`.`flusurv` ON `epidata`.`flusurv`.`issue` = `issues`.`latest` AND `epidata`.`flusurv`.`epiweek` = `issues`.`epiweek` " . - "WHERE `location` = 'network_all' ORDER BY `epidata`.`flusurv`.`epiweek` ASC"); - - $dateArr = array(); - $rateArr = array(); - - $currentWeek = $firstWeek; - while ($row = $result->fetch_assoc()) { - $currentEpiweek = intval($row['epiweek']); - - // Push -1 for all weeks with no data - while ($currentWeek < $currentEpiweek) { - array_push($dateArr, $currentWeek); - array_push($rateArr, -1); - $currentWeek = addEpiweeks($currentWeek, 1); - } - array_push($dateArr, $currentEpiweek); - array_push($rateArr, floatval($row['rate'])); - // print($currentEpiweek); - // print(floatval($row['rate'])); - $currentWeek = addEpiweeks($currentWeek, 1); - } - $output['history'] = array('date' => $dateArr, 'rate' => $rateArr); - setResult($output, 1); - return getResult($output); -} - -function getHistory_mturk($dbh, &$output, $regionID, $firstWeek) { - $result = $dbh->query("SELECT fv.`epiweek`, fv.`wili` FROM epidata.`fluview` AS fv JOIN ( SELECT `epiweek`, max(`issue`) AS `latest` FROM epidata.`fluview` AS fv JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} GROUP BY fv.`epiweek` ) AS issues ON fv.`epiweek` = issues.`epiweek` AND fv.`issue` = issues.`latest` JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} ORDER BY fv.`epiweek` ASC"); - $date = array(); - $wili = array(); - while($row = $result->fetch_assoc()) { - $ew = intval($row['epiweek']); - while($firstWeek < $ew) { - array_push($date, $firstWeek); - array_push($wili, -1); - $firstWeek = addEpiweeks($firstWeek, 1); - } - array_push($date, $ew); - array_push($wili, floatval($row['wili'])); - $firstWeek = addEpiweeks($firstWeek, 1); - } - $output['history'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - - -function getHistory_mturk_pastSeason($dbh, &$output, $regionID, $firstWeek, $lastweek) { - $result = $dbh->query("SELECT fv.`epiweek`, fv.`wili` FROM epidata.`fluview` AS fv JOIN ( SELECT `epiweek`, max(`issue`) AS `latest` FROM epidata.`fluview` AS fv JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} GROUP BY fv.`epiweek` ) AS issues ON fv.`epiweek` = issues.`epiweek` AND fv.`issue` = issues.`latest` JOIN ec_fluv_regions AS reg ON reg.`fluview_name` = fv.`region` WHERE reg.`id` = {$regionID} AND fv.`epiweek` >= {$firstWeek} ORDER BY fv.`epiweek` ASC"); - $date = array(); - $wili = array(); - echo("$firstWeek, $lastweek"); - - while($row = $result->fetch_assoc()) { - $ew = intval($row['epiweek']); - - while($firstWeek < $ew) { - array_push($date, $firstWeek); - array_push($wili, -1); - $firstWeek = addEpiweeks($firstWeek, 1); - } - - if($ew < $lastweek) { - array_push($date, $ew); - array_push($wili, floatval($row['wili'])); - $firstWeek = addEpiweeks($firstWeek, 1); - } - } - $output['history'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - - - -/** - * Returns an array of age groups in the form of (flusurv_name, name, ages) where - * - flusurv_name is the name by which db identifies the age group, - * - name is a succinct name of the age group (such as age group #2), and - * - ages is the more detailed description of the age group (such as "18-30 years old") - */ -function listAgeGroups($dbh) { - $returnAgeGroups = array(); - $result = $dbh->query("SELECT * FROM ec_fluv_age_groups"); - - while ($row = $result->fetch_assoc()) { - $returnAgeGroups[] = $row; - } - // $returnAgeGroups = getAgeGroupsExtended(&$output, $userID); - return $returnAgeGroups; -} - -/* -===== saveForecast ===== -Purpose: - Saves the user's forecast -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $regionID - The region ID - $forecast - The forecast (array of values) - $commit - Whether or not to flag the forecast as a final submission -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure -*/ -function saveForecast($dbh, &$output, $userID, $regionID, $forecast, $commit) { - - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - $epiweek = $temp['epiweek']['round_epiweek']; - foreach($forecast as $wili) { - $epiweek = addEpiweeks($epiweek, 1); - $dbh->query("INSERT INTO ec_fluv_forecast (`user_id`, `region_id`, `epiweek_now`, `epiweek`, `wili`, `date`) VALUES ({$userID}, {$regionID}, {$temp['epiweek']['round_epiweek']}, {$epiweek}, {$wili}, now()) ON DUPLICATE KEY UPDATE `wili` = {$wili}, `date` = now()"); - } - if($commit) { - $dbh->query("INSERT INTO ec_fluv_submissions (`user_id`, `region_id`, `epiweek_now`, `date`) VALUES ({$userID}, {$regionID}, {$temp['epiweek']['round_epiweek']}, now())"); - } - - $debug = false; - if ($debug) { - echo "-------saveForecast----\n"; - echo $commit; - } - - - setResult($output, 1); - - getRegions($dbh, $output, $userID); - - return getResult($output); -} - -function saveForecast_mturk($dbh, &$output, $userID, $regionID, $forecast, $commit) { - $dbh = databaseConnect(null, null, null, null, 'epicast2'); - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - $epiweek = $temp['epiweek']['round_epiweek']; - foreach($forecast as $wili) { - $epiweek = addEpiweeks($epiweek, 1); - $dbh->query("INSERT INTO ec_fluv_forecast_mturk (`user_id`, `region_id`, `epiweek_now`, `epiweek`, `wili`, `date`) VALUES ({$userID}, {$regionID}, {$temp['epiweek']['round_epiweek']}, {$epiweek}, {$wili}, now()) ON DUPLICATE KEY UPDATE `wili` = {$wili}, `date` = now()"); - } - if($commit) { - $dbh->query("INSERT INTO ec_fluv_submissions_mturk (`user_id`, `region_id`, `epiweek_now`, `date`) VALUES ({$userID}, {$regionID}, {$temp['epiweek']['round_epiweek']}, now())"); - } - setResult($output, 1); - return getResult($output); -} - - -/* -===== saveForecast_hosp ===== -Purpose: - Saves the user's forecast -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $group_id - The age group ID - $forecast - The forecast (array of values) - $commit - Whether or not to flag the forecast as a final submission -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure -*/ - -function saveForecast_hosp($dbh, &$output, $userID, $group_id, $forecast, $commit) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - $epiweek = $temp['epiweek']['round_epiweek']; - foreach($forecast as $wili) { - $epiweek = addEpiweeks($epiweek, 1); - $dbh->query("INSERT INTO ec_fluv_forecast_hosp (`user_id`, `group_id`, `epiweek_now`, `epiweek`, `value`, `date`) VALUES ({$userID}, {$group_id}, {$temp['epiweek']['round_epiweek']}, {$epiweek}, {$wili}, now()) ON DUPLICATE KEY UPDATE `value` = {$wili}, `date` = now()"); - } - if($commit) { - $dbh->query("INSERT INTO ec_fluv_submissions_hosp (`user_id`, `group_id`, `epiweek_now`, `date`) VALUES ({$userID}, {$group_id}, {$temp['epiweek']['round_epiweek']}, now())"); - } - setResult($output, 1); - return getResult($output); -} - -/* -===== loadForecast ===== -Purpose: - Loads the user's forecast -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $regionID - The region ID - $submitted - Whether or not to only load submitted forecasts (default false) -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['forecast'] - Arrays of epiweeks and forecast (wILI) for the region made by the user -*/ -function loadForecast($dbh, &$output, $userID, $regionID, $submitted=false) { - $debug = false; - if ($debug and ($regionID == 1 or $regionID == 8)) { - echo "-----inside loadForecast------\n"; - echo "user ID, region ID, submitted: "; - echo $userID; - echo $regionID; - echo $submitted; - } - - if($submitted) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - - $result = $dbh->query("SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_submissions WHERE `user_id` = {$userID} AND `region_id` = {$regionID} AND `epiweek_now` < {$temp['epiweek']['round_epiweek']}"); - } else { - $result = $dbh->query("SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_forecast WHERE `user_id` = {$userID} AND `region_id` = {$regionID}"); - } - if($row = $result->fetch_assoc()) { - $epiweek = intval($row['epiweek']); - } else { - setResult($output, 2); - return getResult($output); - } - $date = array(); - $wili = array(); - $result = $dbh->query("SELECT `epiweek_now`, `epiweek`, `wili` FROM ec_fluv_forecast f WHERE `user_id` = {$userID} AND `region_id` = {$regionID} AND `epiweek_now` = {$epiweek} ORDER BY f.`epiweek` ASC"); - - if ($debug and ($regionID == 1 or $regionID == 8)) { - echo "epiweek: "; - echo $epiweek; - echo "\n"; - } - - while($row = $result->fetch_assoc()) { - array_push($date, intval($row['epiweek'])); - array_push($wili, floatval($row['wili'])); - - if ($debug and ($regionID == 1 or $regionID == 8)) { - echo intval($row['epiweek']); - echo ", "; - echo floatval($row['wili']); - echo "\n"; - } - } - $output['forecast'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - -function loadForecast_mturk($dbh, &$output, $userID, $regionID, $submitted=false) { - if($submitted) { - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - $result = $dbh->query("SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_submissions_mturk WHERE `user_id` = {$userID} AND `region_id` = {$regionID} AND `epiweek_now` < {$temp['epiweek']['round_epiweek']}"); - } else { - $result = $dbh->query("SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_forecast_mturk WHERE `user_id` = {$userID} AND `region_id` = {$regionID}"); - } - if($row = $result->fetch_assoc()) { - $epiweek = intval($row['epiweek']); - } else { - setResult($output, 2); - return getResult($output); - } - - $date = array(); - $wili = array(); - $query = "SELECT `epiweek_now`, `epiweek`, `wili` FROM ec_fluv_forecast_mturk f WHERE `user_id` = {$userID} AND `region_id` = {$regionID} AND `epiweek_now` = {$epiweek} ORDER BY f.`epiweek` ASC"; - $result = $dbh->query($query); - while($row = $result->fetch_assoc()) { - array_push($date, intval($row['epiweek'])); - array_push($wili, floatval($row['wili'])); - } - $output['forecast'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - -function loadForecast_mturk_pastSeason($dbh, &$output, $userID, $regionID, $epiweek, $submitted=false) { - $date = array(); - $wili = array(); - $query = "SELECT `epiweek_now`, `epiweek`, `wili` FROM ec_fluv_forecast_mturk f WHERE `user_id` = {$userID} AND `region_id` = {$regionID} AND `epiweek_now` = {$epiweek} ORDER BY f.`epiweek` ASC"; - $result = $dbh->query($query); - while($row = $result->fetch_assoc()) { - array_push($date, intval($row['epiweek'])); - array_push($wili, floatval($row['wili'])); - } - $output['forecast'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - - -/* -===== loadForecast_hosp ===== -Purpose: - Loads the user's forecast -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $group_id - The age group ID - $submitted - Whether or not to only load submitted forecasts (default false) -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['forecast'] - Arrays of epiweeks and forecast (value) for the region made by the user -*/ -function loadForecast_hosp($dbh, &$output, $userID, $group_id, $submitted=false) { - if($submitted) { - $temp = array(); - if(getEpiweekInfo($dbh, $temp) !== 1) { - return getResult($temp); - } - $q = "SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_submissions_hosp WHERE `user_id` = {$userID} AND `group_id` = {$group_id} AND `epiweek_now` < {$temp['epiweek']['round_epiweek']}"; - $result = $dbh->query($q) or die($q."

".$dbh->error); - } else { - $q = "SELECT coalesce(max(`epiweek_now`), 0) `epiweek` FROM ec_fluv_forecast_hosp WHERE `user_id` = {$userID} AND `group_id` = {$group_id}"; - $result = $dbh->query($q) or die($q."

".$dbh->error); - } - if($row = $result->fetch_assoc()) { - $epiweek = intval($row['epiweek']); - } else { - setResult($output, 2); - return getResult($output); - } - $date = array(); - $wili = array(); - $result = $dbh->query("SELECT `epiweek_now`, `epiweek`, `value` FROM ec_fluv_forecast_hosp f WHERE `user_id` = {$userID} AND `group_id` = {$group_id} AND `epiweek_now` = {$epiweek} ORDER BY f.`epiweek` ASC"); - while($row = $result->fetch_assoc()) { - array_push($date, intval($row['epiweek'])); - array_push($wili, floatval($row['value'])); - } - $output['forecast'] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} - - -/* -===== registerUser ===== -*** THIS WILL SEND AN EMAIL TO THE USER *** -Purpose: - Registers a new user -Input: - $output - The array of return values (array reference) - $name - The user's (nick)name - $email - The user's email - $adminEmail - The email to which replies should be directed -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['user_new'] - Whether or not the user is a new user (as determined by email address) - $output['user_id'] - The user's ID, whether nascent or pre-existing -*/ -function registerUser($dbh, &$output, $name, $email, $adminEmail) { - //Find, or create, the user - if(getUserByEmail($output, $email) === 1) { - $output['user_new'] = false; - } else { - $dbh->query("INSERT INTO ec_fluv_users (`hash`, `name`, `email`, `first_seen`, `last_seen`) VALUES (md5(rand()), '{$name}', '{$email}', now(), now())"); - $output['user_new'] = true; - if(getUserByEmail($output, $email) !== 1) { - return getResult($output); - } - } - //Send an email to the user - $hash = strtoupper(substr($output['user_hash'], 0, 8)); - $subject = mysqli_real_escape_string('Welcome to Crowdcast!'); - $body = mysqli_real_escape_string(sprintf("Hi %s,\r\n\r\nWelcome to Crowdcast (formerly known as Epicast)! Here's your User ID: %s\r\nYou can login and begin forecasting here: https://delphi.cmu.edu/epicast/launch.php?user=%s\r\n\r\nThank you,\r\nThe Delphi Team\r\n\r\n[This is an automated message. Please direct all replies to: %s. Unsubscribe: https://delphi.cmu.edu/epicast/preferences.php?user=%s]", $name, $hash, $hash, $adminEmail, $hash)); - $dbh->query("INSERT INTO automation.email_queue (`from`, `to`, `subject`, `body`) VALUES ('delphi@epicast.net', '{$email}', '{$subject}', '{$body}')"); - $dbh->query("CALL automation.RunStep(2)"); - setResult($output, 1); - return getResult($output); -} - -function registerUser_mturk($dbh, $mturkID) { - //Find, or create, the user - if (userAlreadyExist($mturkID) === 1) { - return; - } else { - $email = md5(rand()); - $hash = md5(rand()); - $escapedInput = mysqli_real_escape_string($mturkID); - $query = "INSERT INTO ec_fluv_users_mturk (`hash`, `name`, `email`, `first_seen`, `last_seen`) - VALUES ('{$hash}', '{$escapedInput}', '{$email}', now(), now())"; - $result = $dbh->query($query); - } - return; -} - -function registerUser_mturk_2019($dbh, $mturkID, $taskID) { - //Find, or create, the user - if (userAlreadyExist($mturkID) === 1) { - return; - } else { - $email = md5(rand()); - $hash = md5(rand()); - $escapedInput = mysqli_real_escape_string($mturkID); - $query = "INSERT INTO ec_fluv_users_mturk_2019 (`hash`, `name`, `email`, `first_seen`, `last_seen`, `taskID`) - VALUES ('{$hash}', '{$escapedInput}', '{$email}', now(), now(), {$taskID})"; - $dbh->query($query); - - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - $epiweek_now = $temp['epiweek']['round_epiweek']; - $query = "UPDATE ec_fluv_mturk_tasks SET numWorker = numWorker + 1 WHERE taskID = {$taskID}"; - $dbh->query($query); - } - return; -} - -function readSqlResult($dbh, $query, $dest) { - $result = $dbh->query($query); - while ($row = $result->fetch_assoc()) { - array_push($dest, $row); - } - return $dest; - -} - -function getAvailableTaskSets($dbh) { - $temp = array(); - if(getEpiweekInfo_mturk($temp) !== 1) { - return getResult($temp); - } - $epiweek_now = $temp['epiweek']['round_epiweek']; - $query = "select taskID, states from ec_fluv_mturk_tasks where numWorker < maxWorker"; - $availableTasks = array(); - $availableTasks = readSqlResult($dbh, $query, $availableTasks); - return $availableTasks; -} - - -function getNextLocation($dbh, $mturkID, $regionID) { - if ($regionID === -1 && !userAlreadyExist($mturkID)) { - // return the state with the smallest region ID in this task group - $availableTasks = getAvailableTaskSets(); - $task = $availableTasks[array_rand($availableTasks)]; - $taskID = $task['taskID']; - registerUser_mturk_2019($mturkID, $taskID); - - $states = $task['states']; - $regionIDs = explode(",",$states); - $regionID = array(min($regionIDs)); - return $regionID; - - } else { - // return an array of unfinished states - $escapedInput = mysqli_real_escape_string($mturkID); - $query = "select taskID from ec_fluv_users_mturk_2019 where name = '{$escapedInput}'"; - $result = $dbh->query($query); -// $taskID = intval($result->fetch_assoc()); - while($row = $result->fetch_assoc()) { - $taskID = intval($row['taskID']); - } - - $query = "select states from ec_fluv_mturk_tasks where taskID = {$taskID}"; - $states = array(); - $states = readSqlResult($dbh, $query, $states); - $states = $states[0]['states']; - $states = explode(",", $states); - return $states; - } -} - - -function get_user_forecast_regions($dbh, $user_ID) { - $num_task_groups = 6; - $task_group = $user_ID % ($num_task_groups + 1); - if ($task_group == 0) { - $task_group = ($user_ID % $num_task_groups) + 1; - } - - $query = "SELECT states FROM ec_fluv_mturk_tasks WHERE `taskID` = {$task_group}"; - $states = array(); - $states = readSqlResult($dbh, $query, $states); - $states = $states[0]['states']; - $states = explode(",", $states); - - if ($user_ID == 1775) { - array_push($states, 13); - - } - - if ($user_ID == 1) { - array_push($states, 24); - - } - - return $states; -} - - - -function save_random_code_mturk($dbh, $userID, $code) { - $result = $dbh->query("INSERT INTO ec_fluv_mturk_code_match (`user_id`, `code`) VALUES ({$userID}, {$code})"); - if ($result == FALSE) { - echo("failed to insert"); - echo(mysqli_error($dbh)); - } - else {echo("success");} - return; -} - -/* -===== loadDefaultPreferences ===== -Purpose: - Gets default preferences -Input: - $output - The array of return values (array reference) -Output: - $output['result'] will contain the following values: - 1 - Success - $output['default_preferences'] - An array of preferences in the form of (name, value) pairs -*/ -function loadDefaultPreferences($dbh, &$output) { - $output['default_preferences'] = array(); - $result = $dbh->query("SELECT `name`, `value` FROM ec_fluv_defaults ORDER BY `name` ASC"); - while($row = $result->fetch_assoc()) { - $output['default_preferences'][$row['name']] = $row['value']; - } - setResult($output, 1); - return getResult($output); -} - -/* -===== loadUserPreferences ===== -Purpose: - Gets user preferences -Input: - $output - The array of return values (array reference) - $userID - The user's ID -Output: - $output['result'] will contain the following values: - 1 - Success - $output['user_preferences'] - An array of preferences in the form of (name, value) pairs -*/ -function loadUserPreferences($dbh, &$output, $userID) { - $output['user_preferences'] = array(); - $result = $dbh->query("SELECT `name`, `value` FROM ec_fluv_user_preferences WHERE `user_id` = {$userID} ORDER BY `name` ASC"); - while($row = $result->fetch_assoc()) { - $output['user_preferences'][$row['name']] = $row['value']; - } - setResult($output, 1); - return getResult($output); -} - -/* -===== saveUserPreferences ===== -Purpose: - Gets, merges, and stores user preferences -Input: - $output - The array of return values (array reference) - $userID - The user's ID - $preferences - The preferences to save -Output: - See loadUserPreferences -*/ -function saveUserPreferences($dbh, &$output, $userID, $preferences) { - foreach(array_keys($preferences) as $name) { - $value = $preferences[$name]; - if($value === null) { - $dbh->query("DELETE FROM ec_fluv_user_preferences WHERE `user_id` = {$userID} AND `name` = '{$name}'"); - } else { - $dbh->query("INSERT INTO ec_fluv_user_preferences (`user_id`, `name`, `value`, `date`) VALUES ({$userID}, '{$name}', '{$value}', now()) ON DUPLICATE KEY UPDATE `value` = '{$value}', `date` = now()"); - } - } - return loadUserPreferences($dbh, $output, $userID); -} - -/* -===== getUserbase ===== -*** ADMIN ONLY *** -Purpose: - Return information on all registered users -Input: - $output - The array of return values (array reference) - $sortField - Sort field: 'n', 'fs', 'ls' - $sortDir - Sort direction: 'a', 'd' -Output: - $output['result'] will contain the following values: - 1 - Success - 2, 3, 4 - Failure - $output['userbase'] - An array of users -*/ -function getUserbase($dbh, &$output, $sortField, $sortDir) { - if(!isAdmin($output)) { - setResult($output, 3); - return getResult($output); - } - $fields = array('n' => 'name', 'fs' => 'first_seen', 'ls' => 'last_seen'); - $dirs = array('a' => 'ASC', 'd' => 'DESC'); - if(!in_array($sortField, array_keys($fields)) || !in_array($sortDir, array_keys($dirs))) { - setResult($output, 4); - return getResult($output); - } - $users = array(); - $result = $dbh->query("SELECT `id`, `hash`, `name`, `email`, `first_seen`, `last_seen`, CASE WHEN `last_seen` >= date_sub(now(), INTERVAL 7 DAY) THEN 1 ELSE 0 END `active`, CASE WHEN `last_seen` = `first_seen` THEN -1 WHEN `last_seen` >= date_sub(now(), INTERVAL 10 MINUTE) THEN 1 ELSE 0 END `online`, CASE WHEN `first_seen` >= date_sub(now(), INTERVAL 7 DAY) THEN 1 ELSE 0 END `new` FROM ec_fluv_users ORDER BY `{$fields[$sortField]}` {$dirs[$sortDir]}"); - while($row = $result->fetch_assoc()) { - $user = array( - 'id' => intval($row['id']), - 'hash' => $row['hash'], - 'name' => $row['name'], - 'email' => $row['email'], - 'first_seen' => $row['first_seen'], - 'last_seen' => $row['last_seen'], - 'active' => intval($row['active']) === 1, - 'online' => intval($row['online']), - 'new' => intval($row['new']) === 1, - 'default_preferences' => &$output['default_preferences'], - 'submissions' => array(), - 'submissions_hosp' => array() - ); - - if(loadUserPreferences($dbh, $user, $user['id']) !== 1) { - return getResult($user); - } - - $result2 = $dbh->query("SELECT epiweek_now, count(region_id) num FROM ec_fluv_submissions WHERE user_id = {$user['id']} GROUP BY epiweek_now ORDER BY epiweek_now ASC"); - while($row2 = $result2->fetch_assoc()) { - array_push($user['submissions'], array(intval($row2['epiweek_now']), intval($row2['num']))); - } - - $result3 = $dbh->query("SELECT epiweek_now, count(group_id) num FROM ec_fluv_submissions_hosp WHERE user_id = {$user['id']} GROUP BY epiweek_now ORDER BY epiweek_now ASC"); - while($row3 = $result3->fetch_assoc()) { - array_push($user['submissions_hosp'], array(intval($row3['epiweek_now']), intval($row3['num']))); - } - - array_push($users, $user); - - } - $output['userbase'] = &$users; - setResult($output, 1); - return getResult($output); -} - - -function loadUserPreferences_mturk($dbh, &$output, $userID) { - $output['user_preferences'] = array(); - $result = $dbh->query("SELECT `name`, `value` FROM ec_fluv_user_preferences_mturk WHERE `user_id` = {$userID} ORDER BY `name` ASC"); - while($row = $result->fetch_assoc()) { - $output['user_preferences'][$row['name']] = $row['value']; - } - setResult($output, 1); - return getResult($output); -} - - -function saveUserPreferences_mturk($dbh, &$output, $userID, $preferences) { - foreach(array_keys($preferences) as $name) { - $value = $preferences[$name]; - if($value === null) { - $dbh->query("DELETE FROM ec_fluv_user_preferences_mturk WHERE `user_id` = {$userID} AND `name` = '{$name}'"); - } else { - $dbh->query("INSERT INTO ec_fluv_user_preferences_mturk (`user_id`, `name`, `value`, `date`) VALUES ({$userID}, '{$name}', '{$value}', now()) ON DUPLICATE KEY UPDATE `value` = '{$value}', `date` = now()"); - } - } - return loadUserPreferences_mturk($output, $userID); -} - - - -/* -===== getLeaderboard ===== -Purpose: - Return leaderboard data -Input: - $output - The array of return values (array reference) - $type - 'total' or 'last' - $limit - Number of results to return, default 25 -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['leaderboard'] - The leaderboard array, sorted by score -*/ -function getLeaderboard($dbh, &$output, $type, $limit=25) { - $leaderboard = array(); - if($type === 'total' || $type === 'last') { - $field = $type; - } else { - setResult($output, 2); - return getResult($output); - } - $result = $dbh->query("SELECT u.`id`, u.`hash`, coalesce(CASE WHEN coalesce(p1.`value`, d1.`value`) = '1' THEN p2.`value` ELSE NULL END, d2.`value`) `name`, s.`{$field}` `score`, coalesce(p3.`value`, d3.`value`) `delphi` FROM ec_fluv_users u JOIN ec_fluv_scores s ON s.`user_id` = u.`id` JOIN ec_fluv_defaults d1 ON d1.`name` = 'advanced_leaderboard' LEFT JOIN ec_fluv_user_preferences p1 ON p1.`name` = d1.`name` AND p1.`user_id` = u.`id` JOIN ec_fluv_defaults d2 ON d2.`name` = 'advanced_initials' LEFT JOIN ec_fluv_user_preferences p2 ON p2.`name` = d2.`name` AND p2.`user_id` = u.`id` JOIN ec_fluv_defaults d3 ON d3.`name` = '_delphi' LEFT JOIN ec_fluv_user_preferences p3 ON p3.`name` = d3.`name` AND p3.`user_id` = u.`id` ORDER BY s.`{$field}` DESC, u.`id` DESC LIMIT {$limit}"); - $lastScore = -1; - $rank = 0; - $rownum = 0; - while($row = $result->fetch_assoc()) { - $rownum++; - $entry = array( - 'hash' => getMiniHash($row['hash']), - 'name' => $row['name'], - 'score' => intval($row['score']), - ); - if($entry['score'] !== $lastScore) { - $lastScore = $entry['score']; - $rank = $rownum; - } - $entry['rank'] = $rank; - array_push($leaderboard, $entry); - } - $output['leaderboard'] = &$leaderboard; - setResult($output, 1); - return getResult($output); -} - -/* -===== getNowcast ===== -Purpose: - Return nowcast for a given region -Input: - $output - The array of return values (array reference) - $epiweek - The epiweek to predict - $region - The region name -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['nowcast'] - Array containing point prediction and standard deviation -*/ -function getNowcast($dbh, &$output, $epiweek, $region) { - $epiweek = $epiweek; - $regions = array( - 1 => 'nat', - 2 => 'hhs1', - 3 => 'hhs2', - 4 => 'hhs3', - 5 => 'hhs4', - 6 => 'hhs5', - 7 => 'hhs6', - 8 => 'hhs7', - 9 => 'hhs8', - 10 => 'hhs9', - 11 => 'hhs10', - ); - $region = $regions[$region]; - $result = $dbh->query("SELECT value, std FROM epidata.`nowcasts` WHERE `epiweek` = {$epiweek} AND `location` = '{$region}'"); - if($row = $result->fetch_assoc()) { - $output['nowcast'] = array( - 'value' => floatval($row['value']), - 'std' => floatval($row['std']), - ); - setResult($output, 1); - } else { - setResult($output, 2); - } - return getResult($output); -} - -/* -===== getYearForCurrentSeason ===== -Purpose: - Return the year number for the current flu season (e.g. 2016 for the - 2016--2017 flu season) -Input: - $output - The array of return values (array reference) -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['season']['year'] - The year of the season start - $output['season']['first_epiweek'] - The first epiweek of the contest - $output['season']['last_epiweek'] - The last epiweek of the contest -*/ -function getYearForCurrentSeason($dbh, &$output) { - $result = $dbh->query("SELECT `year`, `first_round_epiweek`, `last_round_epiweek` FROM `ec_fluv_season`"); - if($row = $result->fetch_assoc()) { - $output['season'] = array( - 'year' => intval($row['year']), - 'first_epiweek' => intval($row['first_round_epiweek']), - 'last_epiweek' => intval($row['last_round_epiweek']) - ); - setResult($output, 1); - } else { - setResult($output, 2); - } - return getResult($output); -} - -/* -===== getTaskDate ===== -Purpose: - Get the datetime when the given task is scheduled to run next. -Input: - $output - The array of return values (array reference) - $taskId - The ID of the task -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure - $output['task'][<$taskId>] - The datetime when the task will be executed -*/ -function getTaskDate($dbh, &$output, $taskId) { - $result = $dbh->query("SELECT `date` FROM `automation`.`tasks` WHERE `id` = {$taskId}"); - if($row = $result->fetch_assoc()) { - if(!isset($output['task'])) { - $output['task'] = array(); - } - $output['task'][$taskId] = $row['date']; - setResult($output, 1); - } else { - setResult($output, 2); - } - return getResult($output); -} - -/* -===== updateSeason ===== -Purpose: - Update epiweek range of the current flu contest. -Input: - $output - The array of return values (array reference) - $firstWeek - The first epiweek of the contest - $lastWeek - The last epiweek of the contest -Output: - $output['result'] will contain the following values: - 1 - Success -*/ -function updateSeason($dbh, &$output, $firstWeek, $lastWeek) { - $dbh->query("UPDATE `ec_fluv_season` SET `first_round_epiweek` = {$firstWeek}, `last_round_epiweek` = {$lastWeek}"); - setResult($output, 1); - return getResult($output); -} - -/* -===== updateRound ===== -Purpose: - Update epiweek and deadline of the current forecasting round. -Input: - $output - The array of return values (array reference) - $epiweek - The epiweek of the current round - $deadline - The deadline for the current round -Output: - $output['result'] will contain the following values: - 1 - Success -*/ -function updateRound($dbh, &$output, $epiweek, $deadline) { - $dbh->query("UPDATE `ec_fluv_round` SET `round_epiweek` = {$epiweek}, `deadline` = '{$deadline}'"); - setResult($output, 1); - return getResult($output); -} - -/* -===== setTaskDate ===== -Purpose: - Sets the datetime when the given task is scheduled to run next. -Input: - $output - The array of return values (array reference) - $taskId - The ID of the task - $date - The datetime when the task should be executed -Output: - $output['result'] will contain the following values: - 1 - Success -*/ -function setTaskDate($dbh, &$output, $taskId, $date) { - $dbh->query("UPDATE `automation`.`tasks` SET `date` = '{$date}' WHERE `id` = {$taskId}"); - setResult($output, 1); - return getResult($output); -} - -/* -===== resetEpicast ===== -Purpose: - Resets Epicast for a new forecasing season. -Input: - $output - The array of return values (array reference) - $year - The year of the *new* season (e.g. 2017 for 2017--2018) - $firstEpiweek - The first epiweek of the contest - $lastEpiweek - The last epiweek of the contest - $deadline - The first deadline - $admin - The admin name and email, as an array with those keys -Output: - $output['result'] will contain the following values: - 1 - Success - 2 - Failure -*/ -function resetEpicast($dbh, &$output, $year, $firstEpiweek, $lastEpiweek, $deadline, $admin) { - $tbl_old = ($year - 1) . "_ec_fluv_"; - $tbl_new = 'ec_fluv_'; - $tables = array('defaults', 'forecast', 'regions', 'round', 'scores', 'season', 'submissions', 'user_preferences', 'users', 'age_groups', 'forecast_hosp', 'submissions_hosp'); - foreach($tables as $name) { - $dbh->query("CREATE TABLE {$tbl_old}{$name} AS SELECT * FROM {$tbl_new}{$name}"); - } - $tables = array('forecast', 'scores', 'submissions', 'user_preferences', 'users', 'forecast_hosp', 'submissions_hosp'); - foreach($tables as $name) { - $dbh->query("TRUNCATE TABLE {$tbl_new}{$name}"); - } - $dbh->query("UPDATE `ec_fluv_season` SET `year` = {$year}, `first_round_epiweek` = {$firstEpiweek}, `last_round_epiweek` = {$lastEpiweek}"); - $dbh->query("UPDATE `ec_fluv_round` SET `round_epiweek` = {$firstEpiweek}, `deadline` = '{$deadline}'"); - $temp = array(); - registerUser($temp, $admin['name'], $admin['email'], $admin['email']); - $preferences = array('_admin' => 1, '_delphi' => 1); - saveUserPreferences($temp, $temp['user_id'], $preferences); - setResult($output, 1); - return getResult($output); -} - -/* -===== getECDCILI ===== -Purpose: - Returns ECDC ILI history for a country -Input: - $output - The array of return values (array reference) - $regionID - The numeric ID for the country - $firstWeek - The first epiweek (currently ignored; will always return data for the 2019/2020 season) -Output: - $output['result'] will contain the following values: - 1 - Success - 1 - Failure - $output['history'] - Arrays of epiweeks and historical incidence (ILI per 100k) for the country -*/ -function getECDCILI($dbh, &$output, $regionID, $firstWeek) { - $country = ""; - switch($regionID) { - case 8001: $country = "Italy"; break; - case 8002: $country = "Spain"; break; - case 8003: $country = "France"; break; - case 8004: $country = "Netherlands"; break; - case 8005: $country = "Ireland"; break; - case 8006: $country = "United Kingdom - Scotland"; break; - case 8007: $country = "Belgium"; break; - default: $country = "?"; break; - } - $query = "SELECT ed.`epiweek`, ed.`incidence_rate` - FROM epidata.`ecdc_ili` AS ed - JOIN ( - SELECT `epiweek`, max(`issue`) AS `latest` - FROM epidata.`ecdc_ili` AS latest_ed - WHERE latest_ed.`region` = \"{$country}\" AND latest_ed.`epiweek` >= {$firstWeek} - GROUP BY latest_ed.`epiweek` - ) AS issues ON ed.`epiweek` = issues.`epiweek` AND ed.`issue` = issues.`latest` - WHERE ed.`region` = \"{$country}\" AND ed.`epiweek` >= {$firstWeek} - ORDER BY ed.`epiweek` ASC"; - $result = $dbh->query($query); - - $date = array(); - $wili = array(); - while($row=$result->fetch_assoc()) { - $ew = intval($row['epiweek']); - while($firstWeek < $ew) { - array_push($date, $firstWeek); - array_push($wili, -1); - $firstWeek = addEpiweeks($firstWeek, 1); - } - array_push($date, $ew); - array_push($wili, floatval($row['incidence_rate'])); - $firstWeek = addEpiweeks($firstWeek, 1); - } - if (!array_key_exists("ecdc",$output)) { - $output['ecdc'] = array(); - } - // leaving this as wili for now even though it's not really - $output['ecdc'][$regionID] = array('date' => &$date, 'wili' => &$wili); - setResult($output, 1); - return getResult($output); -} -?> diff --git a/site/common/footer.php b/site/common/footer.php deleted file mode 100644 index a34496d..0000000 --- a/site/common/footer.php +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/site/common/header.php b/site/common/header.php deleted file mode 100644 index 27d1d96..0000000 --- a/site/common/header.php +++ /dev/null @@ -1,115 +0,0 @@ - - - - - Delphi Crowdcast COVID-19 - - - - - - - - - - - - - -connect_errno) { - //Couldn't connect to the database - fail("Couldn't connect to the database: (".$dbh->connect_errno.") ".$dbh->connect_error); - require_once('footer.php'); - $error = true; -} else { - $hash = attemptLogin($dbh, $output); - if($hash == null || (isset($fullHeader) && $fullHeader)) { - //Big header - ?> -
-
- - Crowdcast -
- <COVID-19 Edition> -
-
-
Epidemiological Forecasting by DELPHI
-
- -
-

- Oops, we need you to login again!
- (Either your user ID was wrong or your session has expired.) -

- -
- -
- -
-
-
Crowdcast COVID-19
-
- Crowdcaster: []
- Admin', 'admin.php'); - createDivider('|'); - } - print(''); - createLink('DELPHI', 'https://delphi.cmu.edu/', true, 'delphi'); - print(''); - ?> -
-
-
- - -
- preferences page to reactivate it!', 'account_deactivated_warning'); - } - } -} -?> diff --git a/site/common/headerR.php b/site/common/headerR.php deleted file mode 100644 index 6bbc04e..0000000 --- a/site/common/headerR.php +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Delphi Epicast-FLUV - - - - - - - - - - - - -
-
- Welcome to Epicast -
- <Influenza Edition - California> -
- -
Epidemiological Forecasting by DELPHI
- -
- '); - createLink('DELPHI', 'https://delphi.midas.cs.cmu.edu/', true, 'delphi'); - print(''); - ?> -
- -
- - - - -
-

- Oops, we need you to login again!
- (Either your user ID was wrong or your session has expired.) -

- -
- -
- diff --git a/site/common/header_mturk.php b/site/common/header_mturk.php deleted file mode 100644 index b6a7fad..0000000 --- a/site/common/header_mturk.php +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Delphi Epicast-FLUV - - - - - - - - - - - - - - -
-
-
Epicast FLUV
-
-
-
- diff --git a/site/common/navigation.php b/site/common/navigation.php deleted file mode 100644 index ec7ac21..0000000 --- a/site/common/navigation.php +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - -
-
-
- -
- -
-
-
- -
-
-
- -
- -
- -
- -
- Per Age Group Hospitalization -
- - - -
-
-
- - - -
- -
-
-
- -
-
-
-
- - -
-
- Submitted:      Still Missing: -
- - - -
- -
- -
- diff --git a/site/common/navigationR.php b/site/common/navigationR.php deleted file mode 100644 index 35fd5c7..0000000 --- a/site/common/navigationR.php +++ /dev/null @@ -1,125 +0,0 @@ - - - -
-
-
- -
- -
-
-
- -
-
-
- -
- - - -
-
-
- - - -
- -
-
-
- -
-
-
-
- -
- - - -
- National and Regional Forecast -
- - - - -
- - -
- -
- diff --git a/site/common/settings.php b/site/common/settings.php deleted file mode 100644 index e6c84ee..0000000 --- a/site/common/settings.php +++ /dev/null @@ -1,14 +0,0 @@ - "Jiaxian Sheng", - "email" => "jiaxians@andrew.cmu.edu", -); -?> diff --git a/site/common/utils.php b/site/common/utils.php deleted file mode 100644 index 3f5f0e6..0000000 --- a/site/common/utils.php +++ /dev/null @@ -1,147 +0,0 @@ - {$message}
"); -} - -function success($message, $id=null, $hidden=false) { - $id = ($id === null) ? '' : sprintf('id="%s"', $id); - $class = $hidden ? 'any_hidden' : ''; - echo("
{$message}
"); -} - -function button($icon, $text, $onClick, $classes='', $id=null, $code='') { - $id = ($id === null) ? '' : sprintf('id="%s"', $id); - printf('
  %s
', $id, $classes, $onClick, $code, $icon, $text); -} - - - -function createForm($id, $action, $values) { - ?> -
- - - -
- %s', $classes, $newTab ? 'target="_blank"' : '', $url, $text); -} - -function createDivider($text) { - printf('  %s  ', $text); -} - -function getMiniHash($hash) { - return strtoupper(substr($hash, 0, 8)); -} - -function attemptLogin($dbh, &$output) { - $hash = null; - if(isset($_REQUEST['user']) || isset($_SESSION['hash_fluv'])) { - if(isset($_REQUEST['user'])) { - $hash = mysqli_real_escape_string($dbh, $_REQUEST['user']); - } else { - $hash = mysqli_real_escape_string($dbh, $_SESSION['hash_fluv']); - } - if(getUserByHash($dbh, $output, $hash) === 1) { - $hash = getMiniHash($output['user_hash']); - $_SESSION['hash_fluv'] = $hash; - if(loadDefaultPreferences($dbh, $output) !== 1) { - fail('Error loading default preferences'); - } - if(loadUserPreferences($dbh, $output, $output['user_id']) !== 1) { - fail('Error loading user preferences'); - } - } else { - $hash = null; - } - } - return $hash; -} - -function getPreference(&$output, $name, $type='string') { - $value = null; - if(isset($output['default_preferences'][$name])) { - $value = $output['default_preferences'][$name]; - } - if(isset($output['user_preferences'][$name])) { - $value = $output['user_preferences'][$name]; - } - if($value !== null) { - if($type === 'int') { - $value = intval($value); - } else if($type === 'float') { - $value = floatval($value); - } - } - return $value; -} - -function isActivated(&$output) { - return getPreference($output, 'email_alerts', 'int') === 1 || getPreference($output, 'email_notifications', 'int') === 1 || getPreference($output, 'email_reminders', 'int') === 1 || getPreference($output, 'email_receipts', 'int') === 1; -} - -function isAdmin(&$output) { - return getPreference($output, '_admin', 'int') === 1; -} - -function allSet() { - foreach(func_get_args() as $arg) { - if(is_array($arg)) { - foreach($arg as $name) { - if(!isset($_REQUEST[$name])) { - return false; - } - } - } else if(!isset($_REQUEST[$arg])) { - return false; - } - } - return true; -} - -function formatEpiweek($epiweek) { - return sprintf('%04dw%02d', floor($epiweek / 100), $epiweek % 100); -} - -function getNumWeeks($year) { - return ($year == 1997 || $year == 2003 || $year == 2008 || $year == 2014) ? 53 : 52; -} - -function getDeltaWeeks($start, $end) { - $x = ($end > $start) ? 1 : -1; - $num = 0; - while($start != $end && $num < 1e3) { - $start = addEpiweeks($start, $x); - $num += $x; - } - return $num; -} - -function addEpiweeks($ew, $i) { - $year = intval($ew / 100); - $week = $ew % 100; - $week += $i; - $limit = getNumWeeks($year); - if($week >= $limit + 1) { - $week -= $limit; - $year += 1; - } else if($week < 1) { - $week += getNumWeeks($year - 1); - $year -= 1; - } - return $year * 100 + $week; -} - -?> diff --git a/site/control.php b/site/control.php deleted file mode 100644 index 098b335..0000000 --- a/site/control.php +++ /dev/null @@ -1,281 +0,0 @@ - - -', $name); -} -function createInput($label, $name, $value='') { - printf('
', $label, $name, $value); -} -function hasSubmission($name) { - return isset($_REQUEST['submit_' . $name]); -} -function getSafeValue($name) { - return mysql_real_escape_string($_REQUEST['input_' . $name]); -} - -// Automation constants -$TASK_SEND_REMINDER_EMAILS = 5; -$TASK_DRY_RUN_FORECAST = 19; -$TASK_SUBMIT_FORECAST = 8; - -if(isAdmin($output)) { -?> -
-
-
- ☢ Warning ☢ -
- These are dangerous settings. -
-
-
- This page allows you to modify Crowdcast's database and to control Crowdcast's scheduled execution. - Invalid inputs can break Crowdcast, or worse. - Be extra cautious. - When in doubt, ask! -
-
-
-
- User Preferences -
- Override user preferences, e.g. admin status. -
-
- $prefValue); - if(saveUserPreferences($dbh, $temp, $temp['user_id'], $preferences) !== 1) { - fail('User found, but unable to save preferences.'); - } else { - success('User preferences have been updated.'); - } - } - } - ?> -
-

- You can view all emails and preference names on the - admin page. There are a few special - preferences that users don't set directly but are very important. - The "_admin" bit determines who can access - the "Admin" and "Control" pages. The "_debug" bit determines - who is excluded from the aggregate forecast (i.e. test accounts or - spammers). The "_delphi" bit is unused, but can be helpful during - post-season analysis. All other - preferences should only be set by the user, unless they - specifically ask us to do so on their behalf. - Don't disable your own admin bit unless you really want to lock - yourself out. -

-
-
-
-
- Crowdcast Settings -
- Update season info, round info, and timing of emails and submission. -
-
- $maxEpiweek) { - fail('First epiweek was not in the season.'); - $ok = false; - } - if($lastEpiweek < $minEpiweek || $lastEpiweek > $maxEpiweek) { - fail('Last epiweek was not in the season.'); - $ok = false; - } - if($lastEpiweek < $firstEpiweek) { - fail('First epiweek was after last epiweek.'); - $ok = false; - } - $temp = array(); - if(!$ok || updateSeason($dbh, $temp, $firstEpiweek, $lastEpiweek) !== 1) { - fail('Unable to update season info.'); - } else { - success('Updated season info.'); - } - } - if(hasSubmission('update_round')) { - $currentEpiweek = intval(getSafeValue('current_contest_round')); - $deadline = getSafeValue('round_deadline'); - $ok = true; - if($currentEpiweek < $minEpiweek || $currentEpiweek > $maxEpiweek) { - fail('Current epiweek was not in the season.'); - $ok = false; - } - $temp = array(); - if(!$ok || updateRound($dbh, $temp, $currentEpiweek, $deadline) !== 1) { - fail('Unable to update round info.'); - } else { - success('Updated round info.'); - } - } - if(hasSubmission('update_tasks')) { - $emailReminders = getSafeValue('email_reminders'); - $dryRunForeast = getSafeValue('dry_run_forecast'); - $submitForecast = getSafeValue('submit_forecast'); - $temp = array(); - if(setTaskDate($dbh, $temp, $TASK_SEND_REMINDER_EMAILS, $emailReminders) !== 1 || - setTaskDate($dbh, $temp, $TASK_DRY_RUN_FORECAST, $dryRunForeast) !== 1 || - setTaskDate($dbh, $temp, $TASK_SUBMIT_FORECAST, $submitForecast) !== 1 - ) { - fail('Unable to update task info.'); - } else { - success('Updated task info.'); - } - } - // get fresh values - if(getEpiweekInfo($dbh, $output) !== 1) { - fail('Unable to get round info.'); - } - if(getYearForCurrentSeason($dbh, $output) !== 1) { - fail('Unable to get season info.'); - } - if(getTaskDate($dbh, $output, $TASK_SEND_REMINDER_EMAILS) !== 1 || - getTaskDate($dbh, $output, $TASK_DRY_RUN_FORECAST) !== 1 || - getTaskDate($dbh, $output, $TASK_SUBMIT_FORECAST) !== 1 - ) { - fail('Unable to get task info.'); - } - ?> -
-

- When new FluView data is scraped, these values determine whether - notification emails are sent and whether scores are generated for - the previous week. See fluv_updater.py. -

-

- The round number (data as-of this issue) determines how user - predictions are saved. Submissions are stored separately each week, - depending on what data was available at the time. This is - incremented automatically when the forecast is submitted. - The deadline is only used in communication with the user and doesn't - have any real effect. The deadline shared with users is actually - this value minus 12 hours (i.e. is this is midnight, then we tell - users the preceding noon). -

-

- These values are the date/time of next execution for the indicated - task. The tasks repeat on an exact interval of - 604,800 seconds, or one week—except when daylight savings time - starts or ends, then one week plus or minus an hour. To effectively - disable Crowdcast, set these far into the future (e.g. 2030). - If you set these values in the past, the - corresponding tasks will be executed immediately. -

-
-
-
-
- Reset for New Season -
- Archive the database for the past season, and create a new database for the coming season. -
-
- $maxEpiweek) { - fail('First epiweek was not in the season.'); - $ok = false; - } - if($lastEpiweek < $minEpiweek || $lastEpiweek > $maxEpiweek) { - fail('Last epiweek was not in the season.'); - $ok = false; - } - if($lastEpiweek < $firstEpiweek) { - fail('First epiweek was after last epiweek.'); - $ok = false; - } - $temp = array(); - if(!$ok || resetEpicast($dbh, $temp, $year1, $firstEpiweek, $lastEpiweek, $deadline, $epicastAdmin) !== 1) { - fail('Unable to reset Crowdcast.'); - } else { - success('Crowdcast has been reset.'); - } - } - ?> -
-

- This effectively wipes the database. All - forecasts and users will be lost. This should only be done once, at - the start of each season. A single user account will be - created— as specified here—and - it'll have the admin and delphi bits set. Note - that the new user ID will be sent to in a normal activation email. - The existing database will be backed up, and a new one will be - created. It is not easy to restore this backup, so make sure you - really, really want to do this. Good luck! -

- This will reset Crowdcast for the season. -

-
-
-
- diff --git a/site/css/.htaccess b/site/css/.htaccess deleted file mode 100644 index a1edbe2..0000000 --- a/site/css/.htaccess +++ /dev/null @@ -1 +0,0 @@ -AddHandler application/x-httpd-php .css \ No newline at end of file diff --git a/site/css/consts.php b/site/css/consts.php deleted file mode 100644 index d047b4f..0000000 --- a/site/css/consts.php +++ /dev/null @@ -1,48 +0,0 @@ - \ No newline at end of file diff --git a/site/css/style.css b/site/css/style.css deleted file mode 100644 index f94841f..0000000 --- a/site/css/style.css +++ /dev/null @@ -1,570 +0,0 @@ - -::selection { - background: #888; -} -a:link { - color: ; - text-decoration: none; - -} -a:visited { - color: ; - text-decoration: none; -} -a:hover { - color: ; - text-decoration: underline; - -} -a:active { - color: ; - text-decoration: underline; -} -a.delphi:link { - color: ; - text-decoration: none; - -} -a.delphi:visited { - color: ; - text-decoration: none; -} -a.delphi:hover { - color: ; - text-decoration: underline; - -} -a.delphi:active { - color: ; - text-decoration: underline; -} -html, body { - min-height: 100%; - margin: 0px; - padding: 0px; - font-size: 100%; -} -body { - height: 100%; - font-family: ; - color: ; - background-color: ; - background-repeat: no-repeat; - background-attachment: fixed; -} -div.box_header { - padding: 0px; - color: ; - border-bottom: 1px solid ; -} -div.box_header_narrow { - width: 100%; - height: 55px; -} -div.box_header_fixed0 { - background-color: ; - z-index: 1; -} -div.box_header_fixed1 { - position: fixed; - top: 0px; - left: 0px; - background-color: ; - z-index: 1; -} -div.box_title { - font-family: ; - font-size: 2em; - font-weight: bold; - text-shadow: 0px 0px 10px ; - letter-spacing: 1px; -} -div.box_title_mega { - font-size: 3em; - padding: 12px; - text-align: center; -} -div.box_title_mini { - padding-top: 4px; - padding-bottom: 4px; - padding-left: 24px; - text-align: left; - display: inline-block; - float: left; -} -div.box_subtitle { - text-align: center; - padding-bottom: 12px; - color: ; - text-shadow: 0px 0px 4px ; -} -div.box_mininav { - color: ; - text-align: right; - font-weight: bold; - padding-top: 4px; - padding-bottom: 4px; - padding-right: 24px; - display: inline-block; - float: right; - text-shadow: 0px 0px 1px ; -} -div.box_miniclear { - clear: both; -} -div.box_content { - padding: 8px; - color: ; - background-color: ; - -} -div.box_footer { - padding: 8px; - color: ; - text-align: center; - font-size: 0.8em; - border-top: 1px solid ; -} -div.box_navigation { - text-align: right; - position: fixed; - top: 4px; - right: 4px; -} -div.box_article { - width: 90%; - margin-left: auto; - margin-right: auto; - color: ; -} -div.box_overlay { - position: fixed; - top: 0px; - left: 0px; - width: 100%; - height: 200%; - background-color: rgba(128, 128, 128, 0.8); - display: none; -} -div.box_dialog { - width: 80%; - max-height: 40%; - overflow: scroll; - margin-left: auto; - margin-right: auto; - margin-top: 5%; - border-radius: 6px; - padding: 15px; - background-color: ; - -} -div.box_button { - text-align: center; - font-weight: bold; - display: inline-block; - min-width: 100px; - height: 20px; - padding: 4px; - margin: 5px; - border-radius: 3px; - color: ; - cursor: pointer; - background-color: ; - - -} -div.box_button:hover { - background-color: ; - -} -div.box_button_icon { - min-width: 0px; -} -div.box_button_disabled { - color: ; - background-color: ; - cursor: progress; -} -div.box_button_disabled:hover { - background-color: ; -} -div.box_cursor_help { - cursor: help; -} -div.box_decision { - display: inline-block; - vertical-align: top; - padding-top: 12px; - padding-bottom: 12px; - padding-left: 24px; - padding-right: 24px; - margin: 8px; - border: 1px solid ; - border-radius: 5px; - -} -div.box_decision:hover { - - -} -div.box_decision_title { - font-size: 1.2em; - font-weight: bold; - display: inline-block; - margin-bottom: 10px; - text-shadow: 0px 0px 1px ; - -} -div.box_section { - padding: 24px; -} -div.box_section_title { - font-size: 2.5em; - font-weight: bold; - text-align: center; - padding: 12px; - margin-bottom: 12px; - color: ; - background-color: ; - text-shadow: 0px 0px 1px ; - -} -div.box_section_subtitle { - font-size: 0.4em; - font-weight: bold; - margin-top: -4px; - padding-bottom: 4px; - color: ; -} -div.box_section_subtitle_alert { - font-size: 0.6em; - font-weight: bold; - margin-top: -4px; - padding-bottom: 4px; - color: #DC143C; -} -div.box_stat { - display: inline-block; - min-width: 200px; -} -div.bot_stat_value { - font-size: 2em; - font-weight: bold; -} -div.bot_stat_description { - margin-top: -6px; - font-size: 0.75em; - font-style: italic; -} -div.box_message { - text-align: center; - font-weight: bold; - border-radius: 5px; - border: 2px solid ; - padding: 8px; - margin-top: 5px; - margin-bottom: 5px; - margin-left: auto; - margin-right: auto; - width: 50%; - -} -div.box_status { - padding: 4px; - border-bottom: 1px solid ; -} -div.box_float_left { - display: inline-block; - float: left; -} -div.box_float_right { - display: inline-block; - float: right; -} -div.box_list { - display: inline-block; - vertical-align: top; -} -div.box_region_completed { - background-color: ; -} -div.box_info { - position: absolute; - display: inline-block; - border-radius: 3px; - padding: 5px; - background-color: ; - font-size: 0.8em; - -} -div.box_region_nav { - display: inline-block; - margin: 2px; - text-align: center; - width: 110px; - height: 110px; - border-radius: 55px; - background: ; - cursor: pointer; - border: 1px solid ; - -} -div.box_region_nav:hover { - -} -div.box_region_nav_complete { - color: #06c; -} -div.box_region_nav_incomplete { - color: #c20; -} -div.box_region_nav_content { - position: relative; - text-shadow: 0px 0px 2px ; -} -div.box_region_nav_content_stack { - position: absolute; - top: 0px; - left: 0px; - width: 110px; - z-index: 0; -} -div.box_status_line { - padding-left: 10px; - padding-right: 10px; - font-weight: bold; - font-size: 1.1em; -} -div.box_region_label { - padding-left: 10px; - padding-top: 5px; - float: left; - font-size: 1.5em; - color: ; - text-shadow: 0px 0px 2px ; -} -div.box_status_info { - padding-right: 10px; - padding-top: 10px; - float: right; -} -div.box_scroll_test { - width: 100%; - height: 100%; -} -div.box_leaderboard { - display: inline-block; - width: 225px; - margin: 50px; - vertical-align: top; - border: 1px solid ; - -} -p { - margin-top: 8px; - margin-bottom: 8px; -} -p.text_title { - font-weight: bold; - font-size: 1.5em; -} -p.text_body { - padding-left: 48px; - padding-right: 48px; -} -span.effect_delphi { - font-family: ; -} -span.effect_fluv { - font-family: ; - font-style: italic; - font-size: 0.9em; - color: ; -} -span.effect_footnote { - font-size: 0.9em; - font-style: italic; -} -span.effect_highlight { - font-weight: bold; - font-size: 1.2em; - color: ; - text-shadow: 0px 0px 2px ; -} -span.effect_tiny_header { - font-weight: normal; - font-size: 0.8em; -} -span.effect_tiny { - font-weight: normal; - font-size: 0.8em; -} -span.effect_italics { - font-style: italic; -} -canvas { - cursor: crosshair; -} -canvas.canvas_drag { - cursor: move; -} -canvas.canvas_button { - cursor: pointer; -} -img.img_flag_large { - width: 55px; - margin-bottom: -8px; -} -img.img_flag_small { - width: 20px; - margin-bottom: -4px; -} -table { - display: inline-table; - margin: 16px; -} -tr:nth-child(2n+1) { - background: ; -} -tr:nth-child(2n) { - background: ; -} -tr.leaderboard:nth-child(2) { - font-weight: bold; - font-size: 1.25em; -} -td { - padding: 4px; - border-bottom: 1px dotted ; -} -th { - padding: 8px; - border: 1px dotted ; - background-color: #ccc; - font-size: 1.2em; -} -input.padded { - margin: 4px; - margin-bottom: 12px; -} -.centered { - text-align: center; -} -.left { - text-align: left; -} -.right { - text-align: right; -} -.any_failure { - color: ; - border-color: ; - background-color: ; -} -.any_success { - color: ; - border-color: ; - background-color: ; -} -.any_neutral { - color: ; - border-color: ; - background-color: ; -} -.any_hidden { - display: none; -} -.any_noselect { - -} -.any_bold { - font-weight: bold; -} -.any_cursor_pointer { - cursor: pointer; -} -.any_extrasmall { - font-size: 0.65em; -} -.any_warning { - font-weight: bold; - color: #c22; -} -#box_main_ui { - margin: 12px; - - -} -#box_canvas { - padding: 0px; - margin: 0px; - vertical-align: top; - display: inline-block; -} -#box_side_bar { - text-align: center; - padding: 0px; - margin: 0px; - margin-left: auto; - margin-right: auto; - vertical-align: top; - display: inline-block; -} -#box_histories { - text-align: left; - width: 142px; - overflow-y: scroll; - padding: 4px; - margin: 0px; - vertical-align: top; - display: block; -} - -img.age_group_img { - height: 65px; - width: auto; -} - -/*** Screen Size Queries ***/ -@media only screen and (max-width: 800px), only screen and (max-device-width: 800px), only screen and (max-height: 400px), only screen and (max-device-height: 400px) { - body { - font-size: 75%; - } - div.box_dialog { - max-height: 30%; - overflow: scroll; - padding: 10px; - } - div.box_title_mini { - padding-top: 0px; - padding-left: 0px; - padding-right: 0px; - padding-bottom: 0px; - display: block; - float: none; - text-align: center; - } - div.box_mininav { - padding-top: 0px; - padding-left: 0px; - padding-right: 0px; - padding-bottom: 3px; - display: block; - float: none; - text-align: center; - } - span.effect_tiny_header { - display: none; - } -} -@media only screen and (max-width: 639px), only screen and (max-device-width: 639px), only screen and (max-height: 250px), only screen and (max-device-height: 250px) { - #box_main_ui { - display: none; - } - #box_nocanvas { - display: block; - } - div.box_leaderboard { - margin: 10px; - } -} diff --git a/site/css/style.php b/site/css/style.php deleted file mode 100644 index d50d355..0000000 --- a/site/css/style.php +++ /dev/null @@ -1,587 +0,0 @@ - -::selection { - background: #888; -} -a:link { - color: ; - text-decoration: none; - -} -a:visited { - color: ; - text-decoration: none; -} -a:hover { - color: ; - text-decoration: underline; - -} -a:active { - color: ; - text-decoration: underline; -} -a.delphi:link { - color: ; - text-decoration: none; - -} -a.delphi:visited { - color: ; - text-decoration: none; -} -a.delphi:hover { - color: ; - text-decoration: underline; - -} -a.delphi:active { - color: ; - text-decoration: underline; -} -html, body { - min-height: 100%; - margin: 0px; - padding: 0px; - font-size: 100%; -} -body { - height: 100%; - font-family: ; - color: ; - background-color: ; - background-repeat: no-repeat; - background-attachment: fixed; -} -div.box_header { - padding: 0px; - color: ; - border-bottom: 1px solid ; -} -div.box_header_narrow { - width: 100%; - height: 55px; -} -div.box_header_fixed0 { - background-color: ; - z-index: 1; -} -div.box_header_fixed1 { - position: fixed; - top: 0px; - left: 0px; - background-color: ; - z-index: 1; -} -div.box_title { - font-family: ; - font-size: 2em; - font-weight: bold; - text-shadow: 0px 0px 10px ; - letter-spacing: 1px; -} -div.box_title_mega { - font-size: 3em; - padding: 12px; - text-align: center; -} -div.box_title_mini { - padding-top: 4px; - padding-bottom: 4px; - padding-left: 24px; - text-align: left; - display: inline-block; - float: left; -} -div.box_subtitle { - text-align: center; - padding-bottom: 12px; - color: ; - text-shadow: 0px 0px 4px ; -} -div.box_mininav { - color: ; - text-align: right; - font-weight: bold; - padding-top: 4px; - padding-bottom: 4px; - padding-right: 24px; - display: inline-block; - float: right; - text-shadow: 0px 0px 1px ; -} -div.box_miniclear { - clear: both; -} -div.box_content { - padding: 8px; - color: ; - background-color: ; - -} -div.box_footer { - padding: 8px; - color: ; - text-align: center; - font-size: 0.8em; - border-top: 1px solid ; -} -div.box_navigation { - text-align: right; - position: fixed; - top: 4px; - right: 4px; -} -div.box_article { - width: 90%; - margin-left: auto; - margin-right: auto; - color: ; -} -div.box_overlay { - position: fixed; - top: 0px; - left: 0px; - width: 100%; - height: 200%; - background-color: rgba(128, 128, 128, 0.8); - display: none; -} -div.box_dialog { - width: 80%; - max-height: 40%; - overflow: scroll; - margin-left: auto; - margin-right: auto; - margin-top: 5%; - border-radius: 6px; - padding: 15px; - background-color: ; - -} -div.box_button { - text-align: center; - font-weight: bold; - display: inline-block; - min-width: 100px; - height: 20px; - padding: 4px; - margin: 5px; - border-radius: 3px; - color: ; - cursor: pointer; - background-color: ; - - -} -div.box_button:hover { - background-color: ; - -} -div.box_button_icon { - min-width: 0px; -} -div.box_button_disabled { - color: ; - background-color: ; - cursor: progress; -} -div.box_button_disabled:hover { - background-color: ; -} -div.box_cursor_help { - cursor: help; -} -div.box_decision { - display: inline-block; - vertical-align: top; - padding-top: 12px; - padding-bottom: 12px; - padding-left: 24px; - padding-right: 24px; - margin: 8px; - border: 1px solid ; - border-radius: 5px; - -} -div.box_decision:hover { - - -} -div.box_decision_title { - font-size: 1.2em; - font-weight: bold; - display: inline-block; - margin-bottom: 10px; - text-shadow: 0px 0px 1px ; - -} -div.box_section { - padding: 24px; -} -div.box_section_title { - font-size: 2.5em; - font-weight: bold; - text-align: center; - padding: 12px; - margin-bottom: 12px; - color: ; - background-color: ; - text-shadow: 0px 0px 1px ; - -} -div.box_section_subtitle { - font-size: 0.4em; - font-weight: bold; - margin-top: -4px; - padding-bottom: 4px; - color: ; -} -div.box_section_subtitle_alert { - font-size: 0.6em; - font-weight: bold; - margin-top: -4px; - padding-bottom: 4px; - color: #DC143C; -} -div.box_stat { - display: inline-block; - min-width: 200px; -} -div.bot_stat_value { - font-size: 2em; - font-weight: bold; -} -div.bot_stat_description { - margin-top: -6px; - font-size: 0.75em; - font-style: italic; -} -div.box_message { - text-align: center; - font-weight: bold; - border-radius: 5px; - border: 2px solid ; - padding: 8px; - margin-top: 5px; - margin-bottom: 5px; - margin-left: auto; - margin-right: auto; - width: 50%; - -} -div.box_status { - padding: 4px; - border-bottom: 1px solid ; -} -div.box_float_left { - display: inline-block; - float: left; -} -div.box_float_right { - display: inline-block; - float: right; -} -div.box_list { - display: inline-block; - vertical-align: top; -} -div.box_region_completed { - background-color: ; -} -div.box_info { - position: absolute; - display: inline-block; - border-radius: 3px; - padding: 5px; - background-color: ; - font-size: 0.8em; - -} -div.box_region_nav { - display: inline-block; - margin: 2px; - text-align: center; - width: 110px; - height: 110px; - border-radius: 55px; - background: ; - cursor: pointer; - border: 1px solid ; - -} -div.box_region_nav:hover { - -} -div.box_region_nav_complete { - color: #06c; -} -div.box_region_nav_incomplete { - color: #c20; -} -div.box_region_nav_content { - position: relative; - text-shadow: 0px 0px 2px ; -} -div.box_region_nav_content_stack { - position: absolute; - top: 0px; - left: 0px; - width: 110px; - z-index: 0; -} -div.box_status_line { - padding-left: 10px; - padding-right: 10px; - font-weight: bold; - font-size: 1.1em; -} -div.box_region_label { - padding-left: 10px; - padding-top: 5px; - float: left; - font-size: 1.5em; - color: ; - text-shadow: 0px 0px 2px ; -} -div.box_status_info { - padding-right: 10px; - padding-top: 10px; - float: right; -} - -div.sidebar_entry i.fa {margin-right:5px} -div.sidebar_region {margin-left:15px} -div.sidebar_region i.fa {margin-right:5px} - -div.box_scroll_test { - width: 100%; - height: 100%; -} -div.box_leaderboard { - display: inline-block; - width: 225px; - margin: 50px; - vertical-align: top; - border: 1px solid ; - -} -p { - margin-top: 8px; - margin-bottom: 8px; -} -p.text_title { - font-weight: bold; - font-size: 1.5em; -} -p.text_body { - padding-left: 48px; - padding-right: 48px; -} -span.effect_delphi { - font-family: ; -} -span.effect_fluv { - font-family: ; - font-style: italic; - font-size: 0.9em; - color: ; -} -span.effect_footnote { - font-size: 0.9em; - font-style: italic; -} -span.effect_highlight { - font-weight: bold; - font-size: 1.2em; - color: ; - text-shadow: 0px 0px 2px ; -} -span.effect_tiny_header { - font-weight: normal; - font-size: 0.8em; -} -span.effect_tiny { - font-weight: normal; - font-size: 0.8em; -} -span.effect_italics { - font-style: italic; -} -canvas { - cursor: crosshair; -} -canvas.canvas_drag { - cursor: move; -} -canvas.canvas_button { - cursor: pointer; -} -img.img_flag_large { - width: 55px; - margin-bottom: -8px; -} -img.img_flag_small { - width: 20px; - margin-bottom: -4px; -} -table { - display: inline-table; - margin: 16px; -} -tr:nth-child(2n+1) { - background: ; -} -tr:nth-child(2n) { - background: ; -} -tr.leaderboard:nth-child(2) { - font-weight: bold; - font-size: 1.25em; -} -td { - padding: 4px; - border-bottom: 1px dotted ; -} -th { - padding: 8px; - border: 1px dotted ; - background-color: #ccc; - font-size: 1.2em; -} -input.padded { - margin: 4px; - margin-bottom: 12px; -} -.centered { - text-align: center; -} -.left { - text-align: left; -} -.right { - text-align: right; -} -.any_failure { - color: ; - border-color: ; - background-color: ; -} -.any_success { - color: ; - border-color: ; - background-color: ; -} -.any_neutral { - color: ; - border-color: ; - background-color: ; -} -.any_hidden { - display: none; -} -.any_noselect { - -} -.any_bold { - font-weight: bold; -} -.any_cursor_pointer { - cursor: pointer; -} -.any_extrasmall { - font-size: 0.65em; -} -.any_warning { - font-weight: bold; - color: #c22; -} -#box_main_ui { - margin: 12px; - - -} -#box_canvas { - padding: 0px; - margin: 0px; - vertical-align: top; - display: inline-block; -} -#box_side_bar { - text-align: center; - padding: 0px; - margin: 0px; - margin-left: auto; - margin-right: auto; - vertical-align: top; - display: inline-block; -} -#box_histories { - text-align: left; - width: 152px; - overflow-y: scroll; - padding: 4px; - margin: 0px; - vertical-align: top; - display: block; -} - -#news li { - list-style-type:none; - padding-top:5px; -} - -#share .social { - text-align: center - } - -img.age_group_img { - height: 65px; - width: auto; -} - -/*** Screen Size Queries ***/ -@media only screen and (max-width: 800px), only screen and (max-device-width: 800px), only screen and (max-height: 400px), only screen and (max-device-height: 400px) { - body { - font-size: 75%; - } - div.box_dialog { - max-height: 30%; - overflow: scroll; - padding: 10px; - } - div.box_title_mini { - padding-top: 0px; - padding-left: 0px; - padding-right: 0px; - padding-bottom: 0px; - display: block; - float: none; - text-align: center; - } - div.box_mininav { - padding-top: 0px; - padding-left: 0px; - padding-right: 0px; - padding-bottom: 3px; - display: block; - float: none; - text-align: center; - } - span.effect_tiny_header { - display: none; - } -} -@media only screen and (max-width: 639px), only screen and (max-device-width: 639px), only screen and (max-height: 250px), only screen and (max-device-height: 250px) { - #box_main_ui { - display: none; - } - #box_nocanvas { - display: block; - } - div.box_leaderboard { - margin: 10px; - } -} diff --git a/site/data/covid19_benchmarks_us.csv b/site/data/covid19_benchmarks_us.csv deleted file mode 100644 index 952b127..0000000 --- a/site/data/covid19_benchmarks_us.csv +++ /dev/null @@ -1,60 +0,0 @@ -State,First,Hundred -Alabama,3/15/20,3/22/20 -Alaska,3/15/20,3/31/20 -American Samoa,, -Arizona,1/28/20,3/23/20 -Arkansas,3/15/20,3/23/20 -California,1/28/20,3/11/20 -Colorado,3/8/20,3/16/20 -Connecticut,3/12/20,3/21/20 -Delaware,3/13/20,3/26/20 -Diamond Princess,3/18/20, -District of Columbia,3/18/20,3/24/20 -Florida,3/4/20,3/18/20 -Georgia,3/5/20,3/18/20 -Grand Princess,3/17/20,3/29/20 -Guam,3/17/20,4/6/20 -Hawaii,3/9/20,3/29/20 -Idaho,3/15/20,3/28/20 -Illinois,1/26/20,3/19/20 -Indiana,3/8/20,3/23/20 -Iowa,3/11/20,3/25/20 -Kansas,3/10/20,3/27/20 -Kentucky,3/8/20,3/24/20 -Louisiana,3/13/20,3/18/20 -Maine,3/14/20,3/25/20 -Maryland,3/8/20,3/21/20 -Massachusetts,2/3/20,3/14/20 -Michigan,3/13/20,3/20/20 -Minnesota,3/8/20,3/22/20 -Mississippi,3/14/20,3/23/20 -Missouri,3/10/20,3/25/20 -Montana,3/15/20,3/29/20 -Nebraska,3/8/20,3/31/20 -Nevada,3/7/20,3/22/20 -New Hampshire,3/4/20,3/25/20 -New Jersey,3/7/20,3/18/20 -New Mexico,3/13/20,3/27/20 -New York,3/4/20,3/10/20 -North Carolina,3/5/20,3/21/20 -North Dakota,3/14/20,4/1/20 -Northern Mariana Islands,4/1/20, -Ohio,3/12/20,3/21/20 -Oklahoma,3/9/20,3/26/20 -Oregon,3/2/20,3/22/20 -Pennsylvania,3/8/20,3/19/20 -Puerto Rico,3/17/20,3/30/20 -Rhode Island,3/3/20,3/25/20 -South Carolina,3/9/20,3/22/20 -South Dakota,3/13/20,4/1/20 -Tennessee,3/7/20,3/21/20 -Texas,3/7/20,3/19/20 -Utah,3/9/20,3/23/20 -Vermont,3/10/20,3/27/20 -Virginia,3/10/20,3/21/20 -Virgin Islands,3/17/20, -Washington,1/24/20,3/9/20 -West Virginia,3/20/20,3/31/20 -Wisconsin,3/12/20,3/20/20 -Wyoming,3/14/20,4/2/20 -National,1/24/20,3/6/20 diff --git a/site/endOfSurvey.php b/site/endOfSurvey.php deleted file mode 100644 index a2ff4aa..0000000 --- a/site/endOfSurvey.php +++ /dev/null @@ -1,26 +0,0 @@ - -
-
Thank you for your input!
- -

- Congratulations! You have reached the end of the survey. We will shortly be reviewing your results. You can now close this window. -

-

- Thank you so much for your contribution to flu forecasting. Stay healthy! -

-
- - diff --git a/site/forecast.php b/site/forecast.php deleted file mode 100644 index 954b039..0000000 --- a/site/forecast.php +++ /dev/null @@ -1,382 +0,0 @@ - explode("/",$data[1]), 'hundred' => explode("/",$data[2])); - break; - } - fclose($covidcases); -} else { printf(""); } - - -// We only want history back to 2009 -$minEpiweek = 200936; - -// ...and we're going forward to wk 41 -$maxEpiweek = 202040; - -//User's previous forecast for this region -$output['forecast'] = &$output['regions'][$regionID]['forecast']; -//Settings -// Crowdcast: always show pandemic -$showPandemic = 1; //getPreference($output, 'advanced_pandemic', 'int'); - -//Calculate a few helpful stats -$firstWeekOfChart = 35; -$currentWeek = $output['epiweek']['round_epiweek']; -if(($currentWeek % 100) >= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = 201936; - -//Nowcast (may or may not be available) -getNowcast($dbh, $output, addEpiweeks($currentWeek, 1), $regionID); - -if(getPreference($output, 'skip_instructions', 'int') !== 1) { - ?> -
-
- How to Enter Your Forecast -
Draw your forecast curve across the chart by clicking and dragging.
-
-
-

-
-    You can draw in one motion the entire trajectory.
-    You can edit any part of your forecast by redrawing just that part.
-    You can adjust a single point by dragging it up or down.
- The animation below demonstrates these actions. - (If you don't see the animation, click here.) -

- -

- -

-
-
- - - -
-
-
-
- - - [] - -
-
- -
-
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
- -
-
-
-
History
- -
-
-
- -
-
- - - - - - - - diff --git a/site/forecast_hosp.php b/site/forecast_hosp.php deleted file mode 100644 index 3bdc09d..0000000 --- a/site/forecast_hosp.php +++ /dev/null @@ -1,1004 +0,0 @@ -= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = $yearStart * 100 + $firstWeekOfChart; -$seasonEnd = ($yearStart + 1) * 100 + ($firstWeekOfChart - 23); -$numPastWeeks = getDeltaWeeks($seasonStart, $currentWeek); -$numFutureWeeks = getDeltaWeeks($currentWeek, $seasonEnd); -$maxAgeGroupRate = 0; -for($i = 0; $i < count($ageGroup['history']['rate']); $i++) { - $epiweek = $ageGroup['history']['date'][$i]; - if($epiweek < 200940 || $epiweek > 201020) { - $maxAgeGroupRate = max($maxAgeGroupRate, $ageGroup['history']['rate'][$i]); - } -} -// print($maxAgeGroupRate); - -max($ageGroup['history']['rate']); -$target = $seasonStart; // 201730 -$seasonOffsets = array(); -$seasonYears = array(); -// print(count($ageGroup['history']['date'])); // 666 -for($i = count($ageGroup['history']['date']) - 1; $i >= 0; $i--) { - if($ageGroup['history']['date'][$i] <= $target) { - array_push($seasonOffsets, $i); - array_push($seasonYears, intval($target / 100)); - $target -= 100; - } -} -if($seasonOffsets[count($seasonOffsets) - 1] != 0) { - array_push($seasonOffsets, 0); - array_push($seasonYears, intval($target / 100)); -} -$seasonOffsets = array_reverse($seasonOffsets); -$seasonYears = array_reverse($seasonYears); -// print (count($seasonYears)); // 14, 2004 ~ now (2018) - -if(getPreference($output, 'skip_instructions', 'int') !== 1) { - ?> -
-
- How to Enter Your Forecast -
Draw your forecast curve across the chart by clicking and dragging.
-
-
-

-
-    You can draw in one motion the entire trajectory.
-    You can edit any part of your forecast by redrawing just that part.
-    You can adjust a single point by dragging it up or down.
- The animation below demonstrates these actions. - (If you don't see the animation, click here.) -

- -

- -

-
-
- - - - - - -
-
-
-
- Forecasting for - - - -
-
- -
-
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
-
-
-
-
History
- - - - -
-   - -
- -
-      -   - Show all -
- - - -
-      - - - - -
- -
-      - - - - - -
- -
-      - - - - - -
- - -
-
-
-
- - - - - diff --git a/site/forecast_hosp_recruitment.php b/site/forecast_hosp_recruitment.php deleted file mode 100644 index f07c70e..0000000 --- a/site/forecast_hosp_recruitment.php +++ /dev/null @@ -1,989 +0,0 @@ -= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = $yearStart * 100 + $firstWeekOfChart; -$seasonEnd = ($yearStart + 1) * 100 + ($firstWeekOfChart - 23); -$numPastWeeks = getDeltaWeeks($seasonStart, $currentWeek); -$numFutureWeeks = getDeltaWeeks($currentWeek, $seasonEnd); -$maxAgeGroupRate = 0; -for($i = 0; $i < count($ageGroup['history']['rate']); $i++) { - $epiweek = $ageGroup['history']['date'][$i]; - if($epiweek < 200940 || $epiweek > 201020) { - $maxAgeGroupRate = max($maxAgeGroupRate, $ageGroup['history']['rate'][$i]); - } -} -// print($maxAgeGroupRate); - -max($ageGroup['history']['rate']); -$target = $seasonStart; // 201730 -$seasonOffsets = array(); -$seasonYears = array(); -// print(count($ageGroup['history']['date'])); // 666 -for($i = count($ageGroup['history']['date']) - 1; $i >= 0; $i--) { - if($ageGroup['history']['date'][$i] <= $target) { - array_push($seasonOffsets, $i); - array_push($seasonYears, intval($target / 100)); - $target -= 100; - } -} -if($seasonOffsets[count($seasonOffsets) - 1] != 0) { - array_push($seasonOffsets, 0); - array_push($seasonYears, intval($target / 100)); -} -$seasonOffsets = array_reverse($seasonOffsets); -$seasonYears = array_reverse($seasonYears); -// print (count($seasonYears)); // 14, 2004 ~ now (2018) - -//if(getPreference($output, 'skip_instructions', 'int') !== 1) { -// ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- Forecasting for - - - -
- -
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
-
-
-
-
History
- - - - -
-   - -
- -
-      -   - Show all -
- - - -
-      - - - - - -
- -
-      - - - - - -
- -
-      - - - - - -
- -
-
-
-
- - - - - diff --git a/site/forecast_mturk.php b/site/forecast_mturk.php deleted file mode 100644 index 4a07f92..0000000 --- a/site/forecast_mturk.php +++ /dev/null @@ -1,1020 +0,0 @@ - - -= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = $yearStart * 100 + $firstWeekOfChart; -$seasonEnd = ($yearStart + 1) * 100 + ($firstWeekOfChart - 1); -$numPastWeeks = getDeltaWeeks($seasonStart, $currentWeek); -$numFutureWeeks = getDeltaWeeks($currentWeek, $seasonEnd); -$maxRegionalWILI = 0; -for($i = 0; $i < count($region['history']['wili']); $i++) { - $epiweek = $region['history']['date'][$i]; - if($showPandemic || $epiweek < 200940 || $epiweek > 201020) { - $maxRegionalWILI = max($maxRegionalWILI, $region['history']['wili'][$i]); - } -} -max($region['history']['wili']); -$target = $seasonStart; -$seasonOffsets = array(); -$seasonYears = array(); -for($i = count($region['history']['date']) - 1; $i >= 0; $i--) { - if($region['history']['date'][$i] <= $target) { - array_push($seasonOffsets, $i); - array_push($seasonYears, intval($target / 100)); - $target -= 100; - } -} -if($seasonOffsets[count($seasonOffsets) - 1] != 0) { - array_push($seasonOffsets, 0); - array_push($seasonYears, intval($target / 100)); -} -$seasonOffsets = array_reverse($seasonOffsets); -$seasonYears = array_reverse($seasonYears); -//$seasonYears = array_slice($seasonYears, 0, count($seasonYears)); - -if(getPreference($output, 'skip_instructions', 'int') !== 1) { - ?> -
-
- How to Enter Your Forecast -
Draw your forecast curve across the chart by clicking and dragging.
-
-
-

-
-    You can draw in one motion the entire trajectory.
-    You can edit any part of your forecast by redrawing just that part.
-    You can adjust a single point by dragging it up or down.
- The animation below demonstrates these actions. - (If you don't see the animation, click here.) -

- -

- -

-
-
- - - -
-
-
-
- - - [] - -
-
- -
-
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
-
-
-
-
History
- - - -
 
-
     Show all
- - -
     - -
- -
     - -
- - - - -
-
- - - - - - - - - - diff --git a/site/forecast_recruitment.php b/site/forecast_recruitment.php deleted file mode 100644 index 4e5bf1d..0000000 --- a/site/forecast_recruitment.php +++ /dev/null @@ -1,1050 +0,0 @@ -= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = $yearStart * 100 + $firstWeekOfChart; -$seasonEnd = ($yearStart + 1) * 100 + ($firstWeekOfChart - 1); -$numPastWeeks = getDeltaWeeks($seasonStart, $currentWeek); -$numFutureWeeks = getDeltaWeeks($currentWeek, $seasonEnd); -$maxRegionalWILI = 0; -for($i = 0; $i < count($region['history']['wili']); $i++) { - $epiweek = $region['history']['date'][$i]; - if($showPandemic || $epiweek < 200940 || $epiweek > 201020) { - $maxRegionalWILI = max($maxRegionalWILI, $region['history']['wili'][$i]); - } -} -max($region['history']['wili']); -$target = $seasonStart; -$seasonOffsets = array(); -$seasonYears = array(); -for($i = count($region['history']['date']) - 1; $i >= 0; $i--) { - if($region['history']['date'][$i] <= $target) { - array_push($seasonOffsets, $i); - array_push($seasonYears, intval($target / 100)); - $target -= 100; - } -} -if($seasonOffsets[count($seasonOffsets) - 1] != 0) { - array_push($seasonOffsets, 0); - array_push($seasonYears, intval($target / 100)); -} -$seasonOffsets = array_reverse($seasonOffsets); -$seasonYears = array_reverse($seasonYears); -//Nowcast (may or may not be available) -//getNowcast($output, addEpiweeks($currentWeek, 1), $regionID); -//if(getPreference($output, 'skip_instructions', 'int') !== 1) { -// ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - [] - -
- - - -
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
-
-
-
-
History
- -
 
- -
     Show all
- -
     - -
- -
     - -
- -
     - -
- -
     - -
- -
     - -
- -
     - -
- -
-
- - - diff --git a/site/forecast_test.php b/site/forecast_test.php deleted file mode 100644 index 63e7e2c..0000000 --- a/site/forecast_test.php +++ /dev/null @@ -1,1029 +0,0 @@ - - -echo("after getRegionsExtended_mturk_pastSeason"); - -= $firstWeekOfChart) { - $yearStart = intval($currentWeek / 100); -} else { - $yearStart = intval($currentWeek / 100) - 1; -} -$seasonStart = $yearStart * 100 + $firstWeekOfChart; -$seasonEnd = ($yearStart + 1) * 100 + ($firstWeekOfChart - 1); -$numPastWeeks = getDeltaWeeks($seasonStart, $currentWeek); -$numFutureWeeks = getDeltaWeeks($currentWeek, $seasonEnd); -$maxRegionalWILI = 0; -for($i = 0; $i < count($region['history']['wili']); $i++) { - $epiweek = $region['history']['date'][$i]; - if($showPandemic || $epiweek < 200940 || $epiweek > 201020) { - $maxRegionalWILI = max($maxRegionalWILI, $region['history']['wili'][$i]); - } -} -max($region['history']['wili']); -$target = $seasonStart; -$seasonOffsets = array(); -$seasonYears = array(); -for($i = count($region['history']['date']) - 1; $i >= 0; $i--) { - if($region['history']['date'][$i] <= $target) { - array_push($seasonOffsets, $i); - array_push($seasonYears, intval($target / 100)); - $target -= 100; - } -} -if($seasonOffsets[count($seasonOffsets) - 1] != 0) { - array_push($seasonOffsets, 0); - array_push($seasonYears, intval($target / 100)); -} -$seasonOffsets = array_reverse($seasonOffsets); -$seasonYears = array_reverse($seasonYears); -//$seasonYears = array_slice($seasonYears, 0, count($seasonYears)); - -if(getPreference($output, 'skip_instructions', 'int') !== 1) { - ?> -
-
- How to Enter Your Forecast -
Draw your forecast curve across the chart by clicking and dragging.
-
-
-

-
-    You can draw in one motion the entire trajectory.
-    You can edit any part of your forecast by redrawing just that part.
-    You can adjust a single point by dragging it up or down.
- The animation below demonstrates these actions. - (If you don't see the animation, click here.) -

- -

- -

-
-
- - - - -
-
-
-
- - - [] - -
-
- -
-
- Draw your forecast by clicking and dragging across the chart below. - -
-
-
-
-
-
-
History
- - - -
 
-
     Show all
- - -
     - -
- -
     - -
- - - - -
-
- - - - - - - - - - diff --git a/site/home.php b/site/home.php deleted file mode 100644 index dd4cfb1..0000000 --- a/site/home.php +++ /dev/null @@ -1,247 +0,0 @@ -Crowdcast is temporarily unavailable. Please check back soon."); -} else { -?> - - - -
- - - -
-
- Post Forecast - -
- Due by 10:00 AM (ET) on . -
- - - -
-
- - - - -
- 0) { - $value = $time['days']; - $unit = 'days' . $unit; - } else if ($time['hours'] > 0) { - $value = $time['days'] * 24 + $time['hours']; - $unit = 'hours' . $unit; - } else if ($time['minutes'] > 0) { - $value = ''; - $unit = 'due very soon'; -// $value = $time['hours'] * 60 + $time['minutes']; -// $unit = 'minutes' . $unit; -// } else if ($time['seconds'] > 0) { -// $value = $time['minutes'] * 60 + $time['seconds']; -// $unit = 'seconds' . $unit; - } else { - $value = ''; - $unit = 'past due'; - } - ?> -
-
-
-
- -
-
-
latest available data
-
-
- = $numRegion) { - $missing = 0; - foreach (get_user_forecast_regions($dbh, $output['user_id']) as $ri) { - if (!$output['regions'][$ri]['completed']) { $missing++; } - } - if ($missing == 0) { - ?> - - -
-
- Nice job, you're finished! -
- But you can still edit your forecasts below! -
-
-
- - - - -

Hover a button above to see which states are in that region or the location of the state in the map below.

-
- - - - - - -
-
- Help Spread The Word -
- Please share Crowdcast with your colleagues, friends, and family! -
-
- - - - -
- - - -
-
- External Resources -
- COVID-19 Information and Data -
-
- -

DELPHI COVID-19 and ILI Data Sources - spreadsheet updated continually

-
- - -
-
- - diff --git a/site/images/flags/ages_1.png b/site/images/flags/ages_1.png deleted file mode 100644 index e067c39..0000000 Binary files a/site/images/flags/ages_1.png and /dev/null differ diff --git a/site/images/flags/ages_2.png b/site/images/flags/ages_2.png deleted file mode 100644 index 0ef2cca..0000000 Binary files a/site/images/flags/ages_2.png and /dev/null differ diff --git a/site/images/flags/ages_3.png b/site/images/flags/ages_3.png deleted file mode 100644 index 16a1448..0000000 Binary files a/site/images/flags/ages_3.png and /dev/null differ diff --git a/site/images/flags/ages_4.png b/site/images/flags/ages_4.png deleted file mode 100644 index 864f59e..0000000 Binary files a/site/images/flags/ages_4.png and /dev/null differ diff --git a/site/images/flags/ages_5.jpeg b/site/images/flags/ages_5.jpeg deleted file mode 100644 index 4577562..0000000 Binary files a/site/images/flags/ages_5.jpeg and /dev/null differ diff --git a/site/images/flags/ages_5.png b/site/images/flags/ages_5.png deleted file mode 100644 index 4577562..0000000 Binary files a/site/images/flags/ages_5.png and /dev/null differ diff --git a/site/images/flags/ages_6.png b/site/images/flags/ages_6.png deleted file mode 100644 index dbfd15e..0000000 Binary files a/site/images/flags/ages_6.png and /dev/null differ diff --git a/site/images/flags/icon_01.png b/site/images/flags/icon_01.png deleted file mode 100644 index c0158fd..0000000 Binary files a/site/images/flags/icon_01.png and /dev/null differ diff --git a/site/images/flags/icon_02.png b/site/images/flags/icon_02.png deleted file mode 100644 index 1a8b29c..0000000 Binary files a/site/images/flags/icon_02.png and /dev/null differ diff --git a/site/images/flags/icon_03.png b/site/images/flags/icon_03.png deleted file mode 100644 index cf8ed02..0000000 Binary files a/site/images/flags/icon_03.png and /dev/null differ diff --git a/site/images/flags/icon_04.png b/site/images/flags/icon_04.png deleted file mode 100644 index 475dcbb..0000000 Binary files a/site/images/flags/icon_04.png and /dev/null differ diff --git a/site/images/flags/icon_05.png b/site/images/flags/icon_05.png deleted file mode 100644 index 567226d..0000000 Binary files a/site/images/flags/icon_05.png and /dev/null differ diff --git a/site/images/flags/icon_06.png b/site/images/flags/icon_06.png deleted file mode 100644 index 6ebe75b..0000000 Binary files a/site/images/flags/icon_06.png and /dev/null differ diff --git a/site/images/flags/icon_07.png b/site/images/flags/icon_07.png deleted file mode 100644 index 71a0cd8..0000000 Binary files a/site/images/flags/icon_07.png and /dev/null differ diff --git a/site/images/flags/icon_08.png b/site/images/flags/icon_08.png deleted file mode 100644 index 8651ea4..0000000 Binary files a/site/images/flags/icon_08.png and /dev/null differ diff --git a/site/images/flags/icon_09.png b/site/images/flags/icon_09.png deleted file mode 100644 index 71faaff..0000000 Binary files a/site/images/flags/icon_09.png and /dev/null differ diff --git a/site/images/flags/icon_10.png b/site/images/flags/icon_10.png deleted file mode 100644 index e86b931..0000000 Binary files a/site/images/flags/icon_10.png and /dev/null differ diff --git a/site/images/flags/icon_11.png b/site/images/flags/icon_11.png deleted file mode 100644 index b0336d9..0000000 Binary files a/site/images/flags/icon_11.png and /dev/null differ diff --git a/site/images/flags/icon_12.png b/site/images/flags/icon_12.png deleted file mode 100644 index c6da292..0000000 Binary files a/site/images/flags/icon_12.png and /dev/null differ diff --git a/site/images/flags/icon_13.png b/site/images/flags/icon_13.png deleted file mode 100644 index 09d7b66..0000000 Binary files a/site/images/flags/icon_13.png and /dev/null differ diff --git a/site/images/flags/icon_14.png b/site/images/flags/icon_14.png deleted file mode 100644 index 63c1fbe..0000000 Binary files a/site/images/flags/icon_14.png and /dev/null differ diff --git a/site/images/flags/icon_15.png b/site/images/flags/icon_15.png deleted file mode 100644 index 996476a..0000000 Binary files a/site/images/flags/icon_15.png and /dev/null differ diff --git a/site/images/flags/icon_16.png b/site/images/flags/icon_16.png deleted file mode 100644 index 76a9efa..0000000 Binary files a/site/images/flags/icon_16.png and /dev/null differ diff --git a/site/images/flags/icon_17.png b/site/images/flags/icon_17.png deleted file mode 100644 index 5ef6ba3..0000000 Binary files a/site/images/flags/icon_17.png and /dev/null differ diff --git a/site/images/flags/icon_18.png b/site/images/flags/icon_18.png deleted file mode 100644 index 1052250..0000000 Binary files a/site/images/flags/icon_18.png and /dev/null differ diff --git a/site/images/flags/icon_19.png b/site/images/flags/icon_19.png deleted file mode 100644 index 146b0f4..0000000 Binary files a/site/images/flags/icon_19.png and /dev/null differ diff --git a/site/images/flags/icon_20.png b/site/images/flags/icon_20.png deleted file mode 100644 index d7d880d..0000000 Binary files a/site/images/flags/icon_20.png and /dev/null differ diff --git a/site/images/flags/icon_21.png b/site/images/flags/icon_21.png deleted file mode 100644 index 29ef58a..0000000 Binary files a/site/images/flags/icon_21.png and /dev/null differ diff --git a/site/images/flags/icon_22.png b/site/images/flags/icon_22.png deleted file mode 100644 index a9c4948..0000000 Binary files a/site/images/flags/icon_22.png and /dev/null differ diff --git a/site/images/flags/icon_23.png b/site/images/flags/icon_23.png deleted file mode 100644 index 88f4ed4..0000000 Binary files a/site/images/flags/icon_23.png and /dev/null differ diff --git a/site/images/flags/icon_24.png b/site/images/flags/icon_24.png deleted file mode 100644 index 589562c..0000000 Binary files a/site/images/flags/icon_24.png and /dev/null differ diff --git a/site/images/flags/icon_25.png b/site/images/flags/icon_25.png deleted file mode 100644 index b661edd..0000000 Binary files a/site/images/flags/icon_25.png and /dev/null differ diff --git a/site/images/flags/icon_26.png b/site/images/flags/icon_26.png deleted file mode 100644 index a2ce1e3..0000000 Binary files a/site/images/flags/icon_26.png and /dev/null differ diff --git a/site/images/flags/icon_27.png b/site/images/flags/icon_27.png deleted file mode 100644 index 4a072cd..0000000 Binary files a/site/images/flags/icon_27.png and /dev/null differ diff --git a/site/images/flags/icon_28.png b/site/images/flags/icon_28.png deleted file mode 100644 index ee00e46..0000000 Binary files a/site/images/flags/icon_28.png and /dev/null differ diff --git a/site/images/flags/icon_29.png b/site/images/flags/icon_29.png deleted file mode 100644 index 02bc12c..0000000 Binary files a/site/images/flags/icon_29.png and /dev/null differ diff --git a/site/images/flags/icon_31.png b/site/images/flags/icon_31.png deleted file mode 100644 index 148298f..0000000 Binary files a/site/images/flags/icon_31.png and /dev/null differ diff --git a/site/images/flags/icon_32.png b/site/images/flags/icon_32.png deleted file mode 100644 index ad83424..0000000 Binary files a/site/images/flags/icon_32.png and /dev/null differ diff --git a/site/images/flags/icon_33.png b/site/images/flags/icon_33.png deleted file mode 100644 index dcae361..0000000 Binary files a/site/images/flags/icon_33.png and /dev/null differ diff --git a/site/images/flags/icon_34.png b/site/images/flags/icon_34.png deleted file mode 100644 index c2e8c8c..0000000 Binary files a/site/images/flags/icon_34.png and /dev/null differ diff --git a/site/images/flags/icon_35.png b/site/images/flags/icon_35.png deleted file mode 100644 index 620c350..0000000 Binary files a/site/images/flags/icon_35.png and /dev/null differ diff --git a/site/images/flags/icon_36.png b/site/images/flags/icon_36.png deleted file mode 100644 index 63e11d8..0000000 Binary files a/site/images/flags/icon_36.png and /dev/null differ diff --git a/site/images/flags/icon_37.png b/site/images/flags/icon_37.png deleted file mode 100644 index 5a3bcb8..0000000 Binary files a/site/images/flags/icon_37.png and /dev/null differ diff --git a/site/images/flags/icon_38.png b/site/images/flags/icon_38.png deleted file mode 100644 index e308c42..0000000 Binary files a/site/images/flags/icon_38.png and /dev/null differ diff --git a/site/images/flags/icon_39.png b/site/images/flags/icon_39.png deleted file mode 100644 index 3101d01..0000000 Binary files a/site/images/flags/icon_39.png and /dev/null differ diff --git a/site/images/flags/icon_40.png b/site/images/flags/icon_40.png deleted file mode 100644 index 41a0d0b..0000000 Binary files a/site/images/flags/icon_40.png and /dev/null differ diff --git a/site/images/flags/icon_41.png b/site/images/flags/icon_41.png deleted file mode 100644 index 4546993..0000000 Binary files a/site/images/flags/icon_41.png and /dev/null differ diff --git a/site/images/flags/icon_42.png b/site/images/flags/icon_42.png deleted file mode 100644 index 57a6ba8..0000000 Binary files a/site/images/flags/icon_42.png and /dev/null differ diff --git a/site/images/flags/icon_43.png b/site/images/flags/icon_43.png deleted file mode 100644 index 959d757..0000000 Binary files a/site/images/flags/icon_43.png and /dev/null differ diff --git a/site/images/flags/icon_44.png b/site/images/flags/icon_44.png deleted file mode 100644 index 1944ea9..0000000 Binary files a/site/images/flags/icon_44.png and /dev/null differ diff --git a/site/images/flags/icon_45.png b/site/images/flags/icon_45.png deleted file mode 100644 index c011265..0000000 Binary files a/site/images/flags/icon_45.png and /dev/null differ diff --git a/site/images/flags/icon_46.png b/site/images/flags/icon_46.png deleted file mode 100644 index 5f9f0e2..0000000 Binary files a/site/images/flags/icon_46.png and /dev/null differ diff --git a/site/images/flags/icon_47.png b/site/images/flags/icon_47.png deleted file mode 100644 index 2754ec3..0000000 Binary files a/site/images/flags/icon_47.png and /dev/null differ diff --git a/site/images/flags/icon_48.png b/site/images/flags/icon_48.png deleted file mode 100644 index 8f98d29..0000000 Binary files a/site/images/flags/icon_48.png and /dev/null differ diff --git a/site/images/flags/icon_49.png b/site/images/flags/icon_49.png deleted file mode 100644 index 9be80ea..0000000 Binary files a/site/images/flags/icon_49.png and /dev/null differ diff --git a/site/images/flags/icon_50.png b/site/images/flags/icon_50.png deleted file mode 100644 index 356bb33..0000000 Binary files a/site/images/flags/icon_50.png and /dev/null differ diff --git a/site/images/flags/icon_51.png b/site/images/flags/icon_51.png deleted file mode 100644 index 9b2a431..0000000 Binary files a/site/images/flags/icon_51.png and /dev/null differ diff --git a/site/images/flags/icon_52.png b/site/images/flags/icon_52.png deleted file mode 100644 index d8b04df..0000000 Binary files a/site/images/flags/icon_52.png and /dev/null differ diff --git a/site/images/flags/icon_53.png b/site/images/flags/icon_53.png deleted file mode 100644 index eeb6b9b..0000000 Binary files a/site/images/flags/icon_53.png and /dev/null differ diff --git a/site/images/flags/icon_54.png b/site/images/flags/icon_54.png deleted file mode 100644 index f8464e8..0000000 Binary files a/site/images/flags/icon_54.png and /dev/null differ diff --git a/site/images/flags/icon_55.png b/site/images/flags/icon_55.png deleted file mode 100644 index 4f84f9c..0000000 Binary files a/site/images/flags/icon_55.png and /dev/null differ diff --git a/site/images/flags/icon_56.png b/site/images/flags/icon_56.png deleted file mode 100644 index a95e4d7..0000000 Binary files a/site/images/flags/icon_56.png and /dev/null differ diff --git a/site/images/flags/icon_57.png b/site/images/flags/icon_57.png deleted file mode 100644 index 7b95d37..0000000 Binary files a/site/images/flags/icon_57.png and /dev/null differ diff --git a/site/images/flags/icon_58.png b/site/images/flags/icon_58.png deleted file mode 100644 index ba5dc35..0000000 Binary files a/site/images/flags/icon_58.png and /dev/null differ diff --git a/site/images/flags/icon_59.png b/site/images/flags/icon_59.png deleted file mode 100644 index 9878170..0000000 Binary files a/site/images/flags/icon_59.png and /dev/null differ diff --git a/site/images/flags/icon_60.png b/site/images/flags/icon_60.png deleted file mode 100644 index 5f0cdf9..0000000 Binary files a/site/images/flags/icon_60.png and /dev/null differ diff --git a/site/images/flags/icon_61.png b/site/images/flags/icon_61.png deleted file mode 100644 index 39e2f3d..0000000 Binary files a/site/images/flags/icon_61.png and /dev/null differ diff --git a/site/images/flags/icon_62.png b/site/images/flags/icon_62.png deleted file mode 100644 index 78b60e2..0000000 Binary files a/site/images/flags/icon_62.png and /dev/null differ diff --git a/site/images/flags/icon_63.png b/site/images/flags/icon_63.png deleted file mode 100644 index 53ab01d..0000000 Binary files a/site/images/flags/icon_63.png and /dev/null differ diff --git a/site/images/flags/icon_64.png b/site/images/flags/icon_64.png deleted file mode 100644 index 02616a9..0000000 Binary files a/site/images/flags/icon_64.png and /dev/null differ diff --git a/site/images/flags/icon_65.png b/site/images/flags/icon_65.png deleted file mode 100644 index 45679c2..0000000 Binary files a/site/images/flags/icon_65.png and /dev/null differ diff --git a/site/images/tutorial.gif b/site/images/tutorial.gif deleted file mode 100644 index 10492b2..0000000 Binary files a/site/images/tutorial.gif and /dev/null differ diff --git a/site/images/tutorial.mp4 b/site/images/tutorial.mp4 deleted file mode 100644 index bf20bb9..0000000 Binary files a/site/images/tutorial.mp4 and /dev/null differ diff --git a/site/index.php b/site/index.php deleted file mode 100644 index f360d98..0000000 --- a/site/index.php +++ /dev/null @@ -1,66 +0,0 @@ - - -
-
-

- Check out the leaderboards! -

- -
- -

- Please double-check your ID and try again. -
- Lost your ID? Click here to have it sent to you. -

- -
Existing Users
-
-

- Enter your User ID to continue: -
- -

-
- -

 

New Users

Sign up here!

- -
- -
-
Click to Continue
-

- Welcome back! -

- - -
- -
-
- \ No newline at end of file diff --git a/site/js/.htaccess b/site/js/.htaccess deleted file mode 100644 index cf6ce55..0000000 --- a/site/js/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Header set Cache-Control must-revalidate \ No newline at end of file diff --git a/site/js/delphi_epidata.js b/site/js/delphi_epidata.js deleted file mode 100644 index d71e58f..0000000 --- a/site/js/delphi_epidata.js +++ /dev/null @@ -1,453 +0,0 @@ -// Generated by CoffeeScript 1.12.3 - -/* -A module for DELPHI's Epidata API. - -https://github.com/cmu-delphi/delphi-epidata - -Notes: - - If running in node.js (or using browserify), there are no external - dependencies. Otherwise, a global jQuery object named `$` must be available. - */ - -(function() { - var Epidata, https, querystring; - - if ((typeof $ !== "undefined" && $ !== null ? $.getJSON : void 0) == null) { - https = require('https'); - querystring = require('querystring'); - } - - Epidata = (function() { - var BASE_URL, _list, _listitem, _request; - - function Epidata() {} - - BASE_URL = 'https://delphi.midas.cs.cmu.edu/epidata/api.php'; - - _listitem = function(value) { - if (value.hasOwnProperty('from') && value.hasOwnProperty('to')) { - return value['from'] + "-" + value['to']; - } else { - return "" + value; - } - }; - - _list = function(values) { - var value; - if (!Array.isArray(values)) { - values = [values]; - } - return ((function() { - var i, len, results; - results = []; - for (i = 0, len = values.length; i < len; i++) { - value = values[i]; - results.push(_listitem(value)); - } - return results; - })()).join(','); - }; - - _request = function(callback, params) { - var handler, reader; - handler = function(data) { - if ((data != null ? data.result : void 0) != null) { - return callback(data.result, data.message, data.epidata); - } else { - return callback(0, 'unknown error', null); - } - }; - if ((typeof $ !== "undefined" && $ !== null ? $.getJSON : void 0) != null) { - return $.getJSON(BASE_URL, params, handler); - } else { - reader = function(response) { - var text; - text = ''; - response.setEncoding('utf8'); - response.on('data', function(chunk) { - return text += chunk; - }); - response.on('error', function(e) { - return error(e.message); - }); - return response.on('end', function() { - return handler(JSON.parse(text)); - }); - }; - return https.get(BASE_URL + "?" + (querystring.stringify(params)), reader); - } - }; - - Epidata.range = function(from, to) { - var ref; - if (to <= from) { - ref = [to, from], from = ref[0], to = ref[1]; - } - return { - from: from, - to: to - }; - }; - - Epidata.fluview = function(callback, regions, epiweeks, issues, lag, auth) { - var params; - if (!((regions != null) && (epiweeks != null))) { - throw { - msg: '`regions` and `epiweeks` are both required' - }; - } - if ((issues != null) && (lag != null)) { - throw { - msg: '`issues` and `lag` are mutually exclusive' - }; - } - params = { - 'source': 'fluview', - 'regions': _list(regions), - 'epiweeks': _list(epiweeks) - }; - if (issues != null) { - params.issues = _list(issues); - } - if (lag != null) { - params.lag = lag; - } - if (auth != null) { - params.auth = auth; - } - return _request(callback, params); - }; - - Epidata.fluview_clinical = function(callback, regions, epiweeks, issues, lag) { - var params; - if (!((regions != null) && (epiweeks != null))) { - throw { - msg: '`regions` and `epiweeks` are both required' - }; - } - if ((issues != null) && (lag != null)) { - throw { - msg: '`issues` and `lag` are mutually exclusive' - }; - } - params = { - 'source': 'fluview_clinical', - 'regions': _list(regions), - 'epiweeks': _list(epiweeks) - }; - if (issues != null) { - params.issues = _list(issues); - } - if (lag != null) { - params.lag = lag; - } - return _request(callback, params); - }; - - Epidata.flusurv = function(callback, locations, epiweeks, issues, lag) { - var params; - if (!((locations != null) && (epiweeks != null))) { - throw { - msg: '`locations` and `epiweeks` are both required' - }; - } - if ((issues != null) && (lag != null)) { - throw { - msg: '`issues` and `lag` are mutually exclusive' - }; - } - params = { - 'source': 'flusurv', - 'locations': _list(locations), - 'epiweeks': _list(epiweeks) - }; - if (issues != null) { - params.issues = _list(issues); - } - if (lag != null) { - params.lag = lag; - } - return _request(callback, params); - }; - - Epidata.gft = function(callback, locations, epiweeks) { - var params; - if (!((locations != null) && (epiweeks != null))) { - throw { - msg: '`locations` and `epiweeks` are both required' - }; - } - params = { - 'source': 'gft', - 'locations': _list(locations), - 'epiweeks': _list(epiweeks) - }; - return _request(callback, params); - }; - - Epidata.ght = function(callback, auth, locations, epiweeks, query) { - var params; - if (!((auth != null) && (locations != null) && (epiweeks != null) && (query != null))) { - throw { - msg: '`auth`, `locations`, `epiweeks`, and `query` are all required' - }; - } - params = { - 'source': 'ght', - 'auth': auth, - 'locations': _list(locations), - 'epiweeks': _list(epiweeks), - 'query': query - }; - return _request(callback, params); - }; - - Epidata.twitter = function(callback, auth, locations, dates, epiweeks) { - var params; - if (!((auth != null) && (locations != null))) { - throw { - msg: '`auth` and `locations` are both required' - }; - } - if (!((dates != null) ^ (epiweeks != null))) { - throw { - msg: 'exactly one of `dates` and `epiweeks` is required' - }; - } - params = { - 'source': 'twitter', - 'auth': auth, - 'locations': _list(locations) - }; - if (dates != null) { - params.dates = _list(dates); - } - if (epiweeks != null) { - params.epiweeks = _list(epiweeks); - } - return _request(callback, params); - }; - - Epidata.wiki = function(callback, articles, dates, epiweeks, hours) { - var params; - if (articles == null) { - throw { - msg: '`articles` is required' - }; - } - if (!((dates != null) ^ (epiweeks != null))) { - throw { - msg: 'exactly one of `dates` and `epiweeks` is required' - }; - } - params = { - 'source': 'wiki', - 'articles': _list(articles) - }; - if (dates != null) { - params.dates = _list(dates); - } - if (epiweeks != null) { - params.epiweeks = _list(epiweeks); - } - if (hours != null) { - params.hours = _list(hours); - } - return _request(callback, params); - }; - - Epidata.cdc = function(callback, auth, epiweeks, locations) { - var params; - if (!((auth != null) && (epiweeks != null) && (locations != null))) { - throw { - msg: '`auth`, `epiweeks`, and `locations` are all required' - }; - } - params = { - 'source': 'cdc', - 'auth': auth, - 'epiweeks': _list(epiweeks), - 'locations': _list(locations) - }; - return _request(callback, params); - }; - - Epidata.quidel = function(callback, auth, epiweeks, locations) { - var params; - if (!((auth != null) && (epiweeks != null) && (locations != null))) { - throw { - msg: '`auth`, `epiweeks`, and `locations` are all required' - }; - } - params = { - 'source': 'quidel', - 'auth': auth, - 'epiweeks': _list(epiweeks), - 'locations': _list(locations) - }; - return _request(callback, params); - }; - - Epidata.norostat = function(callback, auth, location, epiweeks) { - var params; - if (!((auth != null) && (location != null) && (epiweeks != null))) { - throw { - msg: '`auth`, `location`, and `epiweeks` are all required' - }; - } - params = { - 'source': 'norostat', - 'auth': auth, - 'location': location, - 'epiweeks': _list(epiweeks) - }; - return _request(callback, params); - }; - - Epidata.meta_norostat = function(callback, auth) { - var params; - if (auth == null) { - throw { - msg: '`auth` is required' - }; - } - params = { - 'source': 'meta_norostat', - 'auth': auth - }; - return _request(callback, params); - }; - - Epidata.afhsb = function(callback, auth, locations, epiweeks, flu_types) { - var params; - if (!((auth != null) && (locations != null) && (epiweeks != null) && (flu_types != null))) { - throw { - msg: '`auth`, `locations`, `epiweeks` and `flu_types` are all required' - }; - } - params = { - 'source': 'afhsb', - 'auth': auth, - 'locations': _list(locations), - 'epiweeks': _list(epiweeks), - 'flu_types': _list(flu_types) - }; - return _request(callback, params); - }; - - Epidata.meta_afhsb = function(callback, auth) { - var params; - if (auth == null) { - throw { - msg: '`auth` is required' - }; - } - params = { - 'source': 'meta_afhsb', - 'auth': auth - }; - return _request(callback, params); - }; - - Epidata.nidss_flu = function(callback, regions, epiweeks, issues, lag) { - var params; - if (!((regions != null) && (epiweeks != null))) { - throw { - msg: '`regions` and `epiweeks` are both required' - }; - } - if ((issues != null) && (lag != null)) { - throw { - msg: '`issues` and `lag` are mutually exclusive' - }; - } - params = { - 'source': 'nidss_flu', - 'regions': _list(regions), - 'epiweeks': _list(epiweeks) - }; - if (issues != null) { - params.issues = _list(issues); - } - if (lag != null) { - params.lag = lag; - } - return _request(callback, params); - }; - - Epidata.nidss_dengue = function(callback, locations, epiweeks) { - var params; - if (!((locations != null) && (epiweeks != null))) { - throw { - msg: '`locations` and `epiweeks` are both required' - }; - } - params = { - 'source': 'nidss_dengue', - 'locations': _list(locations), - 'epiweeks': _list(epiweeks) - }; - return _request(callback, params); - }; - - Epidata.delphi = function(callback, system, epiweek) { - var params; - if (!((system != null) && (epiweek != null))) { - throw { - msg: '`system` and `epiweek` are both required' - }; - } - params = { - 'source': 'delphi', - 'system': system, - 'epiweek': epiweek - }; - return _request(callback, params); - }; - - Epidata.sensors = function(callback, auth, names, locations, epiweeks) { - var params; - if (!((auth != null) && (names != null) && (locations != null) && (epiweeks != null))) { - throw { - msg: '`auth`, `names`, `locations`, and `epiweeks` are all required' - }; - } - params = { - 'source': 'sensors', - 'auth': auth, - 'names': _list(names), - 'locations': _list(locations), - 'epiweeks': _list(epiweeks) - }; - return _request(callback, params); - }; - - Epidata.nowcast = function(callback, locations, epiweeks) { - var params; - if (!((locations != null) && (epiweeks != null))) { - throw { - msg: '`locations` and `epiweeks` are both required' - }; - } - params = { - 'source': 'nowcast', - 'locations': _list(locations), - 'epiweeks': _list(epiweeks) - }; - return _request(callback, params); - }; - - Epidata.meta = function(callback) { - return _request(callback, { - 'source': 'meta' - }); - }; - - return Epidata; - - })(); - - (typeof exports !== "undefined" && exports !== null ? exports : window).Epidata = Epidata; - -}).call(this); diff --git a/site/js/forecast.js b/site/js/forecast.js deleted file mode 100644 index 9ab10ef..0000000 --- a/site/js/forecast.js +++ /dev/null @@ -1,888 +0,0 @@ -//x-axis -function getChartWidth() { - return canvas.width - marginLeft() - marginRight(); -} -function getX(epiweek, season) { - if (season) { - epiweek = epiweek + 100*(currentSeason - season); - } - var ew = epiweekToDecimal(epiweek); - var left = epiweekToDecimal(xRange[0]); - var right = epiweekToDecimal(xRange[1]); - return marginLeft() + (getChartWidth() / (right - left)) * (ew - left); -} -function getEpiweek(x) { - var left = epiweekToDecimal(xRange[0]); - var right = epiweekToDecimal(xRange[1]); - var ew = (x - marginLeft()) * ((right - left) / getChartWidth()) + left; - return decimalToEpiweek(ew); -} -//y-axis -function getChartHeight() { - return canvas.height - marginTop() - marginBottom(); -} -function getY(i) { - return (canvas.height - marginBottom()) - (getChartHeight() / (yRange[1] - yRange[0])) * (i - yRange[0]); -} -function getIncidence(y) { - return (-y + (canvas.height - marginBottom())) * ((yRange[1] - yRange[0]) / getChartHeight()) + yRange[0]; -} -//utilities -function getGraphics() { - var g = $('#canvas')[0].getContext('2d'); - //some browsers don't support dashed lines - see http://www.rgraph.net/blog/2013/january/html5-canvas-dashed-lines.html#examples - if(!g.setLineDash){g.setLineDash = function(x){}} - return g; -} -var Align = { - left: 0, - right: 1, - bottom: 2, - top: 3, - center: 4 -}; -function findPoint(region, epiweek, interp) { - var year = Math.floor(epiweek/100); - if (epiweek % 100 < seasonDefn[1]) { year--; } - var season = curves[region].season[year]; - // we usually are finding something near the end, so start - // there and work backwards - // (if we ever need true random-access, convert this to binary search) - for (var i = season.end; i >= season.start; i--) { - var point = curves[region].data[i]; - if (point.epiweek == epiweek) { - return point; - } - if (point.epiweek < epiweek && interp) { - return point; - } - } - return false; -} -function drawText(g, str, x, y, angle, alignX, alignY, scale, font) { - scale = typeof scale !== 'undefined' ? scale : 1; - font = typeof font !== 'undefined' ? font : ['', 'Calibri']; - var size = Math.round(12 * scale * uiScale); - g.font = font[0] + ' ' + size + 'px ' + font[1]; - var w = g.measureText(str).width; - var h = size; - var dx = 0; - var dy = 0; - if(alignX == Align.left) { - dx = 0; - } else if(alignX == Align.right) { - dx = -w; - } else if(alignX == Align.center) { - dx = -w / 2; - } else { - g.strokeStyle = '#ff0000'; - } - if(alignY == Align.bottom) { - dy = 0; - } else if(alignY == Align.top) { - dy = h; - } else if(alignY == Align.center) { - dy = h / 2; - } else { - g.strokeStyle = '#ff0000'; - } - g.save(); - g.translate(x, y); - g.rotate(angle); - g.fillText(str, dx, dy); - g.restore(); - return {x: x + dx, y: y + dy - h, w: w, h: h}; -} -function drawLine(x1, y1, x2, y2, style) { - var g = getGraphics(); - g.strokeStyle = style.color; - g.lineWidth = style.size * uiScale; - g.setLineDash(style.dash); - g.beginPath(); - g.moveTo(x1, y1); - g.lineTo(x2, y2); - g.stroke(); - g.setLineDash([]); -} -function drawPoints(xs, ys, style, g) { - if (typeof g == 'undefined') { - var g = getGraphics(); - g.strokeStyle = style.color; - g.lineWidth = style.size * uiScale; - g.setLineDash([]); - } - g.lineWidth = 3 * style.size * uiScale; - for(var i = 0; i < xs.length; i++) { - if(ys[i] >= 0) { - g.beginPath(); - var x = getX(xs[i]); - var y = getY(ys[i]); - g.moveTo(x, y); - g.lineTo(x + 1, y); - g.stroke(); - } - } -} - -function drawCurveData(curve, style, do_drawPoints, season, key) { - if (typeof season == "undefined") { - season = currentSeason; - } - if (typeof key == "undefined") { - key = "wili"; - } - var g = getGraphics(); - g.strokeStyle = style.color; - g.lineWidth = style.size * uiScale; - g.setLineDash(style.dash); - g.beginPath(); - var first = true; - for(var i = 0; i < curve.length; i++) { - if (curve[i][key] < 0) { continue; } - var x = getX(curve[i].epiweek, season); - var y = getY(curve[i][key]); - if(first) { - first = false; - g.moveTo(x, y); - } else { - g.lineTo(x, y); - } - - } - g.stroke(); - if(do_drawPoints) { - g.setLineDash([]); - drawPoints(curve.map(function (item) { return item.epiweek; }), - curve.map(function (item) { return item[key]; }), - style, g); - } -} - -function drawCurve(curve, start, end, epiweekOffset, style) { - var g = getGraphics(); - g.strokeStyle = style.color; - g.lineWidth = style.size * uiScale; - g.setLineDash(style.dash); - g.beginPath(); - var first = true; - var epiweek = addEpiweeks(xRange[0], epiweekOffset); - for(var i = start; i < end; i++) { - if(curve[i] >= 0) { - var x = getX(epiweek); - var y = getY(curve[i]); - if(first) { - first = false; - g.moveTo(x, y); - } else { - g.lineTo(x, y); - } - } - epiweek = addEpiweeks(epiweek, 1); - } - g.stroke(); - g.setLineDash([]); - if(DRAW_POINTS) drawPoints(curve, start, end, epiweekOffset, style, g); -} -function drawCurveXY(xs, ys, start, end, style) { - var g = getGraphics(); - g.strokeStyle = style.color; - g.lineWidth = style.size * uiScale; - g.setLineDash(style.dash); - g.beginPath(); - var first = true; - for(var i = start; i < end; i++) { - if(ys[i] >= 0) { - var x = getX(modulusEpiweek(xs[i])); - var y = getY(ys[i]); - if(first) { - first = false; - g.moveTo(x, y); - } else { - g.lineTo(x, y); - } - } - } - g.stroke(); - g.setLineDash([]); - if(DRAW_POINTS) drawPoints(xs, ys, start, end, style, g); -} -function stitchCurves(rid, style, y2, xoffset) { - if(forecast[0] < 0) { - return; - } - if (typeof y2 == "undefined") { - y2 = getY(forecast[0]); - } - if (typeof xoffset == "undefined") { - xoffset = 1; - - } - - var seasonIndex = seasonIndices[2019]; - var seasonLength = seasonOffsets[seasonIndex+1] - seasonOffsets[seasonIndex]; - var x1 = getX(addEpiweeks(xRange[0], seasonLength - 1)); - var y1 = getY(pastWili[seasonOffsets[seasonIndex + 1] - 1]); - var x2 = getX(addEpiweeks(currentWeek, xoffset)); - drawLine(x1, y1, x2, y2, style); -} -function drawTooltip(g, str) { - str = ' ' + str; - var cx = getChartWidth() / 2; - var cy = getChartHeight() / 2; - var bt = drawText(g, str, cx, cy, 0, Align.center, Align.center, 1.5); - var bi = drawText(g, "\uf05a", bt.x, cy, 0, Align.right, Align.center, 1.5, ['', 'FontAwesome']); - var padding = 6; - var border = 3; - g.fillStyle = '#000'; - g.fillRect(bi.x - padding - border, bt.y - padding - border, bi.w + bt.w + 2 * (padding + border), bt.h + 2 * (padding + border)); - g.fillStyle = '#fff'; - g.fillRect(bi.x - padding, bt.y - padding, bi.w + bt.w + 2 * padding, bt.h + 2 * padding); - g.fillStyle = '#000'; - drawText(g, str, cx, cy, 0, Align.center, Align.center, 1.5); - drawText(g, "\uf05a", bt.x, cy, 0, Align.right, Align.center, 1.5, ['', 'FontAwesome']); -} -function getStyle(region, season) { - var ret; - - if (region==regionID && season==currentSeason) { - ret = {color: '#000', size: 2, dash: [], alpha: 1}; - } else if (region.startsWith("hhs")) { - ret = {color: '#66f', size: 1, dash: [], alpha: 0.4}; - } else if (season==2009) { //pandemic - ret = {color: '#666', size: 1, dash: [], alpha: 0.4}; - } else { - ret = {color: '#aaa', size: 0.5, dash: [], alpha: 0.4}; - } - - if (hoverCurve(region,season)) { - ret.size++; - } - - return ret; -} -function repaint() { - var g = getGraphics(); - //clear the canvas - g.clearRect(0, 0, canvas.width, canvas.height); - g.fillStyle = '#fff'; - g.fillRect(0, 0, canvas.width, canvas.height); - //past/future - var weekX = getX(currentWeek + 0.5); - var x1 = getX(xRange[0]); - var x2 = getX(xRange[1]); - var y1 = getY(yRange[0]); - var y2 = getY(yRange[1]); - var scale_y0 = 0; - var scale_y1 = 0; - //past - g.fillStyle = '#eee'; - g.fillRect(x1, y2, weekX - x1, y1 - y2); - g.fillStyle = '#888'; - drawText(g, '< past', weekX - 15, y2, 0, Align.right, Align.top); - //future - g.fillStyle = '#fff'; - g.fillRect(weekX, y2, x2 - weekX, y1 - y2); - g.fillStyle = '#888'; - drawText(g, 'future >', weekX + 15, y2, 0, Align.left, Align.top); - //axis styles - g.lineCap = 'round'; - g.fillStyle = '#000'; - g.lineWidth = 1 * uiScale; - //y-axis - { - var row1 = 12.5 * uiScale; - var row2 = marginLeft() - 12.5 * uiScale; - scale_y0 = getY(yRange[0]); - scale_y1 = getY(yRange[0]+yInterval); - var scale = scale_y0 - scale_y1; - //ticks and lines - for(var incidence = yRange[0]; incidence <= yRange[1]; incidence += yInterval) { - var y = getY(incidence); - drawText(g, '' + incidence, row2, y, 0, Align.right, Align.center); - drawLine(marginLeft() - TICK_SIZE, y, marginLeft() - 1, y, AXIS_STYLE); - drawLine(getX(xRange[0]), y, getX(xRange[1]), y, GRID_STYLE); - } - //label - drawText(g, LABEL_Y, row1 - 8 * uiScale, canvas.height / 2, -Math.PI / 2, Align.center, Align.center, 1.5, ['bold', 'Calibri']); - //drawText(g, "(% of all doctors’ office visits that involve flu-like symptoms)", row1 + 7 * uiScale, canvas.height / 2, -Math.PI / 2, Align.center, Align.center, 1.5, ['', 'Calibri']); - - //zoom controls - var x = 16 * uiScale; - var dy = BUTTON_SIZE * uiScale; - zoomUpBounds = drawText(g, "\uf151", x, y2, 0, Align.center, Align.top, 2, ['', 'FontAwesome']); - zoomDownBounds = drawText(g, "\uf150", x, y2 + dy, 0, Align.center, Align.top, 2, ['', 'FontAwesome']); - } - //x-axis - { - var row1 = 0.75 * (marginBottom() / 3); - var row2 = 1.75 * (marginBottom() / 3); - var row3 = 2.5 * (marginBottom() / 3); - var axisY = canvas.height - marginBottom(); - //pandemic season - //ticks - var skip = 0; - for(var epiweek = xRange[0]; epiweek <= xRange[1]; epiweek = addEpiweeks(epiweek, 1)) { - var x = getX(epiweek); - if(skip == 0) { - drawText(g, 'w' + (epiweek % 100), x, canvas.height - row3, 0, Align.center, Align.center); - } - skip = (skip + 1) % xInterval; - drawLine(x, axisY + TICK_SIZE, x, axisY + 1, AXIS_STYLE); - } - //months - var on = true; - var decStart = epiweekToDecimal(xRange[0]-1); - var decEnd = epiweekToDecimal(xRange[1]); - // run through the year twice so we get everybody no matter how long our current season goes on - for (var si = 0; si<2; si++) { - for (var li=0; li decEnd || x2 < decStart) { - continue; - } - x1 = decimalToFEpiweek(max(decStart,x1)); - x2 = decimalToFEpiweek(min(decEnd,x2)); - - // skip truncated months that are too short for their label - if (x2-x1<1.5) { continue; } - - x1 = getX(x1); - x2 = getX(x2); - y1 = canvas.height - row3 + row2/4; - oldFillStyle=g.fillStyle; - g.fillStyle = on ? '#eee' : '#fff'; on = !on; - g.fillRect(x1, y1, x2-x1, row2/2); - g.fillStyle = oldFillStyle; - - drawText(g, label, 0.5*(x1 + x2), canvas.height - row2, 0, Align.center, Align.center); - } - } - //label - drawText(g, LABEL_X, canvas.width / 2, canvas.height - row1, 0, Align.center, Align.center, 1.5, ['bold', 'Calibri']); - } - - //covid-19 benchmarks - oldFillStyle=g.fillStyle; - if (covidBenchmarks.first) { - covid_1 = getX(decimalToFEpiweek(covidBenchmarks.first*1.)); // first cases - drawLine(covid_1, getY(yRange[0]), covid_1, getY(yRange[1]), {color:"#F00", size:0.5, dash:[], alpha:0.4}); - g.fillStyle="#600"; - drawText(g, "First COVID-19 case in "+benchmarksName+" ->", covid_1 - 10, marginTop() + 36*uiScale, 0, Align.right, Align.top); - } - if (covidBenchmarks.hundred) { - covid_100 = getX(decimalToFEpiweek(covidBenchmarks.hundred*1.)); // 100 cases - drawLine(covid_100, getY(yRange[0]), covid_100, getY(yRange[1]), {color:"#F00", size:1.5, dash:[], alpha:0.4}); - g.fillStyle="#600"; - drawText(g, "<- 100 cases in "+benchmarksName, covid_100 + 10, marginTop() + 36*uiScale, 0, Align.left, Align.top); - } - g.fillStyle=oldFillStyle; - - //other regions or past seasons - function repaintSeason(r, s, do_drawPoints) { - if (typeof s == "undefined") { - i = r; - var r = selectedSeasons[i][0]; - var s = selectedSeasons[i][1]; - do_drawPoints = false; - } - var style = getStyle(r, s); //curveStyles[r][s]; - - if (typeof curves[r] == "undefined") { - console.log("repaint:",r,"not yet available"); - return; - } - drawCurveData( - curves[r].data.slice( - curves[r].season[s].start, - curves[r].season[s].end+1), style, do_drawPoints, s); - } - for(var i = 0; i < selectedSeasons.length; i++) { - var isCurrentSeason = (selectedSeasons[i][1] == 2019); - if(selectedSeasons[i][0] == regionID && isCurrentSeason) { - // Skip the current region's latest season - // so it can be plotted on top of everything else - continue; - } - repaintSeason(i); - } - - var lfStyle = {color: '#aaa', size: 2, dash: DASH_STYLE}; - var style = {color: '#000', size: 2, dash: DASH_STYLE}; - if (regionID in curves) { - //last forecast - - if(showLastForecast) { - // shift x axis by 30 weeks. - // drawCurve(lastForecast, 0, lastForecast.length, totalWeeks - lastForecast.length, lfStyle); - drawCurveData([findPoint(regionID, curves.lastForecast[0].epiweek -1)].concat(curves.lastForecast), lfStyle, true); - - //stitchCurves(regionID, lfStyle, getY(lastForecast[0]), 0); - } - - //current region and latest season - repaintSeason(regionID, 2019, true); - //var start = seasonOffsets[seasonOffsets.length - 1]; - //var end = Math.min(pastWili.length, start + totalWeeks); - //drawCurve(pastWili, start, end, 0, style); - //drawCurve(forecast, 0, 52, numPastWeeks + 1, style); - drawCurveData([findPoint(regionID, currentWeek, true)].concat(curves.forecast), style, true); - //stitchCurves(regionID, style); - } - - //nowcast - if(showNowcast) { - g.fillStyle = 'rgba(0, 0, 0, 0.5)'; - var epiweek = addEpiweeks(currentWeek, 1); - var x = getX(epiweek); - var y1 = getY(nowcast[0] - 2 * nowcast[1]); - var y2 = getY(nowcast[0] + 2 * nowcast[1]); - g.fillRect(x - 2, y1, 5, y2 - y1); - y1 = getY(nowcast[0] - 1 * nowcast[1]); - y2 = getY(nowcast[0] + 1 * nowcast[1]); - g.fillRect(x - 4, y1, 9, y2 - y1); - y1 = getY(nowcast[0]); - g.fillRect(x - 5, y1, 11, 1); - } - - //error bars // what the actual what is this??? -kmm - var errors = { - 'nat':[-0.24705835, 0.26585897, -0.15209838, 0.19588030, -0.12080783, 0.14845500, -0.10822840, 0.13591350, -0.10105576, 0.11903400], - 'hhs1':[-0.37140890, 0.28183701, -0.22718089, 0.22283626, -0.17166020, 0.15932419, -0.15244192, 0.13857609, -0.13520489, 0.12653161], - 'hhs2':[-0.53510369, 0.89618800, -0.29194798, 0.65376200, -0.13691200, 0.53989966, -0.12287200, 0.46070700, -0.07438098, 0.41997600], - 'hhs3':[-0.37340794, 0.40633099, -0.28260333, 0.17494332, -0.22924145, 0.12111835, -0.18220829, 0.09744193, -0.15922900, 0.08408102], - 'hhs4':[-0.20515699, 0.30015400, -0.11709100, 0.25312400, -0.08401870, 0.22570893, -0.06906100, 0.20316300, -0.06395200, 0.17931200], - 'hhs5':[-0.25007300, 0.20134411, -0.13535207, 0.12399100, -0.13027507, 0.10968548, -0.12658071, 0.09060300, -0.12210600, 0.09081896], - 'hhs6':[-0.57142423, 0.64259200, -0.26681298, 0.44821271, -0.17997876, 0.42294960, -0.18924163, 0.40526105, -0.18486160, 0.41010436], - 'hhs7':[-0.31905190, 0.53929610, -0.28534067, 0.25807903, -0.18014395, 0.17609501, -0.09770261, 0.15003601, -0.06749161, 0.11253900], - 'hhs8':[-0.34997449, 0.16271156, -0.30672299, 0.11085698, -0.28115293, 0.08104906, -0.24976742, 0.07652170, -0.27224423, 0.07954395], - 'hhs9':[-1.35720500, 0.36575900, -0.83282601, 0.33934500, -0.57508135, 0.29297430, -0.25338298, 0.25961193, -0.22189758, 0.23839696], - 'hhs10':[-0.27577982, 0.67580001, -0.13440096, 0.51631755, -0.08888274, 0.42762205, -0.08109139, 0.37271498, -0.05693280, 0.26734400] - }; - - if (errors.hasOwnProperty(regionID) && curves.hasOwnProperty(regionID)) { - var end = curves[regionID].season[currentSeason].end; - // the first error bar is for the most recent data available on the current season - var epiweek = curves[regionID].data[end].epiweek; // was: currentWeek; - var error = errors[regionID]; - for (var i=0; i<9; i = i + 2) { - var currentSeasonIndex = end - i/2; - var above = -error[i]*scale; - var below = error[i+1]*scale; - var x_weekNumber = addEpiweeks(epiweek, -(i/2)); - var x = getX(x_weekNumber); - var y = getY(curves[regionID].data[currentSeasonIndex].wili); - g.fillStyle = 'rgba(0, 0, 0, 0.5)'; - var bar_width = 5; - g.fillRect(x-(bar_width/2.), y-above, bar_width, above); - g.fillRect(x-(bar_width/2.), y, bar_width, below); - } - } - - //legend - var x1 = canvas.width - marginRight(); - var x2 = canvas.width - marginRight() - (15 * uiScale); - var dy = 12 * uiScale; - var y = marginTop() + dy; - var labelBounds = drawText(g, 'Your Forecast, Last Week', x2 - 3, y, 0, Align.right, Align.center); - drawLine(x1, y - 3, x2, y + 3, lfStyle); - g.fillStyle = '#000'; - showLastBounds = drawText(g, showLastForecast ? "\uf046" : "\uf096", labelBounds.x - 5 * uiScale, y, 0, Align.right, Align.center, 1.25, ['', 'FontAwesome']); - snapLastBounds = drawText(g, "\uf08d", showLastBounds.x - 5 * uiScale, y, 0, Align.right, Align.center, 1.25, ['', 'FontAwesome']); - y += dy; - drawText(g, 'Your Forecast, This Week', x2 - 3, y, 0, Align.right, Align.center); - drawLine(x1, y - 3, x2, y + 3, style); // NB style still contains DASH STYLE from drawing the forecast curve above - y += dy; - drawText(g, regionName + ', ' + Math.round(xRange[0] / 100) + '+', x2 - 3, y, 0, Align.right, Align.center); - style.dash = []; - drawLine(x1, y - 3, x2, y + 3, style); - - // error bar legend - if (errors.hasOwnProperty(regionID)) { - // error bar legend - drawText(g, '90% Confidence Interval', x2 - 3, y+25, 0, Align.right, Align.center); - g.fillStyle = 'rgba(0, 0, 0, 0.5)'; - g.fillRect(x2+5, y+10, 5, 35); - } - - //tooltip - if(tooltip != null) { - drawTooltip(g, tooltip); - } -} -//more utilities -function getNumWeeks(year) { - return (year == 1997 || year == 2003 || year == 2008 || year == 2014) ? 53 : 52; -} -function getDeltaWeeks(start, end) { - var x = (end > start) ? 1 : -1; - var num = 0; - while(start != end && num < 1e3) { - start = addEpiweeks(start, x); - num += x; - } - return num; -} -function addEpiweeks(ew, i) { - var year = Math.floor(ew / 100); - var week = ew % 100; - week += i; - var limit = getNumWeeks(year); - if(week >= limit + 1) { - week -= limit; - year += 1; - } else if(week < 1) { - week += getNumWeeks(year - 1); - year -= 1; - } - return year * 100 + week; -} -function modulusEpiweek(ew) { - var startingWeek = xRange[0] % 100; - var weekOffset = (ew % 100) - startingWeek; - if (weekOffset < 0) weekOffset = weekOffset + 100; - return xRange[0] + weekOffset; -} -function epiweekToDecimal(ew) { - var year = Math.floor(ew / 100); - var week = ew % 100; - return year + (week - 1) / getNumWeeks(year); -} -function decimalToFEpiweek(yr) { - yr += 0.5 / 52; - var year = Math.floor(yr); - var wk = yr - year; - var week = wk * getNumWeeks(year); - return year * 100 + week; -} -function decimalToEpiweek(yr) { - yr += 0.5 / 52; - var year = Math.floor(yr); - var wk = yr - year; - var week = Math.floor(wk * getNumWeeks(year)) + 1; - return year * 100 + week; -} -function animate() { - repaint(); - if(dragging) { - requestAnimationFrame(animate); - } else { - repaint(); - } -} -function adjustForecast(x, y) { - var epiweek = getEpiweek(x); - if(epiweek > currentWeek && epiweek <= xRange[1]) { - var wili = Math.min(yRange[1], Math.max(yRange[0], getIncidence(y))); - var point = {'epiweek':epiweek, 'wili':wili}; - curves.forecast[getDeltaWeeks(currentWeek, epiweek) - 1] = point; - if(lastDrag != null && epiweek != lastDrag.epiweek) { - var direction = (epiweek > lastDrag.epiweek) ? 1 : -1; - for(var i = addEpiweeks(lastDrag.epiweek, direction); i != epiweek; i = addEpiweeks(i, direction)) { - curves.forecast[getDeltaWeeks(currentWeek, i) - 1] = {'epiweek':i, 'wili':point.wili}; - } - } - lastDrag = point;//{epiweek: epiweek, wili: wili}; - modified = true; - } else { - lastDrag = null; - } -} -function contains(bounds, point) { - var x1 = bounds.x; - var x2 = bounds.x + bounds.w; - var y1 = bounds.y; - var y2 = bounds.y + bounds.h; - return (point.x >= x1 && point.x <= x2 && point.y >= y1 && point.y <= y2); -} -//user interaction -function mouseDown(m) { - tooltip = null; - if(contains(zoomUpBounds, m)) { - zoom(1 / ZOOM_AMOUNT); - } else if(contains(zoomDownBounds, m)) { - zoom(ZOOM_AMOUNT); - //} else if(contains(undoBounds, m)) { - // undo(); - //} else if(contains(redoBounds, m)) { - // redo(); - } else if(contains(showLastBounds, m)) { - showLastForecast = !showLastForecast; - repaint(); - } else if(contains(snapLastBounds, m)) { - if(confirm('Are you sure you want to reset your current forecast to your previous forecast?')) { - snapToLastForecast(); - } - } else { - $('#canvas').addClass('canvas_drag'); - adjustForecast(m.x, m.y); - dragging = true; - animate(); - } -} -function mouseUp(m) { - $('#canvas').removeClass('canvas_drag'); - if(dragging) { - dragging = false; - lastDrag = null; - if(modified) { - ++modifyCounter; - setTimeout(submitForecastDelayed, AUTOSAVE_INTERVAL * 1000); - } - modified = false; - } -} -function mouseMove(m) { - //Drawing ecast - if(dragging) { - adjustForecast(m.x, m.y); - return; - } - //Interacting with a button - var buttons = [ - { - bounds: zoomUpBounds, - tooltip: 'Decrease the scale of the Y axis. (Zoom in.)', - },{ - bounds: zoomDownBounds, - tooltip: 'Increase the scale of the Y axis. (Zoom out.)', - },{ - bounds: showLastBounds, - tooltip: 'Show or hide your forecast from last week.', - },{ - bounds: snapLastBounds, - tooltip: 'Pin your current forecast to your forecast from last week.', - }, - ]; - //Find out which button (if any) - var hb = null; - tooltip = null; - for(var i = 0; i < buttons.length; i++) { - if(contains(buttons[i].bounds, m)) { - hb = buttons[i].bounds; - tooltip = buttons[i].tooltip; - break; - } - } - //Update if the hovered button has changed - if(hoveringButton != hb) { - if(hoveringButton != null && hb == null) { - //back to the normal cursor - $('#canvas').removeClass('canvas_button'); - } else if(hoveringButton == null && hb != null) { - //use the button cursor - $('#canvas').addClass('canvas_button'); - } - hoveringButton = hb; - repaint(); - } -} -function mousePosition(e) { - if(e.type.toLowerCase().indexOf('touch') == 0) { - e = e.originalEvent.changedTouches[0]; - } - var canvas = $('#canvas'); - return { - x: e.pageX - canvas.offset().left, - y: e.pageY - canvas.offset().top - }; -} -function zoom(scale) { - yRange[1] = Math.min(WILI_MAX, Math.max(WILI_MIN, yRange[1] * scale)); - repaint(); -} -function submitForecastDelayed() { - ++submitCounter; - if(modifyCounter == submitCounter && !dragging) { - //No modifications in the last AUTOSAVE_INTERVAL seconds - submitForecast(false); - } -} -function submitForecast(commit) { - if(commit && $('#button_submit').hasClass('box_button_disabled')) { - return; - } - var foundZero = false; - var f = []; - for(var i = 0; i < 52; i++) { - if (!curves.forecast[i]) { continue; } - if (curves.forecast[i].wili == 0) { - foundZero = curves.forecast[i].epiweek; - break; - } - f[i] = curves.forecast[i].wili; - } - if(commit) { - if(foundZero) { - alert('Some points are still at zero (for '+Math.floor(foundZero/100)+' w'+foundZero%100+'; maybe others). Please double check your forecast and try again.'); - return; - } - timeoutID = setTimeout(submitTimeout, 10000); - submitStatus = SubmitStatus.sent; - updateStatus(); - $('#button_submit').addClass('box_button_disabled'); - } - var params = { - 'action': commit ? 'forecast' : 'autosave', - 'hash': userHash, - 'region_id': regionNo, - 'f[]': f, - }; - $.get("api.php", params, handleResponse, 'json'); -} -function updateStatus() { - $('#box_status').removeClass('any_success any_failure any_neutral'); - if(submitStatus == SubmitStatus.sent) { - $('#status_icon').html(''); - $('#status_message').html('Uploading forecast...'); - $('#box_status').addClass('any_neutral'); - } else if(submitStatus == SubmitStatus.success) { - $('#status_icon').html(''); - $('#status_message').html('Forecast submitted successfully!'); - $('#box_status').addClass('any_success'); - //Move to the next missing region, or go home - submit('forecast'); - } else if(submitStatus == SubmitStatus.failure) { - $('#status_icon').html(''); - $('#status_message').html('Uh oh, something went wrong. Please try again later.'); - $('#box_status').addClass('any_failure'); - } -} -//other events -function submitTimeout() { - handleResponse({result: 0, action: 'forecast'}); -} -function handleResponse(data) { - if(data.action != 'forecast') { - //don't really care what the result was unless it has to do with the submit forecast button - return; - } - clearTimeout(timeoutID); - //$('#stat_completed').removeClass(); - $('#button_submit').removeClass('box_button_disabled'); - if(data.result == 1) { - //$('#stat_completed').addClass('any_success'); - //$('#stat_completed').html('Submitted'); - submitStatus = SubmitStatus.success; - } else { - submitStatus = SubmitStatus.failure; - } - updateStatus(); -} -function resize() { - //Find the right fit for the canvas - var w = $('body').innerWidth() - $('#box_histories').width() - 48; - var h = $(window).height(); - w = Math.floor(w - 24); - h = Math.floor((h - (56 + 24 + 47 + 24 + 33)) * 0.98); - //Get the drawing scale - uiScale = ((w * 2 + h * 1) / 3) / 1000; - //Apply the resize - canvas.width = w; - canvas.height = h; - $('#box_canvas').width(w); - $('#box_canvas').height(h); - $('#box_side_bar').height(h); - $('#box_histories').height(h - 8); - //Finally, repaint the canvas - repaint(); -} -function hoverCurve(rid, season) { - return curves[rid] - && curves[rid].season - && curves[rid].season[season] - && curves[rid].season[season].hover; -} -function hoverCurveOn(rid, season) { - curves[rid].season[season].hover = true; - repaint(); -} -function hoverCurveOff(rid, season) { - curves[rid].season[season].hover = false; - repaint(); -} -function toggleSeasonList(rid) { - var closedClass = 'fa-plus-square-o'; - var openedClass = 'fa-minus-square-o'; - var checkbox = $('#checkbox_region_' + rid); - if(checkbox.hasClass(closedClass)) { - //Expand region - checkbox.removeClass(closedClass); - checkbox.addClass(openedClass); - $('#container_' + rid + '_all').removeClass('any_hidden'); - } else { - //Shrink region - checkbox.removeClass(openedClass); - checkbox.addClass(closedClass); - $('#container_' + rid + '_all').addClass('any_hidden'); - } - repaint(); -} -function toggleAllSeasons(rid) { - var uncheckedClass = 'fa-square-o'; - var checkedClass = 'fa-check-square-o'; - var checkbox = $('#checkbox_' + rid + '_all'); - if(checkbox.hasClass(uncheckedClass)) { - //Enable history - checkbox.removeClass(uncheckedClass); - checkbox.addClass(checkedClass); - for(var season in curves[rid].season) { - if($('#checkbox_' + rid + '_' + season).hasClass(uncheckedClass)) { - toggleSeason(rid, season); - } - } - } else { - //Disable history - checkbox.removeClass(checkedClass); - checkbox.addClass(uncheckedClass); - for(var season in curves[rid].season) { - if($('#checkbox_' + rid + '_' + season).hasClass(checkedClass)) { - toggleSeason(rid, season); - } - } - } - repaint(); -} -function toggleSeason(rid, seasonID) { - var uncheckedClass = 'fa-square-o'; - var checkedClass = 'fa-check-square-o'; - var checkbox = $('#checkbox_' + rid + '_' + seasonID); - if(checkbox.hasClass(uncheckedClass)) { - //Enable history - checkbox.removeClass(uncheckedClass); - checkbox.addClass(checkedClass); - selectedSeasons.push([rid, seasonID]); - } else { - //Disable history - checkbox.removeClass(checkedClass); - checkbox.addClass(uncheckedClass); - var index = -1; - for(var i = 0; i < selectedSeasons.length; i++) { - if(selectedSeasons[i][0] == rid && selectedSeasons[i][1] == seasonID) { - index = i; - break; - } - } - if(index > -1) { - selectedSeasons.splice(index, 1); - } - } - repaint(); -} -function snapToLastForecast() { - var extra = curves.lastForecast.length - curves.forecast.length; - for(var i = 0; i < Math.min(curves.forecast.length, curves.lastForecast.length - extra); i++) { - curves.forecast[i] = curves.lastForecast[i + extra]; - } - repaint(); - ++modifyCounter; - setTimeout(submitForecastDelayed, AUTOSAVE_INTERVAL * 1000); - modified = false; -} - - diff --git a/site/js/mustache.min.js b/site/js/mustache.min.js deleted file mode 100644 index 4369a58..0000000 --- a/site/js/mustache.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=global||self,global.Mustache=factory())})(this,function(){"use strict";var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}function primitiveHasOwnProperty(primitive,propName){return primitive!=null&&typeof primitive!=="object"&&primitive.hasOwnProperty&&primitive.hasOwnProperty(propName)}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var lineHasNonSpace=false;var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;var indentation="";var tagIndex=0;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i"){token=[type,value,start,scanner.pos,indentation,tagIndex,lineHasNonSpace]}else{token=[type,value,start,scanner.pos]}tagIndex++;tokens.push(token);if(type==="#"||type==="^"){sections.push(token)}else if(type==="/"){openSection=sections.pop();if(!openSection)throw new Error('Unopened section "'+value+'" at '+start);if(openSection[1]!==value)throw new Error('Unclosed section "'+openSection[1]+'" at '+start)}else if(type==="name"||type==="{"||type==="&"){nonSpace=true}else if(type==="="){compileTags(value)}}stripSpace();openSection=sections.pop();if(openSection)throw new Error('Unclosed section "'+openSection[1]+'" at '+scanner.pos);return nestTokens(squashTokens(tokens))}function squashTokens(tokens){var squashedTokens=[];var token,lastToken;for(var i=0,numTokens=tokens.length;i values - tolerance) { - return value - rem + values; - } - } - return value; - }; - - - var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { - return function () { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); - }; - })(/[xy]/g, function (c) { - var r = math.random() * 16 | 0, - v = c == "x" ? r : (r & 3 | 8); - return v.toString(16); - }); - - - R.setWindow = function (newwin) { - eve("setWindow", R, g.win, newwin); - g.win = newwin; - g.doc = g.win.document; - if (initWin) { - initWin(g.win); - } - }; - var toHex = function (color) { - if (R.vml) { - // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ - var trim = /^\s+|\s+$/g; - var bod; - try { - var docum = new ActiveXObject("htmlfile"); - docum.write(""); - docum.close(); - bod = docum.body; - } catch(e) { - bod = createPopup().document.body; - } - var range = bod.createTextRange(); - toHex = cacher(function (color) { - try { - bod.style.color = Str(color).replace(trim, E); - var value = range.queryCommandValue("ForeColor"); - value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); - return "#" + ("000000" + value.toString(16)).slice(-6); - } catch(e) { - return "none"; - } - }); - } else { - var i = g.doc.createElement("i"); - i.title = "Rapha\xebl Colour Picker"; - i.style.display = "none"; - g.doc.body.appendChild(i); - toHex = cacher(function (color) { - i.style.color = color; - return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); - }); - } - return toHex(color); - }, - hsbtoString = function () { - return "hsb(" + [this.h, this.s, this.b] + ")"; - }, - hsltoString = function () { - return "hsl(" + [this.h, this.s, this.l] + ")"; - }, - rgbtoString = function () { - return this.hex; - }, - prepareRGB = function (r, g, b) { - if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { - b = r.b; - g = r.g; - r = r.r; - } - if (g == null && R.is(r, string)) { - var clr = R.getRGB(r); - r = clr.r; - g = clr.g; - b = clr.b; - } - if (r > 1 || g > 1 || b > 1) { - r /= 255; - g /= 255; - b /= 255; - } - - return [r, g, b]; - }, - packageRGB = function (r, g, b, o) { - r *= 255; - g *= 255; - b *= 255; - var rgb = { - r: r, - g: g, - b: b, - hex: R.rgb(r, g, b), - toString: rgbtoString - }; - R.is(o, "finite") && (rgb.opacity = o); - return rgb; - }; - - - R.color = function (clr) { - var rgb; - if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { - rgb = R.hsb2rgb(clr); - clr.r = rgb.r; - clr.g = rgb.g; - clr.b = rgb.b; - clr.hex = rgb.hex; - } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { - rgb = R.hsl2rgb(clr); - clr.r = rgb.r; - clr.g = rgb.g; - clr.b = rgb.b; - clr.hex = rgb.hex; - } else { - if (R.is(clr, "string")) { - clr = R.getRGB(clr); - } - if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { - rgb = R.rgb2hsl(clr); - clr.h = rgb.h; - clr.s = rgb.s; - clr.l = rgb.l; - rgb = R.rgb2hsb(clr); - clr.v = rgb.b; - } else { - clr = {hex: "none"}; - crl.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; - } - } - clr.toString = rgbtoString; - return clr; - }; - - R.hsb2rgb = function (h, s, v, o) { - if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { - v = h.b; - s = h.s; - h = h.h; - o = h.o; - } - h *= 360; - var R, G, B, X, C; - h = (h % 360) / 60; - C = v * s; - X = C * (1 - abs(h % 2 - 1)); - R = G = B = v - C; - - h = ~~h; - R += [C, X, 0, 0, X, C][h]; - G += [X, C, C, X, 0, 0][h]; - B += [0, 0, X, C, C, X][h]; - return packageRGB(R, G, B, o); - }; - - R.hsl2rgb = function (h, s, l, o) { - if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { - l = h.l; - s = h.s; - h = h.h; - } - if (h > 1 || s > 1 || l > 1) { - h /= 360; - s /= 100; - l /= 100; - } - h *= 360; - var R, G, B, X, C; - h = (h % 360) / 60; - C = 2 * s * (l < .5 ? l : 1 - l); - X = C * (1 - abs(h % 2 - 1)); - R = G = B = l - C / 2; - - h = ~~h; - R += [C, X, 0, 0, X, C][h]; - G += [X, C, C, X, 0, 0][h]; - B += [0, 0, X, C, C, X][h]; - return packageRGB(R, G, B, o); - }; - - R.rgb2hsb = function (r, g, b) { - b = prepareRGB(r, g, b); - r = b[0]; - g = b[1]; - b = b[2]; - - var H, S, V, C; - V = mmax(r, g, b); - C = V - mmin(r, g, b); - H = (C == 0 ? null : - V == r ? (g - b) / C : - V == g ? (b - r) / C + 2 : - (r - g) / C + 4 - ); - H = ((H + 360) % 6) * 60 / 360; - S = C == 0 ? 0 : C / V; - return {h: H, s: S, b: V, toString: hsbtoString}; - }; - - R.rgb2hsl = function (r, g, b) { - b = prepareRGB(r, g, b); - r = b[0]; - g = b[1]; - b = b[2]; - - var H, S, L, M, m, C; - M = mmax(r, g, b); - m = mmin(r, g, b); - C = M - m; - H = (C == 0 ? null : - M == r ? (g - b) / C : - M == g ? (b - r) / C + 2 : - (r - g) / C + 4); - H = ((H + 360) % 6) * 60 / 360; - L = (M + m) / 2; - S = (C == 0 ? 0 : - L < .5 ? C / (2 * L) : - C / (2 - 2 * L)); - return {h: H, s: S, l: L, toString: hsltoString}; - }; - R._path2string = function () { - return this.join(",").replace(p2s, "$1"); - }; - function repush(array, item) { - for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { - return array.push(array.splice(i, 1)[0]); - } - } - function cacher(f, scope, postprocessor) { - function newf() { - var arg = Array.prototype.slice.call(arguments, 0), - args = arg.join("\u2400"), - cache = newf.cache = newf.cache || {}, - count = newf.count = newf.count || []; - if (cache[has](args)) { - repush(count, args); - return postprocessor ? postprocessor(cache[args]) : cache[args]; - } - count.length >= 1e3 && delete cache[count.shift()]; - count.push(args); - cache[args] = f[apply](scope, arg); - return postprocessor ? postprocessor(cache[args]) : cache[args]; - } - return newf; - } - - var preload = R._preload = function (src, f) { - var img = g.doc.createElement("img"); - img.style.cssText = "position:absolute;left:-9999em;top-9999em"; - img.onload = function () { - f.call(this); - this.onload = null; - g.doc.body.removeChild(this); - }; - img.onerror = function () { - g.doc.body.removeChild(this); - }; - g.doc.body.appendChild(img); - img.src = src; - }; - - function clrToString() { - return this.hex; - } - - - R.getRGB = cacher(function (colour) { - if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { - return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; - } - if (colour == "none") { - return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; - } - !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); - var res, - red, - green, - blue, - opacity, - t, - values, - rgb = colour.match(colourRegExp); - if (rgb) { - if (rgb[2]) { - blue = toInt(rgb[2].substring(5), 16); - green = toInt(rgb[2].substring(3, 5), 16); - red = toInt(rgb[2].substring(1, 3), 16); - } - if (rgb[3]) { - blue = toInt((t = rgb[3].charAt(3)) + t, 16); - green = toInt((t = rgb[3].charAt(2)) + t, 16); - red = toInt((t = rgb[3].charAt(1)) + t, 16); - } - if (rgb[4]) { - values = rgb[4].split(commaSpaces); - red = toFloat(values[0]); - values[0].slice(-1) == "%" && (red *= 2.55); - green = toFloat(values[1]); - values[1].slice(-1) == "%" && (green *= 2.55); - blue = toFloat(values[2]); - values[2].slice(-1) == "%" && (blue *= 2.55); - rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); - values[3] && values[3].slice(-1) == "%" && (opacity /= 100); - } - if (rgb[5]) { - values = rgb[5].split(commaSpaces); - red = toFloat(values[0]); - values[0].slice(-1) == "%" && (red *= 2.55); - green = toFloat(values[1]); - values[1].slice(-1) == "%" && (green *= 2.55); - blue = toFloat(values[2]); - values[2].slice(-1) == "%" && (blue *= 2.55); - (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); - rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); - values[3] && values[3].slice(-1) == "%" && (opacity /= 100); - return R.hsb2rgb(red, green, blue, opacity); - } - if (rgb[6]) { - values = rgb[6].split(commaSpaces); - red = toFloat(values[0]); - values[0].slice(-1) == "%" && (red *= 2.55); - green = toFloat(values[1]); - values[1].slice(-1) == "%" && (green *= 2.55); - blue = toFloat(values[2]); - values[2].slice(-1) == "%" && (blue *= 2.55); - (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); - rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); - values[3] && values[3].slice(-1) == "%" && (opacity /= 100); - return R.hsl2rgb(red, green, blue, opacity); - } - rgb = {r: red, g: green, b: blue, toString: clrToString}; - rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); - R.is(opacity, "finite") && (rgb.opacity = opacity); - return rgb; - } - return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; - }, R); - - R.hsb = cacher(function (h, s, b) { - return R.hsb2rgb(h, s, b).hex; - }); - - R.hsl = cacher(function (h, s, l) { - return R.hsl2rgb(h, s, l).hex; - }); - - R.rgb = cacher(function (r, g, b) { - return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); - }); - - R.getColor = function (value) { - var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, - rgb = this.hsb2rgb(start.h, start.s, start.b); - start.h += .075; - if (start.h > 1) { - start.h = 0; - start.s -= .2; - start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); - } - return rgb.hex; - }; - - R.getColor.reset = function () { - delete this.start; - }; - - // http://schepers.cc/getting-to-the-point - function catmullRom2bezier(crp) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 > i; i += 2) { - var p = [{x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i + 2], y: +crp[i + 3]}, - {x: +crp[i + 4], y: +crp[i + 5]}]; - if (iLen - 4 == i) { - p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; - p[3] = p[2]; - } else if (i) { - p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; - } - d.push(["C", - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6*p[2].y - p[3].y) / 6, - p[2].x, - p[2].y - ]); - } - - return d; - } - - R.parsePathString = cacher(function (pathString) { - if (!pathString) { - return null; - } - var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, - data = []; - if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption - data = pathClone(pathString); - } - if (!data.length) { - Str(pathString).replace(pathCommand, function (a, b, c) { - var params = [], - name = b.toLowerCase(); - c.replace(pathValues, function (a, b) { - b && params.push(+b); - }); - if (name == "m" && params.length > 2) { - data.push([b][concat](params.splice(0, 2))); - name = "l"; - b = b == "m" ? "l" : "L"; - } - if (name == "r") { - data.push([b][concat](params)); - } else while (params.length >= paramCounts[name]) { - data.push([b][concat](params.splice(0, paramCounts[name]))); - if (!paramCounts[name]) { - break; - } - } - }); - } - data.toString = R._path2string; - return data; - }); - - R.parseTransformString = cacher(function (TString) { - if (!TString) { - return null; - } - var paramCounts = {r: 3, s: 4, t: 2, m: 6}, - data = []; - if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption - data = pathClone(TString); - } - if (!data.length) { - Str(TString).replace(tCommand, function (a, b, c) { - var params = [], - name = lowerCase.call(b); - c.replace(pathValues, function (a, b) { - b && params.push(+b); - }); - data.push([name][concat](params)); - }); - } - data.toString = R._path2string; - return data; - }); - - R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { - var t1 = 1 - t, - t13 = pow(t1, 3), - t12 = pow(t1, 2), - t2 = t * t, - t3 = t2 * t, - x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, - y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, - mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), - my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), - nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), - ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), - ax = t1 * p1x + t * c1x, - ay = t1 * p1y + t * c1y, - cx = t1 * c2x + t * p2x, - cy = t1 * c2y + t * p2y, - alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); - (mx > nx || my < ny) && (alpha += 180); - return { - x: x, - y: y, - m: {x: mx, y: my}, - n: {x: nx, y: ny}, - start: {x: ax, y: ay}, - end: {x: cx, y: cy}, - alpha: alpha - }; - }; - var pathDimensions = cacher(function (path) { - if (!path) { - return {x: 0, y: 0, width: 0, height: 0}; - } - path = path2curve(path); - var x = 0, - y = 0, - X = [], - Y = [], - p; - for (var i = 0, ii = path.length; i < ii; i++) { - p = path[i]; - if (p[0] == "M") { - x = p[1]; - y = p[2]; - X.push(x); - Y.push(y); - } else { - var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); - X = X[concat](dim.min.x, dim.max.x); - Y = Y[concat](dim.min.y, dim.max.y); - x = p[5]; - y = p[6]; - } - } - var xmin = mmin[apply](0, X), - ymin = mmin[apply](0, Y); - return { - x: xmin, - y: ymin, - width: mmax[apply](0, X) - xmin, - height: mmax[apply](0, Y) - ymin - }; - }, null, function (o) { - return { - x: o.x, - y: o.y, - width: o.width, - height: o.height - }; - }), - pathClone = function (pathArray) { - var res = []; - if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption - pathArray = R.parsePathString(pathArray); - } - for (var i = 0, ii = pathArray.length; i < ii; i++) { - res[i] = []; - for (var j = 0, jj = pathArray[i].length; j < jj; j++) { - res[i][j] = pathArray[i][j]; - } - } - res.toString = R._path2string; - return res; - }, - pathToRelative = R._pathToRelative = cacher(function (pathArray) { - if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption - pathArray = R.parsePathString(pathArray); - } - var res = [], - x = 0, - y = 0, - mx = 0, - my = 0, - start = 0; - if (pathArray[0][0] == "M") { - x = pathArray[0][1]; - y = pathArray[0][2]; - mx = x; - my = y; - start++; - res.push(["M", x, y]); - } - for (var i = start, ii = pathArray.length; i < ii; i++) { - var r = res[i] = [], - pa = pathArray[i]; - if (pa[0] != lowerCase.call(pa[0])) { - r[0] = lowerCase.call(pa[0]); - switch (r[0]) { - case "a": - r[1] = pa[1]; - r[2] = pa[2]; - r[3] = pa[3]; - r[4] = pa[4]; - r[5] = pa[5]; - r[6] = +(pa[6] - x).toFixed(3); - r[7] = +(pa[7] - y).toFixed(3); - break; - case "v": - r[1] = +(pa[1] - y).toFixed(3); - break; - case "m": - mx = pa[1]; - my = pa[2]; - default: - for (var j = 1, jj = pa.length; j < jj; j++) { - r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); - } - } - } else { - r = res[i] = []; - if (pa[0] == "m") { - mx = pa[1] + x; - my = pa[2] + y; - } - for (var k = 0, kk = pa.length; k < kk; k++) { - res[i][k] = pa[k]; - } - } - var len = res[i].length; - switch (res[i][0]) { - case "z": - x = mx; - y = my; - break; - case "h": - x += +res[i][len - 1]; - break; - case "v": - y += +res[i][len - 1]; - break; - default: - x += +res[i][len - 2]; - y += +res[i][len - 1]; - } - } - res.toString = R._path2string; - return res; - }, 0, pathClone), - pathToAbsolute = R._pathToAbsolute = cacher(function (pathArray) { - if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption - pathArray = R.parsePathString(pathArray); - } - if (!pathArray || !pathArray.length) { - return [["M", 0, 0]]; - } - var res = [], - x = 0, - y = 0, - mx = 0, - my = 0, - start = 0; - if (pathArray[0][0] == "M") { - x = +pathArray[0][1]; - y = +pathArray[0][2]; - mx = x; - my = y; - start++; - res[0] = ["M", x, y]; - } - for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { - res.push(r = []); - pa = pathArray[i]; - if (pa[0] != upperCase.call(pa[0])) { - r[0] = upperCase.call(pa[0]); - switch (r[0]) { - case "A": - r[1] = pa[1]; - r[2] = pa[2]; - r[3] = pa[3]; - r[4] = pa[4]; - r[5] = pa[5]; - r[6] = +(pa[6] + x); - r[7] = +(pa[7] + y); - break; - case "V": - r[1] = +pa[1] + y; - break; - case "H": - r[1] = +pa[1] + x; - break; - case "R": - var dots = [x, y][concat](pa.slice(1)); - for (var j = 2, jj = dots.length; j < jj; j++) { - dots[j] = +dots[j] + x; - dots[++j] = +dots[j] + y; - } - res.pop(); - res = res[concat](catmullRom2bezier(dots)); - break; - case "M": - mx = +pa[1] + x; - my = +pa[2] + y; - default: - for (j = 1, jj = pa.length; j < jj; j++) { - r[j] = +pa[j] + ((j % 2) ? x : y); - } - } - } else if (pa[0] == "R") { - dots = [x, y][concat](pa.slice(1)); - res.pop(); - res = res[concat](catmullRom2bezier(dots)); - r = ["R"][concat](pa.slice(-2)); - } else { - for (var k = 0, kk = pa.length; k < kk; k++) { - r[k] = pa[k]; - } - } - switch (r[0]) { - case "Z": - x = mx; - y = my; - break; - case "H": - x = r[1]; - break; - case "V": - y = r[1]; - break; - case "M": - mx = r[r.length - 2]; - my = r[r.length - 1]; - default: - x = r[r.length - 2]; - y = r[r.length - 1]; - } - } - res.toString = R._path2string; - return res; - }, null, pathClone), - l2c = function (x1, y1, x2, y2) { - return [x1, y1, x2, y2, x2, y2]; - }, - q2c = function (x1, y1, ax, ay, x2, y2) { - var _13 = 1 / 3, - _23 = 2 / 3; - return [ - _13 * x1 + _23 * ax, - _13 * y1 + _23 * ay, - _13 * x2 + _23 * ax, - _13 * y2 + _23 * ay, - x2, - y2 - ]; - }, - a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { - // for more information of where this math came from visit: - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - var _120 = PI * 120 / 180, - rad = PI / 180 * (+angle || 0), - res = [], - xy, - rotate = cacher(function (x, y, rad) { - var X = x * math.cos(rad) - y * math.sin(rad), - Y = x * math.sin(rad) + y * math.cos(rad); - return {x: X, y: Y}; - }); - if (!recursive) { - xy = rotate(x1, y1, -rad); - x1 = xy.x; - y1 = xy.y; - xy = rotate(x2, y2, -rad); - x2 = xy.x; - y2 = xy.y; - var cos = math.cos(PI / 180 * angle), - sin = math.sin(PI / 180 * angle), - x = (x1 - x2) / 2, - y = (y1 - y2) / 2; - var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); - if (h > 1) { - h = math.sqrt(h); - rx = h * rx; - ry = h * ry; - } - var rx2 = rx * rx, - ry2 = ry * ry, - k = (large_arc_flag == sweep_flag ? -1 : 1) * - math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), - cx = k * rx * y / ry + (x1 + x2) / 2, - cy = k * -ry * x / rx + (y1 + y2) / 2, - f1 = math.asin(((y1 - cy) / ry).toFixed(9)), - f2 = math.asin(((y2 - cy) / ry).toFixed(9)); - - f1 = x1 < cx ? PI - f1 : f1; - f2 = x2 < cx ? PI - f2 : f2; - f1 < 0 && (f1 = PI * 2 + f1); - f2 < 0 && (f2 = PI * 2 + f2); - if (sweep_flag && f1 > f2) { - f1 = f1 - PI * 2; - } - if (!sweep_flag && f2 > f1) { - f2 = f2 - PI * 2; - } - } else { - f1 = recursive[0]; - f2 = recursive[1]; - cx = recursive[2]; - cy = recursive[3]; - } - var df = f2 - f1; - if (abs(df) > _120) { - var f2old = f2, - x2old = x2, - y2old = y2; - f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); - x2 = cx + rx * math.cos(f2); - y2 = cy + ry * math.sin(f2); - res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); - } - df = f2 - f1; - var c1 = math.cos(f1), - s1 = math.sin(f1), - c2 = math.cos(f2), - s2 = math.sin(f2), - t = math.tan(df / 4), - hx = 4 / 3 * rx * t, - hy = 4 / 3 * ry * t, - m1 = [x1, y1], - m2 = [x1 + hx * s1, y1 - hy * c1], - m3 = [x2 + hx * s2, y2 - hy * c2], - m4 = [x2, y2]; - m2[0] = 2 * m1[0] - m2[0]; - m2[1] = 2 * m1[1] - m2[1]; - if (recursive) { - return [m2, m3, m4][concat](res); - } else { - res = [m2, m3, m4][concat](res).join().split(","); - var newres = []; - for (var i = 0, ii = res.length; i < ii; i++) { - newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; - } - return newres; - } - }, - findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { - var t1 = 1 - t; - return { - x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, - y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y - }; - }, - curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { - var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), - b = 2 * (c1x - p1x) - 2 * (c2x - c1x), - c = p1x - c1x, - t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, - t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, - y = [p1y, p2y], - x = [p1x, p2x], - dot; - abs(t1) > "1e12" && (t1 = .5); - abs(t2) > "1e12" && (t2 = .5); - if (t1 > 0 && t1 < 1) { - dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); - x.push(dot.x); - y.push(dot.y); - } - if (t2 > 0 && t2 < 1) { - dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); - x.push(dot.x); - y.push(dot.y); - } - a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); - b = 2 * (c1y - p1y) - 2 * (c2y - c1y); - c = p1y - c1y; - t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; - t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; - abs(t1) > "1e12" && (t1 = .5); - abs(t2) > "1e12" && (t2 = .5); - if (t1 > 0 && t1 < 1) { - dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); - x.push(dot.x); - y.push(dot.y); - } - if (t2 > 0 && t2 < 1) { - dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); - x.push(dot.x); - y.push(dot.y); - } - return { - min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, - max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} - }; - }), - path2curve = R._path2curve = cacher(function (path, path2) { - var p = pathToAbsolute(path), - p2 = path2 && pathToAbsolute(path2), - attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, - attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, - processPath = function (path, d) { - var nx, ny; - if (!path) { - return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; - } - !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); - switch (path[0]) { - case "M": - d.X = path[1]; - d.Y = path[2]; - break; - case "A": - path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); - break; - case "S": - nx = d.x + (d.x - (d.bx || d.x)); - ny = d.y + (d.y - (d.by || d.y)); - path = ["C", nx, ny][concat](path.slice(1)); - break; - case "T": - d.qx = d.x + (d.x - (d.qx || d.x)); - d.qy = d.y + (d.y - (d.qy || d.y)); - path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); - break; - case "Q": - d.qx = path[1]; - d.qy = path[2]; - path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); - break; - case "L": - path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); - break; - case "H": - path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); - break; - case "V": - path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); - break; - case "Z": - path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); - break; - } - return path; - }, - fixArc = function (pp, i) { - if (pp[i].length > 7) { - pp[i].shift(); - var pi = pp[i]; - while (pi.length) { - pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); - } - pp.splice(i, 1); - ii = mmax(p.length, p2 && p2.length || 0); - } - }, - fixM = function (path1, path2, a1, a2, i) { - if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { - path2.splice(i, 0, ["M", a2.x, a2.y]); - a1.bx = 0; - a1.by = 0; - a1.x = path1[i][1]; - a1.y = path1[i][2]; - ii = mmax(p.length, p2 && p2.length || 0); - } - }; - for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { - p[i] = processPath(p[i], attrs); - fixArc(p, i); - p2 && (p2[i] = processPath(p2[i], attrs2)); - p2 && fixArc(p2, i); - fixM(p, p2, attrs, attrs2, i); - fixM(p2, p, attrs2, attrs, i); - var seg = p[i], - seg2 = p2 && p2[i], - seglen = seg.length, - seg2len = p2 && seg2.length; - attrs.x = seg[seglen - 2]; - attrs.y = seg[seglen - 1]; - attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; - attrs.by = toFloat(seg[seglen - 3]) || attrs.y; - attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); - attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); - attrs2.x = p2 && seg2[seg2len - 2]; - attrs2.y = p2 && seg2[seg2len - 1]; - } - return p2 ? [p, p2] : p; - }, null, pathClone), - parseDots = R._parseDots = cacher(function (gradient) { - var dots = []; - for (var i = 0, ii = gradient.length; i < ii; i++) { - var dot = {}, - par = gradient[i].match(/^([^:]*):?([\d\.]*)/); - dot.color = R.getRGB(par[1]); - if (dot.color.error) { - return null; - } - dot.color = dot.color.hex; - par[2] && (dot.offset = par[2] + "%"); - dots.push(dot); - } - for (i = 1, ii = dots.length - 1; i < ii; i++) { - if (!dots[i].offset) { - var start = toFloat(dots[i - 1].offset || 0), - end = 0; - for (var j = i + 1; j < ii; j++) { - if (dots[j].offset) { - end = dots[j].offset; - break; - } - } - if (!end) { - end = 100; - j = ii; - } - end = toFloat(end); - var d = (end - start) / (j - i + 1); - for (; i < j; i++) { - start += d; - dots[i].offset = start + "%"; - } - } - } - return dots; - }), - tear = R._tear = function (el, paper) { - el == paper.top && (paper.top = el.prev); - el == paper.bottom && (paper.bottom = el.next); - el.next && (el.next.prev = el.prev); - el.prev && (el.prev.next = el.next); - }, - tofront = R._tofront = function (el, paper) { - if (paper.top === el) { - return; - } - tear(el, paper); - el.next = null; - el.prev = paper.top; - paper.top.next = el; - paper.top = el; - }, - toback = R._toback = function (el, paper) { - if (paper.bottom === el) { - return; - } - tear(el, paper); - el.next = paper.bottom; - el.prev = null; - paper.bottom.prev = el; - paper.bottom = el; - }, - insertafter = R._insertafter = function (el, el2, paper) { - tear(el, paper); - el2 == paper.top && (paper.top = el); - el2.next && (el2.next.prev = el); - el.next = el2.next; - el.prev = el2; - el2.next = el; - }, - insertbefore = R._insertbefore = function (el, el2, paper) { - tear(el, paper); - el2 == paper.bottom && (paper.bottom = el); - el2.prev && (el2.prev.next = el); - el.prev = el2.prev; - el2.prev = el; - el.next = el2; - }, - removed = function (methodname) { - return function () { - throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); - }; - }, - extractTransform = R._extractTransform = function (el, tstr) { - if (tstr == null) { - return el._.transform; - } - tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); - var tdata = R.parseTransformString(tstr), - deg = 0, - dx = 0, - dy = 0, - sx = 1, - sy = 1, - _ = el._, - m = new Matrix; - _.transform = tdata || []; - if (tdata) { - for (var i = 0, ii = tdata.length; i < ii; i++) { - var t = tdata[i], - tlen = t.length, - bb; - t[0] = Str(t[0]).toLowerCase(); - if (t[0] == "t" && tlen == 3) { - m.translate(t[1], t[2]); - } else if (t[0] == "r") { - if (tlen == 2) { - bb = bb || el.getBBox(1); - m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); - deg += t[1]; - } else if (tlen == 4) { - m.rotate(t[1], t[2], t[3]); - deg += t[1]; - } - } else if (t[0] == "s") { - if (tlen == 2 || tlen == 3) { - bb = bb || el.getBBox(1); - m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); - sx *= t[1]; - sy *= t[tlen - 1]; - } else if (tlen == 5) { - m.scale(t[1], t[2], t[3], t[4]); - sx *= t[1]; - sy *= t[2]; - } - } else if (t[0] == "m" && tlen == 7) { - m.add(t[1], t[2], t[3], t[4], t[5], t[6]); - } - _.dirtyT = 1; - el.matrix = m; - } - } - - el.matrix = m; - - _.sx = sx; - _.sy = sy; - _.deg = deg; - _.dx = dx = m.e; - _.dy = dy = m.f; - - if (sx == 1 && sy == 1 && !deg && _.bbox) { - _.bbox.x += +dx; - _.bbox.y += +dy; - } else { - _.dirtyT = 1; - } - }, - getEmpty = function (item) { - switch (item[0]) { - case "t": return ["t", 0, 0]; - case "m": return ["m", 1, 0, 0, 1, 0, 0]; - case "r": if (item.length == 4) { - return ["r", 0, item[2], item[3]]; - } else { - return ["r", 0]; - } - case "s": if (item.length == 5) { - return ["s", 1, 1, item[3], item[4]]; - } else if (item.length == 3) { - return ["s", 1, 1]; - } else { - return ["s", 1]; - } - } - }, - equaliseTransform = R._equaliseTransform = function (t1, t2) { - t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); - t1 = R.parseTransformString(t1) || []; - t2 = R.parseTransformString(t2) || []; - var maxlength = mmax(t1.length, t2.length), - from = [], - to = [], - i = 0, j, jj, - tt1, tt2; - for (; i < maxlength; i++) { - tt1 = t1[i] || getEmpty(t2[i]); - tt2 = t2[i] || getEmpty(tt1); - if ((tt1[0] != tt2[0]) || - (tt1[0] == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || - (tt1[0] == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) - ) { - return; - } - from[i] = []; - to[i] = []; - for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { - j in tt1 && (from[i][j] = tt1[j]); - j in tt2 && (to[i][j] = tt2[j]); - } - } - return { - from: from, - to: to - }; - }; - R._getContainer = function (x, y, w, h) { - var container; - container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; - if (container == null) { - return; - } - if (container.tagName) { - if (y == null) { - return { - container: container, - width: container.style.pixelWidth || container.offsetWidth, - height: container.style.pixelHeight || container.offsetHeight - }; - } else { - return { - container: container, - width: y, - height: w - }; - } - } - return { - container: 1, - x: x, - y: y, - width: w, - height: h - }; - }; - - R.pathToRelative = pathToRelative; - R._engine = {}; - - R.path2curve = path2curve; - - R.matrix = function (a, b, c, d, e, f) { - return new Matrix(a, b, c, d, e, f); - }; - function Matrix(a, b, c, d, e, f) { - if (a != null) { - this.a = +a; - this.b = +b; - this.c = +c; - this.d = +d; - this.e = +e; - this.f = +f; - } else { - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.e = 0; - this.f = 0; - } - } - (function (matrixproto) { - - matrixproto.add = function (a, b, c, d, e, f) { - var out = [[], [], []], - m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], - matrix = [[a, c, e], [b, d, f], [0, 0, 1]], - x, y, z, res; - - if (a && a instanceof Matrix) { - matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; - } - - for (x = 0; x < 3; x++) { - for (y = 0; y < 3; y++) { - res = 0; - for (z = 0; z < 3; z++) { - res += m[x][z] * matrix[z][y]; - } - out[x][y] = res; - } - } - this.a = out[0][0]; - this.b = out[1][0]; - this.c = out[0][1]; - this.d = out[1][1]; - this.e = out[0][2]; - this.f = out[1][2]; - }; - - matrixproto.invert = function () { - var me = this, - x = me.a * me.d - me.b * me.c; - return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); - }; - - matrixproto.clone = function () { - return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); - }; - - matrixproto.translate = function (x, y) { - this.add(1, 0, 0, 1, x, y); - }; - - matrixproto.scale = function (x, y, cx, cy) { - y == null && (y = x); - (cx || cy) && this.add(1, 0, 0, 1, cx, cy); - this.add(x, 0, 0, y, 0, 0); - (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); - }; - - matrixproto.rotate = function (a, x, y) { - a = R.rad(a); - x = x || 0; - y = y || 0; - var cos = +math.cos(a).toFixed(9), - sin = +math.sin(a).toFixed(9); - this.add(cos, sin, -sin, cos, x, y); - this.add(1, 0, 0, 1, -x, -y); - }; - - matrixproto.x = function (x, y) { - return x * this.a + y * this.c + this.e; - }; - - matrixproto.y = function (x, y) { - return x * this.b + y * this.d + this.f; - }; - matrixproto.get = function (i) { - return +this[Str.fromCharCode(97 + i)].toFixed(4); - }; - matrixproto.toString = function () { - return R.svg ? - "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : - [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); - }; - matrixproto.toFilter = function () { - return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + - ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + - ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; - }; - matrixproto.offset = function () { - return [this.e.toFixed(4), this.f.toFixed(4)]; - }; - function norm(a) { - return a[0] * a[0] + a[1] * a[1]; - } - function normalize(a) { - var mag = math.sqrt(norm(a)); - a[0] && (a[0] /= mag); - a[1] && (a[1] /= mag); - } - - matrixproto.split = function () { - var out = {}; - // translation - out.dx = this.e; - out.dy = this.f; - - // scale and shear - var row = [[this.a, this.c], [this.b, this.d]]; - out.scalex = math.sqrt(norm(row[0])); - normalize(row[0]); - - out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; - row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; - - out.scaley = math.sqrt(norm(row[1])); - normalize(row[1]); - out.shear /= out.scaley; - - // rotation - var sin = -row[0][1], - cos = row[1][1]; - if (cos < 0) { - out.rotate = R.deg(math.acos(cos)); - if (sin < 0) { - out.rotate = 360 - out.rotate; - } - } else { - out.rotate = R.deg(math.asin(sin)); - } - - out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); - out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; - out.noRotation = !+out.shear.toFixed(9) && !out.rotate; - return out; - }; - - matrixproto.toTransformString = function () { - var s = this.split(); - if (s.isSimple) { - return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0]; - } else { - return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; - } - }; - })(Matrix.prototype); - - // WebKit rendering bug workaround method - var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); - if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || - (navigator.vendor == "Google Inc." && version && version[1] < 8)) { - - paperproto.safari = function () { - var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); - setTimeout(function () {rect.remove();}); - }; - } else { - paperproto.safari = fun; - } - - var preventDefault = function () { - this.returnValue = false; - }, - preventTouch = function () { - return this.originalEvent.preventDefault(); - }, - stopPropagation = function () { - this.cancelBubble = true; - }, - stopTouch = function () { - return this.originalEvent.stopPropagation(); - }, - addEvent = (function () { - if (g.doc.addEventListener) { - return function (obj, type, fn, element) { - var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, - f = function (e) { - var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, - scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, - x = e.clientX + scrollX, - y = e.clientY + scrollY; - if (supportsTouch && touchMap[has](type)) { - for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { - if (e.targetTouches[i].target == obj) { - var olde = e; - e = e.targetTouches[i]; - e.originalEvent = olde; - e.preventDefault = preventTouch; - e.stopPropagation = stopTouch; - break; - } - } - } - return fn.call(element, e, x, y); - }; - obj.addEventListener(realName, f, false); - return function () { - obj.removeEventListener(realName, f, false); - return true; - }; - }; - } else if (g.doc.attachEvent) { - return function (obj, type, fn, element) { - var f = function (e) { - e = e || g.win.event; - var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, - scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, - x = e.clientX + scrollX, - y = e.clientY + scrollY; - e.preventDefault = e.preventDefault || preventDefault; - e.stopPropagation = e.stopPropagation || stopPropagation; - return fn.call(element, e, x, y); - }; - obj.attachEvent("on" + type, f); - var detacher = function () { - obj.detachEvent("on" + type, f); - return true; - }; - return detacher; - }; - } - })(), - drag = [], - dragMove = function (e) { - var x = e.clientX, - y = e.clientY, - scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, - scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, - dragi, - j = drag.length; - while (j--) { - dragi = drag[j]; - if (supportsTouch) { - var i = e.touches.length, - touch; - while (i--) { - touch = e.touches[i]; - if (touch.identifier == dragi.el._drag.id) { - x = touch.clientX; - y = touch.clientY; - (e.originalEvent ? e.originalEvent : e).preventDefault(); - break; - } - } - } else { - e.preventDefault(); - } - var node = dragi.el.node, - o, - next = node.nextSibling, - parent = node.parentNode, - display = node.style.display; - g.win.opera && parent.removeChild(node); - node.style.display = "none"; - o = dragi.el.paper.getElementByPoint(x, y); - node.style.display = display; - g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); - o && eve("drag.over." + dragi.el.id, dragi.el, o); - x += scrollX; - y += scrollY; - eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); - } - }, - dragUp = function (e) { - R.unmousemove(dragMove).unmouseup(dragUp); - var i = drag.length, - dragi; - while (i--) { - dragi = drag[i]; - dragi.el._drag = {}; - eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); - } - drag = []; - }, - - elproto = R.el = {}; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - for (var i = events.length; i--;) { - (function (eventName) { - R[eventName] = elproto[eventName] = function (fn, scope) { - if (R.is(fn, "function")) { - this.events = this.events || []; - this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); - } - return this; - }; - R["un" + eventName] = elproto["un" + eventName] = function (fn) { - var events = this.events, - l = events.length; - while (l--) if (events[l].name == eventName && events[l].f == fn) { - events[l].unbind(); - events.splice(l, 1); - !events.length && delete this.events; - return this; - } - return this; - }; - })(events[i]); - } - - - elproto.data = function (key, value) { - var data = eldata[this.id] = eldata[this.id] || {}; - if (arguments.length == 1) { - if (R.is(key, "object")) { - for (var i in key) if (key[has](i)) { - this.data(i, key[i]); - } - return this; - } - eve("data.get." + this.id, this, data[key], key); - return data[key]; - } - data[key] = value; - eve("data.set." + this.id, this, value, key); - return this; - }; - - elproto.removeData = function (key) { - if (key == null) { - eldata[this.id] = {}; - } else { - eldata[this.id] && delete eldata[this.id][key]; - } - return this; - }; - - elproto.hover = function (f_in, f_out, scope_in, scope_out) { - return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); - }; - - elproto.unhover = function (f_in, f_out) { - return this.unmouseover(f_in).unmouseout(f_out); - }; - - elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { - function start(e) { - (e.originalEvent || e).preventDefault(); - var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, - scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; - this._drag.x = e.clientX + scrollX; - this._drag.y = e.clientY + scrollY; - this._drag.id = e.identifier; - !drag.length && R.mousemove(dragMove).mouseup(dragUp); - drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); - onstart && eve.on("drag.start." + this.id, onstart); - onmove && eve.on("drag.move." + this.id, onmove); - onend && eve.on("drag.end." + this.id, onend); - eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); - } - this._drag = {}; - this.mousedown(start); - return this; - }; - - elproto.onDragOver = function (f) { - f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); - }; - - elproto.undrag = function () { - var i = drag.length; - while (i--) if (drag[i].el == this) { - R.unmousedown(drag[i].start); - drag.splice(i++, 1); - eve.unbind("drag.*." + this.id); - } - !drag.length && R.unmousemove(dragMove).unmouseup(dragUp); - }; - - paperproto.circle = function (x, y, r) { - var out = R._engine.circle(this, x || 0, y || 0, r || 0); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.rect = function (x, y, w, h, r) { - var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.ellipse = function (x, y, rx, ry) { - var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.path = function (pathString) { - pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); - var out = R._engine.path(R.format[apply](R, arguments), this); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.image = function (src, x, y, w, h) { - var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.text = function (x, y, text) { - var out = R._engine.text(this, x || 0, y || 0, Str(text)); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.set = function (itemsArray) { - !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); - var out = new Set(itemsArray); - this.__set__ && this.__set__.push(out); - return out; - }; - - paperproto.setStart = function (set) { - this.__set__ = set || this.set(); - }; - - paperproto.setFinish = function (set) { - var out = this.__set__; - delete this.__set__; - return out; - }; - - paperproto.setSize = function (width, height) { - return R._engine.setSize.call(this, width, height); - }; - - paperproto.setViewBox = function (x, y, w, h, fit) { - return R._engine.setViewBox.call(this, x, y, w, h, fit); - }; - - - paperproto.top = paperproto.bottom = null; - - paperproto.raphael = R; - var getOffset = function (elem) { - var box = elem.getBoundingClientRect(), - doc = elem.ownerDocument, - body = doc.body, - docElem = doc.documentElement, - clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, - top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, - left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; - return { - y: top, - x: left - }; - }; - - paperproto.getElementByPoint = function (x, y) { - var paper = this, - svg = paper.canvas, - target = g.doc.elementFromPoint(x, y); - if (g.win.opera && target.tagName == "svg") { - var so = getOffset(svg), - sr = svg.createSVGRect(); - sr.x = x - so.x; - sr.y = y - so.y; - sr.width = sr.height = 1; - var hits = svg.getIntersectionList(sr, null); - if (hits.length) { - target = hits[hits.length - 1]; - } - } - if (!target) { - return null; - } - while (target.parentNode && target != svg.parentNode && !target.raphael) { - target = target.parentNode; - } - target == paper.canvas.parentNode && (target = svg); - target = target && target.raphael ? paper.getById(target.raphaelid) : null; - return target; - }; - - paperproto.getById = function (id) { - var bot = this.bottom; - while (bot) { - if (bot.id == id) { - return bot; - } - bot = bot.next; - } - return null; - }; - - paperproto.forEach = function (callback, thisArg) { - var bot = this.bottom; - while (bot) { - if (callback.call(thisArg, bot) === false) { - return this; - } - bot = bot.next; - } - return this; - }; - function x_y() { - return this.x + S + this.y; - } - function x_y_w_h() { - return this.x + S + this.y + S + this.width + " \xd7 " + this.height; - } - - elproto.getBBox = function (isWithoutTransform) { - if (this.removed) { - return {}; - } - var _ = this._; - if (isWithoutTransform) { - if (_.dirty || !_.bboxwt) { - this.realPath = getPath[this.type](this); - _.bboxwt = pathDimensions(this.realPath); - _.bboxwt.toString = x_y_w_h; - _.dirty = 0; - } - return _.bboxwt; - } - if (_.dirty || _.dirtyT || !_.bbox) { - if (_.dirty || !this.realPath) { - _.bboxwt = 0; - this.realPath = getPath[this.type](this); - } - _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); - _.bbox.toString = x_y_w_h; - _.dirty = _.dirtyT = 0; - } - return _.bbox; - }; - - elproto.clone = function () { - if (this.removed) { - return null; - } - return this.paper[this.type]().attr(this.attr()); - }; - - elproto.glow = function (glow) { - if (this.type == "text") { - return null; - } - glow = glow || {}; - var s = { - width: (glow.width || 10) + (+this.attr("stroke-width") || 1), - fill: glow.fill || false, - opacity: glow.opacity || .5, - offsetx: glow.offsetx || 0, - offsety: glow.offsety || 0, - color: glow.color || "#000" - }, - c = s.width / 2, - r = this.paper, - out = r.set(), - path = this.realPath || getPath[this.type](this); - path = this.matrix ? mapPath(path, this.matrix) : path; - for (var i = 1; i < c + 1; i++) { - out.push(r.path(path).attr({ - stroke: s.color, - fill: s.fill ? s.color : "none", - "stroke-linejoin": "round", - "stroke-linecap": "round", - "stroke-width": +(s.width / c * i).toFixed(3), - opacity: +(s.opacity / c).toFixed(3) - })); - } - return out.insertBefore(this).translate(s.offsetx, s.offsety); - }; - var curveslengths = {}, - getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { - var len = 0, - precision = 100, - name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(), - cache = curveslengths[name], - old, dot; - !cache && (curveslengths[name] = cache = {data: []}); - cache.timer && clearTimeout(cache.timer); - cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3); - if (length != null && !cache.precision) { - var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); - cache.precision = ~~total * 10; - cache.data = []; - } - precision = cache.precision || precision; - for (var i = 0; i < precision + 1; i++) { - if (cache.data[i * precision]) { - dot = cache.data[i * precision]; - } else { - dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision); - cache.data[i * precision] = dot; - } - i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5)); - if (length != null && len >= length) { - return dot; - } - old = dot; - } - if (length == null) { - return len; - } - }, - getLengthFactory = function (istotal, subpath) { - return function (path, length, onlystart) { - path = path2curve(path); - var x, y, p, l, sp = "", subpaths = {}, point, - len = 0; - for (var i = 0, ii = path.length; i < ii; i++) { - p = path[i]; - if (p[0] == "M") { - x = +p[1]; - y = +p[2]; - } else { - l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); - if (len + l > length) { - if (subpath && !subpaths.start) { - point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); - sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; - if (onlystart) {return sp;} - subpaths.start = sp; - sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); - len += l; - x = +p[5]; - y = +p[6]; - continue; - } - if (!istotal && !subpath) { - point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); - return {x: point.x, y: point.y, alpha: point.alpha}; - } - } - len += l; - x = +p[5]; - y = +p[6]; - } - sp += p.shift() + p; - } - subpaths.end = sp; - point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); - point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); - return point; - }; - }; - var getTotalLength = getLengthFactory(1), - getPointAtLength = getLengthFactory(), - getSubpathsAtLength = getLengthFactory(0, 1); - - R.getTotalLength = getTotalLength; - - R.getPointAtLength = getPointAtLength; - - R.getSubpath = function (path, from, to) { - if (this.getTotalLength(path) - to < 1e-6) { - return getSubpathsAtLength(path, from).end; - } - var a = getSubpathsAtLength(path, to, 1); - return from ? getSubpathsAtLength(a, from).end : a; - }; - - elproto.getTotalLength = function () { - if (this.type != "path") {return;} - if (this.node.getTotalLength) { - return this.node.getTotalLength(); - } - return getTotalLength(this.attrs.path); - }; - - elproto.getPointAtLength = function (length) { - if (this.type != "path") {return;} - return getPointAtLength(this.attrs.path, length); - }; - - elproto.getSubpath = function (from, to) { - if (this.type != "path") {return;} - return R.getSubpath(this.attrs.path, from, to); - }; - - var ef = R.easing_formulas = { - linear: function (n) { - return n; - }, - "<": function (n) { - return pow(n, 1.7); - }, - ">": function (n) { - return pow(n, .48); - }, - "<>": function (n) { - var q = .48 - n / 1.04, - Q = math.sqrt(.1734 + q * q), - x = Q - q, - X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), - y = -Q - q, - Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), - t = X + Y + .5; - return (1 - t) * 3 * t * t + t * t * t; - }, - backIn: function (n) { - var s = 1.70158; - return n * n * ((s + 1) * n - s); - }, - backOut: function (n) { - n = n - 1; - var s = 1.70158; - return n * n * ((s + 1) * n + s) + 1; - }, - elastic: function (n) { - if (n == !!n) { - return n; - } - return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; - }, - bounce: function (n) { - var s = 7.5625, - p = 2.75, - l; - if (n < (1 / p)) { - l = s * n * n; - } else { - if (n < (2 / p)) { - n -= (1.5 / p); - l = s * n * n + .75; - } else { - if (n < (2.5 / p)) { - n -= (2.25 / p); - l = s * n * n + .9375; - } else { - n -= (2.625 / p); - l = s * n * n + .984375; - } - } - } - return l; - } - }; - ef.easeIn = ef["ease-in"] = ef["<"]; - ef.easeOut = ef["ease-out"] = ef[">"]; - ef.easeInOut = ef["ease-in-out"] = ef["<>"]; - ef["back-in"] = ef.backIn; - ef["back-out"] = ef.backOut; - - var animationElements = [], - requestAnimFrame = window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { - setTimeout(callback, 16); - }, - animation = function () { - var Now = +new Date, - l = 0; - for (; l < animationElements.length; l++) { - var e = animationElements[l]; - if (e.el.removed || e.paused) { - continue; - } - var time = Now - e.start, - ms = e.ms, - easing = e.easing, - from = e.from, - diff = e.diff, - to = e.to, - t = e.t, - that = e.el, - set = {}, - now; - if (e.initstatus) { - time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; - e.status = e.initstatus; - delete e.initstatus; - e.stop && animationElements.splice(l--, 1); - } else { - e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; - } - if (time < 0) { - continue; - } - if (time < ms) { - var pos = easing(time / ms); - for (var attr in from) if (from[has](attr)) { - switch (availableAnimAttrs[attr]) { - case nu: - now = +from[attr] + pos * ms * diff[attr]; - break; - case "colour": - now = "rgb(" + [ - upto255(round(from[attr].r + pos * ms * diff[attr].r)), - upto255(round(from[attr].g + pos * ms * diff[attr].g)), - upto255(round(from[attr].b + pos * ms * diff[attr].b)) - ].join(",") + ")"; - break; - case "path": - now = []; - for (var i = 0, ii = from[attr].length; i < ii; i++) { - now[i] = [from[attr][i][0]]; - for (var j = 1, jj = from[attr][i].length; j < jj; j++) { - now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; - } - now[i] = now[i].join(S); - } - now = now.join(S); - break; - case "transform": - if (diff[attr].real) { - now = []; - for (i = 0, ii = from[attr].length; i < ii; i++) { - now[i] = [from[attr][i][0]]; - for (j = 1, jj = from[attr][i].length; j < jj; j++) { - now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; - } - } - } else { - var get = function (i) { - return +from[attr][i] + pos * ms * diff[attr][i]; - }; - // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; - now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; - } - break; - case "csv": - if (attr == "clip-rect") { - now = []; - i = 4; - while (i--) { - now[i] = +from[attr][i] + pos * ms * diff[attr][i]; - } - } - break; - default: - var from2 = [].concat(from[attr]); - now = []; - i = that.paper.customAttributes[attr].length; - while (i--) { - now[i] = +from2[i] + pos * ms * diff[attr][i]; - } - break; - } - set[attr] = now; - } - that.attr(set); - (function (id, that, anim) { - setTimeout(function () { - eve("anim.frame." + id, that, anim); - }); - })(that.id, that, e.anim); - } else { - (function(f, el, a) { - setTimeout(function() { - eve("anim.frame." + el.id, el, a); - eve("anim.finish." + el.id, el, a); - R.is(f, "function") && f.call(el); - }); - })(e.callback, that, e.anim); - that.attr(to); - animationElements.splice(l--, 1); - if (e.repeat > 1 && !e.next) { - runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); - } - if (e.next && !e.stop) { - runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); - } - } - } - R.svg && that && that.paper && that.paper.safari(); - animationElements.length && requestAnimFrame(animation); - }, - upto255 = function (color) { - return color > 255 ? 255 : color < 0 ? 0 : color; - }; - - elproto.animateWith = function (element, anim, params, ms, easing, callback) { - var a = params ? R.animation(params, ms, easing, callback) : anim; - status = element.status(anim); - return this.animate(a).status(a, status * anim.ms / a.ms); - }; - function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { - var cx = 3 * p1x, - bx = 3 * (p2x - p1x) - cx, - ax = 1 - cx - bx, - cy = 3 * p1y, - by = 3 * (p2y - p1y) - cy, - ay = 1 - cy - by; - function sampleCurveX(t) { - return ((ax * t + bx) * t + cx) * t; - } - function solve(x, epsilon) { - var t = solveCurveX(x, epsilon); - return ((ay * t + by) * t + cy) * t; - } - function solveCurveX(x, epsilon) { - var t0, t1, t2, x2, d2, i; - for(t2 = x, i = 0; i < 8; i++) { - x2 = sampleCurveX(t2) - x; - if (abs(x2) < epsilon) { - return t2; - } - d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; - if (abs(d2) < 1e-6) { - break; - } - t2 = t2 - x2 / d2; - } - t0 = 0; - t1 = 1; - t2 = x; - if (t2 < t0) { - return t0; - } - if (t2 > t1) { - return t1; - } - while (t0 < t1) { - x2 = sampleCurveX(t2); - if (abs(x2 - x) < epsilon) { - return t2; - } - if (x > x2) { - t0 = t2; - } else { - t1 = t2; - } - t2 = (t1 - t0) / 2 + t0; - } - return t2; - } - return solve(t, 1 / (200 * duration)); - } - elproto.onAnimation = function (f) { - f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id); - return this; - }; - function Animation(anim, ms) { - var percents = [], - newAnim = {}; - this.ms = ms; - this.times = 1; - if (anim) { - for (var attr in anim) if (anim[has](attr)) { - newAnim[toFloat(attr)] = anim[attr]; - percents.push(toFloat(attr)); - } - percents.sort(sortByNumber); - } - this.anim = newAnim; - this.top = percents[percents.length - 1]; - this.percents = percents; - } - - Animation.prototype.delay = function (delay) { - var a = new Animation(this.anim, this.ms); - a.times = this.times; - a.del = +delay || 0; - return a; - }; - - Animation.prototype.repeat = function (times) { - var a = new Animation(this.anim, this.ms); - a.del = this.del; - a.times = math.floor(mmax(times, 0)) || 1; - return a; - }; - function runAnimation(anim, element, percent, status, totalOrigin, times) { - percent = toFloat(percent); - var params, - isInAnim, - isInAnimSet, - percents = [], - next, - prev, - timestamp, - ms = anim.ms, - from = {}, - to = {}, - diff = {}; - if (status) { - for (i = 0, ii = animationElements.length; i < ii; i++) { - var e = animationElements[i]; - if (e.el.id == element.id && e.anim == anim) { - if (e.percent != percent) { - animationElements.splice(i, 1); - isInAnimSet = 1; - } else { - isInAnim = e; - } - element.attr(e.totalOrigin); - break; - } - } - } else { - status = +to; // NaN - } - for (var i = 0, ii = anim.percents.length; i < ii; i++) { - if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { - percent = anim.percents[i]; - prev = anim.percents[i - 1] || 0; - ms = ms / anim.top * (percent - prev); - next = anim.percents[i + 1]; - params = anim.anim[percent]; - break; - } else if (status) { - element.attr(anim.anim[anim.percents[i]]); - } - } - if (!params) { - return; - } - if (!isInAnim) { - for (attr in params) if (params[has](attr)) { - if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { - from[attr] = element.attr(attr); - (from[attr] == null) && (from[attr] = availableAttrs[attr]); - to[attr] = params[attr]; - switch (availableAnimAttrs[attr]) { - case nu: - diff[attr] = (to[attr] - from[attr]) / ms; - break; - case "colour": - from[attr] = R.getRGB(from[attr]); - var toColour = R.getRGB(to[attr]); - diff[attr] = { - r: (toColour.r - from[attr].r) / ms, - g: (toColour.g - from[attr].g) / ms, - b: (toColour.b - from[attr].b) / ms - }; - break; - case "path": - var pathes = path2curve(from[attr], to[attr]), - toPath = pathes[1]; - from[attr] = pathes[0]; - diff[attr] = []; - for (i = 0, ii = from[attr].length; i < ii; i++) { - diff[attr][i] = [0]; - for (var j = 1, jj = from[attr][i].length; j < jj; j++) { - diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; - } - } - break; - case "transform": - var _ = element._, - eq = equaliseTransform(_[attr], to[attr]); - if (eq) { - from[attr] = eq.from; - to[attr] = eq.to; - diff[attr] = []; - diff[attr].real = true; - for (i = 0, ii = from[attr].length; i < ii; i++) { - diff[attr][i] = [from[attr][i][0]]; - for (j = 1, jj = from[attr][i].length; j < jj; j++) { - diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; - } - } - } else { - var m = (element.matrix || new Matrix), - to2 = { - _: {transform: _.transform}, - getBBox: function () { - return element.getBBox(1); - } - }; - from[attr] = [ - m.a, - m.b, - m.c, - m.d, - m.e, - m.f - ]; - extractTransform(to2, to[attr]); - to[attr] = to2._.transform; - diff[attr] = [ - (to2.matrix.a - m.a) / ms, - (to2.matrix.b - m.b) / ms, - (to2.matrix.c - m.c) / ms, - (to2.matrix.d - m.d) / ms, - (to2.matrix.e - m.e) / ms, - (to2.matrix.e - m.f) / ms - ]; - // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; - // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; - // extractTransform(to2, to[attr]); - // diff[attr] = [ - // (to2._.sx - _.sx) / ms, - // (to2._.sy - _.sy) / ms, - // (to2._.deg - _.deg) / ms, - // (to2._.dx - _.dx) / ms, - // (to2._.dy - _.dy) / ms - // ]; - } - break; - case "csv": - var values = Str(params[attr]).split(separator), - from2 = Str(from[attr]).split(separator); - if (attr == "clip-rect") { - from[attr] = from2; - diff[attr] = []; - i = from2.length; - while (i--) { - diff[attr][i] = (values[i] - from[attr][i]) / ms; - } - } - to[attr] = values; - break; - default: - values = [].concat(params[attr]); - from2 = [].concat(from[attr]); - diff[attr] = []; - i = element.paper.customAttributes[attr].length; - while (i--) { - diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; - } - break; - } - } - } - var easing = params.easing, - easyeasy = R.easing_formulas[easing]; - if (!easyeasy) { - easyeasy = Str(easing).match(bezierrg); - if (easyeasy && easyeasy.length == 5) { - var curve = easyeasy; - easyeasy = function (t) { - return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); - }; - } else { - easyeasy = pipe; - } - } - timestamp = params.start || anim.start || +new Date; - e = { - anim: anim, - percent: percent, - timestamp: timestamp, - start: timestamp + (anim.del || 0), - status: 0, - initstatus: status || 0, - stop: false, - ms: ms, - easing: easyeasy, - from: from, - diff: diff, - to: to, - el: element, - callback: params.callback, - prev: prev, - next: next, - repeat: times || anim.times, - origin: element.attr(), - totalOrigin: totalOrigin - }; - animationElements.push(e); - if (status && !isInAnim && !isInAnimSet) { - e.stop = true; - e.start = new Date - ms * status; - if (animationElements.length == 1) { - return animation(); - } - } - if (isInAnimSet) { - e.start = new Date - e.ms * status; - } - animationElements.length == 1 && requestAnimFrame(animation); - } else { - isInAnim.initstatus = status; - isInAnim.start = new Date - isInAnim.ms * status; - } - eve("anim.start." + element.id, element, anim); - } - - R.animation = function (params, ms, easing, callback) { - if (params instanceof Animation) { - return params; - } - if (R.is(easing, "function") || !easing) { - callback = callback || easing || null; - easing = null; - } - params = Object(params); - ms = +ms || 0; - var p = {}, - json, - attr; - for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { - json = true; - p[attr] = params[attr]; - } - if (!json) { - return new Animation(params, ms); - } else { - easing && (p.easing = easing); - callback && (p.callback = callback); - return new Animation({100: p}, ms); - } - }; - - elproto.animate = function (params, ms, easing, callback) { - var element = this; - if (element.removed) { - callback && callback.call(element); - return element; - } - var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); - runAnimation(anim, element, anim.percents[0], null, element.attr()); - return element; - }; - - elproto.setTime = function (anim, value) { - if (anim && value != null) { - this.status(anim, mmin(value, anim.ms) / anim.ms); - } - return this; - }; - - elproto.status = function (anim, value) { - var out = [], - i = 0, - len, - e; - if (value != null) { - runAnimation(anim, this, -1, mmin(value, 1)); - return this; - } else { - len = animationElements.length; - for (; i < len; i++) { - e = animationElements[i]; - if (e.el.id == this.id && (!anim || e.anim == anim)) { - if (anim) { - return e.status; - } - out.push({ - anim: e.anim, - status: e.status - }); - } - } - if (anim) { - return 0; - } - return out; - } - }; - - elproto.pause = function (anim) { - for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { - if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) { - animationElements[i].paused = true; - } - } - return this; - }; - - elproto.resume = function (anim) { - for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { - var e = animationElements[i]; - if (eve("anim.resume." + this.id, this, e.anim) !== false) { - delete e.paused; - this.status(e.anim, e.status); - } - } - return this; - }; - - elproto.stop = function (anim) { - for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { - if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) { - animationElements.splice(i--, 1); - } - } - return this; - }; - elproto.toString = function () { - return "Rapha\xebl\u2019s object"; - }; - - // Set - var Set = function (items) { - this.items = []; - this.length = 0; - this.type = "set"; - if (items) { - for (var i = 0, ii = items.length; i < ii; i++) { - if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { - this[this.items.length] = this.items[this.items.length] = items[i]; - this.length++; - } - } - } - }, - setproto = Set.prototype; - - setproto.push = function () { - var item, - len; - for (var i = 0, ii = arguments.length; i < ii; i++) { - item = arguments[i]; - if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { - len = this.items.length; - this[len] = this.items[len] = item; - this.length++; - } - } - return this; - }; - - setproto.pop = function () { - this.length && delete this[this.length--]; - return this.items.pop(); - }; - - setproto.forEach = function (callback, thisArg) { - for (var i = 0, ii = this.items.length; i < ii; i++) { - if (callback.call(thisArg, this.items[i]) === false) { - return this; - } - } - return this; - }; - for (var method in elproto) if (elproto[has](method)) { - setproto[method] = (function (methodname) { - return function () { - var arg = arguments; - return this.forEach(function (el) { - el[methodname][apply](el, arg); - }); - }; - })(method); - } - setproto.attr = function (name, value) { - if (name && R.is(name, array) && R.is(name[0], "object")) { - for (var j = 0, jj = name.length; j < jj; j++) { - this.items[j].attr(name[j]); - } - } else { - for (var i = 0, ii = this.items.length; i < ii; i++) { - this.items[i].attr(name, value); - } - } - return this; - }; - - setproto.clear = function () { - while (this.length) { - this.pop(); - } - }; - - setproto.splice = function (index, count, insertion) { - index = index < 0 ? mmax(this.length + index, 0) : index; - count = mmax(0, mmin(this.length - index, count)); - var tail = [], - todel = [], - args = [], - i; - for (i = 2; i < arguments.length; i++) { - args.push(arguments[i]); - } - for (i = 0; i < count; i++) { - todel.push(this[index + i]); - } - for (; i < this.length - index; i++) { - tail.push(this[index + i]); - } - var arglen = args.length; - for (i = 0; i < arglen + tail.length; i++) { - this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; - } - i = this.items.length = this.length -= count - arglen; - while (this[i]) { - delete this[i++]; - } - return new Set(todel); - }; - - setproto.exclude = function (el) { - for (var i = 0, ii = this.length, found; i < ii; i++) if (found || this[i] == el) { - this[i] = this[i + 1]; - found = 1; - } - if (found) { - this.length--; - delete this[i]; - return true; - } - }; - setproto.animate = function (params, ms, easing, callback) { - (R.is(easing, "function") || !easing) && (callback = easing || null); - var len = this.items.length, - i = len, - item, - set = this, - collector; - if (!len) { - return this; - } - callback && (collector = function () { - !--len && callback.call(set); - }); - easing = R.is(easing, string) ? easing : collector; - var anim = R.animation(params, ms, easing, collector); - item = this.items[--i].animate(anim); - while (i--) { - this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim); - } - return this; - }; - setproto.insertAfter = function (el) { - var i = this.items.length; - while (i--) { - this.items[i].insertAfter(el); - } - return this; - }; - setproto.getBBox = function () { - var x = [], - y = [], - w = [], - h = []; - for (var i = this.items.length; i--;) if (!this.items[i].removed) { - var box = this.items[i].getBBox(); - x.push(box.x); - y.push(box.y); - w.push(box.x + box.width); - h.push(box.y + box.height); - } - x = mmin[apply](0, x); - y = mmin[apply](0, y); - return { - x: x, - y: y, - width: mmax[apply](0, w) - x, - height: mmax[apply](0, h) - y - }; - }; - setproto.clone = function (s) { - s = new Set; - for (var i = 0, ii = this.items.length; i < ii; i++) { - s.push(this.items[i].clone()); - } - return s; - }; - setproto.toString = function () { - return "Rapha\xebl\u2018s set"; - }; - - - R.registerFont = function (font) { - if (!font.face) { - return font; - } - this.fonts = this.fonts || {}; - var fontcopy = { - w: font.w, - face: {}, - glyphs: {} - }, - family = font.face["font-family"]; - for (var prop in font.face) if (font.face[has](prop)) { - fontcopy.face[prop] = font.face[prop]; - } - if (this.fonts[family]) { - this.fonts[family].push(fontcopy); - } else { - this.fonts[family] = [fontcopy]; - } - if (!font.svg) { - fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); - for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { - var path = font.glyphs[glyph]; - fontcopy.glyphs[glyph] = { - w: path.w, - k: {}, - d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { - return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; - }) + "z" - }; - if (path.k) { - for (var k in path.k) if (path[has](k)) { - fontcopy.glyphs[glyph].k[k] = path.k[k]; - } - } - } - } - return font; - }; - - paperproto.getFont = function (family, weight, style, stretch) { - stretch = stretch || "normal"; - style = style || "normal"; - weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; - if (!R.fonts) { - return; - } - var font = R.fonts[family]; - if (!font) { - var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); - for (var fontName in R.fonts) if (R.fonts[has](fontName)) { - if (name.test(fontName)) { - font = R.fonts[fontName]; - break; - } - } - } - var thefont; - if (font) { - for (var i = 0, ii = font.length; i < ii; i++) { - thefont = font[i]; - if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { - break; - } - } - } - return thefont; - }; - - paperproto.print = function (x, y, string, font, size, origin, letter_spacing) { - origin = origin || "middle"; // baseline|middle - letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); - var out = this.set(), - letters = Str(string).split(E), - shift = 0, - path = E, - scale; - R.is(font, string) && (font = this.getFont(font)); - if (font) { - scale = (size || 16) / font.face["units-per-em"]; - var bb = font.face.bbox.split(separator), - top = +bb[0], - height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); - for (var i = 0, ii = letters.length; i < ii; i++) { - var prev = i && font.glyphs[letters[i - 1]] || {}, - curr = font.glyphs[letters[i]]; - shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; - curr && curr.d && out.push(this.path(curr.d).attr({ - fill: "#000", - stroke: "none", - transform: [["t", shift * scale, 0]] - })); - } - out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); - } - return out; - }; - - - R.format = function (token, params) { - var args = R.is(params, array) ? [0][concat](params) : arguments; - token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { - return args[++i] == null ? E : args[i]; - })); - return token || E; - }; - - R.fullfill = (function () { - var tokenRegex = /\{([^\}]+)\}/g, - objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties - replacer = function (all, key, obj) { - var res = obj; - key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { - name = name || quotedName; - if (res) { - if (name in res) { - res = res[name]; - } - typeof res == "function" && isFunc && (res = res()); - } - }); - res = (res == null || res == obj ? all : res) + ""; - return res; - }; - return function (str, obj) { - return String(str).replace(tokenRegex, function (all, key) { - return replacer(all, key, obj); - }); - }; - })(); - - R.ninja = function () { - oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; - return R; - }; - - R.st = setproto; - // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html - (function (doc, loaded, f) { - if (doc.readyState == null && doc.addEventListener){ - doc.addEventListener(loaded, f = function () { - doc.removeEventListener(loaded, f, false); - doc.readyState = "complete"; - }, false); - doc.readyState = "loading"; - } - function isLoaded() { - (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload"); - } - isLoaded(); - })(document, "DOMContentLoaded"); - - oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); - - eve.on("DOMload", function () { - loaded = true; - }); -})(); - -// ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2 - JavaScript Vector Library │ \\ -// ├─────────────────────────────────────────────────────────────────────┤ \\ -// │ SVG Module │ \\ -// ├─────────────────────────────────────────────────────────────────────┤ \\ -// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ -// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ -// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ -// └─────────────────────────────────────────────────────────────────────┘ \\ -window.Raphael.svg && function (R) { - var has = "hasOwnProperty", - Str = String, - toFloat = parseFloat, - toInt = parseInt, - math = Math, - mmax = math.max, - abs = math.abs, - pow = math.pow, - separator = /[, ]+/, - eve = R.eve, - E = "", - S = " "; - var xlink = "http://www.w3.org/1999/xlink", - markers = { - block: "M5,0 0,2.5 5,5z", - classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", - diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", - open: "M6,1 1,3.5 6,6", - oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" - }, - markerCounter = {}; - R.toString = function () { - return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; - }; - var $ = function (el, attr) { - if (attr) { - if (typeof el == "string") { - el = $(el); - } - for (var key in attr) if (attr[has](key)) { - if (key.substring(0, 6) == "xlink:") { - el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); - } else { - el.setAttribute(key, Str(attr[key])); - } - } - } else { - el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); - el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); - } - return el; - }, - gradients = {}, - rgGrad = /^url\(#(.*)\)$/, - removeGradientFill = function (node, paper) { - var oid = node.getAttribute("fill"); - oid = oid && oid.match(rgGrad); - if (oid && !--gradients[oid[1]]) { - delete gradients[oid[1]]; - paper.defs.removeChild(R._g.doc.getElementById(oid[1])); - } - }, - addGradientFill = function (element, gradient) { - var type = "linear", - id = element.id + gradient, - fx = .5, fy = .5, - o = element.node, - SVG = element.paper, - s = o.style, - el = R._g.doc.getElementById(id); - if (!el) { - gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { - type = "radial"; - if (_fx && _fy) { - fx = toFloat(_fx); - fy = toFloat(_fy); - var dir = ((fy > .5) * 2 - 1); - pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && - (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && - fy != .5 && - (fy = fy.toFixed(5) - 1e-5 * dir); - } - return E; - }); - gradient = gradient.split(/\s*\-\s*/); - if (type == "linear") { - var angle = gradient.shift(); - angle = -toFloat(angle); - if (isNaN(angle)) { - return null; - } - var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], - max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); - vector[2] *= max; - vector[3] *= max; - if (vector[2] < 0) { - vector[0] = -vector[2]; - vector[2] = 0; - } - if (vector[3] < 0) { - vector[1] = -vector[3]; - vector[3] = 0; - } - } - var dots = R._parseDots(gradient); - if (!dots) { - return null; - } - if (element.gradient) { - SVG.defs.removeChild(element.gradient); - delete element.gradient; - } - - id = id.replace(/[\(\)\s,\xb0#]/g, "-"); - el = $(type + "Gradient", {id: id}); - element.gradient = el; - $(el, type == "radial" ? { - fx: fx, - fy: fy - } : { - x1: vector[0], - y1: vector[1], - x2: vector[2], - y2: vector[3], - gradientTransform: element.matrix.invert() - }); - SVG.defs.appendChild(el); - for (var i = 0, ii = dots.length; i < ii; i++) { - el.appendChild($("stop", { - offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", - "stop-color": dots[i].color || "#fff" - })); - } - } - $(o, { - fill: "url(#" + id + ")", - opacity: 1, - "fill-opacity": 1 - }); - s.fill = E; - s.opacity = 1; - s.fillOpacity = 1; - return 1; - }, - updatePosition = function (o) { - var bbox = o.getBBox(1); - $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); - }, - addArrow = function (o, value, isEnd) { - if (o.type == "path") { - var values = Str(value).toLowerCase().split("-"), - p = o.paper, - se = isEnd ? "end" : "start", - node = o.node, - attrs = o.attrs, - stroke = attrs["stroke-width"], - i = values.length, - type = "classic", - from, - to, - dx, - refX, - attr, - w = 3, - h = 3, - t = 5; - while (i--) { - switch (values[i]) { - case "block": - case "classic": - case "oval": - case "diamond": - case "open": - case "none": - type = values[i]; - break; - case "wide": h = 5; break; - case "narrow": h = 2; break; - case "long": w = 5; break; - case "short": w = 2; break; - } - } - if (type == "open") { - w += 2; - h += 2; - t += 2; - dx = 1; - refX = isEnd ? 4 : 1; - attr = { - fill: "none", - stroke: attrs.stroke - }; - } else { - refX = dx = w / 2; - attr = { - fill: attrs.stroke, - stroke: "none" - }; - } - if (o._.arrows) { - if (isEnd) { - o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; - o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; - } else { - o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; - o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; - } - } else { - o._.arrows = {}; - } - if (type != "none") { - var pathId = "raphael-marker-" + type, - markerId = "raphael-marker-" + se + type + w + h; - if (!R._g.doc.getElementById(pathId)) { - p.defs.appendChild($($("path"), { - "stroke-linecap": "round", - d: markers[type], - id: pathId - })); - markerCounter[pathId] = 1; - } else { - markerCounter[pathId]++; - } - var marker = R._g.doc.getElementById(markerId), - use; - if (!marker) { - marker = $($("marker"), { - id: markerId, - markerHeight: h, - markerWidth: w, - orient: "auto", - refX: refX, - refY: h / 2 - }); - use = $($("use"), { - "xlink:href": "#" + pathId, - transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")", - "stroke-width": 1 / ((w / t + h / t) / 2) - }); - marker.appendChild(use); - p.defs.appendChild(marker); - markerCounter[markerId] = 1; - } else { - markerCounter[markerId]++; - use = marker.getElementsByTagName("use")[0]; - } - $(use, attr); - var delta = dx * (type != "diamond" && type != "oval"); - if (isEnd) { - from = o._.arrows.startdx * stroke || 0; - to = R.getTotalLength(attrs.path) - delta * stroke; - } else { - from = delta * stroke; - to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); - } - attr = {}; - attr["marker-" + se] = "url(#" + markerId + ")"; - if (to || from) { - attr.d = Raphael.getSubpath(attrs.path, from, to); - } - $(node, attr); - o._.arrows[se + "Path"] = pathId; - o._.arrows[se + "Marker"] = markerId; - o._.arrows[se + "dx"] = delta; - o._.arrows[se + "Type"] = type; - o._.arrows[se + "String"] = value; - } else { - if (isEnd) { - from = o._.arrows.startdx * stroke || 0; - to = R.getTotalLength(attrs.path) - from; - } else { - from = 0; - to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); - } - o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)}); - delete o._.arrows[se + "Path"]; - delete o._.arrows[se + "Marker"]; - delete o._.arrows[se + "dx"]; - delete o._.arrows[se + "Type"]; - delete o._.arrows[se + "String"]; - } - for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { - var item = R._g.doc.getElementById(attr); - item && item.parentNode.removeChild(item); - } - } - }, - dasharray = { - "": [0], - "none": [0], - "-": [3, 1], - ".": [1, 1], - "-.": [3, 1, 1, 1], - "-..": [3, 1, 1, 1, 1, 1], - ". ": [1, 3], - "- ": [4, 3], - "--": [8, 3], - "- .": [4, 3, 1, 3], - "--.": [8, 3, 1, 3], - "--..": [8, 3, 1, 3, 1, 3] - }, - addDashes = function (o, value, params) { - value = dasharray[Str(value).toLowerCase()]; - if (value) { - var width = o.attrs["stroke-width"] || "1", - butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, - dashes = [], - i = value.length; - while (i--) { - dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; - } - $(o.node, {"stroke-dasharray": dashes.join(",")}); - } - }, - setFillAndStroke = function (o, params) { - var node = o.node, - attrs = o.attrs, - vis = node.style.visibility; - node.style.visibility = "hidden"; - for (var att in params) { - if (params[has](att)) { - if (!R._availableAttrs[has](att)) { - continue; - } - var value = params[att]; - attrs[att] = value; - switch (att) { - case "blur": - o.blur(value); - break; - case "href": - case "title": - case "target": - var pn = node.parentNode; - if (pn.tagName.toLowerCase() != "a") { - var hl = $("a"); - pn.insertBefore(hl, node); - hl.appendChild(node); - pn = hl; - } - if (att == "target" && value == "blank") { - pn.setAttributeNS(xlink, "show", "new"); - } else { - pn.setAttributeNS(xlink, att, value); - } - break; - case "cursor": - node.style.cursor = value; - break; - case "transform": - o.transform(value); - break; - case "arrow-start": - addArrow(o, value); - break; - case "arrow-end": - addArrow(o, value, 1); - break; - case "clip-rect": - var rect = Str(value).split(separator); - if (rect.length == 4) { - o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); - var el = $("clipPath"), - rc = $("rect"); - el.id = R.createUUID(); - $(rc, { - x: rect[0], - y: rect[1], - width: rect[2], - height: rect[3] - }); - el.appendChild(rc); - o.paper.defs.appendChild(el); - $(node, {"clip-path": "url(#" + el.id + ")"}); - o.clip = rc; - } - if (!value) { - var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E)); - clip && clip.parentNode.removeChild(clip); - $(node, {"clip-path": E}); - delete o.clip; - } - break; - case "path": - if (o.type == "path") { - $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); - o._.dirty = 1; - if (o._.arrows) { - "startString" in o._.arrows && addArrow(o, o._.arrows.startString); - "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); - } - } - break; - case "width": - node.setAttribute(att, value); - o._.dirty = 1; - if (attrs.fx) { - att = "x"; - value = attrs.x; - } else { - break; - } - case "x": - if (attrs.fx) { - value = -attrs.x - (attrs.width || 0); - } - case "rx": - if (att == "rx" && o.type == "rect") { - break; - } - case "cx": - node.setAttribute(att, value); - o.pattern && updatePosition(o); - o._.dirty = 1; - break; - case "height": - node.setAttribute(att, value); - o._.dirty = 1; - if (attrs.fy) { - att = "y"; - value = attrs.y; - } else { - break; - } - case "y": - if (attrs.fy) { - value = -attrs.y - (attrs.height || 0); - } - case "ry": - if (att == "ry" && o.type == "rect") { - break; - } - case "cy": - node.setAttribute(att, value); - o.pattern && updatePosition(o); - o._.dirty = 1; - break; - case "r": - if (o.type == "rect") { - $(node, {rx: value, ry: value}); - } else { - node.setAttribute(att, value); - } - o._.dirty = 1; - break; - case "src": - if (o.type == "image") { - node.setAttributeNS(xlink, "href", value); - } - break; - case "stroke-width": - if (o._.sx != 1 || o._.sy != 1) { - value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; - } - if (o.paper._vbSize) { - value *= o.paper._vbSize; - } - node.setAttribute(att, value); - if (attrs["stroke-dasharray"]) { - addDashes(o, attrs["stroke-dasharray"], params); - } - if (o._.arrows) { - "startString" in o._.arrows && addArrow(o, o._.arrows.startString); - "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); - } - break; - case "stroke-dasharray": - addDashes(o, value, params); - break; - case "fill": - var isURL = Str(value).match(R._ISURL); - if (isURL) { - el = $("pattern"); - var ig = $("image"); - el.id = R.createUUID(); - $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); - $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); - el.appendChild(ig); - - (function (el) { - R._preload(isURL[1], function () { - var w = this.offsetWidth, - h = this.offsetHeight; - $(el, {width: w, height: h}); - $(ig, {width: w, height: h}); - o.paper.safari(); - }); - })(el); - o.paper.defs.appendChild(el); - node.style.fill = "url(#" + el.id + ")"; - $(node, {fill: "url(#" + el.id + ")"}); - o.pattern = el; - o.pattern && updatePosition(o); - break; - } - var clr = R.getRGB(value); - if (!clr.error) { - delete params.gradient; - delete attrs.gradient; - !R.is(attrs.opacity, "undefined") && - R.is(params.opacity, "undefined") && - $(node, {opacity: attrs.opacity}); - !R.is(attrs["fill-opacity"], "undefined") && - R.is(params["fill-opacity"], "undefined") && - $(node, {"fill-opacity": attrs["fill-opacity"]}); - } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { - if ("opacity" in attrs || "fill-opacity" in attrs) { - var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); - if (gradient) { - var stops = gradient.getElementsByTagName("stop"); - $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); - } - } - attrs.gradient = value; - attrs.fill = "none"; - break; - } - clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); - case "stroke": - clr = R.getRGB(value); - node.setAttribute(att, clr.hex); - att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); - if (att == "stroke" && o._.arrows) { - "startString" in o._.arrows && addArrow(o, o._.arrows.startString); - "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); - } - break; - case "gradient": - (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); - break; - case "opacity": - if (attrs.gradient && !attrs[has]("stroke-opacity")) { - $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); - } - // fall - case "fill-opacity": - if (attrs.gradient) { - gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); - if (gradient) { - stops = gradient.getElementsByTagName("stop"); - $(stops[stops.length - 1], {"stop-opacity": value}); - } - break; - } - default: - att == "font-size" && (value = toInt(value, 10) + "px"); - var cssrule = att.replace(/(\-.)/g, function (w) { - return w.substring(1).toUpperCase(); - }); - node.style[cssrule] = value; - o._.dirty = 1; - node.setAttribute(att, value); - break; - } - } - } - - tuneText(o, params); - node.style.visibility = vis; - }, - leading = 1.2, - tuneText = function (el, params) { - if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { - return; - } - var a = el.attrs, - node = el.node, - fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; - - if (params[has]("text")) { - a.text = params.text; - while (node.firstChild) { - node.removeChild(node.firstChild); - } - var texts = Str(params.text).split("\n"), - tspans = [], - tspan; - for (var i = 0, ii = texts.length; i < ii; i++) { - tspan = $("tspan"); - i && $(tspan, {dy: fontSize * leading, x: a.x}); - tspan.appendChild(R._g.doc.createTextNode(texts[i])); - node.appendChild(tspan); - tspans[i] = tspan; - } - } else { - tspans = node.getElementsByTagName("tspan"); - for (i = 0, ii = tspans.length; i < ii; i++) if (i) { - $(tspans[i], {dy: fontSize * leading, x: a.x}); - } else { - $(tspans[0], {dy: 0}); - } - } - $(node, {x: a.x, y: a.y}); - el._.dirty = 1; - var bb = el._getBBox(), - dif = a.y - (bb.y + bb.height / 2); - dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); - }, - Element = function (node, svg) { - var X = 0, - Y = 0; - - this[0] = this.node = node; - - node.raphael = true; - - this.id = R._oid++; - node.raphaelid = this.id; - this.matrix = R.matrix(); - this.realPath = null; - - this.paper = svg; - this.attrs = this.attrs || {}; - this._ = { - transform: [], - sx: 1, - sy: 1, - deg: 0, - dx: 0, - dy: 0, - dirty: 1 - }; - !svg.bottom && (svg.bottom = this); - - this.prev = svg.top; - svg.top && (svg.top.next = this); - svg.top = this; - - this.next = null; - }, - elproto = R.el; - - Element.prototype = elproto; - elproto.constructor = Element; - - R._engine.path = function (pathString, SVG) { - var el = $("path"); - SVG.canvas && SVG.canvas.appendChild(el); - var p = new Element(el, SVG); - p.type = "path"; - setFillAndStroke(p, { - fill: "none", - stroke: "#000", - path: pathString - }); - return p; - }; - - elproto.rotate = function (deg, cx, cy) { - if (this.removed) { - return this; - } - deg = Str(deg).split(separator); - if (deg.length - 1) { - cx = toFloat(deg[1]); - cy = toFloat(deg[2]); - } - deg = toFloat(deg[0]); - (cy == null) && (cx = cy); - if (cx == null || cy == null) { - var bbox = this.getBBox(1); - cx = bbox.x + bbox.width / 2; - cy = bbox.y + bbox.height / 2; - } - this.transform(this._.transform.concat([["r", deg, cx, cy]])); - return this; - }; - - elproto.scale = function (sx, sy, cx, cy) { - if (this.removed) { - return this; - } - sx = Str(sx).split(separator); - if (sx.length - 1) { - sy = toFloat(sx[1]); - cx = toFloat(sx[2]); - cy = toFloat(sx[3]); - } - sx = toFloat(sx[0]); - (sy == null) && (sy = sx); - (cy == null) && (cx = cy); - if (cx == null || cy == null) { - var bbox = this.getBBox(1); - } - cx = cx == null ? bbox.x + bbox.width / 2 : cx; - cy = cy == null ? bbox.y + bbox.height / 2 : cy; - this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); - return this; - }; - - elproto.translate = function (dx, dy) { - if (this.removed) { - return this; - } - dx = Str(dx).split(separator); - if (dx.length - 1) { - dy = toFloat(dx[1]); - } - dx = toFloat(dx[0]) || 0; - dy = +dy || 0; - this.transform(this._.transform.concat([["t", dx, dy]])); - return this; - }; - - elproto.transform = function (tstr) { - var _ = this._; - if (tstr == null) { - return _.transform; - } - R._extractTransform(this, tstr); - - this.clip && $(this.clip, {transform: this.matrix.invert()}); - this.pattern && updatePosition(this); - this.node && $(this.node, {transform: this.matrix}); - - if (_.sx != 1 || _.sy != 1) { - var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; - this.attr({"stroke-width": sw}); - } - - return this; - }; - - elproto.hide = function () { - !this.removed && this.paper.safari(this.node.style.display = "none"); - return this; - }; - - elproto.show = function () { - !this.removed && this.paper.safari(this.node.style.display = ""); - return this; - }; - - elproto.remove = function () { - if (this.removed) { - return; - } - eve.unbind("*.*." + this.id); - R._tear(this, this.paper); - this.node.parentNode.removeChild(this.node); - for (var i in this) { - delete this[i]; - } - this.removed = true; - }; - elproto._getBBox = function () { - if (this.node.style.display == "none") { - this.show(); - var hide = true; - } - var bbox = {}; - try { - bbox = this.node.getBBox(); - } catch(e) { - // Firefox 3.0.x plays badly here - } finally { - bbox = bbox || {}; - } - hide && this.hide(); - return bbox; - }; - - elproto.attr = function (name, value) { - if (this.removed) { - return this; - } - if (name == null) { - var res = {}; - for (var a in this.attrs) if (this.attrs[has](a)) { - res[a] = this.attrs[a]; - } - res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; - res.transform = this._.transform; - return res; - } - if (value == null && R.is(name, "string")) { - if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { - return this.attrs.gradient; - } - if (name == "transform") { - return this._.transform; - } - var names = name.split(separator), - out = {}; - for (var i = 0, ii = names.length; i < ii; i++) { - name = names[i]; - if (name in this.attrs) { - out[name] = this.attrs[name]; - } else if (R.is(this.paper.customAttributes[name], "function")) { - out[name] = this.paper.customAttributes[name].def; - } else { - out[name] = R._availableAttrs[name]; - } - } - return ii - 1 ? out : out[names[0]]; - } - if (value == null && R.is(name, "array")) { - out = {}; - for (i = 0, ii = name.length; i < ii; i++) { - out[name[i]] = this.attr(name[i]); - } - return out; - } - if (value != null) { - var params = {}; - params[name] = value; - } else if (name != null && R.is(name, "object")) { - params = name; - } - for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { - var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); - this.attrs[key] = params[key]; - for (var subkey in par) if (par[has](subkey)) { - params[subkey] = par[subkey]; - } - } - setFillAndStroke(this, params); - return this; - }; - - elproto.toFront = function () { - if (this.removed) { - return this; - } - this.node.parentNode.appendChild(this.node); - var svg = this.paper; - svg.top != this && R._tofront(this, svg); - return this; - }; - - elproto.toBack = function () { - if (this.removed) { - return this; - } - if (this.node.parentNode.firstChild != this.node) { - this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); - R._toback(this, this.paper); - var svg = this.paper; - } - return this; - }; - - elproto.insertAfter = function (element) { - if (this.removed) { - return this; - } - var node = element.node || element[element.length - 1].node; - if (node.nextSibling) { - node.parentNode.insertBefore(this.node, node.nextSibling); - } else { - node.parentNode.appendChild(this.node); - } - R._insertafter(this, element, this.paper); - return this; - }; - - elproto.insertBefore = function (element) { - if (this.removed) { - return this; - } - var node = element.node || element[0].node; - node.parentNode.insertBefore(this.node, node); - R._insertbefore(this, element, this.paper); - return this; - }; - elproto.blur = function (size) { - // Experimental. No Safari support. Use it on your own risk. - var t = this; - if (+size !== 0) { - var fltr = $("filter"), - blur = $("feGaussianBlur"); - t.attrs.blur = size; - fltr.id = R.createUUID(); - $(blur, {stdDeviation: +size || 1.5}); - fltr.appendChild(blur); - t.paper.defs.appendChild(fltr); - t._blur = fltr; - $(t.node, {filter: "url(#" + fltr.id + ")"}); - } else { - if (t._blur) { - t._blur.parentNode.removeChild(t._blur); - delete t._blur; - delete t.attrs.blur; - } - t.node.removeAttribute("filter"); - } - }; - R._engine.circle = function (svg, x, y, r) { - var el = $("circle"); - svg.canvas && svg.canvas.appendChild(el); - var res = new Element(el, svg); - res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; - res.type = "circle"; - $(el, res.attrs); - return res; - }; - R._engine.rect = function (svg, x, y, w, h, r) { - var el = $("rect"); - svg.canvas && svg.canvas.appendChild(el); - var res = new Element(el, svg); - res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; - res.type = "rect"; - $(el, res.attrs); - return res; - }; - R._engine.ellipse = function (svg, x, y, rx, ry) { - var el = $("ellipse"); - svg.canvas && svg.canvas.appendChild(el); - var res = new Element(el, svg); - res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; - res.type = "ellipse"; - $(el, res.attrs); - return res; - }; - R._engine.image = function (svg, src, x, y, w, h) { - var el = $("image"); - $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); - el.setAttributeNS(xlink, "href", src); - svg.canvas && svg.canvas.appendChild(el); - var res = new Element(el, svg); - res.attrs = {x: x, y: y, width: w, height: h, src: src}; - res.type = "image"; - return res; - }; - R._engine.text = function (svg, x, y, text) { - var el = $("text"); - // $(el, {x: x, y: y, "text-anchor": "middle"}); - svg.canvas && svg.canvas.appendChild(el); - var res = new Element(el, svg); - res.attrs = { - x: x, - y: y, - "text-anchor": "middle", - text: text, - font: R._availableAttrs.font, - stroke: "none", - fill: "#000" - }; - res.type = "text"; - setFillAndStroke(res, res.attrs); - return res; - }; - R._engine.setSize = function (width, height) { - this.width = width || this.width; - this.height = height || this.height; - this.canvas.setAttribute("width", this.width); - this.canvas.setAttribute("height", this.height); - if (this._viewBox) { - this.setViewBox.apply(this, this._viewBox); - } - return this; - }; - R._engine.create = function () { - var con = R._getContainer.apply(0, arguments), - container = con && con.container, - x = con.x, - y = con.y, - width = con.width, - height = con.height; - if (!container) { - throw new Error("SVG container not found."); - } - var cnvs = $("svg"), - css = "overflow:hidden;", - isFloating; - x = x || 0; - y = y || 0; - width = width || 512; - height = height || 342; - $(cnvs, { - height: height, - version: 1.1, - width: width, - xmlns: "http://www.w3.org/2000/svg" - }); - if (container == 1) { - cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; - R._g.doc.body.appendChild(cnvs); - isFloating = 1; - } else { - cnvs.style.cssText = css + "position:relative"; - if (container.firstChild) { - container.insertBefore(cnvs, container.firstChild); - } else { - container.appendChild(cnvs); - } - } - container = new R._Paper; - container.width = width; - container.height = height; - container.canvas = cnvs; - // plugins.call(container, container, R.fn); - container.clear(); - container._left = container._top = 0; - isFloating && (container.renderfix = function () {}); - container.renderfix(); - return container; - }; - R._engine.setViewBox = function (x, y, w, h, fit) { - eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); - var size = mmax(w / this.width, h / this.height), - top = this.top, - aspectRatio = fit ? "meet" : "xMinYMin", - vb, - sw; - if (x == null) { - if (this._vbSize) { - size = 1; - } - delete this._vbSize; - vb = "0 0 " + this.width + S + this.height; - } else { - this._vbSize = size; - vb = x + S + y + S + w + S + h; - } - $(this.canvas, { - viewBox: vb, - preserveAspectRatio: aspectRatio - }); - while (size && top) { - sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; - top.attr({"stroke-width": sw}); - top._.dirty = 1; - top._.dirtyT = 1; - top = top.prev; - } - this._viewBox = [x, y, w, h, !!fit]; - return this; - }; - - R.prototype.renderfix = function () { - var cnvs = this.canvas, - s = cnvs.style, - pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(), - left = -pos.e % 1, - top = -pos.f % 1; - if (left || top) { - if (left) { - this._left = (this._left + left) % 1; - s.left = this._left + "px"; - } - if (top) { - this._top = (this._top + top) % 1; - s.top = this._top + "px"; - } - } - }; - - R.prototype.clear = function () { - R.eve("clear", this); - var c = this.canvas; - while (c.firstChild) { - c.removeChild(c.firstChild); - } - this.bottom = this.top = null; - (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); - c.appendChild(this.desc); - c.appendChild(this.defs = $("defs")); - }; - - R.prototype.remove = function () { - eve("remove", this); - this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); - for (var i in this) { - this[i] = removed(i); - } - }; - var setproto = R.st; - for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { - setproto[method] = (function (methodname) { - return function () { - var arg = arguments; - return this.forEach(function (el) { - el[methodname].apply(el, arg); - }); - }; - })(method); - } -}(window.Raphael); - -// ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2 - JavaScript Vector Library │ \\ -// ├─────────────────────────────────────────────────────────────────────┤ \\ -// │ VML Module │ \\ -// ├─────────────────────────────────────────────────────────────────────┤ \\ -// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ -// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ -// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ -// └─────────────────────────────────────────────────────────────────────┘ \\ -window.Raphael.vml && function (R) { - var has = "hasOwnProperty", - Str = String, - toFloat = parseFloat, - math = Math, - round = math.round, - mmax = math.max, - mmin = math.min, - abs = math.abs, - fillString = "fill", - separator = /[, ]+/, - eve = R.eve, - ms = " progid:DXImageTransform.Microsoft", - S = " ", - E = "", - map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, - bites = /([clmz]),?([^clmz]*)/gi, - blurregexp = / progid:\S+Blur\([^\)]+\)/g, - val = /-?[^,\s-]+/g, - cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", - zoom = 21600, - pathTypes = {path: 1, rect: 1, image: 1}, - ovalTypes = {circle: 1, ellipse: 1}, - path2vml = function (path) { - var total = /[ahqstv]/ig, - command = R._pathToAbsolute; - Str(path).match(total) && (command = R._path2curve); - total = /[clmz]/g; - if (command == R._pathToAbsolute && !Str(path).match(total)) { - var res = Str(path).replace(bites, function (all, command, args) { - var vals = [], - isMove = command.toLowerCase() == "m", - res = map[command]; - args.replace(val, function (value) { - if (isMove && vals.length == 2) { - res += vals + map[command == "m" ? "l" : "L"]; - vals = []; - } - vals.push(round(value * zoom)); - }); - return res + vals; - }); - return res; - } - var pa = command(path), p, r; - res = []; - for (var i = 0, ii = pa.length; i < ii; i++) { - p = pa[i]; - r = pa[i][0].toLowerCase(); - r == "z" && (r = "x"); - for (var j = 1, jj = p.length; j < jj; j++) { - r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); - } - res.push(r); - } - return res.join(S); - }, - compensation = function (deg, dx, dy) { - var m = R.matrix(); - m.rotate(-deg, .5, .5); - return { - dx: m.x(dx, dy), - dy: m.y(dx, dy) - }; - }, - setCoords = function (p, sx, sy, dx, dy, deg) { - var _ = p._, - m = p.matrix, - fillpos = _.fillpos, - o = p.node, - s = o.style, - y = 1, - flip = "", - dxdy, - kx = zoom / sx, - ky = zoom / sy; - s.visibility = "hidden"; - if (!sx || !sy) { - return; - } - o.coordsize = abs(kx) + S + abs(ky); - s.rotation = deg * (sx * sy < 0 ? -1 : 1); - if (deg) { - var c = compensation(deg, dx, dy); - dx = c.dx; - dy = c.dy; - } - sx < 0 && (flip += "x"); - sy < 0 && (flip += " y") && (y = -1); - s.flip = flip; - o.coordorigin = (dx * -kx) + S + (dy * -ky); - if (fillpos || _.fillsize) { - var fill = o.getElementsByTagName(fillString); - fill = fill && fill[0]; - o.removeChild(fill); - if (fillpos) { - c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); - fill.position = c.dx * y + S + c.dy * y; - } - if (_.fillsize) { - fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); - } - o.appendChild(fill); - } - s.visibility = "visible"; - }; - R.toString = function () { - return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; - }; - addArrow = function (o, value, isEnd) { - var values = Str(value).toLowerCase().split("-"), - se = isEnd ? "end" : "start", - i = values.length, - type = "classic", - w = "medium", - h = "medium"; - while (i--) { - switch (values[i]) { - case "block": - case "classic": - case "oval": - case "diamond": - case "open": - case "none": - type = values[i]; - break; - case "wide": - case "narrow": h = values[i]; break; - case "long": - case "short": w = values[i]; break; - } - } - var stroke = o.node.getElementsByTagName("stroke")[0]; - stroke[se + "arrow"] = type; - stroke[se + "arrowlength"] = w; - stroke[se + "arrowwidth"] = h; - }; - setFillAndStroke = function (o, params) { - // o.paper.canvas.style.display = "none"; - o.attrs = o.attrs || {}; - var node = o.node, - a = o.attrs, - s = node.style, - xy, - newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r), - isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), - res = o; - - - for (var par in params) if (params[has](par)) { - a[par] = params[par]; - } - if (newpath) { - a.path = R._getPath[o.type](o); - o._.dirty = 1; - } - params.href && (node.href = params.href); - params.title && (node.title = params.title); - params.target && (node.target = params.target); - params.cursor && (s.cursor = params.cursor); - "blur" in params && o.blur(params.blur); - if (params.path && o.type == "path" || newpath) { - node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); - if (o.type == "image") { - o._.fillpos = [a.x, a.y]; - o._.fillsize = [a.width, a.height]; - setCoords(o, 1, 1, 0, 0, 0); - } - } - "transform" in params && o.transform(params.transform); - if (isOval) { - var cx = +a.cx, - cy = +a.cy, - rx = +a.rx || +a.r || 0, - ry = +a.ry || +a.r || 0; - node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom)); - } - if ("clip-rect" in params) { - var rect = Str(params["clip-rect"]).split(separator); - if (rect.length == 4) { - rect[2] = +rect[2] + (+rect[0]); - rect[3] = +rect[3] + (+rect[1]); - var div = node.clipRect || R._g.doc.createElement("div"), - dstyle = div.style; - dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); - if (!node.clipRect) { - dstyle.position = "absolute"; - dstyle.top = 0; - dstyle.left = 0; - dstyle.width = o.paper.width + "px"; - dstyle.height = o.paper.height + "px"; - node.parentNode.insertBefore(div, node); - div.appendChild(node); - node.clipRect = div; - } - } - if (!params["clip-rect"]) { - node.clipRect && (node.clipRect.style.clip = E); - } - } - if (o.textpath) { - var textpathStyle = o.textpath.style; - params.font && (textpathStyle.font = params.font); - params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); - params["font-size"] && (textpathStyle.fontSize = params["font-size"]); - params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); - params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); - } - if ("arrow-start" in params) { - addArrow(res, params["arrow-start"]); - } - if ("arrow-end" in params) { - addArrow(res, params["arrow-end"], 1); - } - if (params.opacity != null || - params["stroke-width"] != null || - params.fill != null || - params.src != null || - params.stroke != null || - params["stroke-width"] != null || - params["stroke-opacity"] != null || - params["fill-opacity"] != null || - params["stroke-dasharray"] != null || - params["stroke-miterlimit"] != null || - params["stroke-linejoin"] != null || - params["stroke-linecap"] != null) { - var fill = node.getElementsByTagName(fillString), - newfill = false; - fill = fill && fill[0]; - !fill && (newfill = fill = createNode(fillString)); - if (o.type == "image" && params.src) { - fill.src = params.src; - } - params.fill && (fill.on = true); - if (fill.on == null || params.fill == "none" || params.fill === null) { - fill.on = false; - } - if (fill.on && params.fill) { - var isURL = Str(params.fill).match(R._ISURL); - if (isURL) { - fill.parentNode == node && node.removeChild(fill); - fill.rotate = true; - fill.src = isURL[1]; - fill.type = "tile"; - var bbox = o.getBBox(1); - fill.position = bbox.x + S + bbox.y; - o._.fillpos = [bbox.x, bbox.y]; - - R._preload(isURL[1], function () { - o._.fillsize = [this.offsetWidth, this.offsetHeight]; - }); - } else { - fill.color = R.getRGB(params.fill).hex; - fill.src = E; - fill.type = "solid"; - if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { - a.fill = "none"; - a.gradient = params.fill; - fill.rotate = false; - } - } - } - if ("fill-opacity" in params || "opacity" in params) { - var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); - opacity = mmin(mmax(opacity, 0), 1); - fill.opacity = opacity; - if (fill.src) { - fill.color = "none"; - } - } - node.appendChild(fill); - var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), - newstroke = false; - !stroke && (newstroke = stroke = createNode("stroke")); - if ((params.stroke && params.stroke != "none") || - params["stroke-width"] || - params["stroke-opacity"] != null || - params["stroke-dasharray"] || - params["stroke-miterlimit"] || - params["stroke-linejoin"] || - params["stroke-linecap"]) { - stroke.on = true; - } - (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); - var strokeColor = R.getRGB(params.stroke); - stroke.on && params.stroke && (stroke.color = strokeColor.hex); - opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); - var width = (toFloat(params["stroke-width"]) || 1) * .75; - opacity = mmin(mmax(opacity, 0), 1); - params["stroke-width"] == null && (width = a["stroke-width"]); - params["stroke-width"] && (stroke.weight = width); - width && width < 1 && (opacity *= width) && (stroke.weight = 1); - stroke.opacity = opacity; - - params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); - stroke.miterlimit = params["stroke-miterlimit"] || 8; - params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); - if (params["stroke-dasharray"]) { - var dasharray = { - "-": "shortdash", - ".": "shortdot", - "-.": "shortdashdot", - "-..": "shortdashdotdot", - ". ": "dot", - "- ": "dash", - "--": "longdash", - "- .": "dashdot", - "--.": "longdashdot", - "--..": "longdashdotdot" - }; - stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; - } - newstroke && node.appendChild(stroke); - } - if (res.type == "text") { - res.paper.canvas.style.display = E; - var span = res.paper.span, - m = 100, - fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); - s = span.style; - a.font && (s.font = a.font); - a["font-family"] && (s.fontFamily = a["font-family"]); - a["font-weight"] && (s.fontWeight = a["font-weight"]); - a["font-style"] && (s.fontStyle = a["font-style"]); - fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]); - s.fontSize = fontSize * m + "px"; - res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/")); - var brect = span.getBoundingClientRect(); - res.W = a.w = (brect.right - brect.left) / m; - res.H = a.h = (brect.bottom - brect.top) / m; - // res.paper.canvas.style.display = "none"; - res.X = a.x; - res.Y = a.y + res.H / 2; - - ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1)); - var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; - for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { - res._.dirty = 1; - break; - } - - // text-anchor emulation - switch (a["text-anchor"]) { - case "start": - res.textpath.style["v-text-align"] = "left"; - res.bbx = res.W / 2; - break; - case "end": - res.textpath.style["v-text-align"] = "right"; - res.bbx = -res.W / 2; - break; - default: - res.textpath.style["v-text-align"] = "center"; - res.bbx = 0; - break; - } - res.textpath.style["v-text-kern"] = true; - } - // res.paper.canvas.style.display = E; - }; - addGradientFill = function (o, gradient, fill) { - o.attrs = o.attrs || {}; - var attrs = o.attrs, - opacity, - oindex, - type = "linear", - fxfy = ".5 .5"; - o.attrs.gradient = gradient; - gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { - type = "radial"; - if (fx && fy) { - fx = toFloat(fx); - fy = toFloat(fy); - pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); - fxfy = fx + S + fy; - } - return E; - }); - gradient = gradient.split(/\s*\-\s*/); - if (type == "linear") { - var angle = gradient.shift(); - angle = -toFloat(angle); - if (isNaN(angle)) { - return null; - } - } - var dots = R._parseDots(gradient); - if (!dots) { - return null; - } - o = o.shape || o.node; - if (dots.length) { - o.removeChild(fill); - fill.on = true; - fill.method = "none"; - fill.color = dots[0].color; - fill.color2 = dots[dots.length - 1].color; - var clrs = []; - for (var i = 0, ii = dots.length; i < ii; i++) { - dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); - } - fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; - if (type == "radial") { - fill.type = "gradientTitle"; - fill.focus = "100%"; - fill.focussize = "0 0"; - fill.focusposition = fxfy; - fill.angle = 0; - } else { - // fill.rotate= true; - fill.type = "gradient"; - fill.angle = (270 - angle) % 360; - } - o.appendChild(fill); - } - return 1; - }; - Element = function (node, vml) { - this[0] = this.node = node; - node.raphael = true; - this.id = R._oid++; - node.raphaelid = this.id; - this.X = 0; - this.Y = 0; - this.attrs = {}; - this.paper = vml; - this.matrix = R.matrix(); - this._ = { - transform: [], - sx: 1, - sy: 1, - dx: 0, - dy: 0, - deg: 0, - dirty: 1, - dirtyT: 1 - }; - !vml.bottom && (vml.bottom = this); - this.prev = vml.top; - vml.top && (vml.top.next = this); - vml.top = this; - this.next = null; - }; - var elproto = R.el; - - Element.prototype = elproto; - elproto.constructor = Element; - elproto.transform = function (tstr) { - if (tstr == null) { - return this._.transform; - } - var vbs = this.paper._viewBoxShift, - vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, - oldt; - if (vbs) { - oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); - } - R._extractTransform(this, vbt + tstr); - var matrix = this.matrix.clone(), - skew = this.skew, - o = this.node, - split, - isGrad = ~Str(this.attrs.fill).indexOf("-"), - isPatt = !Str(this.attrs.fill).indexOf("url("); - matrix.translate(-.5, -.5); - if (isPatt || isGrad || this.type == "image") { - skew.matrix = "1 0 0 1"; - skew.offset = "0 0"; - split = matrix.split(); - if ((isGrad && split.noRotation) || !split.isSimple) { - o.style.filter = matrix.toFilter(); - var bb = this.getBBox(), - bbt = this.getBBox(1), - dx = bb.x - bbt.x, - dy = bb.y - bbt.y; - o.coordorigin = (dx * -zoom) + S + (dy * -zoom); - setCoords(this, 1, 1, dx, dy, 0); - } else { - o.style.filter = E; - setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); - } - } else { - o.style.filter = E; - skew.matrix = Str(matrix); - skew.offset = matrix.offset(); - } - oldt && (this._.transform = oldt); - return this; - }; - elproto.rotate = function (deg, cx, cy) { - if (this.removed) { - return this; - } - if (deg == null) { - return; - } - deg = Str(deg).split(separator); - if (deg.length - 1) { - cx = toFloat(deg[1]); - cy = toFloat(deg[2]); - } - deg = toFloat(deg[0]); - (cy == null) && (cx = cy); - if (cx == null || cy == null) { - var bbox = this.getBBox(1); - cx = bbox.x + bbox.width / 2; - cy = bbox.y + bbox.height / 2; - } - this._.dirtyT = 1; - this.transform(this._.transform.concat([["r", deg, cx, cy]])); - return this; - }; - elproto.translate = function (dx, dy) { - if (this.removed) { - return this; - } - dx = Str(dx).split(separator); - if (dx.length - 1) { - dy = toFloat(dx[1]); - } - dx = toFloat(dx[0]) || 0; - dy = +dy || 0; - if (this._.bbox) { - this._.bbox.x += dx; - this._.bbox.y += dy; - } - this.transform(this._.transform.concat([["t", dx, dy]])); - return this; - }; - elproto.scale = function (sx, sy, cx, cy) { - if (this.removed) { - return this; - } - sx = Str(sx).split(separator); - if (sx.length - 1) { - sy = toFloat(sx[1]); - cx = toFloat(sx[2]); - cy = toFloat(sx[3]); - isNaN(cx) && (cx = null); - isNaN(cy) && (cy = null); - } - sx = toFloat(sx[0]); - (sy == null) && (sy = sx); - (cy == null) && (cx = cy); - if (cx == null || cy == null) { - var bbox = this.getBBox(1); - } - cx = cx == null ? bbox.x + bbox.width / 2 : cx; - cy = cy == null ? bbox.y + bbox.height / 2 : cy; - - this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); - this._.dirtyT = 1; - return this; - }; - elproto.hide = function () { - !this.removed && (this.node.style.display = "none"); - return this; - }; - elproto.show = function () { - !this.removed && (this.node.style.display = E); - return this; - }; - elproto._getBBox = function () { - if (this.removed) { - return {}; - } - if (this.type == "text") { - return { - x: this.X + (this.bbx || 0) - this.W / 2, - y: this.Y - this.H, - width: this.W, - height: this.H - }; - } else { - return pathDimensions(this.attrs.path); - } - }; - elproto.remove = function () { - if (this.removed) { - return; - } - R.eve.unbind("*.*." + this.id); - R._tear(this, this.paper); - this.node.parentNode.removeChild(this.node); - this.shape && this.shape.parentNode.removeChild(this.shape); - for (var i in this) { - delete this[i]; - } - this.removed = true; - }; - elproto.attr = function (name, value) { - if (this.removed) { - return this; - } - if (name == null) { - var res = {}; - for (var a in this.attrs) if (this.attrs[has](a)) { - res[a] = this.attrs[a]; - } - res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; - res.transform = this._.transform; - return res; - } - if (value == null && R.is(name, "string")) { - if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { - return this.attrs.gradient; - } - var names = name.split(separator), - out = {}; - for (var i = 0, ii = names.length; i < ii; i++) { - name = names[i]; - if (name in this.attrs) { - out[name] = this.attrs[name]; - } else if (R.is(this.paper.customAttributes[name], "function")) { - out[name] = this.paper.customAttributes[name].def; - } else { - out[name] = R._availableAttrs[name]; - } - } - return ii - 1 ? out : out[names[0]]; - } - if (this.attrs && value == null && R.is(name, "array")) { - out = {}; - for (i = 0, ii = name.length; i < ii; i++) { - out[name[i]] = this.attr(name[i]); - } - return out; - } - var params; - if (value != null) { - params = {}; - params[name] = value; - } - value == null && R.is(name, "object") && (params = name); - for (var key in params) { - R.eve("attr." + key + "." + this.id, this, params[key]); - } - if (params) { - for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { - var par = this.paper.customAttributes[key].apply(this, [][concat](params[key])); - this.attrs[key] = params[key]; - for (var subkey in par) if (par[has](subkey)) { - params[subkey] = par[subkey]; - } - } - // this.paper.canvas.style.display = "none"; - if (params.text && this.type == "text") { - this.textpath.string = params.text; - } - setFillAndStroke(this, params); - // this.paper.canvas.style.display = E; - } - return this; - }; - elproto.toFront = function () { - !this.removed && this.node.parentNode.appendChild(this.node); - this.paper && this.paper.top != this && R._tofront(this, this.paper); - return this; - }; - elproto.toBack = function () { - if (this.removed) { - return this; - } - if (this.node.parentNode.firstChild != this.node) { - this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); - R._toback(this, this.paper); - } - return this; - }; - elproto.insertAfter = function (element) { - if (this.removed) { - return this; - } - if (element.constructor == R.st.constructor) { - element = element[element.length - 1]; - } - if (element.node.nextSibling) { - element.node.parentNode.insertBefore(this.node, element.node.nextSibling); - } else { - element.node.parentNode.appendChild(this.node); - } - R._insertafter(this, element, this.paper); - return this; - }; - elproto.insertBefore = function (element) { - if (this.removed) { - return this; - } - if (element.constructor == R.st.constructor) { - element = element[0]; - } - element.node.parentNode.insertBefore(this.node, element.node); - R._insertbefore(this, element, this.paper); - return this; - }; - elproto.blur = function (size) { - var s = this.node.runtimeStyle, - f = s.filter; - f = f.replace(blurregexp, E); - if (+size !== 0) { - this.attrs.blur = size; - s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; - s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); - } else { - s.filter = f; - s.margin = 0; - delete this.attrs.blur; - } - }; - - R._engine.path = function (pathString, vml) { - var el = createNode("shape"); - el.style.cssText = cssDot; - el.coordsize = zoom + S + zoom; - el.coordorigin = vml.coordorigin; - var p = new Element(el, vml), - attr = {fill: "none", stroke: "#000"}; - pathString && (attr.path = pathString); - p.type = "path"; - p.path = []; - p.Path = E; - setFillAndStroke(p, attr); - vml.canvas.appendChild(el); - var skew = createNode("skew"); - skew.on = true; - el.appendChild(skew); - p.skew = skew; - p.transform(E); - return p; - }; - R._engine.rect = function (vml, x, y, w, h, r) { - var path = R._rectPath(x, y, w, h, r), - res = vml.path(path), - a = res.attrs; - res.X = a.x = x; - res.Y = a.y = y; - res.W = a.width = w; - res.H = a.height = h; - a.r = r; - a.path = path; - res.type = "rect"; - return res; - }; - R._engine.ellipse = function (vml, x, y, rx, ry) { - var res = vml.path(), - a = res.attrs; - res.X = x - rx; - res.Y = y - ry; - res.W = rx * 2; - res.H = ry * 2; - res.type = "ellipse"; - setFillAndStroke(res, { - cx: x, - cy: y, - rx: rx, - ry: ry - }); - return res; - }; - R._engine.circle = function (vml, x, y, r) { - var res = vml.path(), - a = res.attrs; - res.X = x - r; - res.Y = y - r; - res.W = res.H = r * 2; - res.type = "circle"; - setFillAndStroke(res, { - cx: x, - cy: y, - r: r - }); - return res; - }; - R._engine.image = function (vml, src, x, y, w, h) { - var path = R._rectPath(x, y, w, h), - res = vml.path(path).attr({stroke: "none"}), - a = res.attrs, - node = res.node, - fill = node.getElementsByTagName(fillString)[0]; - a.src = src; - res.X = a.x = x; - res.Y = a.y = y; - res.W = a.width = w; - res.H = a.height = h; - a.path = path; - res.type = "image"; - fill.parentNode == node && node.removeChild(fill); - fill.rotate = true; - fill.src = src; - fill.type = "tile"; - res._.fillpos = [x, y]; - res._.fillsize = [w, h]; - node.appendChild(fill); - setCoords(res, 1, 1, 0, 0, 0); - return res; - }; - R._engine.text = function (vml, x, y, text) { - var el = createNode("shape"), - path = createNode("path"), - o = createNode("textpath"); - x = x || 0; - y = y || 0; - text = text || ""; - path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); - path.textpathok = true; - o.string = Str(text); - o.on = true; - el.style.cssText = "position:absolute;left:0;top:0;width:1px;height:1px"; - el.coordsize = zoom + S + zoom; - el.coordorigin = "0 0"; - var p = new Element(el, vml), - attr = { - fill: "#000", - stroke: "none", - font: R._availableAttrs.font, - text: text - }; - p.shape = el; - p.path = path; - p.textpath = o; - p.type = "text"; - p.attrs.text = Str(text); - p.attrs.x = x; - p.attrs.y = y; - p.attrs.w = 1; - p.attrs.h = 1; - setFillAndStroke(p, attr); - el.appendChild(o); - el.appendChild(path); - vml.canvas.appendChild(el); - var skew = createNode("skew"); - skew.on = true; - el.appendChild(skew); - p.skew = skew; - p.transform(E); - return p; - }; - R._engine.setSize = function (width, height) { - var cs = this.canvas.style; - this.width = width; - this.height = height; - width == +width && (width += "px"); - height == +height && (height += "px"); - cs.width = width; - cs.height = height; - cs.clip = "rect(0 " + width + " " + height + " 0)"; - if (this._viewBox) { - setViewBox.apply(this, this._viewBox); - } - return this; - }; - R._engine.setViewBox = function (x, y, w, h, fit) { - R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); - var width = this.width, - height = this.height, - size = 1 / mmax(w / width, h / height), - H, W; - if (fit) { - H = height / h; - W = width / w; - if (w * H < width) { - x -= (width - w * H) / 2 / H; - } - if (h * W < height) { - y -= (height - h * W) / 2 / W; - } - } - this._viewBox = [x, y, w, h, !!fit]; - this._viewBoxShift = { - dx: -x, - dy: -y, - scale: size - }; - this.forEach(function (el) { - el.transform("..."); - }); - return this; - }; - var createNode, - initWin = function (win) { - var doc = win.document; - doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); - try { - !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); - createNode = function (tagName) { - return doc.createElement(''); - }; - } catch (e) { - createNode = function (tagName) { - return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); - }; - } - }; - initWin(R._g.win); - R._engine.create = function () { - var con = R._getContainer.apply(0, arguments), - container = con.container, - height = con.height, - s, - width = con.width, - x = con.x, - y = con.y; - if (!container) { - throw new Error("VML container not found."); - } - var res = new R._Paper, - c = res.canvas = R._g.doc.createElement("div"), - cs = c.style; - x = x || 0; - y = y || 0; - width = width || 512; - height = height || 342; - res.width = width; - res.height = height; - width == +width && (width += "px"); - height == +height && (height += "px"); - res.coordsize = zoom * 1e3 + S + zoom * 1e3; - res.coordorigin = "0 0"; - res.span = R._g.doc.createElement("span"); - res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; - c.appendChild(res.span); - cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); - if (container == 1) { - R._g.doc.body.appendChild(c); - cs.left = x + "px"; - cs.top = y + "px"; - cs.position = "absolute"; - } else { - if (container.firstChild) { - container.insertBefore(c, container.firstChild); - } else { - container.appendChild(c); - } - } - // plugins.call(res, res, R.fn); - res.renderfix = function () {}; - return res; - }; - R.prototype.clear = function () { - R.eve("clear", this); - this.canvas.innerHTML = E; - this.span = R._g.doc.createElement("span"); - this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; - this.canvas.appendChild(this.span); - this.bottom = this.top = null; - }; - R.prototype.remove = function () { - R.eve("remove", this); - this.canvas.parentNode.removeChild(this.canvas); - for (var i in this) { - this[i] = removed(i); - } - return true; - }; -}(window.Raphael); \ No newline at end of file diff --git a/site/js/us-map/svg/Blank_USA,_w_territories.svg b/site/js/us-map/svg/Blank_USA,_w_territories.svg deleted file mode 100644 index f781572..0000000 --- a/site/js/us-map/svg/Blank_USA,_w_territories.svg +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DC - - - - - MD - - - - - DE - - - - - NJ - - - - - CT - - - - - RI - - - - - MH - - - - - NH - - - - - VT - - - - - AS - - - - - MP - - - - - GU - - - - - VI - - - - - PR - - - - diff --git a/site/js/us-map/svg/Blank_US_Map.svg b/site/js/us-map/svg/Blank_US_Map.svg deleted file mode 100644 index 46ccbd3..0000000 --- a/site/js/us-map/svg/Blank_US_Map.svg +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/js/utils.js b/site/js/utils.js deleted file mode 100644 index 5b7cb16..0000000 --- a/site/js/utils.js +++ /dev/null @@ -1,14 +0,0 @@ -//Submit the form -function submit(formID) { - $('#' + formID).submit(); -} - -//Follow the url -function navigate(url) { - window.location = url; -} - -//Convert number to string with commas - http://stackoverflow.com/a/2901298 -function numberWithCommas(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); -} \ No newline at end of file diff --git a/site/launch.php b/site/launch.php deleted file mode 100644 index cb82fea..0000000 --- a/site/launch.php +++ /dev/null @@ -1,37 +0,0 @@ - - - -

- Please click here to continue. -

- - diff --git a/site/logout.php b/site/logout.php deleted file mode 100644 index 91b4e97..0000000 --- a/site/logout.php +++ /dev/null @@ -1,20 +0,0 @@ - -
-
- You have successfully logged out. -
- Login Again -
-
- diff --git a/site/mturk_entry.php b/site/mturk_entry.php deleted file mode 100644 index e8fdba1..0000000 --- a/site/mturk_entry.php +++ /dev/null @@ -1,43 +0,0 @@ - - - - - -
- Mturk ID:
- -
- - - - - - - diff --git a/site/mturk_test_entry.php b/site/mturk_test_entry.php deleted file mode 100644 index b2af6ac..0000000 --- a/site/mturk_test_entry.php +++ /dev/null @@ -1,42 +0,0 @@ - - - - - -
- Mturk ID:
- -
- - - - - - - diff --git a/site/preferences.php b/site/preferences.php deleted file mode 100644 index 1171242..0000000 --- a/site/preferences.php +++ /dev/null @@ -1,433 +0,0 @@ - - - - - - - - - - /> - - - - -
- 1)); - ?> -
-
- Welcome to Crowdcast -
Thank you for joining us!
-
-
-

- Hi, ! - Since this is your first time to login, we thought it might be helpful to take you to the preferences page. - Below you will find a privacy statement, email settings, and a short survey. - By default, we will notify you by email every week as soon as the new weekly COVID-19 and other ILI data is available (this usually happens by Friday afternoon), and provide a convenient link to your forecasting page. - If you like, we can also send an email reminder before each deadline. - The survey is completely optional, but it would help us analyze the data. - The next time you login you will be taken straight to your forecasting home page, but you can always come back to this page by clicking the "Preferences" link in the top right corner of any Crowdcast page. -

-
-
- -
-
- Your Privacy -
We won't misuse your email address or publish your forecasts.
-
-
-

Email

-

- We will only use your email to communicate with you about Crowdcast, and we will never share your email with anyone else. -

-

Forecasts

-

- We will not release your individual forecasts (unless you tell us to). - Instead, we combine together many such forecasts to create an aggregate forecast which will be compared to forecasts made using other techniques. - We may also want to create aggregate forecasts based on specific subsets of forecasters. -

-
-
-
-
- Account Settings -
Update your account information.
-
-
-
-

Account Status

- - -

- Should you no longer wish to participate, you have the option to completely deactivate your account. - Please note that we will not email you at all if your account has been deactivated, regardless of your email settings below. -

- - -

- Your account has been deactivated. - If you want to participate again, just click the button below to reactive your account! -

- -
- -
-
- -
-
- Email Settings -
Select which emails you would like to receive.
-
-
-
- -

Email Types

-

- Every Friday the CDC publishes new data on COVID-19 and influenza-like illness (ILI), and every Monday the forecasting round ends. - We'll send you an email to notify you as soon as the new data is available, as long as your account is active. - In addition, there are a couple of additional emails you may want to receive which you can select below. -

- - -
-
- -
-
-
-
- Advanced Settings -
Indicate your preferences for advanced options.
-
-
-
- - -

Leaderboards

-

- Each week we'll give you two scores based on your forecasting performance:
-
-    A score between 0 and 1000 based on how well your forecast from last week matches the newly published value for this week
-    An overall, cumulative score based on how well all of your past forecasts match all of the values published so far
-
- We show these scores on the leaderboards, but to preserve your privacy we don't associate your name with the scores. - However we encourage you to identify yourself using your initials for fame and glory. - The initials you give here will appear on the leaderboard. -

- - -
- - - - - -

Default Seasons --- for National and Regional Forecasts

-

- By default, for national and regional level forecasts, all seasons (respectful of your preferences above) are shown on the forecasting chart. - If you prefer to only show a certain subset of the available seasons, you can override the default selection here. - This may be useful, for example, if you only want to display seasons having a strain makeup similar to that of the current season. -

- - =2009) { - if(($hiddenSeasons & 1) === 0) { - $selected = 'checked="checked"'; - } else { - $selected = ''; - } - $name = strval($season); - ?> -
- >= 1; - } - ?> -
- - - - -
- -
 
- -
-
-
-
- Optional Survey -
It would help us if you could self-classify yourself below.
-
-
-
- - I have background in:
- - -

-
- -
-
-
-
- Click below to continue to your home page. Happy forecasting! -
- -
-
- -
- diff --git a/site/preferences_recruitment.php b/site/preferences_recruitment.php deleted file mode 100644 index 8ab992c..0000000 --- a/site/preferences_recruitment.php +++ /dev/null @@ -1,456 +0,0 @@ - - - - - - - - - - /> - - - - -
- 1)); - ?> -
-
- Welcome to Epicast -
Thank you for joining us!
-
-
-

- Hi there! - Since this is your first time to login, we thought it might be helpful to take you to the preferences page. - Below you will find a privacy statement, email settings, and a short survey. - By default, we will notify you by email every week as soon as the new weekly flu data is available (this usually happens by Friday afternoon), and provide a convenient link to your forecasting page. - If you like, we can also send an email reminder before each deadline. - The survey is completely optional, but it would help us analyze the data. - The next time you login you will be taken straight to your forecasting home page, but you can always come back to this page by clicking the "Preferences" link in the top right corner of any Epicast page. -

-
-
- - -
-
- Your Privacy -
We won't misuse your email address or publish your forecasts.
-
-
-

Email

-

- We will only use your email to communicate with you about Epicast, and we will never share your email with anyone else. -

-

Forecasts

-

- We will not release your individual forecasts (unless you tell us to). - Instead, we combine together many such forecasts to create an aggregate forecast which will be compared to forecasts made using other techniques. - We may also want to create aggregate forecasts based on specific subsets of forecasters. -

-
-
- -
-

Select Your Targets

-

- You can choose targets to forecast for in this section! -

- - National
- HHS Region 1
- HHS Region 2
- HHS Region 3
- HHS Region 4
- HHS Region 5
- HHS Region 6
- HHS Region 7
- HHS Region 8
- HHS Region 9
- HHS Region 10
- - Georgia
- California
- Washington DC
- - -
- - - -
-
- Email Settings -
Select which emails you would like to receive.
-
-
-
- -

Email Types

-

- Every Friday the CDC publishes new flu data, and every Monday the forecasting round ends. - We'll send you an email to notify you as soon as the new data is available, as long as your account is active. - In addition, there are a couple of additional emails you may want to receive which you can select below. -

- - -
-
- -
-
-
-
- Advanced Settings -
Indicate your preferences for advanced options.
-
-
-
- - -

Leaderboards

-

- Each week we'll give you two scores based on your forecasting performance:
-
-    A score between 0 and 1000 based on how well your forecast from last week matches the newly published value for this week
-    An overall, cumulative score based on how well all of your past forecasts match all of the values published so far
-
- We show these scores on the leaderboards, but to preserve your privacy we don't associate your name with the scores. - However we encourage you to identify yourself using your initials for fame and glory. - The initials you give here will appear on the leaderboard. -

- - -
- -

2009 Pandemic

-

- The 2009-2010 flu season was atypical because a rare event known as a Pandemic occurred. - This is different from an Epidemic, which is what characterizes most flu seasons. - In comparison to epidemics, pandemics generally have a higher attack rate, unpredictable timing, and other altered dynamics. - For these reasons, the 2009 pandemic season is hidden by default. - However, forecasters who have experience in influenza epidemiology may find it helpful to display this atypical season. - Here you have the option to display the 2009 pandemic season on the chart alongside the more typical epidemic seasons. -

- - -
- -

Additional Seasons --- for National and Regional Forecasts

-

- The flu sentinel surveillance network (ILINet) has been growing and evolving since its inception in 1997. - However, due to the small size of the network initially, the earliest data for the U.S. nation and the 10 HHS regions is noisy and is not available during the summer months. - Starting around the 2004-2005 flu season, the data becomes much more stable and is available year-round. - For these reasons, seasons from 1997 through 2003 for national and regional level forecasts are hidden by default. - However, forecasters who have experience in influenza epidemiology may find it helpful to display these additional seasons. - Here you have the option to display the 1997-2003 seasons on the chart alongside the later seasons for which we have more reliable data. -

- - - - -
-

Default Seasons --- for National and Regional Forecasts

-

- By default, for national and regional level forecasts, all seasons (respectful of your preferences above) are shown on the forecasting chart. - If you prefer to only show a certain subset of the available seasons, you can override the default selection here. - This may be useful, for example, if you only want to display seasons having a strain makeup similar to that of the current season. -

- - -
- >= 1; - } - ?> -
- - -

Turn On Hospitalization Forecast

-

- By selecting yes in this option, you can input your forecast for the hospitalization prediction! -

- - -
- - -

Select Your Targets

-

- You can choose targets to forecast for in this section! -

- - - - - National
- HHS Region 1
- HHS Region 2
- HHS Region 3
- HHS Region 4
- HHS Region 5
- HHS Region 6
- HHS Region 7
- HHS Region 8
- HHS Region 9
- HHS Region 10
- - Georgia
- California
- Washington DC
- - - - - -
- -
 
- -
-
-
-
- Optional Survey -
It would help us if you could self-classify yourself below.
-
-
-
- - I have background in:
- - -

-
- -
-
-
-
- Click below to continue to your home page. Happy forecasting! -
- -
-
- -
- diff --git a/site/recruitment.php b/site/recruitment.php deleted file mode 100644 index 0150d29..0000000 --- a/site/recruitment.php +++ /dev/null @@ -1,265 +0,0 @@ - Crowdcast is temporarily unavailable. Please check back soon."); -} else { -?> - - 0) {$location = ($_REQUEST['location']);} -else {$location = 'CA';} -$map = array( - 'CA' => [1, 10, 56], // [nat, hhs9, ca] - 'GA' => [] -); -?> - - - - -
- -
-
- Post Forecast -
- Due by 10:00 AM (ET) on . -
-
-
- 0) { - $value = $time['days']; - $unit = 'days' . $unit; - } else if ($time['hours'] > 0) { - $value = $time['days'] * 24 + $time['hours']; - $unit = 'hours' . $unit; - } else if ($time['minutes'] > 0) { - $value = $time['hours'] * 60 + $time['minutes']; - $unit = 'minutes' . $unit; - } else if ($time['seconds'] > 0) { - $value = $time['minutes'] * 60 + $time['seconds']; - $unit = 'seconds' . $unit; - } else { - $value = ''; - //$unit = 'past due'; - $unit = 'due very soon'; - } - ?> -
-
-
-
- -
-
-
latest available data
-
-
-
-
weeks remaining in season
-
-
-
- - - - - - - - - - - - -
- ~~ Coming Soon ~~ -
-
- Per Age Group Hospitalization Forecast for -
- - - - -
-
-
- Flu in the News -
- Use the latest flu news to make better forecasts! -
-
- - - -
- -
-
- Help Spread The Word -
- Please share Crowdcast with your colleagues, friends, and family! -
-
-
- - - -
-
- - - -
-
- -
- -
-
- - -
-
-
-
-
- External Resources -
- Flu Information and Data -
-
- - -
-
Literature
- -
-
-
- - diff --git a/site/scores.php b/site/scores.php deleted file mode 100644 index 1aa07ae..0000000 --- a/site/scores.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - -
RankUserScore
#*' : '') ?>
-

*That's you - way to go!

-
-
-
- Leaderboards -
- The best of the best. -
-
- - -
- - - -
- -

Overall Score

- -
- -
- -

Score

- -
- - -
- - - -
-
- diff --git a/site/scores_recruitment.php b/site/scores_recruitment.php deleted file mode 100644 index af9b00b..0000000 --- a/site/scores_recruitment.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - -
RankUserScore
#*' : '') ?>
-

*That's you - way to go!

-
-
-
- Leaderboards -
- The best of the best. -
-
- - -
- - - -
- -

Overall Score

- -
- -
- -

Score

- -
- - -
- - - -
-
- diff --git a/site/signup.php b/site/signup.php deleted file mode 100644 index 9b11ab2..0000000 --- a/site/signup.php +++ /dev/null @@ -1,84 +0,0 @@ -success === true ? 1 : 0; -} -?> - -
-
- -
-
Email Sent
-

- Good news, your User ID is being emailed to you now!
- (Please remember to check your junk/spam folder!)

- Login Here -

-
- -
-
This system, originally called ‘Epicast’, was designed to forecast flu-like illnesses. We are now using it to forecast COVID-19, the flu-like illness now in global pandemic. To help with our COVID-19 forecasting effort, please sign up below.
-
Research Overview
-

- In this research study, being conducted by Carnegie Mellon University, we ask you each Friday during the COVID-19 pandemic to predict current and future COVID-19 activity within a group of states or within one or more Health and Human Services regions of the United States. You will be able to enter and submit your predictions online using any modern web browser, and we expect that the entire process will take no more than two minutes per region. There are no expected risks or benefits to participants in this study. -

- Your privacy and the confidentiality of your predictions will be strictly protected; we will not share your email address or your individual predictions without your prior written consent. The study is entirely voluntary, and you are free to stop participating or withdraw entirely at any time. -

- The primary contact is (Email: ), and the principal investigator is Roni Rosenfeld (Email: Roni.Rosenfeld@cs.cmu.edu; Office: GHC 8002). If you have questions pertaining to your rights as a research participant, or to report concerns with this study, you should contact the Carnegie Mellon University Office of Research Integrity and Compliance (Email: irb-review@andrew.cmu.edu). -

-
New User Signup
-
-
-
I have read and understood the above:
-
I am 18 years old or older:
-
Your email address:
-
Your nickname (optional):
-
-
-
-
-
-
-
-
-
-
- -
- -
-
- diff --git a/site/sw.js b/site/sw.js deleted file mode 100644 index e1a5413..0000000 --- a/site/sw.js +++ /dev/null @@ -1,64 +0,0 @@ -//Initialize Service Worker Properly -"use strict"; -// var workbox = 0; - -"function" == typeof importScripts && - importScripts ( - "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js" - ); - -console.log('Was Workbox able to load?'); - if (workbox) { - console.log('Workbox loaded correctly.'); - } else { - console.log('Workbox did not load correctly, please check your service worker for errors.'); -} - -workbox.precaching.precacheAndRoute([ - // If forecast.php gets cached it will show inaccurate data when accessing different regions - // { url: 'forecast.php', revision: 'fc386e2' }, -]); - -//workbox.googleAnalytics.initialize(); - -workbox.routing.registerRoute( - // Cache JS, CSS, JSON files - /.*\.(?:css|js|json)/, - // Use cache but update in the background ASAP - workbox.strategies.staleWhileRevalidate({ - cacheName: 'filetype-cache', - }) -); - -workbox.routing.registerRoute( - // Cache Image files - /.*\.(?:png|jpg|jpeg|svg|gif)/, - // Use the cache if it's available - workbox.strategies.cacheFirst({ - cacheName: 'image-cache', - plugins: [ - new workbox.expiration.Plugin({ - // Cache up to 50 images - maxEntries: 25, - // Cache for a maximum of 28 days - maxAgeSeconds: 28 * 24 * 60 * 60, - // Automatically cleanup if quota is exceeded. - purgeOnQuotaError: true, - }) - ], - }) -); - -workbox.routing.registerRoute( - /.*(?:facebook|googleapis|ajax.googleapis|fonts.googleapis|fonts.gstatic|maxcdn.bootstrapcdn)\.com.*$/, - workbox.strategies.staleWhileRevalidate({ - cacheName: 'external-cache', - }) -); - -workbox.routing.registerRoute( - /.*(?:delphi.midas.cs.cmu)\.edu.*$/, - workbox.strategies.staleWhileRevalidate({ - cacheName: 'API-cache', - }) -);