diff --git a/api/config_sample.php b/api/config_sample.php
index 67cdd08e4..6ef61ffab 100644
--- a/api/config_sample.php
+++ b/api/config_sample.php
@@ -13,11 +13,6 @@
$isb = array('user' => 'user', 'pass' => 'pass', 'db' => 'localhost/ispyb');
$dbtype = 'mysql';
- # Summary Database credentials
- ######### DELETE if not using connection.
- $summarydbconfig = array('user' => 'user', 'pass' => 'pass', 'db' => 'localhost/ispyb');
- $ifsummary = true;
-
# Encoded JWT key, used to sign and check validaty of jwt tokens
# - Create one of these using /api/authenticate/key
# This can be changed to invalidate all currently active tokens
@@ -302,6 +297,8 @@
# Beamlines on which to scale the gridplot to 1024
$scale_grid = array('i24');
+ # URL for instructions for closed proposals
+ $closed_proposal_link = '';
# These map proposal types to their proposalcode
# - If these are not defined for a proposal type, the api then uses bl_types below
diff --git a/api/index.php b/api/index.php
index 6a500f99e..b7ed25370 100644
--- a/api/index.php
+++ b/api/index.php
@@ -70,9 +70,9 @@ function setupApplication($mode): Slim
global $motd, $authentication_type, $cas_url, $cas_sso, $sso_url, $package_description,
$facility_courier_countries, $facility_courier_countries_nde, $facility_courier_countries_link,
$dhl_enable, $scale_grid, $scale_grid_end_date, $preset_proposal, $timezone,
- $valid_components, $enabled_container_types, $ifsummary, $synchweb_version, $redirects,
+ $valid_components, $enabled_container_types, $synchweb_version, $redirects,
$shipping_service_app_url, $use_shipping_service_redirect, $use_shipping_service_redirect_incoming_shipments,
- $dials_rest_url_rings;
+ $dials_rest_url_rings, $closed_proposal_link;
$app->contentType('application/json');
$options = $app->container['options'];
$app->response()->body(json_encode(array(
@@ -92,10 +92,10 @@ function setupApplication($mode): Slim
'timezone' => $timezone,
'valid_components' => $valid_components,
'enabled_container_types' => $enabled_container_types,
- 'ifsummary' => $ifsummary,
'synchweb_version' => $synchweb_version,
'shipping_service_app_url' => $use_shipping_service_redirect || $use_shipping_service_redirect_incoming_shipments ? $shipping_service_app_url : null,
'shipping_service_app_url_incoming' => $use_shipping_service_redirect_incoming_shipments ? $shipping_service_app_url : null,
+ 'closed_proposal_link' => $closed_proposal_link,
'dials_rest_url_rings' => $dials_rest_url_rings,
'redirects' => $redirects
)));
@@ -112,13 +112,6 @@ function setupDependencyInjectionContainer($app)
return $db;
});
- $app->container->singleton('dbsummary', function () use ($app): DatabaseParent {
- $dbFactory = new DatabaseFactory(new DatabaseConnectionFactory());
- $db = $dbFactory->get("summary");
- $db->set_app($app);
- return $db;
- });
-
$app->container->singleton('authData', function () use ($app) {
return new AuthenticationData($app->container['db']);
});
diff --git a/api/src/Database/DatabaseConnectionFactory.php b/api/src/Database/DatabaseConnectionFactory.php
index 0afb84363..0889645f9 100644
--- a/api/src/Database/DatabaseConnectionFactory.php
+++ b/api/src/Database/DatabaseConnectionFactory.php
@@ -9,7 +9,6 @@ class DatabaseConnectionFactory
public function get($databaseType)
{
global $isb;
- global $summarydbconfig;
if (!$databaseType) {
error_log('Database type variable, dbtype, is not specified in config.php - defaulting to MySql.');
@@ -25,16 +24,6 @@ public function get($databaseType)
$conn = new \mysqli($host, $isb['user'], $isb['pass'], $dbn, $port);
$conn->set_charset("utf8mb4");
}
- elseif ($databaseType == 'PureMySQL') {
- $port = array_key_exists('port', $summarydbconfig) ? $summarydbconfig['port'] : null;
- if (!$port) {
- $port = ini_get("mysqli.default_port");
- }
- list($host, $dbn) = explode('/', $summarydbconfig['db']);
- $conn = new \mysqli($host, $summarydbconfig['user'], $summarydbconfig['pass'], $dbn, $port);
- $conn->set_charset("utf8mb4");
- }
-
if ($conn == null) {
Utils::returnError("Database Configuration Error", "Database connection for type '$databaseType' does not exist.");
diff --git a/api/src/Database/DatabaseFactory.php b/api/src/Database/DatabaseFactory.php
index 61ba33c04..7409013ce 100644
--- a/api/src/Database/DatabaseFactory.php
+++ b/api/src/Database/DatabaseFactory.php
@@ -10,7 +10,6 @@ class DatabaseFactory
// Key is lower case representation of class name.
public $database_types = array(
'mysql' => ["dbClassName" =>'MySQL', "dataConnectionName" => 'MySQL'],
- 'summary' => ["dbClassName" =>'PureMySQL', "dataConnectionName" => 'PureMySQL']
);
function __construct($databaseConnectionFactory)
diff --git a/api/src/Page/Processing.php b/api/src/Page/Processing.php
index 098d77b26..675f43ea4 100644
--- a/api/src/Page/Processing.php
+++ b/api/src/Page/Processing.php
@@ -8,6 +8,7 @@
class Processing extends Page {
public static $dispatch = array(
array('/:id', 'get', '_results'),
+ array('/visit/:visit', 'get', '_results_for_visit'),
array('/status', 'post', '_statuses'),
array('/messages/status', 'post', '_ap_message_status'),
@@ -34,7 +35,15 @@ class Processing extends Page {
'map' => '\d+',
'n' => '\d+',
'sampleGroupId' => '\d+',
- 'resultCount' => '\d+'
+ 'resultCount' => '\d+',
+ 'pipeline' => '[\w\s\+]+',
+ 'spacegroup' => '(\w|\s|\-|\/)+',
+ 'resolution' => '[\d\.]+',
+ 'completeness' => '[\d\.]+',
+ 'anomcompleteness' => '[\d\.]+',
+ 'rmeas' => '[\d\.]+',
+ 'cchalf' => '[\d\.]+',
+ 'ccanom' => '[\d\.]+',
);
/**
@@ -47,6 +56,8 @@ class Processing extends Page {
0 => 3,
);
+ const EVTOA = 12398.4198;
+
function _map_status($status) {
foreach ($this->status_mapping as $state => $value) {
if ($status == $state) {
@@ -238,6 +249,198 @@ function _statuses() {
$this->_output($out);
}
+ function _results_for_visit() {
+ if (!($this->has_arg('visit'))) {
+ $this->_error('No visit specified');
+ }
+ $pattern = '/([A-z]+)(\d+)-(\d+)/';
+ preg_match($pattern, $this->arg('visit'), $matches);
+ if (!sizeof($matches))
+ $this->_error('No such visit');
+
+ $info = $this->db->pq("SELECT s.sessionid FROM blsession s INNER JOIN proposal p ON (p.proposalid = s.proposalid) WHERE p.proposalcode=:1 AND p.proposalnumber=:2 AND s.visit_number=:3", array($matches[1], $matches[2], $matches[3]));
+
+ if (!sizeof($info)) {
+ $this->_error('No such visit');
+ }
+
+ $args = array($info[0]['SESSIONID']);
+
+ $where = 'dc.sessionid=:1 AND dc.overlap = 0 AND dc.axisrange > 0 AND dc.numberOfImages > 150 AND app.processingstatus = 1';
+
+ if ($this->has_arg('pipeline')) {
+ $st = sizeof($args);
+ $where .= " AND app.processingprograms = :" . ($st + 1);
+ array_push($args, $this->arg('pipeline'));
+ }
+
+ if ($this->has_arg('spacegroup')) {
+ $st = sizeof($args);
+ $where .= " AND REPLACE(ap.spacegroup,' ','') = :" . ($st + 1);
+ array_push($args, $this->arg('spacegroup'));
+ }
+
+ if ($this->has_arg('resolution')) {
+ $st = sizeof($args);
+ $where .= " AND apssover.resolutionlimithigh <= :" . ($st + 1);
+ array_push($args, $this->arg('resolution'));
+ }
+
+ if ($this->has_arg('completeness')) {
+ $st = sizeof($args);
+ $where .= " AND apssover.completeness >= :" . ($st + 1);
+ array_push($args, $this->arg('completeness'));
+ }
+
+ if ($this->has_arg('anomcompleteness')) {
+ $st = sizeof($args);
+ $where .= " AND apssover.anomalousCompleteness >= :" . ($st + 1);
+ array_push($args, $this->arg('anomcompleteness'));
+ }
+
+ if ($this->has_arg('rmeas')) {
+ $st = sizeof($args);
+ $where .= " AND apssinner.rmeasalliplusiminus <= :" . ($st + 1);
+ array_push($args, $this->arg('rmeas'));
+ }
+
+ if ($this->has_arg('cchalf')) {
+ $st = sizeof($args);
+ $where .= " AND apssouter.cchalf >= :" . ($st + 1);
+ array_push($args, $this->arg('cchalf'));
+ }
+
+ if ($this->has_arg('ccanom')) {
+ $st = sizeof($args);
+ $where .= " AND apssinner.ccanomalous >= :" . ($st + 1);
+ array_push($args, $this->arg('ccanom'));
+ }
+
+ if ($this->has_arg('s')) {
+ $st = sizeof($args);
+ $where .= " AND (CONCAT(dc.imageprefix,'_',dc.datacollectionnumber) LIKE CONCAT('%',:" . ($st + 1) . ",'%') OR smp.name LIKE CONCAT('%',:" . ($st + 2) . ",'%'))";
+ array_push($args, $this->arg('s'));
+ array_push($args, $this->arg('s'));
+ }
+
+ $start = 0;
+ $pp = $this->has_arg('per_page') ? $this->arg('per_page') : 15;
+
+ if ($this->has_arg('page')) {
+ $pg = $this->arg('page') - 1;
+ $start = $pg * $pp;
+ }
+
+ $order = 'id DESC';
+
+ if ($this->has_arg('sort_by')) {
+ $cols = array(
+ 'PREFIX' => 'prefix', 'SAMPLE' => 'sample',
+ 'ENERGY' => 'energy', 'RESOLUTION' => 'resolution', 'CELL' => 'cell_a',
+ 'RES' => 'overallrhigh', 'INNERRMEAS' => 'innerrmeas',
+ 'COMPLETENESS' => 'overallcompleteness', 'ANOMCOMPLETENESS' => 'anomoverallcompleteness',
+ 'INNERCCANOM' => 'innerccanom', 'OUTERCCHALF' => 'outercchalf',
+ 'SG' => 'sg', 'PIPELINE' => 'pipeline'
+ );
+ $dir = $this->has_arg('order') ? ($this->arg('order') == 'asc' ? 'ASC' : 'DESC') : 'ASC';
+ if (array_key_exists($this->arg('sort_by'), $cols))
+ $order = $cols[$this->arg('sort_by')] . ' ' . $dir;
+ }
+
+ $jobs = $this->db->pq(
+ "SELECT dc.datacollectionid as id,
+ CONCAT(dc.imageprefix, '_', dc.datacollectionnumber) as prefix,
+ ".self::EVTOA."/dc.wavelength as energy,
+ dc.resolution,
+ smp.name as sample,
+ smp.blsampleid,
+ app.processingprograms as pipeline,
+ app.autoprocprogramid as aid,
+ REPLACE(ap.spacegroup,' ','') as sg,
+ ap.refinedcell_a as cell_a,
+ ap.refinedcell_b as cell_b,
+ ap.refinedcell_c as cell_c,
+ ap.refinedcell_alpha as cell_al,
+ ap.refinedcell_beta as cell_be,
+ ap.refinedcell_gamma as cell_ga,
+ apssover.resolutionlimithigh as overallrhigh,
+ apssover.resolutionlimitlow as overallrlow,
+ apssinner.resolutionlimithigh as innerrhigh,
+ apssinner.resolutionlimitlow as innerrlow,
+ apssouter.resolutionlimithigh as outerrhigh,
+ apssouter.resolutionlimitlow as outerrlow,
+ apssover.completeness as overallcompleteness,
+ apssinner.completeness as innercompleteness,
+ apssouter.completeness as outercompleteness,
+ apssover.anomalouscompleteness as anomoverallcompleteness,
+ apssinner.anomalouscompleteness as anominnercompleteness,
+ apssouter.anomalouscompleteness as anomoutercompleteness,
+ apssinner.rmeasalliplusiminus as innerrmeas,
+ apssouter.cchalf as outercchalf,
+ apssinner.ccanomalous as innerccanom
+ FROM datacollection dc
+ LEFT OUTER JOIN blsample smp ON dc.blsampleid = smp.blsampleid
+ INNER JOIN processingjob pj ON dc.datacollectionid = pj.datacollectionid
+ INNER JOIN autoprocprogram app ON pj.processingjobid = app.processingjobid
+ INNER JOIN autoproc ap ON app.autoprocprogramid=ap.autoprocprogramid
+ INNER JOIN autoprocscaling aps ON ap.autoprocid = aps.autoprocid
+ INNER JOIN autoprocscalingstatistics apssover ON aps.autoprocscalingid = apssover.autoprocscalingid AND apssover.scalingStatisticsType='overall'
+ INNER JOIN autoprocscalingstatistics apssinner ON aps.autoprocscalingid = apssinner.autoprocscalingid AND apssinner.scalingStatisticsType='innerShell'
+ INNER JOIN autoprocscalingstatistics apssouter ON aps.autoprocscalingid = apssouter.autoprocscalingid AND apssouter.scalingStatisticsType='outerShell'
+ WHERE $where
+ ORDER BY $order",
+ $args
+ );
+
+ // Only take one processing job per data collection id
+ $data = array();
+ $dcids = array();
+ foreach ($jobs as $job) {
+ $dcid = $job['ID'];
+ if (!(in_array($dcid, $dcids))) {
+ array_push($data, $job);
+ array_push($dcids, $dcid);
+ }
+ }
+
+ // Strip down data to only the page needed
+ $tot = sizeof($data);
+ $data = array_slice($data, $start, $pp);
+
+ // Add classes to highlight fields in red/yellow/green
+ foreach ($data as &$d) {
+ foreach (array('OVERALL', 'INNER', 'OUTER') as $s) {
+ $c = $d[$s.'COMPLETENESS'];
+ $d[$s.'COMPLETENESSCLASS'] = $c > 95 ? 'active' : ($c > 80 ? 'minor' : 'inactive');
+ $c = $d['ANOM'.$s.'COMPLETENESS'];
+ $d['ANOM'.$s.'COMPLETENESSCLASS'] = $c > 95 ? 'active' : ($c > 80 ? 'minor' : 'inactive');
+ }
+ }
+
+ // Set number of decimal places
+ $nf = array(
+ 0 => array('ENERGY'),
+ 2 => array(
+ 'RESOLUTION', 'INNERRMEAS', 'OUTERCCHALF', 'INNERCCANOM',
+ 'CELL_A', 'CELL_B', 'CELL_C', 'CELL_AL', 'CELL_BE', 'CELL_GA',
+ 'OVERALLRHIGH', 'OVERALLRLOW', 'INNERRHIGH', 'INNERRLOW', 'OUTERRHIGH', 'OUTERRLOW',
+ 'OVERALLCOMPLETENESS', 'INNERCOMPLETENESS', 'OUTERCOMPLETENESS',
+ 'ANOMOVERALLCOMPLETENESS', 'ANOMINNERCOMPLETENESS', 'ANOMOUTERCOMPLETENESS'
+ )
+ );
+
+ foreach ($nf as $nff => $cols) {
+ foreach ($cols as $c) {
+ foreach ($data as &$d) {
+ $d[$c] = number_format($d[$c], $nff);
+ }
+ }
+ }
+
+ $this->_output(array('total' => $tot, 'data' => $data));
+
+ }
+
/**
* Auto processing results
* (Integration results only)
diff --git a/api/src/Page/Proposal.php b/api/src/Page/Proposal.php
index f01af7328..31e3931f5 100644
--- a/api/src/Page/Proposal.php
+++ b/api/src/Page/Proposal.php
@@ -206,7 +206,7 @@ function _get_proposals($id = null)
$order = 'p.proposalid DESC';
if ($this->has_arg('sort_by')) {
- $cols = array('ST' => 'p.bltimestamp', 'PROPOSALCODE' => 'p.proposalcode', 'PROPOSALNUMBER' => 'p.proposalnumber', 'VCOUNT' => 'vcount', 'TITLE' => 'lower(p.title)');
+ $cols = array('ST' => 'p.bltimestamp', 'PROPOSALCODE' => 'p.proposalcode', 'PROPOSALNUMBER' => 'p.proposalnumber', 'VCOUNT' => 'vcount', 'TITLE' => 'lower(p.title)', 'STATE' => 'p.state');
$dir = $this->has_arg('order') ? ($this->arg('order') == 'asc' ? 'ASC' : 'DESC') : 'ASC';
if (array_key_exists($this->arg('sort_by'), $cols))
$order = $cols[$this->arg('sort_by')] . ' ' . $dir;
diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php
index 24fbeea13..8e8249016 100644
--- a/api/src/Page/Shipment.php
+++ b/api/src/Page/Shipment.php
@@ -1642,12 +1642,24 @@ function _get_dewars()
$order = $cols[$this->arg('sort_by')] . ' ' . $dir;
}
- $dewars = $this->db->paginate("SELECT CONCAT(p.proposalcode, p.proposalnumber) as prop, CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number) as firstexperiment, r.labcontactid, se.beamlineoperator as localcontact, se.beamlinename, TO_CHAR(se.startdate, 'HH24:MI DD-MM-YYYY') as firstexperimentst, d.firstexperimentid, s.shippingid, s.shippingname, d.facilitycode, count(c.containerid) as ccount, (case when se.visit_number > 0 then (CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number)) else '' end) as exp, d.code, d.barcode, d.storagelocation, d.dewarstatus, d.dewarid, d.trackingnumbertosynchrotron, d.trackingnumberfromsynchrotron, d.externalShippingIdFromSynchrotron, s.deliveryagent_agentname, d.weight, d.deliveryagent_barcode, GROUP_CONCAT(c.code SEPARATOR ', ') as containers, s.sendinglabcontactid, s.returnlabcontactid, pe.givenname, pe.familyname, s.safetylevel as shippingsafetylevel
- FROM dewar d
- LEFT OUTER JOIN container c ON c.dewarid = d.dewarid
- INNER JOIN shipping s ON d.shippingid = s.shippingid
- INNER JOIN proposal p ON p.proposalid = s.proposalid
- LEFT OUTER JOIN blsession se ON d.firstexperimentid = se.sessionid
+ $dewars = $this->db->paginate("SELECT
+ CONCAT(p.proposalcode, p.proposalnumber) as prop,
+ CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number) as firstexperiment,
+ CONCAT(p.proposalcode, p.proposalnumber, '-', se2.visit_number) as udcfirstexperiment,
+ r.labcontactid, se.beamlineoperator as localcontact, se.beamlinename,
+ TO_CHAR(se.startdate, 'HH24:MI DD-MM-YYYY') as firstexperimentst, d.firstexperimentid,
+ s.shippingid, s.shippingname, d.facilitycode, count(c.containerid) as ccount,
+ (case when se.visit_number > 0 then (CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number)) else '' end) as exp,
+ d.code, d.barcode, d.storagelocation, d.dewarstatus, d.dewarid,
+ d.trackingnumbertosynchrotron, d.trackingnumberfromsynchrotron, d.externalShippingIdFromSynchrotron,
+ s.deliveryagent_agentname, d.weight, d.deliveryagent_barcode, GROUP_CONCAT(c.code SEPARATOR ', ') as containers,
+ s.sendinglabcontactid, s.returnlabcontactid, pe.givenname, pe.familyname, s.safetylevel as shippingsafetylevel
+ FROM dewar d
+ LEFT OUTER JOIN container c ON c.dewarid = d.dewarid
+ INNER JOIN shipping s ON d.shippingid = s.shippingid
+ INNER JOIN proposal p ON p.proposalid = s.proposalid
+ LEFT OUTER JOIN blsession se ON d.firstexperimentid = se.sessionid
+ LEFT OUTER JOIN blsession se2 ON c.sessionid = se2.sessionid
LEFT OUTER JOIN dewarregistry r ON r.facilitycode = d.facilitycode
LEFT OUTER JOIN labcontact lc ON s.sendinglabcontactid = lc.labcontactid
LEFT OUTER JOIN person pe ON lc.personid = pe.personid
diff --git a/api/src/Page/Summary.php b/api/src/Page/Summary.php
deleted file mode 100644
index 7b34bc8d7..000000000
--- a/api/src/Page/Summary.php
+++ /dev/null
@@ -1,423 +0,0 @@
- '(\w|\s|\-|\(|\))+',
- 'propid' => '(.*)',
-
- // visit
- 'com' => '(\[[^\ \]]*\],(asc|desc))', //comment
- 'PROPOSALID' => '(\[[^\ \]]*\],(asc|desc))',
-
- 'BEAMLINENAME' => '(\[[^\ \]]*\],(asc|desc))',
- // 'VISITNUMBER' => '(\[[^\ \]]*\],(asc|desc))',
-
- // Filter Parameters - array of parameter orders e.g. ascending, descending and the comparison value
- 'sample' => '(^(\w+),(asc|desc|)+$)', //sample name
- 'filetemp' => '(^(\w+),(asc|desc|)+$)', //file template
- // 'dcid' => '(.*)', //data collection id
- 'pp' => '(\[[^\ \]]*\],(asc|desc|))', // processing programs
- 'sg' => '(\[[^\ \]]*\],(asc|desc|))', // space group
-
-
- // Filter Parameters - array of parameter operands and orders such as greater than, equal to, between, less than, like, ascending, descending and the comparison value.
- 'STARTDATE' => '(.*)', // visit start date
- 'rca' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type a
- 'rcb' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type b
- 'rcc' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type c
- 'rcal' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type alpha
- 'rcbe' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type beta
- 'rcga' => '(^(\d+),(.+),(asc|desc|)+$)', // refined cell type gamma
- 'rlho' => '(^(\d+),(.+),(asc|desc|)+$)', // resolution limit high outer
- 'rmpmi' => '(^(\d+),(.+),(asc|desc|)+$)', // rmeaswithiniplusiminus inner
- 'riso' => '(^(\d+),(.+),(asc|desc|)+$)', // resioversigi2 overall
- 'cci' => '(^(\d+),(.+),(asc|desc|)+$)', // ccanomalous inner
- 'cco' => '(^(\d+),(.+),(asc|desc|)+$)', // ccanomalous overall
- 'rfsi' => '(^(\d+),(.+),(asc|desc|)+$)', // rfreevaluestart inner
- 'rfei' => '(^(\d+),(.+),(asc|desc|)+$)', // rfreevalueend inner
- 'nobi' => '(^(\d+),(.+),(asc|desc|)+$)', // noofblobs inner
-
-
- );
-
- public static $dispatch = array(
- array('/results', 'get', '_get_results'),
- array('/proposal', 'get', '_get_proposal'),
- array('/spacegroup', 'get', '_get_spacegroup'),
- array('/procprogram', 'get', '_get_processingprogram'),
- array('/bl', 'get', '_get_beamline')
- );
-
- public $string_arg_types = array(
- 'pp' => ["order" =>'ppt.processingPrograms ', "where" => 'lower(ppt.processingPrograms) = lower( ? ) '],
- 'sg' => ["order" =>'sgt.spaceGroup ', "where" => 'lower(sgt.spaceGroup) = lower( ? ) '],
- 'BEAMLINENAME' => ["order" =>'vt.beamLineName ', "where" => 'lower(vt.beamLineName) LIKE lower( ? ) ']
- );
-
-
- public $val_arg_types = array(
- 'rca' => ["arg" => 'sf.refinedCell_a '],
- 'rcb' => ["arg" => 'sf.refinedCell_b '],
- 'rcc' => ["arg" => 'sf.refinedCell_c '],
- 'rcal' => ["arg" => 'sf.refinedCell_alpha '],
- 'rcbe' => ["arg" => 'sf.refinedCell_beta '],
- 'rcga' => ["arg" => 'sf.refinedCell_gamma '],
- 'rlho' => ["arg" => 'sf.resolutionLimitHighOuter '],
- 'rmpmi' => ["arg" => 'sf.rMeasWithinIPlusIMinusInner '],
- 'riso' => ["arg" => 'sf.resIOverSigI2Overall '],
- 'cci' => ["arg" => 'sf.ccAnomalousInner '],
- 'cco' => ["arg" => 'sf.ccAnomalousOverall '],
- 'rfsi' => ["arg" => 'sf.rFreeValueStartInner '],
- 'rfei' => ["arg" => 'sf.rFreeValueEndInner '],
- 'nobi' => ["arg" => 'sf.noofblobs ']
-
- );
-
-
- private $summarydb;
-
-
- function __construct(Slim $app, $db, $user)
- {
- global $summarydbconfig;
-
- parent::__construct($app, $db, $user);
-
- if ($summarydbconfig) {
- $dbFactory = new DatabaseFactory(new DatabaseConnectionFactory());
- $db = $dbFactory->get("summary");
- $this->summarydb = $db;
- }
-
- }
-
- private function error_on_no_summary_db(){
- global $summarydbconfig;
- if (!$summarydbconfig) {
- $this->_error("Not valid when summary database not configured.");
- }
- }
-
- function _get_results() {
- $this->error_on_no_summary_db();
- $where = '';
- $where_arr = array();
- $order = '';
- $order_arr = array();
- $args = array();
-
- $op_array = array(">", "LIKE", "=", "<");
-
- if (!$this->has_arg('propid')) $this->_error('No proposal defined');
-
- // $propid_array = explode(',', $this->arg('propid'));
- $propid_args = preg_split('/[,]+(?![^\[]*\])/', urldecode($this->arg('propid')));
- $propid_array = explode(',', implode(str_replace(array('[',']'),'', $propid_args)));
- array_push($order_arr, 'sf.autoProcIntegrationId DESC');
-
-
- if (!$this->staff) {
- $person_id = $this->user->personId;
-
- $where_propid_personid_array = array();
-
-
- // # check user can see selected proposals and get all available visits if so
- foreach ($propid_array as $value) {
- array_push($where_propid_personid_array, '(sf.personid = ?');
- array_push($where_propid_personid_array, 'AND pt.proposalid = ? )');
- array_push($args, $person_id);
- array_push($args, $value);
- };
-
- array_push($where_arr, '('.implode(' OR ', $where_propid_personid_array).')');
-
-
- } else {
- $where_propid_array = array();
-
- foreach ($propid_array as $value) {
- array_push($where_propid_array, 'pt.proposalid = ?');
- array_push($args, $value);
- };
-
- array_push($where_arr, '('.implode(' OR ', $where_propid_array).')');
-
- }
-
-
- // [VALUE, ORDER]
-
- if ($this->has_arg('sample')) {
- $sample_args = explode(',', urldecode($this->arg('sample')));
-
- array_push($args, $sample_args[0]);
- array_push($where_arr, "lower(sf.name) LIKE lower(CONCAT(CONCAT('%',?),'%')) ESCAPE '$' ");
-
- if (isset($sample_args[1]) == 'desc' || isset($sample_args[1]) == 'asc') {
- array_push($order_arr, 'sf.name '.$sample_args[2]);
- }
-
- }
-
-
- if ($this->has_arg('filetemp')) {
- $filetemp_args = explode(',', urldecode($this->arg('filetemp')));
-
- array_push($args, $filetemp_args[0]);
- array_push($where_arr, "lower(sf.fileTemplate) LIKE lower(CONCAT(CONCAT('%',?),'%')) ESCAPE '$' ");
-
- if (isset($filetemp_args[1]) == 'desc' || isset($filetemp_args[1]) == 'asc') {
- array_push($order_arr, 'sf.fileTemplate '.$filetemp_args[1]);
- }
-
- }
-
-
- foreach ($this->string_arg_types as $key => $value) {
-
- if ($this->has_arg($key)) {
-
- $temp_array = array();
-
- $temp_args = preg_split('/[,]+(?![^\[]*\])/', urldecode($this->arg($key)));
-
- $temp_values = explode(',', str_replace(array('[',']'),'', $temp_args[0]));
-
- foreach ($temp_values as $temp_value) {
- array_push($temp_array, $value['where']);
- array_push($args, $temp_value);
- }
-
- array_push($where_arr, '('.implode(" OR ", $temp_array).')');
-
- if (isset($temp_args[1]) == 'desc' || isset($temp_args[1]) == 'asc') {
- array_push($order_arr, $value['order'].$temp_args[1]);
- }
- }
- }
-
-
- // [VALUE, OPERAND, ORDER]
-
- foreach ($this->val_arg_types as $key => $value) {
-
- if ($this->has_arg($key)) {
- $temp_args = explode(',', $this->arg($key));
-
- array_push($args, $temp_args[0]);
-
- if (in_array($temp_args[1], $op_array) ) {
- array_push($where_arr, $value['arg'].$temp_args[1].' ?');
- }
-
-
- if (isset($temp_args[2]) == 'desc' || isset($temp_args[2]) == 'asc') {
- array_push($order_arr, $value['arg'].$temp_args[2]);
- }
-
- }
-
- }
-
-
- // AND is the delimieter between seperate queries, converted to string
- $where = implode(" AND ", $where_arr);
-
- if (count($order_arr) > 0) {
- $order = implode(", ", $order_arr);
- }
-
-
- // add multiselect params to end of where clause.
- // $where = $where.$pp_where.$sg_where.$BEAMLINENAME_where;
-
- // get tot query
- $tot_args = $args;
-
- $tot = $this->summarydb->pq(
- "SELECT COUNT(sf.autoProcIntegrationId) as TOT
- FROM SummaryFact sf
- JOIN ProposalDimension pt on pt.proposalDimId = sf.proposalDimId
- JOIN VisitDimension vt on vt.sessionDimId = sf.sessionDimId
- JOIN ProcessingProgramDimension ppt on ppt.processingProgramsDimId = sf.processingProgramsDimId
- JOIN SpaceGroupDimension sgt on sgt.spaceGroupDimId = sgt.spaceGroupDimId
- WHERE $where
- GROUP BY sf.datacollectionId"
- , $tot_args);
-
- $tot = sizeof($tot) ? intval($tot[0]['TOT']) : 0;
-
- // paginate
- $pp = $this->has_arg('per_page') ? $this->arg('per_page') : 15;
- $pg = $this->has_arg('page') ? $this->arg('page')-1 : 0;
- $start = $pg*$pp;
- $end = $pg*$pp+$pp;
-
- $st = sizeof($args)+1;
- $en = $st + 1;
- array_push($args, $start);
- array_push($args, $end);
-
- $pgs = intval($tot/$pp);
- if ($tot % $pp != 0) $pgs++;
-
-
- $rows = $this->summarydb->paginate(
- "SELECT
- pt.prop,
- sf.autoProcIntegrationId,
- sf.dataCollectionId,
- sf.personId,
- sf.visit_number,
- sf.startTime,
- vt.beamLineName,
- sf.comments,
- GROUP_CONCAT(COALESCE(sf.fileTemplate, 'NULL')) as FILETEMPLATE,
- GROUP_CONCAT(COALESCE(sf.name, 'NULL')) as SAMPLENAME,
- GROUP_CONCAT(COALESCE(sgt.spaceGroup, 'NULL')) as SPACEGROUP,
- GROUP_CONCAT(COALESCE(ppt.processingPrograms, 'NULL')) as PROCESSINGPROGRAMS,
- GROUP_CONCAT(COALESCE(sf.refinedCell_a, 'NULL')) as REFINEDCELL_A,
- GROUP_CONCAT(COALESCE(sf.refinedCell_b, 'NULL')) as REFINEDCELL_B,
- GROUP_CONCAT(COALESCE(sf.refinedCell_c, 'NULL')) as REFINEDCELL_C,
- GROUP_CONCAT(COALESCE(sf.refinedCell_alpha, 'NULL')) as REFINEDCELL_ALPHA,
- GROUP_CONCAT(COALESCE(sf.refinedCell_beta, 'NULL')) as REFINEDCELL_BETA,
- GROUP_CONCAT(COALESCE(sf.refinedCell_gamma, 'NULL')) as REFINEDCELL_GAMMA,
- GROUP_CONCAT(COALESCE(sf.resolutionLimitHighOuter, 'NULL')) as RESOLUTIONLIMITHIGHOUTER,
- GROUP_CONCAT(COALESCE(sf.rMeasWithinIPlusIMinusInner, 'NULL')) as RMEASWITHINIPLUSIMINUSINNER,
- GROUP_CONCAT(COALESCE(sf.resIOverSigI2Overall, 'NULL')) as RESIOVERSIGI2OVERALL,
- GROUP_CONCAT(COALESCE(sf.ccAnomalousInner, 'NULL')) as CCANOMALOUSINNER,
- GROUP_CONCAT(COALESCE(sf.ccAnomalousOverall, 'NULL')) as CCANOMALOUSOVERALL,
- GROUP_CONCAT(COALESCE(sf.rFreeValueStartInner, 'NULL')) as RFREEVALUESTARTINNER,
- GROUP_CONCAT(COALESCE(sf.rFreeValueEndInner, 'NULL')) as RFREEVALUEENDINNER,
- GROUP_CONCAT(COALESCE(sf.noofblobs, 'NULL')) as NOOFBLOBS
- FROM SummaryFact sf
- JOIN ProposalDimension pt on pt.proposalDimId = sf.proposalDimId
- JOIN VisitDimension vt on vt.sessionDimId = sf.sessionDimId
- JOIN ProcessingProgramDimension ppt on ppt.processingProgramsDimId = sf.processingProgramsDimId
- JOIN SpaceGroupDimension sgt on sgt.spaceGroupDimId = sf.spaceGroupDimId
- WHERE $where
- GROUP BY sf.dataCollectionId
- ORDER BY $order "
- , $args);
-
-
- if (!$rows) {
- $this->_error($this->arg('TITLE') . ' could not be found anywhere!', 404);
- }
-
- // sql query output
-
- // $this->_output(array('data' => $where, 'args' => $args));
- $this->_output(array('data' => $rows, 'total' => $tot ));
- // $this->_output(array('data' => $rows, 'where' => $where, 'order' => $order, 'args' => $args));
-
-
-
- }
-
- function _get_proposal() {
- $this->error_on_no_summary_db();
- $args = array();
- $where = "WHERE 1=1";
-
- if (!$this->staff) {
- $person_id = $this->user->personId;
-
- // $person_id = 16565;
-
- $where_person = "sf.personId = ".$person_id;
-
- $rows = $this->summarydb->pq(
- "SELECT pt.prop, pt.proposalid
- FROM ProposalDimension pt
- JOIN SummaryFact sf on pt.proposalDimId = sf.proposalDimId
- WHERE $where_person
- GROUP BY pt.proposalid");
-
- $this->_output($rows);
-
- } else {
-
- $tot = $this->summarydb->pq(
- "SELECT COUNT(proposalid) as TOT
- FROM ProposalDimension pt
- $where", $args);
-
-
- $tot = sizeof($tot) ? intval($tot[0]['TOT']) : 0;
-
- // paginate
- $pp = $this->has_arg('per_page') ? $this->arg('per_page') : 15;
- $pg = $this->has_arg('page') ? $this->arg('page')-1 : 0;
- $start = $pg*$pp;
- $end = $pg*$pp+$pp;
-
- $st = sizeof($args)+1;
- $en = $st + 1;
- array_push($args, $start);
- array_push($args, $end);
-
- $pgs = intval($tot/$pp);
- if ($tot % $pp != 0) $pgs++;
-
- $order = 'p.proposalid DESC';
-
- $rows = $this->summarydb->paginate(
- "SELECT prop, proposalid
- FROM ProposalDimension pt
- $where", $args);
-
- $this->_output($rows);
-
- }
-
-
-
- }
-
- function _get_spacegroup() {
- $this->error_on_no_summary_db();
- $rows = $this->summarydb->pq(
- "SELECT spaceGroup
- FROM SpaceGroupDimension sgt");
-
- $this->_output($rows);
-
- }
-
- function _get_processingprogram() {
- $this->error_on_no_summary_db();
- $rows = $this->summarydb->pq(
- "SELECT processingPrograms
- FROM ProcessingProgramDimension ppt");
-
- $this->_output($rows);
-
- }
-
- function _get_beamline() {
- $this->error_on_no_summary_db();
- $rows = $this->summarydb->pq(
- "SELECT beamLineName
- FROM VisitDimension vt");
-
- $this->_output($rows);
-
- }
-
-
-
-
-}
-
diff --git a/client/src/js/app/components/navbar.vue b/client/src/js/app/components/navbar.vue
index fba7d0302..a1558927b 100644
--- a/client/src/js/app/components/navbar.vue
+++ b/client/src/js/app/components/navbar.vue
@@ -9,18 +9,6 @@
data-cy="navbar"
class="tw-hidden tw-z-10 md:tw-flex md:flex-row tw-bg-sidebar-grad-end tw-justify-center tw-my-4 md:tw-mx-auto tw-border tw-border-gray-400 tw-divide-x tw-divide-gray-400"
>
-
-
-
- Summary
-
-
-
This proposal is closed. You cannot create shipments, proteins or contacts.
+ Click here for more info.
@@ -224,4 +219,4 @@ export default {
margin-top: 1rem;
width: 101%;
}
-
\ No newline at end of file
+
diff --git a/client/src/js/app/layouts/main.vue b/client/src/js/app/layouts/main.vue
index e8c1adbf3..ea5a3cc80 100644
--- a/client/src/js/app/layouts/main.vue
+++ b/client/src/js/app/layouts/main.vue
@@ -39,9 +39,7 @@
class="tw-w-full tw-mx-auto"
>
-
-
-
+
diff --git a/client/src/js/app/router/router.js b/client/src/js/app/router/router.js
index 33ef36c22..3815217f3 100644
--- a/client/src/js/app/router/router.js
+++ b/client/src/js/app/router/router.js
@@ -38,7 +38,6 @@ import FaultRoutes from 'modules/fault/routes.js'
import StatsRoutes from 'modules/stats/routes.js'
import SubmissionRoutes from 'modules/submission/routes.js'
import VisitsRoutes from 'modules/visits/routes.js'
-import SummaryRoutes from 'modules/summary/routes.js'
import { resolve } from 'promise'
@@ -104,7 +103,6 @@ router.addRoutes(FaultRoutes)
router.addRoutes(StatsRoutes)
router.addRoutes(SubmissionRoutes)
router.addRoutes(VisitsRoutes)
-router.addRoutes(SummaryRoutes)
// Hook the marionette navigation methods into vue-router methods
diff --git a/client/src/js/app/store/store.js b/client/src/js/app/store/store.js
index 7832304e5..1c943b813 100644
--- a/client/src/js/app/store/store.js
+++ b/client/src/js/app/store/store.js
@@ -43,7 +43,6 @@ const store = new Vuex.Store({
isLoading: false,
motd: '',
- ifsummary: false,
synchwebVersion: '',
help: false, // Global help flag used to denote if we should display inline help on pages
skipHomePage: config.skipHome || false,
@@ -68,7 +67,6 @@ const store = new Vuex.Store({
state.motd = options.get('motd') || state.motd
- state.ifsummary = options.get('ifsummary') || state.ifsummary
state.synchwebVersion = options.get('synchweb_version') || state.synchwebVersion
app.options = options
diff --git a/client/src/js/collections/datacollectionsforvisit.js b/client/src/js/collections/datacollectionsforvisit.js
new file mode 100644
index 000000000..711a2cc2b
--- /dev/null
+++ b/client/src/js/collections/datacollectionsforvisit.js
@@ -0,0 +1,28 @@
+define(['backbone.paginator', 'models/datacollectionsforvisit', 'utils/kvcollection'], function(PageableCollection, DCs, KVCollection) {
+
+ return PageableCollection.extend(_.extend({}, KVCollection, {
+ model: DCs,
+ mode: 'server',
+ visit: null,
+ url: function() { return '/processing/visit/'+this.visit },
+
+ initialize(collection, options) {
+ if (options && options.queryParams && options.queryParams.visit) {
+ this.visit = options.queryParams.visit
+ }
+ },
+
+ state: {
+ pageSize: 15,
+ },
+
+ parseState: function(r, q, state, options) {
+ return { totalRecords: r.total }
+ },
+
+ parseRecords: function(r, options) {
+ return r.data
+ },
+
+ }))
+})
diff --git a/client/src/js/models/datacollectionsforvisit.js b/client/src/js/models/datacollectionsforvisit.js
new file mode 100644
index 000000000..8d0172cbb
--- /dev/null
+++ b/client/src/js/models/datacollectionsforvisit.js
@@ -0,0 +1,8 @@
+define(['backbone'], function(Backbone) {
+
+ return Backbone.Model.extend({
+ idAttribute: 'DATACOLLECTIONID',
+ })
+
+})
+
diff --git a/client/src/js/modules/blstats/views/histogram.js b/client/src/js/modules/blstats/views/histogram.js
index c6aa26fe5..b1546ec21 100644
--- a/client/src/js/modules/blstats/views/histogram.js
+++ b/client/src/js/modules/blstats/views/histogram.js
@@ -1,7 +1,7 @@
define(['marionette', 'modules/blstats/models/histogram', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
'jquery.flot.tickrotor',
], function(Marionette, Histogram, utils, $) {
diff --git a/client/src/js/modules/blstats/views/robotdewar.js b/client/src/js/modules/blstats/views/robotdewar.js
index 6aadf7276..7645d94a9 100644
--- a/client/src/js/modules/blstats/views/robotdewar.js
+++ b/client/src/js/modules/blstats/views/robotdewar.js
@@ -1,7 +1,7 @@
define(['marionette', 'modules/blstats/models/robotdewar', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
], function(Marionette, Dewar, utils, $) {
return Marionette.ItemView.extend({
diff --git a/client/src/js/modules/cell/views/autoproc.js b/client/src/js/modules/cell/views/autoproc.js
index 886ab354b..bf1dfbc06 100644
--- a/client/src/js/modules/cell/views/autoproc.js
+++ b/client/src/js/modules/cell/views/autoproc.js
@@ -1,7 +1,7 @@
define(['marionette', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.pie',
+ 'flot-pie',
], function(Marionette, utils, $) {
diff --git a/client/src/js/modules/cell/views/states.js b/client/src/js/modules/cell/views/states.js
index 467cd7ae5..12250015a 100644
--- a/client/src/js/modules/cell/views/states.js
+++ b/client/src/js/modules/cell/views/states.js
@@ -1,7 +1,7 @@
define(['marionette', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.pie',
+ 'flot-pie',
], function(Marionette, utils, $) {
diff --git a/client/src/js/modules/dc/routes.js b/client/src/js/modules/dc/routes.js
index 5305fea6c..6b6350bc8 100644
--- a/client/src/js/modules/dc/routes.js
+++ b/client/src/js/modules/dc/routes.js
@@ -16,6 +16,7 @@ const QueueBuilder = import(/* webpackChunkName: "dc" */ 'modules/dc/views/queue
// import DataCollection from 'models/datacollection'
import DCCol from 'collections/datacollections'
+import DCVisit from 'collections/datacollectionsforvisit'
import Visit from 'models/visit'
import RoutesUtil from 'utils/routes'
// import store from 'app/store/store'
@@ -119,8 +120,8 @@ let routes = [
visit: route.params.visit || '',
options: {
model: visitModel,
- collection: new DCCol(null, {
- queryParams: { visit: route.params.visit, t: 'fc', pp: app.mobile() ? 5 : 15 }, running: false
+ collection: new DCVisit(null, {
+ queryParams: { visit: route.params.visit }
})
}
}),
diff --git a/client/src/js/modules/dc/views/aiplots.js b/client/src/js/modules/dc/views/aiplots.js
index a0a9978e7..1fce92216 100644
--- a/client/src/js/modules/dc/views/aiplots.js
+++ b/client/src/js/modules/dc/views/aiplots.js
@@ -3,7 +3,7 @@ define(['marionette', 'backbone', 'modules/dc/collections/aiplots',
'templates/dc/aiplots.html',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
'jquery.flot.tooltip',
], function(Marionette, Backbone, AIPlots, utils, template, $) {
diff --git a/client/src/js/modules/dc/views/distl.js b/client/src/js/modules/dc/views/distl.js
index 76496c70f..120caca7c 100644
--- a/client/src/js/modules/dc/views/distl.js
+++ b/client/src/js/modules/dc/views/distl.js
@@ -1,7 +1,7 @@
define(['marionette', 'modules/dc/models/distl', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
'jquery.flot.selection',
], function(Marionette, DCDISTLModel, utils, $) {
diff --git a/client/src/js/modules/dc/views/rdplot.js b/client/src/js/modules/dc/views/rdplot.js
index 1cd413c94..07e16f91a 100644
--- a/client/src/js/modules/dc/views/rdplot.js
+++ b/client/src/js/modules/dc/views/rdplot.js
@@ -2,7 +2,7 @@ define(['marionette', 'modules/dc/models/rd', 'utils',
'templates/dc/rdplot.html',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
], function(Marionette, RDModel, utils, template, $) {
diff --git a/client/src/js/modules/dc/views/summary.js b/client/src/js/modules/dc/views/summary.js
index 670ad84b4..ad9390f9d 100644
--- a/client/src/js/modules/dc/views/summary.js
+++ b/client/src/js/modules/dc/views/summary.js
@@ -1,66 +1,23 @@
-define(['marionette',
+define(['backbone',
+ 'marionette',
'backgrid',
'views/table',
- 'models/datacollection',
- 'modules/dc/collections/autointegrations',
'utils',
'utils/table',
+ 'utils/kvcollection',
+ 'collections/spacegroups',
'templates/dc/summary.html'],
- function(Marionette, Backgrid, TableView, DataCollection, AutoIntegrations,
+ function(Backbone, Marionette, Backgrid, TableView,
utils,
table,
+ KVCollection,
+ Spacegroups,
template) {
-
- var APCell = Backgrid.Cell.extend({
- initialize: function(options) {
- APCell.__super__.initialize.call(this,options)
- this.listenTo(this.model, 'change reset', this.render, this)
- this.template = options.column.get('template')
- },
-
- render: function() {
- this.$el.empty();
-
- if (this.model.get('BESTAP')) {
- var b = this.model.get('BESTAP')
- var t = _.template(_.result(this, 'template'))
- this.$el.html(t(b.toJSON()))
-
- } else if (this.model.get('APLOADED') == true) {
- if (this.column.get('first')) {
- if (this.model.get('AUTOINTEGRATIONS').length == 0) this.$el.text('No successful auto processing')
- else this.$el.text('No best auto processing determined')
-
- } else {
- this.$el.text('')
- }
-
- } else {
- this.$el.html('')
- }
-
-
- this.delegateEvents();
- return this;
- }
- })
-
-
- var APLenCell = Backgrid.Cell.extend({
- initialize: function(options) {
- APLenCell.__super__.initialize.call(this,options)
- this.listenTo(this.model, 'change reset', this.render, this)
- },
-
- render: function() {
- if (this.model.get('APLOADED')) {
- this.$el.text(this.model.get('AUTOINTEGRATIONS').length)
- } else this.$el.text('')
-
- return this
- }
- })
+ var Pipelines = Backbone.Collection.extend(_.extend({
+ keyAttribute: 'NAME',
+ valueAttribute: 'VALUE',
+ }, KVCollection))
return Marionette.LayoutView.extend({
className: 'content',
@@ -69,64 +26,142 @@ define(['marionette',
regions: {
wrap: '.wrapper',
},
-
- collectionEvents: {
- 'update sync reset': 'updateStatus',
- },
events: {
- 'click a[name=update]': 'scoreAPS',
'click a.dll': utils.signHandler,
+ 'change @ui.pipeline': 'changePipeline',
+ 'change @ui.sg': 'changeSpaceGroup',
+ 'change @ui.minres': 'changeResolution',
+ 'change @ui.mincom': 'changeCompleteness',
+ 'change @ui.minanom': 'changeAnomCompleteness',
+ 'change @ui.maxrmeas': 'changeRmeas',
+ 'change @ui.mincchalf': 'changeCCHalf',
+ 'change @ui.minccanom': 'changeCCAnom',
},
ui: {
- rmerge: 'input[name="rmerge"]',
- res: 'input[name="res"]',
- isigi: 'input[name="isigi"]',
- c: 'input[name="comp"]',
- sg: 'input[name="sg"]',
+ pipeline: 'select[name=pipeline]',
+ sg: 'select[name=SG]',
+ minres: 'input[name=minres]',
+ mincom: 'input[name=mincom]',
+ minanom: 'input[name=minanom]',
+ maxrmeas: 'input[name=maxrmeas]',
+ mincchalf: 'input[name=mincchalf]',
+ minccanom: 'input[name=minccanom]',
},
- updateStatus: function() {
- console.log('updating status')
- var self = this
- var deferreds = []
- this.collection.each(function(dc) {
- var ai = new AutoIntegrations(null, { id: dc.get('ID') })
- var d = ai.fetch().then(function() {
- var filtered = ai.where({ PROCESSINGSTATUS: "1"})
- dc.set({ AUTOINTEGRATIONS: new AutoIntegrations(filtered, { id: dc.get('ID') }) }, { silent: true })
- })
- deferreds.push(d)
- })
-
- $.when.apply($, deferreds).then(function() {
- self.collection.each(function(m) {
- m.set({ APLOADED: true }, { silent: m.get('AUTOINTEGRATIONS').length ? true: false })
- })
- self.scoreAPS()
- })
+ initialize: function(options) {
+ this.visit = options.model.get('VISIT')
+ },
+
+ changePipeline: function() {
+ if (this.ui.pipeline.val()) {
+ this.collection.queryParams.pipeline = this.ui.pipeline.val()
+ } else {
+ delete this.collection.queryParams.pipeline
+ }
+ this.collection.fetch()
+ },
+
+ showSpaceGroups: async function() {
+ this.spacegroups = new Spacegroups(null, { state: { pageSize: 9999 } })
+ await this.spacegroups.fetch();
+ this.ui.sg.html(''+this.spacegroups.opts())
},
+ changeSpaceGroup: function() {
+ if (this.ui.sg.val()) {
+ this.collection.queryParams.spacegroup = this.ui.sg.val()
+ } else {
+ delete this.collection.queryParams.spacegroup
+ }
+ this.collection.fetch()
+ },
+ changeResolution: function() {
+ if (this.ui.minres.val()) {
+ this.collection.queryParams.resolution = this.ui.minres.val()
+ } else {
+ delete this.collection.queryParams.resolution
+ }
+ this.collection.fetch()
+ },
+
+ changeCompleteness: function() {
+ if (this.ui.mincom.val()) {
+ this.collection.queryParams.completeness = this.ui.mincom.val()
+ } else {
+ delete this.collection.queryParams.completeness
+ }
+ this.collection.fetch()
+ },
+
+ changeAnomCompleteness: function() {
+ if (this.ui.minanom.val()) {
+ this.collection.queryParams.anomcompleteness = this.ui.minanom.val()
+ } else {
+ delete this.collection.queryParams.anomcompleteness
+ }
+ this.collection.fetch()
+ },
+
+ changeRmeas: function() {
+ if (this.ui.maxrmeas.val()) {
+ this.collection.queryParams.rmeas = this.ui.maxrmeas.val()
+ } else {
+ delete this.collection.queryParams.rmeas
+ }
+ this.collection.fetch()
+ },
+
+ changeCCHalf: function() {
+ if (this.ui.mincchalf.val()) {
+ this.collection.queryParams.cchalf = this.ui.mincchalf.val()
+ } else {
+ delete this.collection.queryParams.cchalf
+ }
+ this.collection.fetch()
+ },
+
+ changeCCAnom: function() {
+ if (this.ui.minccanom.val()) {
+ this.collection.queryParams.ccanom = this.ui.minccanom.val()
+ } else {
+ delete this.collection.queryParams.ccanom
+ }
+ this.collection.fetch()
+ },
+
onRender: function() {
+ this.showSpaceGroups()
+
+ this.pipelines = new Pipelines([
+ { NAME: 'Any', VALUE: '' },
+ { NAME: 'Xia2 DIALS', VALUE: 'xia2 dials' },
+ { NAME: 'Xia2 3dii', VALUE: 'xia2 3dii' },
+ { NAME: 'Fast DP', VALUE: 'fast_dp' },
+ { NAME: 'autoPROC', VALUE: 'autoPROC' },
+ { NAME: 'autoPROC+STARANISO', VALUE: 'autoPROC+STARANISO' },
+ ])
+
+ this.ui.pipeline.html(this.pipelines.opts())
+
var columns = [
- { label: '', cell: table.TemplateCell, editable: false, template: ' View Data Collection' },
- { name: 'FILETEMPLATETRIM', label: 'Prefix', cell: 'string', editable: false },
- { name: 'SAMPLE', label: 'Sample', cell: 'string', editable: false },
- { name: 'ST', label: 'Date', cell: 'string', editable: false },
- { name: 'NUMIMG', label: '# Images', cell: 'string', editable: false },
- { name: 'AXISRANGE', label: 'Osc', cell: 'string', editable: false },
- { name: 'EXPOSURETIME', label: 'Exposure', cell: 'string', editable: false },
- { name: 'TRANSMISSION', label: 'Transmission', cell: 'string', editable: false },
- { label: '#AP', cell: APLenCell, editable: false },
- { label: 'Spacegroup', cell: APCell, template: '<%-SG%>
<%-TYPE%>', editable: false, first: true },
- { label: 'Unit Cell', cell: APCell, template: '<%-CELL.CELL_A%> (<%-CELL.CELL_AL%>)
<%-CELL.CELL_B%> (<%-CELL.CELL_BE%>)
<%-CELL.CELL_C%> (<%-CELL.CELL_GA%>)', editable: false },
- { label: 'Resolution', cell: APCell, template: '<%-SHELLS.overall.RLOW%> - <%-SHELLS.overall.RHIGH%>
<%-SHELLS.innerShell.RLOW%> - <%-SHELLS.innerShell.RHIGH%>
<%-SHELLS.outerShell.RLOW%> - <%-SHELLS.outerShell.RHIGH%>', editable: false },
- { label: 'Rmeas', cell: APCell, template: '<%-SHELLS.overall.RMEAS%>
<%-SHELLS.innerShell.RMEAS%>
<%-SHELLS.outerShell.RMEAS%>', editable: false },
- { label: 'Completeness', cell: APCell, template: '<%-SHELLS.overall.COMPLETENESS%>
<%-SHELLS.innerShell.COMPLETENESS%>
<%-SHELLS.outerShell.COMPLETENESS%>', editable: false },
- { label: '', cell: APCell, template: ' Download autoprocessing archive', editable: false },
-
+ { label: '', cell: table.TemplateCell, editable: false, template: ' View Data Collection' },
+ { name: 'PREFIX', label: 'Prefix', cell: 'string', editable: false },
+ { name: 'SAMPLE', label: 'Sample', cell: table.TemplateCell, template: '<%-SAMPLE%>',editable: false },
+ { name: 'ENERGY', label: 'Energy', cell: table.TemplateCell, template: '<%-ENERGY%>eV', editable: false },
+ { name: 'RESOLUTION', label: 'Det Resolution', cell: table.TemplateCell, template: '<%-RESOLUTION%>Å', editable: false },
+ { name: 'PIPELINE', label: 'Pipeline', cell: 'string', editable: false },
+ { name: 'SG', label: 'Spacegroup', cell: 'string', editable: false },
+ { name: 'CELL', label: 'Unit Cell', cell: table.TemplateCell, template: '<%-CELL_A%> (<%-CELL_AL%>)
<%-CELL_B%> (<%-CELL_BE%>)
<%-CELL_C%> (<%-CELL_GA%>)', editable: false },
+ { name: 'RES', label: 'Resolution', cell: table.TemplateCell, template: '<%-OVERALLRLOW%> - <%-OVERALLRHIGH%>
<%-INNERRLOW%> - <%-INNERRHIGH%>
<%-OUTERRLOW%> - <%-OUTERRHIGH%>', editable: false },
+ { name: 'COMPLETENESS', label: 'Completeness', cell: table.TemplateCell, template: '<%-OVERALLCOMPLETENESS%>
<%-INNERCOMPLETENESS%>
<%-OUTERCOMPLETENESS%>', editable: false },
+ { name: 'ANOMCOMPLETENESS', label: 'Anom Completeness', cell: table.TemplateCell, template: '<%-ANOMOVERALLCOMPLETENESS%>
<%-ANOMINNERCOMPLETENESS%>
<%-ANOMOUTERCOMPLETENESS%>', editable: false },
+ { name: 'INNERRMEAS', label: 'Rmeas Inner', cell: 'string', editable: false },
+ { name: 'OUTERCCHALF', label: 'CC½ Outer', cell: 'string', editable: false },
+ { name: 'INNERCCANOM', label: 'CCanom Inner', cell: 'string', editable: false },
+ { label: '', cell: table.TemplateCell, template: ' Download autoprocessing archive', editable: false },
]
this.wrap.show(new TableView({
@@ -134,90 +169,12 @@ define(['marionette',
columns: columns,
tableClass: '',
filter: 's',
+ noSearchUrl: true,
loading: true,
backgrid: { emptyText: 'No data collections found' }
}))
-
- this.updateStatus()
- },
-
-
- scoreAPS: function(e) {
- if (e) e.preventDefault()
- console.log('scoring')
-
- // metric weights
- var weights = {
- rmerge: this.ui.rmerge.val(),
- res: this.ui.res.val(),
- isigi: this.ui.isigi.val(),
- c: this.ui.c.val(),
- sg: this.ui.sg.is(':checked')
- }
-
- // shell weights - should probably have per shell metric weights...
- var sweights = { overall: 1, innerShell: 0.5, outerShell: 1 }
-
- var max = {res: {}, isig: {}, resm: {}, rdiff: {}}
- _.each(sweights, function(w, sh) {
- max.res[sh] = 0
- max.isig[sh] = 0
- max.resm[sh] = 999
- max.rdiff[sh] = 0
- })
-
- this.collection.each(function(dc) {
- if (dc.get('APLOADED')) {
- var aps = dc.get('AUTOINTEGRATIONS')
- aps.each(function(d) {
- _.each(sweights, function(w, sh) {
- var s = d.get('SHELLS')[sh]
- if (parseFloat(s.RHIGH) > max.res[sh]) max.res[sh] = parseFloat(s.RHIGH)
- if (parseFloat(s.RHIGH) < max.resm[sh]) max.resm[sh] = parseFloat(s.RHIGH)
- if (parseFloat(s.ISIGI) > max.isig[sh]) max.isig[sh] = parseFloat(s.ISIGI)
- })
- })
-
- _.each(sweights, function(w, sh) {
- max.rdiff[sh] = max.res[sh] - max.resm[sh]
- })
-
- var best = null
- var best_score = 0
- aps.each(function(d) {
- if (d.get('PROCESSINGSTATUS') != 1) return
-
- var score = 0
- _.each(sweights, function(w, sh) {
- var s = d.get('SHELLS')[sh]
-
- var res = ((max.res[sh] - parseFloat(s.RHIGH))/max.rdiff[sh])*weights.res
- var rmerge = (1 - parseFloat(s.RMERGE))*weights.rmerge
- var isigi = (parseFloat(s.ISIGI)/max.isig[sh])*weights.isigi
- var comp = (parseFloat(s.COMPLETENESS)/100)*weights.c
-
- score += (res + rmerge + isigi + comp) * w
- })
-
- score *= (weights.sg ? (this.ui.sg.val() ? this.ui.sg.val() == d.get('SG').replace(/\s+/g,'') : 1) : 1)
-
- //console.log('each ap', score)
-
- if (score > best_score) {
- best_score = score
- best = d
- }
-
- }, this)
-
- //console.log('setting best', best)
- if (best) dc.set('BESTAP', best)
- else if (aps.length == 1) dc.set('BESTAP', aps.at(0))
- }
- }, this)
-
- return false
+
},
})
diff --git a/client/src/js/modules/proposal/list.js b/client/src/js/modules/proposal/list.js
index c2be819b2..847255794 100644
--- a/client/src/js/modules/proposal/list.js
+++ b/client/src/js/modules/proposal/list.js
@@ -27,6 +27,7 @@ define(['marionette',
{ name: 'PROPOSALCODE', label: 'Code', cell: 'string', editable: false },
{ name: 'PROPOSALNUMBER', label: 'Number', cell: 'string', editable: false },
{ name: 'VCOUNT', label: 'Visits', cell: 'string', editable: false },
+ { name: 'STATE', label: 'State', cell: 'string', editable: false },
{ name: 'TITLE', label: 'Title', cell: 'string', editable: false }]
this.table = new TableView({ collection: options.collection, columns: columns, tableClass: 'proposals', filter: 's', search: options.params.s, loading: true, backgrid: { row: this.getOption('clickableRow'), emptyText: 'No proposals found', } })
@@ -41,4 +42,4 @@ define(['marionette',
},
})
-})
\ No newline at end of file
+})
diff --git a/client/src/js/modules/shipment/views/dispatch.js b/client/src/js/modules/shipment/views/dispatch.js
index 416375168..5e0f59999 100644
--- a/client/src/js/modules/shipment/views/dispatch.js
+++ b/client/src/js/modules/shipment/views/dispatch.js
@@ -112,6 +112,7 @@ define(['marionette', 'views/form',
DEWARID: this.getOption('dewar').get('DEWARID'),
LABCONTACTID: this.getOption('dewar').get('LABCONTACTID'),
VISIT: this.getOption('dewar').get('FIRSTEXPERIMENT'),
+ UDCVISIT: this.getOption('dewar').get('UDCFIRSTEXPERIMENT'),
// If no agent specified on inbound, default to diamond dhl
DELIVERYAGENT_AGENTNAME: this.getOption('shipping').get('DELIVERYAGENT_AGENTNAME') || 'DHL'
})
@@ -174,7 +175,8 @@ define(['marionette', 'views/form',
},
doOnRender: function() {
- this.ui.exp.html(this.visits.opts()).val(this.model.get('VISIT'))
+ let visit = this.model.get('VISIT') || this.model.get('UDCVISIT')
+ this.ui.exp.html(this.visits.opts()).val(visit)
this.updateLC()
this.populateCountries()
this.stripPostCode()
diff --git a/client/src/js/modules/stats/views/pie.js b/client/src/js/modules/stats/views/pie.js
index cd75a09a7..54222d28b 100644
--- a/client/src/js/modules/stats/views/pie.js
+++ b/client/src/js/modules/stats/views/pie.js
@@ -1,8 +1,8 @@
define(['marionette', 'modules/stats/models/pie', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
- 'jquery.flot.pie',
+ 'jquery-flot-resize',
+ 'flot-pie',
], function(Marionette, Pie, utils, $) {
return Marionette.ItemView.extend({
diff --git a/client/src/js/modules/summary/collections/summaryresults.js b/client/src/js/modules/summary/collections/summaryresults.js
deleted file mode 100644
index 95c6a87f6..000000000
--- a/client/src/js/modules/summary/collections/summaryresults.js
+++ /dev/null
@@ -1,23 +0,0 @@
-define(['backbone.paginator', 'modules/summary/models/summaryresult'], function(PageableCollection, SummaryResult) {
-
- return PageableCollection.extend({
- model: SummaryResult,
- mode: 'server',
- // url: '/summary/example',
- url: '/summary/results',
-
-
- state: {
- pageSize: 15,
- },
-
- parseState: function(r, q, state, options) {
- return { totalRecords: r.total }
- },
-
- parseRecords: function(r, options) {
- return r.data
- },
-
- })
-})
\ No newline at end of file
diff --git a/client/src/js/modules/summary/models/summaryresult.js b/client/src/js/modules/summary/models/summaryresult.js
deleted file mode 100644
index 1a7ac52d2..000000000
--- a/client/src/js/modules/summary/models/summaryresult.js
+++ /dev/null
@@ -1,13 +0,0 @@
-define(['backbone'], function(Backbone) {
-
- return Backbone.Model.extend({
- idAttribute: 'proposalID', //change this
- // urlRoot: '/summary/example',
- urlRoot: '/summary/results',
-
-
-
- })
-
- })
-
\ No newline at end of file
diff --git a/client/src/js/modules/summary/routes.js b/client/src/js/modules/summary/routes.js
deleted file mode 100644
index 240c886a7..000000000
--- a/client/src/js/modules/summary/routes.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const SummaryViewWrapper = () => import(/* webpackChunkName: "summary" */ 'modules/summary/views/summary.vue')
-
-
-const routes = [
- // Root path has optional parameters so we need to deal with it first
- // It doesn't play nicely with multiple child routes...
- {
- path: '/summary',
- component: SummaryViewWrapper,
-
- }
-]
-
-export default routes
\ No newline at end of file
diff --git a/client/src/js/modules/summary/styles/_summary.scss b/client/src/js/modules/summary/styles/_summary.scss
deleted file mode 100644
index 884d4fca0..000000000
--- a/client/src/js/modules/summary/styles/_summary.scss
+++ /dev/null
@@ -1,248 +0,0 @@
-
-
-
-.copied {
- height: 125px;
- width: 75px;
- justify-content: center;
- align-items: center;
- display: flex;
- position: fixed;
- top: 20%;
- left: 50%;
-}
-
-.status {
- height: 125px;
- width: 75px;
- justify-content: center;
- align-items: center;
- display: flex;
- position: fixed;
- top: 45%;
- left: 50%;
- color: rgb(111, 213, 111);
-}
-
-.proposal-select {
- color: black;
- height: 10px;
-}
-
-
-.order-by {
- cursor: pointer;
- position: relative;
- /* top: 60%; */
- content: "";
- width: 15px;
- height: 20px;
-}
-
-
-.sidebar-button {
- @apply tw-text-center tw-bg-content-active tw-border-content-active tw-text-xs tw-border-4 tw-text-black tw-py-1 tw-px-1 tw-rounded
-}
-.sidebar-button:hover {
- @apply tw-border-teal-700 tw-bg-teal-700
-}
-
-.clear-button {
- @apply tw-flex tw-text-black tw-text-center tw-text-xs tw-py-2 tw-px-1 tw-ml-2
-}
-
-.clear-button:focus {
- @apply tw-text-content-active tw-text-content-active
-}
-
-.filter-grid {
- @apply tw-grid tw-grid-rows-1 tw-grid-cols-4 tw-grid-flow-col
-}
-
-.filter-options-grid {
- @apply tw-grid tw-grid-rows-6 tw-grid-cols-3 tw-grid-flow-col tw-mb-2
-}
-
-.format-options-grid {
- @apply tw-grid tw-grid-rows-6 tw-grid-cols-1 tw-grid-flow-col tw-mb-2
-
-}
-
-.select-column-button {
- @apply tw-h-8 tw-rounded tw-text-xs tw-px-4 tw-text-center tw-inline-flex tw-items-center
- tw-bg-content-sub-header-background tw-border-content-sub-header-background tw-border-4
- tw-text-black tw-py-1 tw-px-5
-}
-
-.select-columns-dropdown {
- @apply tw-absolute tw-bg-white tw-rounded tw-shadow
- tw-transition tw-ease-out tw-duration-100
-}
-
-.select-columns-dropdown-show{
- @apply tw-transform tw-opacity-100 tw-scale-100 tw-z-50
-}
-
-.select-columns-dropdown-hide {
- z-index: -1;
- @apply tw-transform tw-opacity-0 tw-scale-95
-}
-
-.select-columns-checkbox {
- @apply tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-rounded tw-border-gray-300
-}
-
-.download-file {
- @apply tw-mt-10 tw-items-center tw-block tw-pt-1 tw-pl-5 tw-pr-5 tw-h-6 tw-ml-2 tw-mr-2
- tw-bg-content-sub-header-background tw-shadow tw-text-xs tw-rounded tw-shadow
-}
-
-.simple-search {
- @apply tw-pl-6 tw-px-4 tw-border
-}
-
-.simple-search:focus {
- @apply tw-outline-none tw-shadow-outline
-}
-
-/* Tooltip container */
-.tooltip {
- /* position: relative;
- display: inline-block; */
- color: rgb(104, 104, 104); /* If you want dots under the hoverable text */
-}
-
-.add-white {
- color: white;
-}
-
-.add-gray {
- color: rgb(104, 104, 104);
-}
-
-.tooltip-position-relative {
- position: relative;
- display: inline-block;
-}
-
-.tooltip-position-absolute {
- position: absolute;
-}
-
-
-/* Tooltip text */
-.tooltip .tooltiptext {
- font-family: Arial, Helvetica, sans-serif;
- visibility: hidden;
- opacity: 0.9;
- width: 120px;
- background-color: rgb(25, 24, 24);
- color: #fff;
- text-align: center;
- padding: 5px 0;
- border-radius: 6px;
-
- /* Position the tooltip text - see examples below! */
- position: absolute;
- z-index: 1;
-}
-
-/* Show the tooltip text when you mouse over the tooltip container */
-.tooltip:hover .tooltiptext {
- visibility: visible;
-}
-
-.description-options {
- display:none;
- position:absolute;
- border:1px solid #828282;
- font-family: Arial, Helvetica, sans-serif;
- overflow-x:visible;
- overflow-y:visible;
-
-}
-
-.tooltip:hover .description-options {
- display:block;
- min-width:100px;
- min-height:50px;
- background-color: white;
- left:40%;
- top: 50%
-}
-
-.dc-nav {
- position: absolute;
- display: flex;
-}
-
-.tiptext-preview {
- position: absolute;
- font-size:small;
- cursor:pointer;
-}
-
-.description {
- display:none;
- position:absolute;
- left: 50%;
- border:1px solid #000;
- width:400px;
- height:400px;
-}
-
-.tiptext-preview:hover .description {
- display:block;
-}
-
-.param-options-wrapper {
- display:flex;
- margin-left: 65%;
- margin-top: 5px;
-}
-
-
-.param-options-tooltip {
- cursor:default;
- font-size:12px;
- font-weight: bold;
- margin-top: 2px;
- color: blue;
-
- &:hover .param-preview {
- opacity:1;
- display: inline;
- transform: translateX(-50%) translateY(0) scale(1);
- }
-
- &:hover {
- box-shadow: 0 1px 5px rgba(0,0,0,.1);
- border-color: #333;
- }
-}
-
-.param-preview {
- display: none;
- border-radius: 10px;
- transition:.2s ease-in-out opacity, .2s ease-in-out transform;
- opacity:0;
- z-index: 1;
- position:absolute;
- box-shadow:0 1px 5px rgba(0,0,0,.5);
- width:230px;
- height:fit-content;
- border:4px solid #fff;
- background-color: #fff;
- color: black;
- font-weight: normal;
- overflow-x:hidden;
- overflow-y:auto;
- transform-origin:center bottom;
- transform: translateX(-50%) translateY(10px) scale(.9);
-
-// div {
-// transform:scale(.2);
-// transform-origin:0 0;
-// }
-
-}
\ No newline at end of file
diff --git a/client/src/js/modules/summary/utils/utils.js b/client/src/js/modules/summary/utils/utils.js
deleted file mode 100644
index cf7a39c34..000000000
--- a/client/src/js/modules/summary/utils/utils.js
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-export function convertToCSV(data) {
-
- const result = [
- // headers
- Object.keys(data['0']),
- // values
- ...Object.values(data).map(item => Object.values(item))
- ]
- .reduce((string, item) => {
- string += item.join(',') + '\n';
- return string;
- }, '');
-
- return result;
-}
-
-export function exportCSV(csv) {
-
- const anchor = document.createElement('a');
- anchor.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
- anchor.target = '_blank';
- anchor.download = 'summary_export.csv';
- anchor.click();
-
-}
-
diff --git a/client/src/js/modules/summary/views/summary.vue b/client/src/js/modules/summary/views/summary.vue
deleted file mode 100644
index 9eb3ebcae..000000000
--- a/client/src/js/modules/summary/views/summary.vue
+++ /dev/null
@@ -1,1485 +0,0 @@
-
-
-
-
- Data Collection Summary
-
-
-
-
-
-
-
-
-
-
- Use the Advanced Filter Search bar to filter your values
-
-
-
-
-
-
-
- Filter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Click to add filter options
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Toggle column visibility using the select columns drop down
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/src/js/modules/types/gen/dc/datplot.js b/client/src/js/modules/types/gen/dc/datplot.js
index a2254be18..67c3d2d9c 100644
--- a/client/src/js/modules/types/gen/dc/datplot.js
+++ b/client/src/js/modules/types/gen/dc/datplot.js
@@ -1,7 +1,7 @@
define(['marionette', 'modules/types/gen/dc/models/dat', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
], function(Marionette, Dat, utils, $) {
// DAT Plot
diff --git a/client/src/js/modules/types/pow/dc/datplotlarge.js b/client/src/js/modules/types/pow/dc/datplotlarge.js
index 1c9067dc0..a9c96abfc 100644
--- a/client/src/js/modules/types/pow/dc/datplotlarge.js
+++ b/client/src/js/modules/types/pow/dc/datplotlarge.js
@@ -5,8 +5,8 @@ define(['backbone',
'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
- 'jquery.flot.axislabels'
+ 'jquery-flot-resize',
+ 'flot-axislabels'
], function(Backbone, Marionette, Dat, DataCollections, utils, $) {
var DatCollection = Backbone.Collection.extend({
diff --git a/client/src/js/modules/types/saxs/dc/datplot.js b/client/src/js/modules/types/saxs/dc/datplot.js
index 818b02f55..73981dfa4 100644
--- a/client/src/js/modules/types/saxs/dc/datplot.js
+++ b/client/src/js/modules/types/saxs/dc/datplot.js
@@ -1,7 +1,7 @@
define(['marionette', 'modules/types/gen/dc/models/dat', 'utils',
'jquery',
'jquery.flot',
- 'jquery.flot.resize',
+ 'jquery-flot-resize',
], function(Marionette, Dat, utils, $) {
// DAT Plot
diff --git a/client/src/js/templates/dc/summary.html b/client/src/js/templates/dc/summary.html
index f5909677b..451dd1436 100644
--- a/client/src/js/templates/dc/summary.html
+++ b/client/src/js/templates/dc/summary.html
@@ -1,20 +1,18 @@
Data Collection Summary
-
- Data Collections
-
-
-
-
diff --git a/client/src/js/utils.js b/client/src/js/utils.js
index ef29ccb45..aea8e7fda 100644
--- a/client/src/js/utils.js
+++ b/client/src/js/utils.js
@@ -2,7 +2,7 @@ define(['backbone',
'marionette',
'views/dialog',
'jquery',
- 'jquery.color',
+ 'jquery-color',
'jquery-ui/ui/effect',
'jquery-ui/ui/effects/effect-highlight'
], function(Backbone, Marionette, DialogView, $) {
diff --git a/client/src/js/vendor/GLmol.js b/client/src/js/vendor/GLmol.js
deleted file mode 100644
index 9f2f8edc2..000000000
--- a/client/src/js/vendor/GLmol.js
+++ /dev/null
@@ -1,1712 +0,0 @@
-/*
- GLmol - Molecular Viewer on WebGL/Javascript (0.46)
- (C) Copyright 2011-2012, biochem_fan
- License: dual license of MIT or LGPL3
-
- Contributors:
- Robert Hanson for parseXYZ, deferred instantiation
-
- This program uses
- Three.js
- https://github.com/mrdoob/three.js
- Copyright (c) 2010-2012 three.js Authors. All rights reserved.
- jQuery
- http://jquery.org/
- Copyright (c) 2011 John Resig
- */
-
-// Workaround for Intel GMA series (gl_FrontFacing causes compilation error)
-THREE.ShaderLib.lambert.fragmentShader = THREE.ShaderLib.lambert.fragmentShader.replace("gl_FrontFacing", "true");
-THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace(/\}$/, "#ifdef DOUBLE_SIDED\n if (transformedNormal.z < 0.0) vLightFront = vLightBack;\n #endif\n }");
-
-var TV3 = THREE.Vector3, TF3 = THREE.Face3, TCo = THREE.Color;
-
-THREE.Geometry.prototype.colorAll = function (color) {
- for (var i = 0; i < this.faces.length; i++) {
- this.faces[i].color = color;
- }
-};
-
-THREE.Matrix4.prototype.isIdentity = function() {
- for (var i = 0; i < 4; i++)
- for (var j = 0; j < 4; j++)
- if (this.elements[i * 4 + j] != (i == j) ? 1 : 0) return false;
- return true;
-};
-
-var GLmol = (function() {
-function GLmol(id, suppressAutoload) {
- if (id) this.create(id, suppressAutoload);
- return true;
-}
-
-GLmol.prototype.create = function(id, suppressAutoload) {
- this.Nucleotides = [' G', ' A', ' T', ' C', ' U', ' DG', ' DA', ' DT', ' DC', ' DU'];
- this.ElementColors = {"H": 0xCCCCCC, "C": 0xAAAAAA, "O": 0xCC0000, "N": 0x0000CC, "S": 0xCCCC00, "P": 0x6622CC,
- "F": 0x00CC00, "CL": 0x00CC00, "BR": 0x882200, "I": 0x6600AA,
- "FE": 0xCC6600, "CA": 0x8888AA};
-// Reference: A. Bondi, J. Phys. Chem., 1964, 68, 441.
- this.vdwRadii = {"H": 1.2, "Li": 1.82, "Na": 2.27, "K": 2.75, "C": 1.7, "N": 1.55, "O": 1.52,
- "F": 1.47, "P": 1.80, "S": 1.80, "CL": 1.75, "BR": 1.85, "SE": 1.90,
- "ZN": 1.39, "CU": 1.4, "NI": 1.63};
-
- this.id = id;
- this.aaScale = 1; // or 2
-
- this.container = $('#' + this.id);
- this.WIDTH = this.container.width() * this.aaScale, this.HEIGHT = this.container.height() * this.aaScale;
- this.ASPECT = this.WIDTH / this.HEIGHT;
- this.NEAR = 1, FAR = 800;
- this.CAMERA_Z = -150;
- this.renderer = new THREE.WebGLRenderer({antialias: true});
- this.renderer.sortObjects = false; // hopefully improve performance
- // 'antialias: true' now works in Firefox too!
- // setting this.aaScale = 2 will enable antialias in older Firefox but GPU load increases.
- this.renderer.domElement.style.width = "100%";
- this.renderer.domElement.style.height = "100%";
- this.container.append(this.renderer.domElement);
- this.renderer.setSize(this.WIDTH, this.HEIGHT);
-
- this.camera = new THREE.PerspectiveCamera(20, this.ASPECT, 1, 800); // will be updated anyway
- this.camera.position = new TV3(0, 0, this.CAMERA_Z);
- this.camera.lookAt(new TV3(0, 0, 0));
- this.perspectiveCamera = this.camera;
- this.orthoscopicCamera = new THREE.OrthographicCamera();
- this.orthoscopicCamera.position.z = this.CAMERA_Z;
- this.orthoscopicCamera.lookAt(new TV3(0, 0, 0));
-
- var self = this;
- $(window).resize(function() { // only window can capture resize event
- self.WIDTH = self.container.width() * self.aaScale;
- self.HEIGHT = self.container.height() * self.aaScale;
- self.ASPECT = self.WIDTH / self.HEIGHT;
- self.renderer.setSize(self.WIDTH, self.HEIGHT);
- self.camera.aspect = self.ASPECT;
- self.camera.updateProjectionMatrix();
- self.show();
- });
-
- this.scene = null;
- this.rotationGroup = null; // which contains modelGroup
- this.modelGroup = null;
-
- this.bgColor = 0x000000;
- this.fov = 20;
- this.fogStart = 0.4;
- this.slabNear = -50; // relative to the center of rotationGroup
- this.slabFar = +50;
-
- // Default values
- this.sphereRadius = 1.5;
- this.cylinderRadius = 0.4;
- this.lineWidth = 1.5 * this.aaScale;
- this.curveWidth = 3 * this.aaScale;
- this.defaultColor = 0xCCCCCC;
- this.sphereQuality = 16; //16;
- this.cylinderQuality = 16; //8;
- this.axisDIV = 5; // 3 still gives acceptable quality
- this.strandDIV = 6;
- this.nucleicAcidStrandDIV = 4;
- this.tubeDIV = 8;
- this.coilWidth = 0.3;
- this.helixSheetWidth = 1.3;
- this.nucleicAcidWidth = 0.8;
- this.thickness = 0.4;
-
- // UI variables
- this.cq = new THREE.Quaternion(1, 0, 0, 0);
- this.dq = new THREE.Quaternion(1, 0, 0, 0);
- this.isDragging = false;
- this.mouseStartX = 0;
- this.mouseStartY = 0;
- this.currentModelPos = 0;
- this.cz = 0;
- this.enableMouse();
-
- if (suppressAutoload) return;
- this.loadMolecule();
-}
-
-GLmol.prototype.setupLights = function(scene) {
- var directionalLight = new THREE.DirectionalLight(0xFFFFFF);
- directionalLight.position = new TV3(0.2, 0.2, -1).normalize();
- directionalLight.intensity = 1.2;
- scene.add(directionalLight);
- var ambientLight = new THREE.AmbientLight(0x202020);
- scene.add(ambientLight);
-};
-
-GLmol.prototype.parseSDF = function(str) {
- var atoms = this.atoms;
- var protein = this.protein;
-
- var lines = str.split("\n");
- if (lines.length < 4) return;
- var atomCount = parseInt(lines[3].substr(0, 3));
- if (isNaN(atomCount) || atomCount <= 0) return; // might be a PDB file.
- var bondCount = parseInt(lines[3].substr(3, 3));
- var offset = 4;
- if (lines.length < 4 + atomCount + bondCount) return;
- for (var i = 1; i <= atomCount; i++) {
- var line = lines[offset];
- offset++;
- var atom = {};
- atom.serial = i;
- atom.x = parseFloat(line.substr(0, 10));
- atom.y = parseFloat(line.substr(10, 10));
- atom.z = parseFloat(line.substr(20, 10));
- atom.hetflag = true;
- atom.atom = atom.elem = line.substr(31, 3).replace(/ /g, "");
- atom.bonds = [];
- atom.bondOrder = [];
- atoms[i] = atom;
- }
- for (i = 1; i <= bondCount; i++) {
- var line = lines[offset];
- offset++;
- var from = parseInt(line.substr(0, 3));
- var to = parseInt(line.substr(3, 3));
- var order = parseInt(line.substr(6, 3));
- atoms[from].bonds.push(to);
- atoms[from].bondOrder.push(order);
- atoms[to].bonds.push(from);
- atoms[to].bondOrder.push(order);
- }
-
- protein.sdf = true;
-};
-
-GLmol.prototype.parseXYZ = function(str) {
- var atoms = this.atoms;
- var protein = this.protein;
-
- var lines = str.split("\n");
- if (lines.length < 3) return;
- var atomCount = parseInt(lines[0].substr(0, 3));
- if (isNaN(atomCount) || atomCount <= 0) return;
- if (lines.length < atomCount + 2) return;
- var offset = 2;
- for (var i = 1; i <= atomCount; i++) {
- var line = lines[offset++];
- var tokens = line.replace(/^\s+/, "").replace(/\s+/g," ").split(" ");
- console.log(tokens);
- var atom = {};
- atom.serial = i;
- atom.atom = atom.elem = tokens[0];
- atom.x = parseFloat(tokens[1]);
- atom.y = parseFloat(tokens[2]);
- atom.z = parseFloat(tokens[3]);
- atom.hetflag = true;
- atom.bonds = [];
- atom.bondOrder = [];
- atoms[i] = atom;
- }
- for (var i = 1; i < atomCount; i++) // hopefully XYZ is small enough
- for (var j = i + 1; j <= atomCount; j++)
- if (this.isConnected(atoms[i], atoms[j])) {
- atoms[i].bonds.push(j);
- atoms[i].bondOrder.push(1);
- atoms[j].bonds.push(i);
- atoms[j].bondOrder.push(1);
- }
- protein.sdf = true;
-};
-
-GLmol.prototype.parsePDB2 = function(str) {
- var atoms = this.atoms;
- var protein = this.protein;
- var molID;
-
- var atoms_cnt = 0;
- lines = str.split("\n");
- for (var i = 0; i < lines.length; i++) {
- line = lines[i].replace(/^\s*/, ''); // remove indent
- var recordName = line.substr(0, 6);
- if (recordName == 'ATOM ' || recordName == 'HETATM') {
- var atom, resn, chain, resi, x, y, z, hetflag, elem, serial, altLoc, b;
- altLoc = line.substr(16, 1);
- if (altLoc != ' ' && altLoc != 'A') continue; // FIXME: ad hoc
- serial = parseInt(line.substr(6, 5));
- atom = line.substr(12, 4).replace(/ /g, "");
- resn = line.substr(17, 3);
- chain = line.substr(21, 1);
- resi = parseInt(line.substr(22, 5));
- x = parseFloat(line.substr(30, 8));
- y = parseFloat(line.substr(38, 8));
- z = parseFloat(line.substr(46, 8));
- b = parseFloat(line.substr(60, 8));
- elem = line.substr(76, 2).replace(/ /g, "");
- if (elem == '') { // for some incorrect PDB files
- elem = line.substr(12, 4).replace(/ /g,"");
- }
- if (line[0] == 'H') hetflag = true;
- else hetflag = false;
- atoms[serial] = {'resn': resn, 'x': x, 'y': y, 'z': z, 'elem': elem,
- 'hetflag': hetflag, 'chain': chain, 'resi': resi, 'serial': serial, 'atom': atom,
- 'bonds': [], 'ss': 'c', 'color': 0xFFFFFF, 'bonds': [], 'bondOrder': [], 'b': b /*', altLoc': altLoc*/};
- } else if (recordName == 'SHEET ') {
- var startChain = line.substr(21, 1);
- var startResi = parseInt(line.substr(22, 4));
- var endChain = line.substr(32, 1);
- var endResi = parseInt(line.substr(33, 4));
- protein.sheet.push([startChain, startResi, endChain, endResi]);
- } else if (recordName == 'CONECT') {
-// MEMO: We don't have to parse SSBOND, LINK because both are also
-// described in CONECT. But what about 2JYT???
- var from = parseInt(line.substr(6, 5));
- for (var j = 0; j < 4; j++) {
- var to = parseInt(line.substr([11, 16, 21, 26][j], 5));
- if (isNaN(to)) continue;
- if (atoms[from] != undefined) {
- atoms[from].bonds.push(to);
- atoms[from].bondOrder.push(1);
- }
- }
- } else if (recordName == 'HELIX ') {
- var startChain = line.substr(19, 1);
- var startResi = parseInt(line.substr(21, 4));
- var endChain = line.substr(31, 1);
- var endResi = parseInt(line.substr(33, 4));
- protein.helix.push([startChain, startResi, endChain, endResi]);
- } else if (recordName == 'CRYST1') {
- protein.a = parseFloat(line.substr(6, 9));
- protein.b = parseFloat(line.substr(15, 9));
- protein.c = parseFloat(line.substr(24, 9));
- protein.alpha = parseFloat(line.substr(33, 7));
- protein.beta = parseFloat(line.substr(40, 7));
- protein.gamma = parseFloat(line.substr(47, 7));
- protein.spacegroup = line.substr(55, 11);
- this.defineCell();
- } else if (recordName == 'REMARK') {
- var type = parseInt(line.substr(7, 3));
- if (type == 290 && line.substr(13, 5) == 'SMTRY') {
- var n = parseInt(line[18]) - 1;
- var m = parseInt(line.substr(21, 2));
- if (protein.symMat[m] == undefined) protein.symMat[m] = new THREE.Matrix4().identity();
- protein.symMat[m].elements[n] = parseFloat(line.substr(24, 9));
- protein.symMat[m].elements[n + 4] = parseFloat(line.substr(34, 9));
- protein.symMat[m].elements[n + 8] = parseFloat(line.substr(44, 9));
- protein.symMat[m].elements[n + 12] = parseFloat(line.substr(54, 10));
- } else if (type == 350 && line.substr(13, 5) == 'BIOMT') {
- var n = parseInt(line[18]) - 1;
- var m = parseInt(line.substr(21, 2));
- if (protein.biomtMatrices[m] == undefined) protein.biomtMatrices[m] = new THREE.Matrix4().identity();
- protein.biomtMatrices[m].elements[n] = parseFloat(line.substr(24, 9));
- protein.biomtMatrices[m].elements[n + 4] = parseFloat(line.substr(34, 9));
- protein.biomtMatrices[m].elements[n + 8] = parseFloat(line.substr(44, 9));
- protein.biomtMatrices[m].elements[n + 12] = parseFloat(line.substr(54, 10));
- } else if (type == 350 && line.substr(11, 11) == 'BIOMOLECULE') {
- protein.biomtMatrices = []; protein.biomtChains = '';
- } else if (type == 350 && line.substr(34, 6) == 'CHAINS') {
- protein.biomtChains += line.substr(41, 40);
- }
- } else if (recordName == 'HEADER') {
- protein.pdbID = line.substr(62, 4);
- } else if (recordName == 'TITLE ') {
- if (protein.title == undefined) protein.title = "";
- protein.title += line.substr(10, 70) + "\n"; // CHECK: why 60 is not enough???
- } else if (recordName == 'COMPND') {
- // TODO: Implement me!
- }
- }
-
- // Assign secondary structures
- for (i = 0; i < atoms.length; i++) {
- atom = atoms[i]; if (atom == undefined) continue;
-
- var found = false;
- // MEMO: Can start chain and end chain differ?
- for (j = 0; j < protein.sheet.length; j++) {
- if (atom.chain != protein.sheet[j][0]) continue;
- if (atom.resi < protein.sheet[j][1]) continue;
- if (atom.resi > protein.sheet[j][3]) continue;
- atom.ss = 's';
- if (atom.resi == protein.sheet[j][1]) atom.ssbegin = true;
- if (atom.resi == protein.sheet[j][3]) atom.ssend = true;
- }
- for (j = 0; j < protein.helix.length; j++) {
- if (atom.chain != protein.helix[j][0]) continue;
- if (atom.resi < protein.helix[j][1]) continue;
- if (atom.resi > protein.helix[j][3]) continue;
- atom.ss = 'h';
- if (atom.resi == protein.helix[j][1]) atom.ssbegin = true;
- else if (atom.resi == protein.helix[j][3]) atom.ssend = true;
- }
- }
-};
-
-// Catmull-Rom subdivision
-GLmol.prototype.subdivide = function(_points, DIV) { // points as Vector3
- var ret = [];
- var points = _points;
- points = new Array(); // Smoothing test
- points.push(_points[0]);
- for (var i = 1, lim = _points.length - 1; i < lim; i++) {
- var p1 = _points[i], p2 = _points[i + 1];
- if (p1.smoothen) points.push(new TV3((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, (p1.z + p2.z) / 2));
- else points.push(p1);
- }
- points.push(_points[_points.length - 1]);
-
- for (var i = -1, size = points.length; i <= size - 3; i++) {
- var p0 = points[(i == -1) ? 0 : i];
- var p1 = points[i + 1], p2 = points[i + 2];
- var p3 = points[(i == size - 3) ? size - 1 : i + 3];
- var v0 = new TV3().sub(p2, p0).multiplyScalar(0.5);
- var v1 = new TV3().sub(p3, p1).multiplyScalar(0.5);
- for (var j = 0; j < DIV; j++) {
- var t = 1.0 / DIV * j;
- var x = p1.x + t * v0.x
- + t * t * (-3 * p1.x + 3 * p2.x - 2 * v0.x - v1.x)
- + t * t * t * (2 * p1.x - 2 * p2.x + v0.x + v1.x);
- var y = p1.y + t * v0.y
- + t * t * (-3 * p1.y + 3 * p2.y - 2 * v0.y - v1.y)
- + t * t * t * (2 * p1.y - 2 * p2.y + v0.y + v1.y);
- var z = p1.z + t * v0.z
- + t * t * (-3 * p1.z + 3 * p2.z - 2 * v0.z - v1.z)
- + t * t * t * (2 * p1.z - 2 * p2.z + v0.z + v1.z);
- ret.push(new TV3(x, y, z));
- }
- }
- ret.push(points[points.length - 1]);
- return ret;
-};
-
-GLmol.prototype.drawAtomsAsSphere = function(group, atomlist, defaultRadius, forceDefault, scale) {
- var sphereGeometry = new THREE.SphereGeometry(1, this.sphereQuality, this.sphereQuality); // r, seg, ring
- for (var i = 0; i < atomlist.length; i++) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- var sphereMaterial = new THREE.MeshLambertMaterial({color: atom.color});
- var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
- group.add(sphere);
- var r = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius;
- if (!forceDefault && scale) r *= scale;
- sphere.scale.x = sphere.scale.y = sphere.scale.z = r;
- sphere.position.x = atom.x;
- sphere.position.y = atom.y;
- sphere.position.z = atom.z;
- }
-};
-
-// about two times faster than sphere when div = 2
-GLmol.prototype.drawAtomsAsIcosahedron = function(group, atomlist, defaultRadius, forceDefault) {
- var geo = this.IcosahedronGeometry();
- for (var i = 0; i < atomlist.length; i++) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- var mat = new THREE.MeshLambertMaterial({color: atom.color});
- var sphere = new THREE.Mesh(geo, mat);
- sphere.scale.x = sphere.scale.y = sphere.scale.z = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius;
- group.add(sphere);
- sphere.position.x = atom.x;
- sphere.position.y = atom.y;
- sphere.position.z = atom.z;
- }
-};
-
-GLmol.prototype.isConnected = function(atom1, atom2) {
- var s = atom1.bonds.indexOf(atom2.serial);
- if (s != -1) return atom1.bondOrder[s];
-
- if (this.protein.sdf && (atom1.hetflag || atom2.hetflag)) return 0; // CHECK: or should I ?
-
- var distSquared = (atom1.x - atom2.x) * (atom1.x - atom2.x) +
- (atom1.y - atom2.y) * (atom1.y - atom2.y) +
- (atom1.z - atom2.z) * (atom1.z - atom2.z);
-
-// if (atom1.altLoc != atom2.altLoc) return false;
- if (isNaN(distSquared)) return 0;
- if (distSquared < 0.5) return 0; // maybe duplicate position.
-
- if (distSquared > 1.3 && (atom1.elem == 'H' || atom2.elem == 'H' || atom1.elem == 'D' || atom2.elem == 'D')) return 0;
- if (distSquared < 3.42 && (atom1.elem == 'S' || atom2.elem == 'S')) return 1;
- if (distSquared > 2.78) return 0;
- return 1;
-};
-
-GLmol.prototype.drawBondAsStickSub = function(group, atom1, atom2, bondR, order) {
- var delta, tmp;
- if (order > 1) delta = this.calcBondDelta(atom1, atom2, bondR * 2.3);
- var p1 = new TV3(atom1.x, atom1.y, atom1.z);
- var p2 = new TV3(atom2.x, atom2.y, atom2.z);
- var mp = p1.clone().addSelf(p2).multiplyScalar(0.5);
-
- var c1 = new TCo(atom1.color), c2 = new TCo(atom2.color);
- if (order == 1 || order == 3) {
- this.drawCylinder(group, p1, mp, bondR, atom1.color);
- this.drawCylinder(group, p2, mp, bondR, atom2.color);
- }
- if (order > 1) {
- tmp = mp.clone().addSelf(delta);
- this.drawCylinder(group, p1.clone().addSelf(delta), tmp, bondR, atom1.color);
- this.drawCylinder(group, p2.clone().addSelf(delta), tmp, bondR, atom2.color);
- tmp = mp.clone().subSelf(delta);
- this.drawCylinder(group, p1.clone().subSelf(delta), tmp, bondR, atom1.color);
- this.drawCylinder(group, p2.clone().subSelf(delta), tmp, bondR, atom2.color);
- }
-};
-
-GLmol.prototype.drawBondsAsStick = function(group, atomlist, bondR, atomR, ignoreNonbonded, multipleBonds, scale) {
- var sphereGeometry = new THREE.SphereGeometry(1, this.sphereQuality, this.sphereQuality);
- var nAtoms = atomlist.length, mp;
- var forSpheres = [];
- if (!!multipleBonds) bondR /= 2.5;
- for (var _i = 0; _i < nAtoms; _i++) {
- var i = atomlist[_i];
- var atom1 = this.atoms[i];
- if (atom1 == undefined) continue;
- for (var _j = _i + 1; _j < _i + 30 && _j < nAtoms; _j++) {
- var j = atomlist[_j];
- var atom2 = this.atoms[j];
- if (atom2 == undefined) continue;
- var order = this.isConnected(atom1, atom2);
- if (order == 0) continue;
- atom1.connected = atom2.connected = true;
- this.drawBondAsStickSub(group, atom1, atom2, bondR, (!!multipleBonds) ? order : 1);
- }
- for (var _j = 0; _j < atom1.bonds.length; _j++) {
- var j = atom1.bonds[_j];
- if (j < i + 30) continue; // be conservative!
- if (atomlist.indexOf(j) == -1) continue;
- var atom2 = this.atoms[j];
- if (atom2 == undefined) continue;
- atom1.connected = atom2.connected = true;
- this.drawBondAsStickSub(group, atom1, atom2, bondR, (!!multipleBonds) ? atom1.bondOrder[_j] : 1);
- }
- if (atom1.connected) forSpheres.push(i);
- }
- this.drawAtomsAsSphere(group, forSpheres, atomR, !scale, scale);
-};
-
-GLmol.prototype.defineCell = function() {
- var p = this.protein;
- if (p.a == undefined) return;
-
- p.ax = p.a;
- p.ay = 0;
- p.az = 0;
- p.bx = p.b * Math.cos(Math.PI / 180.0 * p.gamma);
- p.by = p.b * Math.sin(Math.PI / 180.0 * p.gamma);
- p.bz = 0;
- p.cx = p.c * Math.cos(Math.PI / 180.0 * p.beta);
- p.cy = p.c * (Math.cos(Math.PI / 180.0 * p.alpha) -
- Math.cos(Math.PI / 180.0 * p.gamma)
- * Math.cos(Math.PI / 180.0 * p.beta))
- / Math.sin(Math.PI / 180.0 * p.gamma);
- p.cz = Math.sqrt(p.c * p.c * Math.sin(Math.PI / 180.0 * p.beta)
- * Math.sin(Math.PI / 180.0 * p.beta) - p.cy * p.cy);
-};
-
-GLmol.prototype.drawUnitcell = function(group) {
- var p = this.protein;
- if (p.a == undefined) return;
-
- var vertices = [[0, 0, 0], [p.ax, p.ay, p.az], [p.bx, p.by, p.bz], [p.ax + p.bx, p.ay + p.by, p.az + p.bz],
- [p.cx, p.cy, p.cz], [p.cx + p.ax, p.cy + p.ay, p.cz + p.az], [p.cx + p.bx, p.cy + p.by, p.cz + p.bz], [p.cx + p.ax + p.bx, p.cy + p.ay + p.by, p.cz + p.az + p.bz]];
- var edges = [0, 1, 0, 2, 1, 3, 2, 3, 4, 5, 4, 6, 5, 7, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7];
-
- var geo = new THREE.Geometry();
- for (var i = 0; i < edges.length; i++) {
- geo.vertices.push(new TV3(vertices[edges[i]][0], vertices[edges[i]][1], vertices[edges[i]][2]));
- }
- var lineMaterial = new THREE.LineBasicMaterial({linewidth: 1, color: 0xcccccc});
- var line = new THREE.Line(geo, lineMaterial);
- line.type = THREE.LinePieces;
- group.add(line);
-};
-
-// TODO: Find inner side of a ring
-GLmol.prototype.calcBondDelta = function(atom1, atom2, sep) {
- var dot;
- var axis = new TV3(atom1.x - atom2.x, atom1.y - atom2.y, atom1.z - atom2.z).normalize();
- var found = null;
- for (var i = 0; i < atom1.bonds.length && !found; i++) {
- var atom = this.atoms[atom1.bonds[i]]; if (!atom) continue;
- if (atom.serial != atom2.serial && atom.elem != 'H') found = atom;
- }
- for (var i = 0; i < atom2.bonds.length && !found; i++) {
- var atom = this.atoms[atom2.bonds[i]]; if (!atom) continue;
- if (atom.serial != atom1.serial && atom.elem != 'H') found = atom;
- }
- if (found) {
- var tmp = new TV3(atom1.x - found.x, atom1.y - found.y, atom1.z - found.z).normalize();
- dot = tmp.dot(axis);
- delta = new TV3(tmp.x - axis.x * dot, tmp.y - axis.y * dot, tmp.z - axis.z * dot);
- }
- if (!found || Math.abs(dot - 1) < 0.001 || Math.abs(dot + 1) < 0.001) {
- if (axis.x < 0.01 && axis.y < 0.01) {
- delta = new TV3(0, -axis.z, axis.y);
- } else {
- delta = new TV3(-axis.y, axis.x, 0);
- }
- }
- delta.normalize().multiplyScalar(sep);
- return delta;
-};
-
-GLmol.prototype.drawBondsAsLineSub = function(geo, atom1, atom2, order) {
- var delta, tmp, vs = geo.vertices, cs = geo.colors;
- if (order > 1) delta = this.calcBondDelta(atom1, atom2, 0.15);
- var p1 = new TV3(atom1.x, atom1.y, atom1.z);
- var p2 = new TV3(atom2.x, atom2.y, atom2.z);
- var mp = p1.clone().addSelf(p2).multiplyScalar(0.5);
-
- var c1 = new TCo(atom1.color), c2 = new TCo(atom2.color);
- if (order == 1 || order == 3) {
- vs.push(p1); cs.push(c1); vs.push(mp); cs.push(c1);
- vs.push(p2); cs.push(c2); vs.push(mp); cs.push(c2);
- }
- if (order > 1) {
- vs.push(p1.clone().addSelf(delta)); cs.push(c1);
- vs.push(tmp = mp.clone().addSelf(delta)); cs.push(c1);
- vs.push(p2.clone().addSelf(delta)); cs.push(c2);
- vs.push(tmp); cs.push(c2);
- vs.push(p1.clone().subSelf(delta)); cs.push(c1);
- vs.push(tmp = mp.clone().subSelf(delta)); cs.push(c1);
- vs.push(p2.clone().subSelf(delta)); cs.push(c2);
- vs.push(tmp); cs.push(c2);
- }
-};
-
-GLmol.prototype.drawBondsAsLine = function(group, atomlist, lineWidth) {
- var geo = new THREE.Geometry();
- var nAtoms = atomlist.length;
-
- for (var _i = 0; _i < nAtoms; _i++) {
- var i = atomlist[_i];
- var atom1 = this.atoms[i];
- if (atom1 == undefined) continue;
- for (var _j = _i + 1; _j < _i + 30 && _j < nAtoms; _j++) {
- var j = atomlist[_j];
- var atom2 = this.atoms[j];
- if (atom2 == undefined) continue;
- var order = this.isConnected(atom1, atom2);
- if (order == 0) continue;
-
- this.drawBondsAsLineSub(geo, atom1, atom2, order);
- }
- for (var _j = 0; _j < atom1.bonds.length; _j++) {
- var j = atom1.bonds[_j];
- if (j < i + 30) continue; // be conservative!
- if (atomlist.indexOf(j) == -1) continue;
- var atom2 = this.atoms[j];
- if (atom2 == undefined) continue;
- this.drawBondsAsLineSub(geo, atom1, atom2, atom1.bondOrder[_j]);
- }
- }
- var lineMaterial = new THREE.LineBasicMaterial({linewidth: lineWidth});
- lineMaterial.vertexColors = true;
-
- var line = new THREE.Line(geo, lineMaterial);
- line.type = THREE.LinePieces;
- group.add(line);
-};
-
-GLmol.prototype.drawSmoothCurve = function(group, _points, width, colors, div) {
- if (_points.length == 0) return;
-
- div = (div == undefined) ? 5 : div;
-
- var geo = new THREE.Geometry();
- var points = this.subdivide(_points, div);
-
- for (var i = 0; i < points.length; i++) {
- geo.vertices.push(points[i]);
- geo.colors.push(new TCo(colors[(i == 0) ? 0 : Math.round((i - 1) / div)]));
- }
- var lineMaterial = new THREE.LineBasicMaterial({linewidth: width});
- lineMaterial.vertexColors = true;
- var line = new THREE.Line(geo, lineMaterial);
- line.type = THREE.LineStrip;
- group.add(line);
-};
-
-GLmol.prototype.drawAsCross = function(group, atomlist, delta) {
- var geo = new THREE.Geometry();
- var points = [[delta, 0, 0], [-delta, 0, 0], [0, delta, 0], [0, -delta, 0], [0, 0, delta], [0, 0, -delta]];
-
- for (var i = 0, lim = atomlist.length; i < lim; i++) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- var c = new TCo(atom.color);
- for (var j = 0; j < 6; j++) {
- geo.vertices.push(new TV3(atom.x + points[j][0], atom.y + points[j][1], atom.z + points[j][2]));
- geo.colors.push(c);
- }
- }
- var lineMaterial = new THREE.LineBasicMaterial({linewidth: this.lineWidth});
- lineMaterial.vertexColors = true;
- var line = new THREE.Line(geo, lineMaterial, THREE.LinePieces);
- group.add(line);
-};
-
-// FIXME: Winkled...
-GLmol.prototype.drawSmoothTube = function(group, _points, colors, radii) {
- if (_points.length < 2) return;
-
- var circleDiv = this.tubeDIV, axisDiv = this.axisDIV;
- var geo = new THREE.Geometry();
- var points = this.subdivide(_points, axisDiv);
- var prevAxis1 = new TV3(), prevAxis2;
-
- for (var i = 0, lim = points.length; i < lim; i++) {
- var r, idx = (i - 1) / axisDiv;
- if (i == 0) r = radii[0];
- else {
- if (idx % 1 == 0) r = radii[idx];
- else {
- var floored = Math.floor(idx);
- var tmp = idx - floored;
- r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
- }
- }
- var delta, axis1, axis2;
-
- if (i < lim - 1) {
- delta = new TV3().sub(points[i], points[i + 1]);
- axis1 = new TV3(0, - delta.z, delta.y).normalize().multiplyScalar(r);
- axis2 = new TV3().cross(delta, axis1).normalize().multiplyScalar(r);
-// var dir = 1, offset = 0;
- if (prevAxis1.dot(axis1) < 0) {
- axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
- }
- prevAxis1 = axis1; prevAxis2 = axis2;
- } else {
- axis1 = prevAxis1; axis2 = prevAxis2;
- }
-
- for (var j = 0; j < circleDiv; j++) {
- var angle = 2 * Math.PI / circleDiv * j; //* dir + offset;
- var c = Math.cos(angle), s = Math.sin(angle);
- geo.vertices.push(new TV3(
- points[i].x + c * axis1.x + s * axis2.x,
- points[i].y + c * axis1.y + s * axis2.y,
- points[i].z + c * axis1.z + s * axis2.z));
- }
- }
-
- var offset = 0;
- for (var i = 0, lim = points.length - 1; i < lim; i++) {
- var c = new TCo(colors[Math.round((i - 1)/ axisDiv)]);
-
- var reg = 0;
- var r1 = new TV3().sub(geo.vertices[offset], geo.vertices[offset + circleDiv]).lengthSq();
- var r2 = new TV3().sub(geo.vertices[offset], geo.vertices[offset + circleDiv + 1]).lengthSq();
- if (r1 > r2) {r1 = r2; reg = 1;};
- for (var j = 0; j < circleDiv; j++) {
- geo.faces.push(new TF3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv));
- geo.faces.push(new TF3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv));
- geo.faces[geo.faces.length -2].color = c;
- geo.faces[geo.faces.length -1].color = c;
- }
- offset += circleDiv;
- }
- geo.computeFaceNormals();
- geo.computeVertexNormals(false);
- var mat = new THREE.MeshLambertMaterial();
- mat.vertexColors = THREE.FaceColors;
- var mesh = new THREE.Mesh(geo, mat);
- mesh.doubleSided = true;
- group.add(mesh);
-};
-
-
-GLmol.prototype.drawMainchainCurve = function(group, atomlist, curveWidth, atomName, div) {
- var points = [], colors = [];
- var currentChain, currentResi;
- if (div == undefined) div = 5;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- if ((atom.atom == atomName) && !atom.hetflag) {
- if (currentChain != atom.chain || currentResi + 1 != atom.resi) {
- this.drawSmoothCurve(group, points, curveWidth, colors, div);
- points = [];
- colors = [];
- }
- points.push(new TV3(atom.x, atom.y, atom.z));
- colors.push(atom.color);
- currentChain = atom.chain;
- currentResi = atom.resi;
- }
- }
- this.drawSmoothCurve(group, points, curveWidth, colors, div);
-};
-
-GLmol.prototype.drawMainchainTube = function(group, atomlist, atomName, radius) {
- var points = [], colors = [], radii = [];
- var currentChain, currentResi;
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- if ((atom.atom == atomName) && !atom.hetflag) {
- if (currentChain != atom.chain || currentResi + 1 != atom.resi) {
- this.drawSmoothTube(group, points, colors, radii);
- points = []; colors = []; radii = [];
- }
- points.push(new TV3(atom.x, atom.y, atom.z));
- if (radius == undefined) {
- radii.push((atom.b > 0) ? atom.b / 100 : 0.3);
- } else {
- radii.push(radius);
- }
- colors.push(atom.color);
- currentChain = atom.chain;
- currentResi = atom.resi;
- }
- }
- this.drawSmoothTube(group, points, colors, radii);
-};
-
-GLmol.prototype.drawStrip = function(group, p1, p2, colors, div, thickness) {
- if ((p1.length) < 2) return;
- div = div || this.axisDIV;
- p1 = this.subdivide(p1, div);
- p2 = this.subdivide(p2, div);
- if (!thickness) return this.drawThinStrip(group, p1, p2, colors, div);
-
- var geo = new THREE.Geometry();
- var vs = geo.vertices, fs = geo.faces;
- var axis, p1v, p2v, a1v, a2v;
- for (var i = 0, lim = p1.length; i < lim; i++) {
- vs.push(p1v = p1[i]); // 0
- vs.push(p1v); // 1
- vs.push(p2v = p2[i]); // 2
- vs.push(p2v); // 3
- if (i < lim - 1) {
- var toNext = p1[i + 1].clone().subSelf(p1[i]);
- var toSide = p2[i].clone().subSelf(p1[i]);
- axis = toSide.crossSelf(toNext).normalize().multiplyScalar(thickness);
- }
- vs.push(a1v = p1[i].clone().addSelf(axis)); // 4
- vs.push(a1v); // 5
- vs.push(a2v = p2[i].clone().addSelf(axis)); // 6
- vs.push(a2v); // 7
- }
- var faces = [[0, 2, -6, -8], [-4, -2, 6, 4], [7, 3, -5, -1], [-3, -7, 1, 5]];
- for (var i = 1, lim = p1.length; i < lim; i++) {
- var offset = 8 * i, color = new TCo(colors[Math.round((i - 1)/ div)]);
- for (var j = 0; j < 4; j++) {
- var f = new THREE.Face4(offset + faces[j][0], offset + faces[j][1], offset + faces[j][2], offset + faces[j][3], undefined, color);
- fs.push(f);
- }
- }
- var vsize = vs.length - 8; // Cap
- for (var i = 0; i < 4; i++) {vs.push(vs[i * 2]); vs.push(vs[vsize + i * 2])};
- vsize += 8;
- fs.push(new THREE.Face4(vsize, vsize + 2, vsize + 6, vsize + 4, undefined, fs[0].color));
- fs.push(new THREE.Face4(vsize + 1, vsize + 5, vsize + 7, vsize + 3, undefined, fs[fs.length - 3].color));
- geo.computeFaceNormals();
- geo.computeVertexNormals(false);
- var material = new THREE.MeshLambertMaterial();
- material.vertexColors = THREE.FaceColors;
- var mesh = new THREE.Mesh(geo, material);
- mesh.doubleSided = true;
- group.add(mesh);
-};
-
-
-GLmol.prototype.drawThinStrip = function(group, p1, p2, colors, div) {
- var geo = new THREE.Geometry();
- for (var i = 0, lim = p1.length; i < lim; i++) {
- geo.vertices.push(p1[i]); // 2i
- geo.vertices.push(p2[i]); // 2i + 1
- }
- for (var i = 1, lim = p1.length; i < lim; i++) {
- var f = new THREE.Face4(2 * i, 2 * i + 1, 2 * i - 1, 2 * i - 2);
- f.color = new TCo(colors[Math.round((i - 1)/ div)]);
- geo.faces.push(f);
- }
- geo.computeFaceNormals();
- geo.computeVertexNormals(false);
- var material = new THREE.MeshLambertMaterial();
- material.vertexColors = THREE.FaceColors;
- var mesh = new THREE.Mesh(geo, material);
- mesh.doubleSided = true;
- group.add(mesh);
-};
-
-
-GLmol.prototype.IcosahedronGeometry = function() {
- if (!this.icosahedron) this.icosahedron = new THREE.IcosahedronGeometry(1);
- return this.icosahedron;
-};
-
-GLmol.prototype.drawCylinder = function(group, from, to, radius, color, cap) {
- if (!from || !to) return;
-
- var midpoint = new TV3().add(from, to).multiplyScalar(0.5);
- var color = new TCo(color);
-
- if (!this.cylinderGeometry) {
- this.cylinderGeometry = new THREE.CylinderGeometry(1, 1, 1, this.cylinderQuality, 1, !cap);
- this.cylinderGeometry.faceUvs = [];
- this.faceVertexUvs = [];
- }
- var cylinderMaterial = new THREE.MeshLambertMaterial({color: color.getHex()});
- var cylinder = new THREE.Mesh(this.cylinderGeometry, cylinderMaterial);
- cylinder.position = midpoint;
- cylinder.lookAt(from);
- cylinder.updateMatrix();
- cylinder.matrixAutoUpdate = false;
- var m = new THREE.Matrix4().makeScale(radius, radius, from.distanceTo(to));
- m.rotateX(Math.PI / 2);
- cylinder.matrix.multiplySelf(m);
- group.add(cylinder);
-};
-
-// FIXME: transition!
-GLmol.prototype.drawHelixAsCylinder = function(group, atomlist, radius) {
- var start = null;
- var currentChain, currentResi;
-
- var others = [], beta = [];
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined || atom.hetflag) continue;
- if ((atom.ss != 'h' && atom.ss != 's') || atom.ssend || atom.ssbegin) others.push(atom.serial);
- if (atom.ss == 's') beta.push(atom.serial);
- if (atom.atom != 'CA') continue;
-
- if (atom.ss == 'h' && atom.ssend) {
- if (start != null) this.drawCylinder(group, new TV3(start.x, start.y, start.z), new TV3(atom.x, atom.y, atom.z), radius, atom.color, true);
- start = null;
- }
- currentChain = atom.chain;
- currentResi = atom.resi;
- if (start == null && atom.ss == 'h' && atom.ssbegin) start = atom;
- }
- if (start != null) this.drawCylinder(group, new TV3(start.x, start.y, start.z), new TV3(atom.x, atom.y, atom.z), radius, atom.color);
- this.drawMainchainTube(group, others, "CA", 0.3);
- this.drawStrand(group, beta, undefined, undefined, true, 0, this.helixSheetWidth, false, this.thickness * 2);
-};
-
-GLmol.prototype.drawCartoon = function(group, atomlist, doNotSmoothen, thickness) {
- this.drawStrand(group, atomlist, 2, undefined, true, undefined, undefined, doNotSmoothen, thickness);
-};
-
-GLmol.prototype.drawStrand = function(group, atomlist, num, div, fill, coilWidth, helixSheetWidth, doNotSmoothen, thickness) {
- num = num || this.strandDIV;
- div = div || this.axisDIV;
- coilWidth = coilWidth || this.coilWidth;
- doNotSmoothen == (doNotSmoothen == undefined) ? false : doNotSmoothen;
- helixSheetWidth = helixSheetWidth || this.helixSheetWidth;
- var points = []; for (var k = 0; k < num; k++) points[k] = [];
- var colors = [];
- var currentChain, currentResi, currentCA;
- var prevCO = null, ss=null, ssborder = false;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- if ((atom.atom == 'O' || atom.atom == 'CA') && !atom.hetflag) {
- if (atom.atom == 'CA') {
- if (currentChain != atom.chain || currentResi + 1 != atom.resi) {
- for (var j = 0; !thickness && j < num; j++)
- this.drawSmoothCurve(group, points[j], 1 ,colors, div);
- if (fill) this.drawStrip(group, points[0], points[num - 1], colors, div, thickness);
- var points = []; for (var k = 0; k < num; k++) points[k] = [];
- colors = [];
- prevCO = null; ss = null; ssborder = false;
- }
- currentCA = new TV3(atom.x, atom.y, atom.z);
- currentChain = atom.chain;
- currentResi = atom.resi;
- ss = atom.ss; ssborder = atom.ssstart || atom.ssend;
- colors.push(atom.color);
- } else { // O
- var O = new TV3(atom.x, atom.y, atom.z);
- O.subSelf(currentCA);
- O.normalize(); // can be omitted for performance
- O.multiplyScalar((ss == 'c') ? coilWidth : helixSheetWidth);
- if (prevCO != undefined && O.dot(prevCO) < 0) O.negate();
- prevCO = O;
- for (var j = 0; j < num; j++) {
- var delta = -1 + 2 / (num - 1) * j;
- var v = new TV3(currentCA.x + prevCO.x * delta,
- currentCA.y + prevCO.y * delta, currentCA.z + prevCO.z * delta);
- if (!doNotSmoothen && ss == 's') v.smoothen = true;
- points[j].push(v);
- }
- }
- }
- }
- for (var j = 0; !thickness && j < num; j++)
- this.drawSmoothCurve(group, points[j], 1 ,colors, div);
- if (fill) this.drawStrip(group, points[0], points[num - 1], colors, div, thickness);
-};
-
-GLmol.prototype.drawNucleicAcidLadderSub = function(geo, lineGeo, atoms, color) {
-// color.r *= 0.9; color.g *= 0.9; color.b *= 0.9;
- if (atoms[0] != undefined && atoms[1] != undefined && atoms[2] != undefined &&
- atoms[3] != undefined && atoms[4] != undefined && atoms[5] != undefined) {
- var baseFaceId = geo.vertices.length;
- for (var i = 0; i <= 5; i++) geo.vertices.push(atoms[i]);
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 1, baseFaceId + 2));
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 2, baseFaceId + 3));
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 3, baseFaceId + 4));
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 4, baseFaceId + 5));
- for (var j = geo.faces.length - 4, lim = geo.faces.length; j < lim; j++) geo.faces[j].color = color;
- }
- if (atoms[4] != undefined && atoms[3] != undefined && atoms[6] != undefined &&
- atoms[7] != undefined && atoms[8] != undefined) {
- var baseFaceId = geo.vertices.length;
- geo.vertices.push(atoms[4]);
- geo.vertices.push(atoms[3]);
- geo.vertices.push(atoms[6]);
- geo.vertices.push(atoms[7]);
- geo.vertices.push(atoms[8]);
- for (var i = 0; i <= 4; i++) geo.colors.push(color);
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 1, baseFaceId + 2));
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 2, baseFaceId + 3));
- geo.faces.push(new TF3(baseFaceId, baseFaceId + 3, baseFaceId + 4));
- for (var j = geo.faces.length - 3, lim = geo.faces.length; j < lim; j++) geo.faces[j].color = color;
- }
-};
-
-GLmol.prototype.drawNucleicAcidLadder = function(group, atomlist) {
- var geo = new THREE.Geometry();
- var lineGeo = new THREE.Geometry();
- var baseAtoms = ["N1", "C2", "N3", "C4", "C5", "C6", "N9", "C8", "N7"];
- var currentChain, currentResi, currentComponent = new Array(baseAtoms.length);
- var color = new TCo(0xcc0000);
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined || atom.hetflag) continue;
-
- if (atom.resi != currentResi || atom.chain != currentChain) {
- this.drawNucleicAcidLadderSub(geo, lineGeo, currentComponent, color);
- currentComponent = new Array(baseAtoms.length);
- }
- var pos = baseAtoms.indexOf(atom.atom);
- if (pos != -1) currentComponent[pos] = new TV3(atom.x, atom.y, atom.z);
- if (atom.atom == 'O3\'') color = new TCo(atom.color);
- currentResi = atom.resi; currentChain = atom.chain;
- }
- this.drawNucleicAcidLadderSub(geo, lineGeo, currentComponent, color);
- geo.computeFaceNormals();
- var mat = new THREE.MeshLambertMaterial();
- mat.vertexColors = THREE.VertexColors;
- var mesh = new THREE.Mesh(geo, mat);
- mesh.doubleSided = true;
- group.add(mesh);
-};
-
-GLmol.prototype.drawNucleicAcidStick = function(group, atomlist) {
- var currentChain, currentResi, start = null, end = null;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined || atom.hetflag) continue;
-
- if (atom.resi != currentResi || atom.chain != currentChain) {
- if (start != null && end != null)
- this.drawCylinder(group, new TV3(start.x, start.y, start.z),
- new TV3(end.x, end.y, end.z), 0.3, start.color, true);
- start = null; end = null;
- }
- if (atom.atom == 'O3\'') start = atom;
- if (atom.resn == ' A' || atom.resn == ' G' || atom.resn == ' DA' || atom.resn == ' DG') {
- if (atom.atom == 'N1') end = atom; // N1(AG), N3(CTU)
- } else if (atom.atom == 'N3') {
- end = atom;
- }
- currentResi = atom.resi; currentChain = atom.chain;
- }
- if (start != null && end != null)
- this.drawCylinder(group, new TV3(start.x, start.y, start.z),
- new TV3(end.x, end.y, end.z), 0.3, start.color, true);
-};
-
-GLmol.prototype.drawNucleicAcidLine = function(group, atomlist) {
- var currentChain, currentResi, start = null, end = null;
- var geo = new THREE.Geometry();
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined || atom.hetflag) continue;
-
- if (atom.resi != currentResi || atom.chain != currentChain) {
- if (start != null && end != null) {
- geo.vertices.push(new TV3(start.x, start.y, start.z));
- geo.colors.push(new TCo(start.color));
- geo.vertices.push(new TV3(end.x, end.y, end.z));
- geo.colors.push(new TCo(start.color));
- }
- start = null; end = null;
- }
- if (atom.atom == 'O3\'') start = atom;
- if (atom.resn == ' A' || atom.resn == ' G' || atom.resn == ' DA' || atom.resn == ' DG') {
- if (atom.atom == 'N1') end = atom; // N1(AG), N3(CTU)
- } else if (atom.atom == 'N3') {
- end = atom;
- }
- currentResi = atom.resi; currentChain = atom.chain;
- }
- if (start != null && end != null) {
- geo.vertices.push(new TV3(start.x, start.y, start.z));
- geo.colors.push(new TCo(start.color));
- geo.vertices.push(new TV3(end.x, end.y, end.z));
- geo.colors.push(new TCo(start.color));
- }
- var mat = new THREE.LineBasicMaterial({linewidth: 1, linejoin: false});
- mat.linewidth = 1.5; mat.vertexColors = true;
- var line = new THREE.Line(geo, mat, THREE.LinePieces);
- group.add(line);
-};
-
-GLmol.prototype.drawCartoonNucleicAcid = function(group, atomlist, div, thickness) {
- this.drawStrandNucleicAcid(group, atomlist, 2, div, true, undefined, thickness);
-};
-
-GLmol.prototype.drawStrandNucleicAcid = function(group, atomlist, num, div, fill, nucleicAcidWidth, thickness) {
- nucleicAcidWidth = nucleicAcidWidth || this.nucleicAcidWidth;
- div = div || this.axisDIV;
- num = num || this.nucleicAcidStrandDIV;
- var points = []; for (var k = 0; k < num; k++) points[k] = [];
- var colors = [];
- var currentChain, currentResi, currentO3;
- var prevOO = null;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]];
- if (atom == undefined) continue;
-
- if ((atom.atom == 'O3\'' || atom.atom == 'OP2') && !atom.hetflag) {
- if (atom.atom == 'O3\'') { // to connect 3' end. FIXME: better way to do?
- if (currentChain != atom.chain || currentResi + 1 != atom.resi) {
- if (currentO3) {
- for (var j = 0; j < num; j++) {
- var delta = -1 + 2 / (num - 1) * j;
- points[j].push(new TV3(currentO3.x + prevOO.x * delta,
- currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta));
- }
- }
- if (fill) this.drawStrip(group, points[0], points[1], colors, div, thickness);
- for (var j = 0; !thickness && j < num; j++)
- this.drawSmoothCurve(group, points[j], 1 ,colors, div);
- var points = []; for (var k = 0; k < num; k++) points[k] = [];
- colors = [];
- prevOO = null;
- }
- currentO3 = new TV3(atom.x, atom.y, atom.z);
- currentChain = atom.chain;
- currentResi = atom.resi;
- colors.push(atom.color);
- } else { // OP2
- if (!currentO3) {prevOO = null; continue;} // for 5' phosphate (e.g. 3QX3)
- var O = new TV3(atom.x, atom.y, atom.z);
- O.subSelf(currentO3);
- O.normalize().multiplyScalar(nucleicAcidWidth); // TODO: refactor
- if (prevOO != undefined && O.dot(prevOO) < 0) {
- O.negate();
- }
- prevOO = O;
- for (var j = 0; j < num; j++) {
- var delta = -1 + 2 / (num - 1) * j;
- points[j].push(new TV3(currentO3.x + prevOO.x * delta,
- currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta));
- }
- currentO3 = null;
- }
- }
- }
- if (currentO3) {
- for (var j = 0; j < num; j++) {
- var delta = -1 + 2 / (num - 1) * j;
- points[j].push(new TV3(currentO3.x + prevOO.x * delta,
- currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta));
- }
- }
- if (fill) this.drawStrip(group, points[0], points[1], colors, div, thickness);
- for (var j = 0; !thickness && j < num; j++)
- this.drawSmoothCurve(group, points[j], 1 ,colors, div);
-};
-
-GLmol.prototype.drawDottedLines = function(group, points, color) {
- var geo = new THREE.Geometry();
- var step = 0.3;
-
- for (var i = 0, lim = Math.floor(points.length / 2); i < lim; i++) {
- var p1 = points[2 * i], p2 = points[2 * i + 1];
- var delta = p2.clone().subSelf(p1);
- var dist = delta.length();
- delta.normalize().multiplyScalar(step);
- var jlim = Math.floor(dist / step);
- for (var j = 0; j < jlim; j++) {
- var p = new TV3(p1.x + delta.x * j, p1.y + delta.y * j, p1.z + delta.z * j);
- geo.vertices.push(p);
- }
- if (jlim % 2 == 1) geo.vertices.push(p2);
- }
-
- var mat = new THREE.LineBasicMaterial({'color': color.getHex()});
- mat.linewidth = 2;
- var line = new THREE.Line(geo, mat, THREE.LinePieces);
- group.add(line);
-};
-
-GLmol.prototype.getAllAtoms = function() {
- var ret = [];
- for (var i in this.atoms) {
- ret.push(this.atoms[i].serial);
- }
- return ret;
-};
-
-// Probably I can refactor using higher-order functions.
-GLmol.prototype.getHetatms = function(atomlist) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag) ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.removeSolvents = function(atomlist) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.resn != 'HOH') ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.getProteins = function(atomlist) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (!atom.hetflag) ret.push(atom.serial);
- }
- return ret;
-};
-
-// TODO: Test
-GLmol.prototype.excludeAtoms = function(atomlist, deleteList) {
- var ret = [];
- var blackList = new Object();
- for (var _i in deleteList) blackList[deleteList[_i]] = true;
-
- for (var _i in atomlist) {
- var i = atomlist[_i];
-
- if (!blackList[i]) ret.push(i);
- }
- return ret;
-};
-
-GLmol.prototype.getSidechains = function(atomlist) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag) continue;
- if (atom.atom == 'C' || atom.atom == 'O' || (atom.atom == 'N' && atom.resn != "PRO")) continue;
- ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.getAtomsWithin = function(atomlist, extent) {
- var ret = [];
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.x < extent[0][0] || atom.x > extent[1][0]) continue;
- if (atom.y < extent[0][1] || atom.y > extent[1][1]) continue;
- if (atom.z < extent[0][2] || atom.z > extent[1][2]) continue;
- ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.getExtent = function(atomlist) {
- var xmin = ymin = zmin = 9999;
- var xmax = ymax = zmax = -9999;
- var xsum = ysum = zsum = cnt = 0;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
- cnt++;
- xsum += atom.x; ysum += atom.y; zsum += atom.z;
-
- xmin = (xmin < atom.x) ? xmin : atom.x;
- ymin = (ymin < atom.y) ? ymin : atom.y;
- zmin = (zmin < atom.z) ? zmin : atom.z;
- xmax = (xmax > atom.x) ? xmax : atom.x;
- ymax = (ymax > atom.y) ? ymax : atom.y;
- zmax = (zmax > atom.z) ? zmax : atom.z;
- }
- return [[xmin, ymin, zmin], [xmax, ymax, zmax], [xsum / cnt, ysum / cnt, zsum / cnt]];
-};
-
-GLmol.prototype.getResiduesById = function(atomlist, resi) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (resi.indexOf(atom.resi) != -1) ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.getResidueBySS = function(atomlist, ss) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (ss.indexOf(atom.ss) != -1) ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.getChain = function(atomlist, chain) {
- var ret = [], chains = {};
- chain = chain.toString(); // concat if Array
- for (var i = 0, lim = chain.length; i < lim; i++) chains[chain.substr(i, 1)] = true;
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (chains[atom.chain]) ret.push(atom.serial);
- }
- return ret;
-};
-
-// for HETATM only
-GLmol.prototype.getNonbonded = function(atomlist, chain) {
- var ret = [];
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag && atom.bonds.length == 0) ret.push(atom.serial);
- }
- return ret;
-};
-
-GLmol.prototype.colorByAtom = function(atomlist, colors) {
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- var c = colors[atom.elem];
- if (c == undefined) c = this.ElementColors[atom.elem];
- if (c == undefined) c = this.defaultColor;
- atom.color = c;
- }
-};
-
-
-// MEMO: Color only CA. maybe I should add atom.cartoonColor.
-GLmol.prototype.colorByStructure = function(atomlist, helixColor, sheetColor, colorSidechains) {
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (!colorSidechains && (atom.atom != 'CA' || atom.hetflag)) continue;
- if (atom.ss[0] == 's') atom.color = sheetColor;
- else if (atom.ss[0] == 'h') atom.color = helixColor;
- }
-};
-
-GLmol.prototype.colorByBFactor = function(atomlist, colorSidechains) {
- var minB = 1000, maxB = -1000;
-
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag) continue;
- if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') {
- if (minB > atom.b) minB = atom.b;
- if (maxB < atom.b) maxB = atom.b;
- }
- }
-
- var mid = (maxB + minB) / 2;
-
- var range = (maxB - minB) / 2;
- if (range < 0.01 && range > -0.01) return;
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag) continue;
- if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') {
- var color = new TCo(0);
- if (atom.b < mid)
- color.setHSV(0.667, (mid - atom.b) / range, 1);
- else
- color.setHSV(0, (atom.b - mid) / range, 1);
- atom.color = color.getHex();
- }
- }
-};
-
-GLmol.prototype.colorByChain = function(atomlist, colorSidechains) {
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if (atom.hetflag) continue;
- if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') {
- var color = new TCo(0);
- color.setHSV((atom.chain.charCodeAt(0)) % 15 / 15.0, 1, 0.9);
- atom.color = color.getHex();
- }
- }
-};
-
-GLmol.prototype.colorByResidue = function(atomlist, residueColors) {
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- c = residueColors[atom.resn]
- if (c != undefined) atom.color = c;
- }
-};
-
-GLmol.prototype.colorAtoms = function(atomlist, c) {
- for (var i in atomlist) {
- var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- atom.color = c;
- }
-};
-
-GLmol.prototype.colorByPolarity = function(atomlist, polar, nonpolar) {
- var polarResidues = ['ARG', 'HIS', 'LYS', 'ASP', 'GLU', 'SER', 'THR', 'ASN', 'GLN', 'CYS'];
- var nonPolarResidues = ['GLY', 'PRO', 'ALA', 'VAL', 'LEU', 'ILE', 'MET', 'PHE', 'TYR', 'TRP'];
- var colorMap = {};
- for (var i in polarResidues) colorMap[polarResidues[i]] = polar;
- for (i in nonPolarResidues) colorMap[nonPolarResidues[i]] = nonpolar;
- this.colorByResidue(atomlist, colorMap);
-};
-
-// TODO: Add near(atomlist, neighbor, distanceCutoff)
-// TODO: Add expandToResidue(atomlist)
-
-GLmol.prototype.colorChainbow = function(atomlist, colorSidechains) {
- var cnt = 0;
- var atom, i;
- for (i in atomlist) {
- atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if ((colorSidechains || atom.atom != 'CA' || atom.atom != 'O3\'') && !atom.hetflag)
- cnt++;
- }
-
- var total = cnt;
- cnt = 0;
- for (i in atomlist) {
- atom = this.atoms[atomlist[i]]; if (atom == undefined) continue;
-
- if ((colorSidechains || atom.atom != 'CA' || atom.atom != 'O3\'') && !atom.hetflag) {
- var color = new TCo(0);
- color.setHSV(240.0 / 360 * (1 - cnt / total), 1, 0.9);
- atom.color = color.getHex();
- cnt++;
- }
- }
-};
-
-GLmol.prototype.drawSymmetryMates2 = function(group, asu, matrices) {
- if (matrices == undefined) return;
- asu.matrixAutoUpdate = false;
-
- var cnt = 1;
- this.protein.appliedMatrix = new THREE.Matrix4();
- for (var i = 0; i < matrices.length; i++) {
- var mat = matrices[i];
- if (mat == undefined || mat.isIdentity()) continue;
- console.log(mat);
- var symmetryMate = THREE.SceneUtils.cloneObject(asu);
- symmetryMate.matrix = mat;
- group.add(symmetryMate);
- for (var j = 0; j < 16; j++) this.protein.appliedMatrix.elements[j] += mat.elements[j];
- cnt++;
- }
- this.protein.appliedMatrix.multiplyScalar(1.0 / cnt);
-};
-
-
-GLmol.prototype.drawSymmetryMatesWithTranslation2 = function(group, asu, matrices) {
- if (matrices == undefined) return;
- var p = this.protein;
- asu.matrixAutoUpdate = false;
-
- for (var i = 0; i < matrices.length; i++) {
- var mat = matrices[i];
- if (mat == undefined) continue;
-
- for (var a = -1; a <=0; a++) {
- for (var b = -1; b <= 0; b++) {
- for (var c = -1; c <= 0; c++) {
- var translationMat = new THREE.Matrix4().makeTranslation(
- p.ax * a + p.bx * b + p.cx * c,
- p.ay * a + p.by * b + p.cy * c,
- p.az * a + p.bz * b + p.cz * c);
- var symop = mat.clone().multiplySelf(translationMat);
- if (symop.isIdentity()) continue;
- var symmetryMate = THREE.SceneUtils.cloneObject(asu);
- symmetryMate.matrix = symop;
- group.add(symmetryMate);
- }
- }
- }
- }
-};
-
-GLmol.prototype.defineRepresentation = function() {
- var all = this.getAllAtoms();
- var hetatm = this.removeSolvents(this.getHetatms(all));
- this.colorByAtom(all, {});
- this.colorByChain(all);
-
- this.drawAtomsAsSphere(this.modelGroup, hetatm, this.sphereRadius);
- this.drawMainchainCurve(this.modelGroup, all, this.curveWidth, 'P');
- this.drawCartoon(this.modelGroup, all, this.curveWidth);
-};
-
-GLmol.prototype.getView = function() {
- if (!this.modelGroup) return [0, 0, 0, 0, 0, 0, 0, 1];
- var pos = this.modelGroup.position;
- var q = this.rotationGroup.quaternion;
- return [pos.x, pos.y, pos.z, this.rotationGroup.position.z, q.x, q.y, q.z, q.w];
-};
-
-GLmol.prototype.setView = function(arg) {
- if (!this.modelGroup || !this.rotationGroup) return;
- this.modelGroup.position.x = arg[0];
- this.modelGroup.position.y = arg[1];
- this.modelGroup.position.z = arg[2];
- this.rotationGroup.position.z = arg[3];
- this.rotationGroup.quaternion.x = arg[4];
- this.rotationGroup.quaternion.y = arg[5];
- this.rotationGroup.quaternion.z = arg[6];
- this.rotationGroup.quaternion.w = arg[7];
- this.show();
-};
-
-GLmol.prototype.setBackground = function(hex, a) {
- a = a | 1.0;
- this.bgColor = hex;
- this.renderer.setClearColorHex(hex, a);
- this.scene.fog.color = new TCo(hex);
-};
-
-GLmol.prototype.initializeScene = function() {
- // CHECK: Should I explicitly call scene.deallocateObject?
- this.scene = new THREE.Scene();
- this.scene.fog = new THREE.Fog(this.bgColor, 100, 200);
-
- this.modelGroup = new THREE.Object3D();
- this.rotationGroup = new THREE.Object3D();
- this.rotationGroup.useQuaternion = true;
- this.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0);
- this.rotationGroup.add(this.modelGroup);
-
- this.scene.add(this.rotationGroup);
- this.setupLights(this.scene);
-};
-
-GLmol.prototype.zoomInto = function(atomlist, keepSlab) {
- // TODO: expand if symmetry mates are present
- var tmp = this.getExtent(atomlist); // atomlist is the problem
- var center = new TV3(tmp[2][0], tmp[2][1], tmp[2][2]);
- center = new TV3((tmp[0][0] + tmp[1][0]) / 2, (tmp[0][1] + tmp[1][1]) / 2, (tmp[0][2] + tmp[1][2]) / 2);
- console.log(center.x, center.y, center.z);
- console.log(this.protein.appliedMatrix);
- if (this.protein.appliedMatrix) {center = this.protein.appliedMatrix.multiplyVector3(center);}
- console.log(center.x, center.y, center.z);
- this.modelGroup.position = center.multiplyScalar(-1);
- var x = tmp[1][0] - tmp[0][0], y = tmp[1][1] - tmp[0][1], z = tmp[1][2] - tmp[0][2];
-
- var maxD = Math.sqrt(x * x + y * y + z * z);
- if (maxD < 25) maxD = 25;
-
- if (!keepSlab) {
- this.slabNear = -maxD / 1.9;
- this.slabFar = maxD / 3;
- }
-
- this.rotationGroup.position.z = maxD * 0.35 / Math.tan(Math.PI / 180.0 * this.camera.fov / 2) - 150;
- this.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0);
-};
-
-GLmol.prototype.rebuildScene = function() {
- time = new Date();
-
- var view = this.getView();
- this.initializeScene();
- this.defineRepresentation();
- this.setView(view);
-
- console.log("builded scene in " + (+new Date() - time) + "ms");
-};
-
-GLmol.prototype.loadMolecule = function(repressZoom) {
- this.loadMoleculeStr(repressZoom, $('#' + this.id + '_src').val());
-};
-
-GLmol.prototype.loadMoleculeStr = function(repressZoom, source) {
- var time = new Date();
-
- this.protein = {sheet: [], helix: [], biomtChains: '', biomtMatrices: [], symMat: [], pdbID: '', title: ''};
- this.atoms = [];
-
- this.parsePDB2(source);
- this.parseSDF(source);
- this.parseXYZ(source);
- console.log("parsed in " + (+new Date() - time) + "ms");
-
- var title = $('#' + this.id + '_pdbTitle');
- var titleStr = '';
- if (this.protein.pdbID != '') titleStr += '' + this.protein.pdbID + '';
- if (this.protein.title != '') titleStr += '
' + this.protein.title;
- title.html(titleStr);
-
- this.rebuildScene(true);
- if (repressZoom == undefined || !repressZoom) this.zoomInto(this.getAllAtoms());
-
- this.show();
- };
-
-GLmol.prototype.setSlabAndFog = function() {
- var center = this.rotationGroup.position.z - this.camera.position.z;
- if (center < 1) center = 1;
- this.camera.near = center + this.slabNear;
- if (this.camera.near < 1) this.camera.near = 1;
- this.camera.far = center + this.slabFar;
- if (this.camera.near + 1 > this.camera.far) this.camera.far = this.camera.near + 1;
- if (this.camera instanceof THREE.PerspectiveCamera) {
- this.camera.fov = this.fov;
- } else {
- this.camera.right = center * Math.tan(Math.PI / 180 * this.fov);
- this.camera.left = - this.camera.right;
- this.camera.top = this.camera.right / this.ASPECT;
- this.camera.bottom = - this.camera.top;
- }
- this.camera.updateProjectionMatrix();
- this.scene.fog.near = this.camera.near + this.fogStart * (this.camera.far - this.camera.near);
-// if (this.scene.fog.near > center) this.scene.fog.near = center;
- this.scene.fog.far = this.camera.far;
-};
-
-GLmol.prototype.enableMouse = function() {
- var me = this, glDOM = $(this.renderer.domElement);
-
- // TODO: Better touch panel support.
- // Contribution is needed as I don't own any iOS or Android device with WebGL support.
- glDOM.bind('mousedown touchstart', function(ev) {
- ev.preventDefault();
- if (!me.scene) return;
- var x = ev.pageX, y = ev.pageY;
- if (ev.originalEvent.targetTouches && ev.originalEvent.targetTouches[0]) {
- x = ev.originalEvent.targetTouches[0].pageX;
- y = ev.originalEvent.targetTouches[0].pageY;
- }
- if (x == undefined) return;
- me.isDragging = true;
- me.mouseButton = ev.which;
- me.mouseStartX = x;
- me.mouseStartY = y;
- me.cq = me.rotationGroup.quaternion;
- me.cz = me.rotationGroup.position.z;
- me.currentModelPos = me.modelGroup.position.clone();
- me.cslabNear = me.slabNear;
- me.cslabFar = me.slabFar;
- });
-
- glDOM.bind('DOMMouseScroll mousewheel', function(ev) { // Zoom
- ev.preventDefault();
- if (!me.scene) return;
- var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85;
- if (ev.originalEvent.detail) { // Webkit
- me.rotationGroup.position.z += scaleFactor * ev.originalEvent.detail / 10;
- } else if (ev.originalEvent.wheelDelta) { // Firefox
- me.rotationGroup.position.z -= scaleFactor * ev.originalEvent.wheelDelta / 400;
- }
- console.log(ev.originalEvent.wheelDelta, ev.originalEvent.detail, me.rotationGroup.position.z);
- me.show();
- });
- glDOM.bind("contextmenu", function(ev) {ev.preventDefault();});
- $('body').bind('mouseup touchend', function(ev) {
- me.isDragging = false;
- if (me.translate_callback) me.translate_callback()
- });
-
- glDOM.bind('mousemove touchmove', function(ev) { // touchmove
- ev.preventDefault();
- if (!me.scene) return;
- if (!me.isDragging) return;
- var mode = 0;
- var modeRadio = $('input[name=' + me.id + '_mouseMode]:checked');
- if (modeRadio.length > 0) mode = parseInt(modeRadio.val());
-
- var x = ev.pageX, y = ev.pageY;
- if (ev.originalEvent.targetTouches && ev.originalEvent.targetTouches[0]) {
- x = ev.originalEvent.targetTouches[0].pageX;
- y = ev.originalEvent.targetTouches[0].pageY;
- }
- if (x == undefined) return;
- var dx = (x - me.mouseStartX) / me.WIDTH;
- var dy = (y - me.mouseStartY) / me.HEIGHT;
- var r = Math.sqrt(dx * dx + dy * dy);
- if (mode == 3 || (me.mouseButton == 3 && ev.ctrlKey)) { // Slab
- me.slabNear = me.cslabNear + dx * 100;
- me.slabFar = me.cslabFar + dy * 100;
- } else if (mode == 2 || me.mouseButton == 3 || ev.shiftKey) { // Zoom
- var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85;
- if (scaleFactor < 80) scaleFactor = 80;
- me.rotationGroup.position.z = me.cz - dy * scaleFactor;
- } else if (mode == 1 || me.mouseButton == 2 || ev.ctrlKey) { // Translate
- var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85;
- if (scaleFactor < 20) scaleFactor = 20;
- var translationByScreen = new TV3(- dx * scaleFactor, - dy * scaleFactor, 0);
- var q = me.rotationGroup.quaternion;
- var qinv = new THREE.Quaternion(q.x, q.y, q.z, q.w).inverse().normalize();
- var translation = qinv.multiplyVector3(translationByScreen);
- me.modelGroup.position.x = me.currentModelPos.x + translation.x;
- me.modelGroup.position.y = me.currentModelPos.y + translation.y;
- me.modelGroup.position.z = me.currentModelPos.z + translation.z;
- } else if ((mode == 0 || me.mouseButton == 1) && r != 0) { // Rotate
- var rs = Math.sin(r * Math.PI) / r;
- me.dq.x = Math.cos(r * Math.PI);
- me.dq.y = 0;
- me.dq.z = rs * dx;
- me.dq.w = rs * dy;
- me.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0);
- me.rotationGroup.quaternion.multiplySelf(me.dq);
- me.rotationGroup.quaternion.multiplySelf(me.cq);
- }
- me.show();
- });
-};
-
-
-GLmol.prototype.show = function() {
- if (!this.scene) return;
-
- var time = new Date();
- this.setSlabAndFog();
- this.renderer.render(this.scene, this.camera);
-
- console.log("rendered in " + (+new Date() - time) + "ms");
-};
-
-// For scripting
-GLmol.prototype.doFunc = function(func) {
- func(this);
-};
-
-return GLmol;
-}());
diff --git a/client/src/js/vendor/MarchingSquares.js b/client/src/js/vendor/MarchingSquares.js
deleted file mode 100644
index 786562540..000000000
--- a/client/src/js/vendor/MarchingSquares.js
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Initially based on Three.js's implementation of Marching Cubes by
- * alteredq http://alteredqualia.com/
- * http://github.com/mrdoob/three.js/blob/master/examples/js/MarchingCubes.js
- *
- * , which is port of greggman's ThreeD version of marching cubes to Three.js
- * http://webglsamples.googlecode.com/hg/blob/blob.html
- *
- * Then @biochem_fan modified it into Marching Squares as implemented in
- * Cuemol http://www.cuemol.org/ja/.
- */
-
-THREE.MarchingCubes = function (map, nc, nr, ns, ncstart, nrstart, nsstart) {
- this.init = function() {
- this.geo = new THREE.Geometry();
- this.vertices = this.geo.vertices;
- this.ncstart = ncstart, this.nrstart = nrstart, this.nsstart = nsstart;
-
- this.size = nc;
- this.size2 = this.size * nr;
- this.size3 = this.size2 * ns;
-
- this.yd = this.size;
- this.zd = this.size2;
-
- this.vlist = new Float32Array( 12 * 3 );
- this.field = map;
-
- this.count = 0;
- };
-
- this.VIntX = function(pout, offset, isol, x, y, z, valp1, valp2 ) {
- pout[offset] = x + (isol - valp1) / (valp2 - valp1);
- pout[offset + 1] = y;
- pout[offset + 2] = z;
- };
-
- this.VIntY = function(pout, offset, isol, x, y, z, valp1, valp2) {
- pout[offset] = x;
- pout[offset + 1] = y + (isol - valp1) / (valp2 - valp1);
- pout[offset + 2] = z;
- };
-
- this.VIntZ = function(pout, offset, isol, x, y, z, valp1, valp2) {
- pout[offset] = x;
- pout[offset + 1] = y;
- pout[offset + 2] = z + (isol - valp1) / (valp2 - valp1);
- };
-
- this.polygonizeYZ = function(fx, fy, fz, q, isol) {
- var q1 = q + this.zd, // TODO: fix variable names!
- qy = q + this.yd,
- q1y = q1 + this.yd;
-
- var cubeindex = 0,
- field0 = this.field[ q ],
- field1 = this.field[ q1 ],
- field2 = this.field[ qy ],
- field3 = this.field[ q1y ];
-
- var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1,
- s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1,
- s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1,
- s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1;
- var fz2 = fz + 1, fy2 = fy + 1;
-
- if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return;
- if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) {
- this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- this.VIntY(this.vlist, 6, isol, fx, fy, fz2, field1, field3); // s1
- this.VIntY(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11]));
- return;
- }
-
- if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) {
- this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) {
- this.VIntY(this.vlist, 0, isol, fx, fy, fz2, field1, field3); // s1
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) {
- this.VIntZ(this.vlist, 0, isol, fx, fy2, fz, field2, field3); // s2
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) {
- this.VIntY(this.vlist, 0, isol, fx, fy, fz2, field1, field3); // s1
- this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) {
- this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntY(this.vlist, 3, isol, fx, fy, fz2, field1, field3); // s1
- } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) {
- this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- }
-
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- };
-
- this.polygonizeXY = function(fx, fy, fz, q, isol) {
- var q1 = q + 1,
- qy = q + this.yd,
- q1y = q1 + this.yd;
-
- var cubeindex = 0,
- field0 = this.field[ q ], // x, y, z
- field1 = this.field[ q1 ], // x + 1, y, z
- field2 = this.field[ qy ], // x, y + 1, z
- field3 = this.field[ q1y ]; // x + 1, y + 1, z
-
- var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1,
- s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1,
- s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1,
- s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1;
- var fx2 = fx + 1, fy2 = fy + 1;
-
- if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return;
- if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- this.VIntY(this.vlist, 6, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntY(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11]));
- return;
- }
-
- if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) {
- this.VIntY(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy2, fz, field2, field3); // s2
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) {
- this.VIntY(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2
- } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntY(this.vlist, 3, isol, fx2, fy, fz, field1, field3); // s1
- } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- }
-
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- };
-
- this.polygonizeXZ = function(fx, fy, fz, q, isol) {
- var q1 = q + 1,
- qy = q + this.zd,
- q1y = q1 + this.zd;
-
- var cubeindex = 0,
- field0 = this.field[ q ],
- field1 = this.field[ q1 ],
- field2 = this.field[ qy ],
- field3 = this.field[ q1y ];
-
- var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1,
- s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1,
- s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1,
- s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1;
- var fx2 = fx + 1, fz2 = fz + 1;
-
- if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return;
- if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2
- this.VIntZ(this.vlist, 6, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntZ(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11]));
- return;
- }
-
- if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2
- } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) {
- this.VIntZ(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz2, field2, field3); // s2
- this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) {
- this.VIntZ(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1
- this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2
- } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntZ(this.vlist, 3, isol, fx2, fy, fz, field1, field3); // s1
- } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) {
- this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0
- this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3
- }
-
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2]));
- this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5]));
- };
-
- this.build = function(cc, cr, cs, radius) {
- var q, x, y, z, y_offset, z_offset;
- var xlo = cc - radius, xhi = cc + radius,
- ylo = cr - radius, yhi = cr + radius,
- zlo = cs - radius, zhi = cs + radius;
- if (xlo < 0) xlo = 0;
- if (ylo < 0) ylo = 0;
- if (zlo < 0) zlo = 0;
- if (xhi > nc - 2) xhi = nc - 2;
- if (yhi > nr - 2) yhi = nr - 2;
- if (zhi > ns - 2) zhi = ns - 2;
- console.log('Mesh Range: ', xlo, xhi, ylo, yhi, zlo, zhi);
-
- for (z = zlo; z <= zhi ; z++) {
- z_offset = this.size2 * z;
- for (y = ylo; y <= yhi; y ++) {
- y_offset = z_offset + this.size * y;
- for (x = xlo; x <= xhi; x ++) {
- q = y_offset + x;
- this.polygonizeXY((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol);
- this.polygonizeYZ((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol);
- this.polygonizeXZ((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol);
- }
- }
- }
- };
-
- this.generateGeometry = function(cc, cr, cs, radius, isol) {
- this.count = 0;
- this.isol = isol; this.cc = cc; this.cr = cr, this.cs = cs;
- var maxvert = 2500000, i = 0;
-
- this.vertices.length = maxvert;
- this.build(cc, cr, cs, radius);
- var dummy = new THREE.Vector3(0, 0, 0);
- for (i = this.count; i < maxvert; i++) this.vertices[i] = dummy;
-
- // TODO: FIXME: if this.count > maxvert, Geometry object has to be rebuilded,
- // since Three.js doesn't support changes of vertex counts.
- this.geo.verticesNeedUpdate = true;
-
- return this.geo;
- };
-
- this.init();
-};
-
diff --git a/client/src/js/vendor/Three49custom.js b/client/src/js/vendor/Three49custom.js
deleted file mode 100644
index 01abdece7..000000000
--- a/client/src/js/vendor/Three49custom.js
+++ /dev/null
@@ -1,382 +0,0 @@
-// Three.js - http://github.com/mrdoob/three.js
-'use strict';var THREE=THREE||{REVISION:"49"};self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array);
-(function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},lerpSelf:function(a,b){this.r=this.r+(a.r-this.r)*b;this.g=this.g+(a.g-this.g)*b;this.b=this.b+(a.b-this.b)*b;return this},getHex:function(){return Math.floor(this.r*255)<<16^Math.floor(this.g*255)<<8^Math.floor(this.b*255)},getContextStyle:function(){return"rgb("+Math.floor(this.r*255)+","+Math.floor(this.g*255)+","+Math.floor(this.b*255)+")"},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}};
-THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0};
-THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;return this},divideScalar:function(a){if(a){this.x=
-this.x/a;this.y=this.y/a}else this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)},
-lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},isZero:function(){return this.lengthSq()<1.0E-4},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0};
-THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;this.z=this.z+a.z;return this},addScalar:function(a){this.x=this.x+a;this.y=this.y+
-a;this.z=this.z+a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x=this.x*a.x;this.y=this.y*a.y;this.z=this.z*a.z;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;return this},divideSelf:function(a){this.x=this.x/a.x;this.y=
-this.y/a.y;this.z=this.z/a.z;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a}else this.z=this.y=this.x=0;return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},
-setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;return this},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){var b=this.x,c=this.y,d=this.z;this.x=c*a.z-d*a.y;this.y=d*a.x-b*a.z;this.z=b*a.y-c*a.x;return this},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){return(new THREE.Vector3).sub(this,
-a).lengthSq()},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},getRotationFromMatrix:function(a,b){var c=b?b.x:1,d=b?b.y:1,e=b?b.z:1,f=a.elements[0]/c,h=a.elements[4]/d,c=a.elements[1]/c,d=a.elements[5]/d,i=a.elements[9]/e,l=a.elements[10]/e;this.y=Math.asin(a.elements[8]/e);e=Math.cos(this.y);if(Math.abs(e)>1.0E-5){this.x=Math.atan2(-i/e,l/e);this.z=Math.atan2(-h/e,f/e)}else{this.x=0;this.z=Math.atan2(c,d)}return this},getScaleFromMatrix:function(a){var b=
-this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},isZero:function(){return this.lengthSq()<1.0E-4},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1};
-THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w!==void 0?a.w:1;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;this.z=this.z+a.z;this.w=this.w+a.w;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},subSelf:function(a){this.x=
-this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;this.w=this.w-a.w;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a;this.w=this.w/a}else{this.z=this.y=this.x=0;this.w=1}return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.dot(this)},length:function(){return Math.sqrt(this.lengthSq())},
-normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;this.w=this.w+(a.w-this.w)*b;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Frustum=function(){this.planes=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4]};
-THREE.Frustum.prototype.setFromMatrix=function(a){var b,c=this.planes,d=a.elements,a=d[0];b=d[1];var e=d[2],f=d[3],h=d[4],i=d[5],l=d[6],k=d[7],j=d[8],m=d[9],n=d[10],o=d[11],s=d[12],p=d[13],q=d[14],d=d[15];c[0].set(f-a,k-h,o-j,d-s);c[1].set(f+a,k+h,o+j,d+s);c[2].set(f+b,k+i,o+m,d+p);c[3].set(f-b,k-i,o-m,d-p);c[4].set(f-e,k-l,o-n,d-q);c[5].set(f+e,k+l,o+n,d+q);for(a=0;a<6;a++){b=c[a];b.divideScalar(Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z))}};
-THREE.Frustum.prototype.contains=function(a){for(var b=this.planes,c=a.matrixWorld,d=c.elements,c=-a.geometry.boundingSphere.radius*c.getMaxScaleOnAxis(),e=0;e<6;e++){a=b[e].x*d[12]+b[e].y*d[13]+b[e].z*d[14]+b[e].w;if(a<=c)return false}return true};THREE.Frustum.__v1=new THREE.Vector3;
-THREE.Ray=function(a,b){function c(a,b,c){s.sub(c,a);w=s.dot(b);A=p.add(a,q.copy(b).multiplyScalar(w));return y=c.distanceTo(A)}function d(a,b,c,d){s.sub(d,b);p.sub(c,b);q.sub(a,b);u=s.dot(s);H=s.dot(p);B=s.dot(q);K=p.dot(p);N=p.dot(q);Y=1/(u*K-H*H);ca=(K*B-H*N)*Y;I=(u*N-H*B)*Y;return ca>=0&&I>=0&&ca+I<1}this.origin=a||new THREE.Vector3;this.direction=b||new THREE.Vector3;var e=1.0E-4;this.setPrecision=function(a){e=a};var f=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,l=new THREE.Vector3,
-k=new THREE.Vector3,j=new THREE.Vector3,m=new THREE.Vector3,n=new THREE.Vector3,o=new THREE.Vector3;this.intersectObject=function(a){var b,s=[];if(a instanceof THREE.Particle){var p=c(this.origin,this.direction,a.matrixWorld.getPosition());if(p>a.scale.x)return[];b={distance:p,point:a.position,face:null,object:a};s.push(b)}else if(a instanceof THREE.Mesh){var p=c(this.origin,this.direction,a.matrixWorld.getPosition()),g=THREE.Frustum.__v1.set(a.matrixWorld.getColumnX().length(),a.matrixWorld.getColumnY().length(),
-a.matrixWorld.getColumnZ().length());if(p>a.geometry.boundingSphere.radius*Math.max(g.x,Math.max(g.y,g.z)))return s;var q,u,y=a.geometry,w=y.vertices,A;a.matrixRotationWorld.extractRotation(a.matrixWorld);p=0;for(g=y.faces.length;p0:q<0))){o.add(k,j.multiplyScalar(u));if(b instanceof THREE.Face3){f=A.multiplyVector3(f.copy(w[b.a]));h=A.multiplyVector3(h.copy(w[b.b]));i=A.multiplyVector3(i.copy(w[b.c]));if(d(o,f,h,i)){b={distance:k.distanceTo(o),point:o.clone(),face:b,object:a};s.push(b)}}else if(b instanceof THREE.Face4){f=A.multiplyVector3(f.copy(w[b.a]));h=A.multiplyVector3(h.copy(w[b.b]));i=A.multiplyVector3(i.copy(w[b.c]));l=A.multiplyVector3(l.copy(w[b.d]));if(d(o,f,h,l)||d(o,h,i,l)){b={distance:k.distanceTo(o),point:o.clone(),
-face:b,object:a};s.push(b)}}}}}}return s};this.intersectObjects=function(a){for(var b=[],c=0,d=a.length;cf?d:f;e=e>h?
-e:h}a()};this.add3Points=function(f,h,j,m,n,o){if(i){i=false;b=fj?f>n?f:n:j>n?j:n;e=h>m?h>o?h:o:m>o?m:o}else{b=fj?f>n?f>d?f:d:n>d?n:d:j>n?j>d?j:d:n>d?n:d;e=h>m?h>o?h>e?h:e:o>e?o:e:m>o?m>e?m:e:o>e?o:e}a()};this.addRectangle=function(f){if(i){i=false;b=f.getLeft();c=f.getTop();d=f.getRight();e=f.getBottom()}else{b=bf.getRight()?d:f.getRight();e=e>f.getBottom()?e:f.getBottom()}a()};this.inflate=function(f){b=b-f;c=c-f;d=d+f;e=e+f;a()};this.minSelf=function(f){b=b>f.getLeft()?b:f.getLeft();c=c>f.getTop()?c:f.getTop();d=da.getRight()||ea.getBottom()?false:true};this.empty=function(){i=true;e=d=c=b=0;a()};this.isEmpty=function(){return i}};
-THREE.Math={clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a0?1:0}};THREE.Matrix3=function(){this.elements=new Float32Array(9)};
-THREE.Matrix3.prototype={constructor:THREE.Matrix3,getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],e=-b[10]*b[4]+b[6]*b[8],f=b[10]*b[0]-b[2]*b[8],h=-b[6]*b[0]+b[2]*b[4],i=b[9]*b[4]-b[5]*b[8],l=-b[9]*b[0]+b[1]*b[8],k=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*e+b[2]*i;b===0&&console.warn("Matrix3.getInverse(): determinant == 0");var b=1/b,j=this.elements;j[0]=b*a;j[1]=b*c;j[2]=b*d;j[3]=b*e;j[4]=b*f;j[5]=b*h;j[6]=b*i;j[7]=b*l;j[8]=b*k;return this},
-transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},transposeIntoArray:function(a){var b=this.m;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this}};THREE.Matrix4=function(a,b,c,d,e,f,h,i,l,k,j,m,n,o,s,p){this.elements=new Float32Array(16);this.set(a!==void 0?a:1,b||0,c||0,d||0,e||0,f!==void 0?f:1,h||0,i||0,l||0,k||0,j!==void 0?j:1,m||0,n||0,o||0,s||0,p!==void 0?p:1)};
-THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,h,i,l,k,j,m,n,o,s,p){var q=this.elements;q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=h;q[13]=i;q[2]=l;q[6]=k;q[10]=j;q[14]=m;q[3]=n;q[7]=o;q[11]=s;q[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15]);return this},lookAt:function(a,b,c){var d=this.elements,
-e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,h=THREE.Matrix4.__v3;h.sub(a,b).normalize();if(h.length()===0)h.z=1;e.cross(c,h).normalize();if(e.length()===0){h.x=h.x+1.0E-4;e.cross(c,h).normalize()}f.cross(h,e);d[0]=e.x;d[4]=f.x;d[8]=h.x;d[1]=e.y;d[5]=f.y;d[9]=h.y;d[2]=e.z;d[6]=f.z;d[10]=h.z;return this},multiply:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],h=c[4],i=c[8],l=c[12],k=c[1],j=c[5],m=c[9],n=c[13],o=c[2],s=c[6],p=c[10],q=c[14],w=c[3],A=c[7],y=c[11],c=c[15],u=d[0],H=d[4],
-B=d[8],K=d[12],N=d[1],Y=d[5],ca=d[9],I=d[13],ba=d[2],ja=d[6],ya=d[10],D=d[14],g=d[3],Na=d[7],za=d[11],d=d[15];e[0]=f*u+h*N+i*ba+l*g;e[4]=f*H+h*Y+i*ja+l*Na;e[8]=f*B+h*ca+i*ya+l*za;e[12]=f*K+h*I+i*D+l*d;e[1]=k*u+j*N+m*ba+n*g;e[5]=k*H+j*Y+m*ja+n*Na;e[9]=k*B+j*ca+m*ya+n*za;e[13]=k*K+j*I+m*D+n*d;e[2]=o*u+s*N+p*ba+q*g;e[6]=o*H+s*Y+p*ja+q*Na;e[10]=o*B+s*ca+p*ya+q*za;e[14]=o*K+s*I+p*D+q*d;e[3]=w*u+A*N+y*ba+c*g;e[7]=w*H+A*Y+y*ja+c*Na;e[11]=w*B+A*ca+y*ya+c*za;e[15]=w*K+A*I+y*D+c*d;return this},multiplySelf:function(a){return this.multiply(this,
-a)},multiplyToArray:function(a,b,c){var d=this.elements;this.multiply(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]=b[0]*a;b[4]=b[4]*a;b[8]=b[8]*a;b[12]=b[12]*a;b[1]=b[1]*a;b[5]=b[5]*a;b[9]=b[9]*a;b[13]=b[13]*a;b[2]=b[2]*a;b[6]=b[6]*a;b[10]=b[10]*a;b[14]=b[14]*a;b[3]=b[3]*a;b[7]=b[7]*a;b[11]=b[11]*a;b[15]=
-b[15]*a;return this},multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=1/(b[3]*c+b[7]*d+b[11]*e+b[15]);a.x=(b[0]*c+b[4]*d+b[8]*e+b[12])*f;a.y=(b[1]*c+b[5]*d+b[9]*e+b[13])*f;a.z=(b[2]*c+b[6]*d+b[10]*e+b[14])*f;return a},multiplyVector4:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w;a.x=b[0]*c+b[4]*d+b[8]*e+b[12]*f;a.y=b[1]*c+b[5]*d+b[9]*e+b[13]*f;a.z=b[2]*c+b[6]*d+b[10]*e+b[14]*f;a.w=b[3]*c+b[7]*d+b[11]*e+b[15]*f;return a},rotateAxis:function(a){var b=this.elements,c=a.x,
-d=a.y,e=a.z;a.x=c*b[0]+d*b[4]+e*b[8];a.y=c*b[1]+d*b[5]+e*b[9];a.z=c*b[2]+d*b[6]+e*b[10];a.normalize();return a},crossVector:function(a){var b=this.elements,c=new THREE.Vector4;c.x=b[0]*a.x+b[4]*a.y+b[8]*a.z+b[12]*a.w;c.y=b[1]*a.x+b[5]*a.y+b[9]*a.z+b[13]*a.w;c.z=b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14]*a.w;c.w=a.w?b[3]*a.x+b[7]*a.y+b[11]*a.z+b[15]*a.w:1;return c},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],h=a[5],i=a[9],l=a[13],k=a[2],j=a[6],m=a[10],n=a[14],o=a[3],s=a[7],
-p=a[11],a=a[15];return e*i*j*o-d*l*j*o-e*h*m*o+c*l*m*o+d*h*n*o-c*i*n*o-e*i*k*s+d*l*k*s+e*f*m*s-b*l*m*s-d*f*n*s+b*i*n*s+e*h*k*p-c*l*k*p-e*f*j*p+b*l*j*p+c*f*n*p-b*h*n*p-d*h*k*a+c*i*k*a+d*f*j*a-b*i*j*a-c*f*m*a+b*h*m*a},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[1];a[2]=b[2];
-a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[12],a[13],
-a[14])},setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getColumnX:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[0],a[1],a[2])},getColumnY:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[4],a[5],a[6])},getColumnZ:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[8],a[9],a[10])},getInverse:function(a){var b=this.elements,c=a.elements,d=c[0],e=c[4],f=c[8],h=c[12],i=c[1],l=c[5],k=c[9],j=c[13],m=c[2],n=c[6],o=c[10],s=
-c[14],p=c[3],q=c[7],w=c[11],c=c[15];b[0]=k*s*q-j*o*q+j*n*w-l*s*w-k*n*c+l*o*c;b[4]=h*o*q-f*s*q-h*n*w+e*s*w+f*n*c-e*o*c;b[8]=f*j*q-h*k*q+h*l*w-e*j*w-f*l*c+e*k*c;b[12]=h*k*n-f*j*n-h*l*o+e*j*o+f*l*s-e*k*s;b[1]=j*o*p-k*s*p-j*m*w+i*s*w+k*m*c-i*o*c;b[5]=f*s*p-h*o*p+h*m*w-d*s*w-f*m*c+d*o*c;b[9]=h*k*p-f*j*p-h*i*w+d*j*w+f*i*c-d*k*c;b[13]=f*j*m-h*k*m+h*i*o-d*j*o-f*i*s+d*k*s;b[2]=l*s*p-j*n*p+j*m*q-i*s*q-l*m*c+i*n*c;b[6]=h*n*p-e*s*p-h*m*q+d*s*q+e*m*c-d*n*c;b[10]=e*j*p-h*l*p+h*i*q-d*j*q-e*i*c+d*l*c;b[14]=h*l*m-
-e*j*m-h*i*n+d*j*n+e*i*s-d*l*s;b[3]=k*n*p-l*o*p-k*m*q+i*o*q+l*m*w-i*n*w;b[7]=e*o*p-f*n*p+f*m*q-d*o*q-e*m*w+d*n*w;b[11]=f*l*p-e*k*p-f*i*q+d*k*q+e*i*w-d*l*w;b[15]=e*k*m-f*l*m+f*i*n-d*k*n-e*i*o+d*l*o;this.multiplyScalar(1/a.determinant());return this},setRotationFromEuler:function(a,b){var c=this.elements,d=a.x,e=a.y,f=a.z,h=Math.cos(d),d=Math.sin(d),i=Math.cos(e),e=Math.sin(e),l=Math.cos(f),f=Math.sin(f);switch(b){case "YXZ":var k=i*l,j=i*f,m=e*l,n=e*f;c[0]=k+n*d;c[4]=m*d-j;c[8]=h*e;c[1]=h*f;c[5]=h*
-l;c[9]=-d;c[2]=j*d-m;c[6]=n+k*d;c[10]=h*i;break;case "ZXY":k=i*l;j=i*f;m=e*l;n=e*f;c[0]=k-n*d;c[4]=-h*f;c[8]=m+j*d;c[1]=j+m*d;c[5]=h*l;c[9]=n-k*d;c[2]=-h*e;c[6]=d;c[10]=h*i;break;case "ZYX":k=h*l;j=h*f;m=d*l;n=d*f;c[0]=i*l;c[4]=m*e-j;c[8]=k*e+n;c[1]=i*f;c[5]=n*e+k;c[9]=j*e-m;c[2]=-e;c[6]=d*i;c[10]=h*i;break;case "YZX":k=h*i;j=h*e;m=d*i;n=d*e;c[0]=i*l;c[4]=n-k*f;c[8]=m*f+j;c[1]=f;c[5]=h*l;c[9]=-d*l;c[2]=-e*l;c[6]=j*f+m;c[10]=k-n*f;break;case "XZY":k=h*i;j=h*e;m=d*i;n=d*e;c[0]=i*l;c[4]=-f;c[8]=e*l;
-c[1]=k*f+n;c[5]=h*l;c[9]=j*f-m;c[2]=m*f-j;c[6]=d*l;c[10]=n*f+k;break;default:k=h*l;j=h*f;m=d*l;n=d*f;c[0]=i*l;c[4]=-i*f;c[8]=e;c[1]=j+m*e;c[5]=k-n*e;c[9]=-d*i;c[2]=n-k*e;c[6]=m+j*e;c[10]=h*i}return this},setRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,h=c+c,i=d+d,l=e+e,a=c*h,k=c*i,c=c*l,j=d*i,d=d*l,e=e*l,h=f*h,i=f*i,f=f*l;b[0]=1-(j+e);b[4]=k-f;b[8]=c+i;b[1]=k+f;b[5]=1-(a+e);b[9]=d-h;b[2]=c-i;b[6]=d+h;b[10]=1-(a+j);return this},compose:function(a,b,c){var d=this.elements,
-e=THREE.Matrix4.__m1,f=THREE.Matrix4.__m2;e.identity();e.setRotationFromQuaternion(b);f.makeScale(c.x,c.y,c.z);this.multiply(e,f);d[12]=a.x;d[13]=a.y;d[14]=a.z;return this},decompose:function(a,b,c){var d=this.elements,e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,h=THREE.Matrix4.__v3;e.set(d[0],d[1],d[2]);f.set(d[4],d[5],d[6]);h.set(d[8],d[9],d[10]);a=a instanceof THREE.Vector3?a:new THREE.Vector3;b=b instanceof THREE.Quaternion?b:new THREE.Quaternion;c=c instanceof THREE.Vector3?c:new THREE.Vector3;
-c.x=e.length();c.y=f.length();c.z=h.length();a.x=d[12];a.y=d[13];a.z=d[14];d=THREE.Matrix4.__m1;d.copy(this);d.elements[0]=d.elements[0]/c.x;d.elements[1]=d.elements[1]/c.x;d.elements[2]=d.elements[2]/c.x;d.elements[4]=d.elements[4]/c.y;d.elements[5]=d.elements[5]/c.y;d.elements[6]=d.elements[6]/c.y;d.elements[8]=d.elements[8]/c.z;d.elements[9]=d.elements[9]/c.z;d.elements[10]=d.elements[10]/c.z;b.setFromRotationMatrix(d);return[a,b,c]},extractPosition:function(a){var b=this.elements,a=a.elements;
-b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractRotation:function(a){var b=this.elements,a=a.elements,c=THREE.Matrix4.__v1,d=1/c.set(a[0],a[1],a[2]).length(),e=1/c.set(a[4],a[5],a[6]).length(),c=1/c.set(a[8],a[9],a[10]).length();b[0]=a[0]*d;b[1]=a[1]*d;b[2]=a[2]*d;b[4]=a[4]*e;b[5]=a[5]*e;b[6]=a[6]*e;b[8]=a[8]*c;b[9]=a[9]*c;b[10]=a[10]*c;return this},translate:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[12]=b[0]*c+b[4]*d+b[8]*a+b[12];b[13]=b[1]*c+b[5]*d+b[9]*a+b[13];b[14]=b[2]*c+b[6]*
-d+b[10]*a+b[14];b[15]=b[3]*c+b[7]*d+b[11]*a+b[15];return this},rotateX:function(a){var b=this.elements,c=b[4],d=b[5],e=b[6],f=b[7],h=b[8],i=b[9],l=b[10],k=b[11],j=Math.cos(a),a=Math.sin(a);b[4]=j*c+a*h;b[5]=j*d+a*i;b[6]=j*e+a*l;b[7]=j*f+a*k;b[8]=j*h-a*c;b[9]=j*i-a*d;b[10]=j*l-a*e;b[11]=j*k-a*f;return this},rotateY:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],h=b[8],i=b[9],l=b[10],k=b[11],j=Math.cos(a),a=Math.sin(a);b[0]=j*c-a*h;b[1]=j*d-a*i;b[2]=j*e-a*l;b[3]=j*f-a*k;b[8]=j*h+a*c;b[9]=
-j*i+a*d;b[10]=j*l+a*e;b[11]=j*k+a*f;return this},rotateZ:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],h=b[4],i=b[5],l=b[6],k=b[7],j=Math.cos(a),a=Math.sin(a);b[0]=j*c+a*h;b[1]=j*d+a*i;b[2]=j*e+a*l;b[3]=j*f+a*k;b[4]=j*h-a*c;b[5]=j*i-a*d;b[6]=j*l-a*e;b[7]=j*k-a*f;return this},rotateByAxis:function(a,b){var c=this.elements;if(a.x===1&&a.y===0&&a.z===0)return this.rotateX(b);if(a.x===0&&a.y===1&&a.z===0)return this.rotateY(b);if(a.x===0&&a.y===0&&a.z===1)return this.rotateZ(b);var d=a.x,
-e=a.y,f=a.z,h=Math.sqrt(d*d+e*e+f*f),d=d/h,e=e/h,f=f/h,h=d*d,i=e*e,l=f*f,k=Math.cos(b),j=Math.sin(b),m=1-k,n=d*e*m,o=d*f*m,m=e*f*m,d=d*j,s=e*j,j=f*j,f=h+(1-h)*k,h=n+j,e=o-s,n=n-j,i=i+(1-i)*k,j=m+d,o=o+s,m=m-d,l=l+(1-l)*k,k=c[0],d=c[1],s=c[2],p=c[3],q=c[4],w=c[5],A=c[6],y=c[7],u=c[8],H=c[9],B=c[10],K=c[11];c[0]=f*k+h*q+e*u;c[1]=f*d+h*w+e*H;c[2]=f*s+h*A+e*B;c[3]=f*p+h*y+e*K;c[4]=n*k+i*q+j*u;c[5]=n*d+i*w+j*H;c[6]=n*s+i*A+j*B;c[7]=n*p+i*y+j*K;c[8]=o*k+m*q+l*u;c[9]=o*d+m*w+l*H;c[10]=o*s+m*A+l*B;c[11]=
-o*p+m*y+l*K;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]=b[0]*c;b[4]=b[4]*d;b[8]=b[8]*a;b[1]=b[1]*c;b[5]=b[5]*d;b[9]=b[9]*a;b[2]=b[2]*c;b[6]=b[6]*d;b[10]=b[10]*a;b[3]=b[3]*c;b[7]=b[7]*d;b[11]=b[11]*a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},
-makeRotationX:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,h=a.y,i=a.z,l=e*f,k=e*h;this.set(l*f+c,l*h-d*i,l*i+d*h,0,l*h+d*i,k*h+c,k*i-d*f,0,l*i-
-d*h,k*i+d*f,e*i*i+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},makeFrustum:function(a,b,c,d,e,f){var h=this.elements;h[0]=2*e/(b-a);h[4]=0;h[8]=(b+a)/(b-a);h[12]=0;h[1]=0;h[5]=2*e/(d-c);h[9]=(d+c)/(d-c);h[13]=0;h[2]=0;h[6]=0;h[10]=-(f+e)/(f-e);h[14]=-2*f*e/(f-e);h[3]=0;h[7]=0;h[11]=-1;h[15]=0;return this},makePerspective:function(a,b,c,d){var a=c*Math.tan(a*Math.PI/360),e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,
-b,c,d,e,f){var h=this.elements,i=b-a,l=c-d,k=f-e;h[0]=2/i;h[4]=0;h[8]=0;h[12]=-((b+a)/i);h[1]=0;h[5]=2/l;h[9]=0;h[13]=-((c+d)/l);h[2]=0;h[6]=0;h[10]=-2/k;h[14]=-((f+e)/k);h[3]=0;h[7]=0;h[11]=0;h[15]=1;return this},clone:function(){var a=this.elements;return new THREE.Matrix4(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}};THREE.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3;THREE.Matrix4.__m1=new THREE.Matrix4;
-THREE.Matrix4.__m2=new THREE.Matrix4;
-THREE.Object3D=function(){this.id=THREE.Object3DCount++;this.name="";this.parent=void 0;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.eulerOrder="XYZ";this.scale=new THREE.Vector3(1,1,1);this.flipSided=this.doubleSided=false;this.renderDepth=null;this.rotationAutoUpdate=true;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixWorldNeedsUpdate=this.matrixAutoUpdate=
-true;this.quaternion=new THREE.Quaternion;this.useQuaternion=false;this.boundRadius=0;this.boundRadiusScale=1;this.visible=true;this.receiveShadow=this.castShadow=false;this.frustumCulled=true;this._vector=new THREE.Vector3};
-THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);this.rotation.getRotationFromMatrix(this.matrix,this.scale);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(b.multiplyScalar(a))},translateX:function(a){this.translate(a,this._vector.set(1,0,0))},translateY:function(a){this.translate(a,this._vector.set(0,1,0))},translateZ:function(a){this.translate(a,
-this._vector.set(0,0,1))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)},add:function(a){if(a===this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");else if(a instanceof THREE.Object3D){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=
-this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,e;c=0;for(d=this.children.length;c=0&&e>=0&&f>=0&&h>=0)return true;if(g<0&&e<0||f<0&&h<0)return false;g<0?c=Math.max(c,g/(g-e)):e<0&&(d=Math.min(d,g/(g-e)));f<0?c=Math.max(c,f/(f-h)):h<0&&(d=Math.min(d,f/(f-h)));if(dD&&h.positionScreen.z0)){Z=l[i-2];ca.copy(J.positionScreen);I.copy(Z.positionScreen);if(c(ca,I)){ca.multiplyScalar(1/ca.w);I.multiplyScalar(1/I.w);Ha=q[p]=q[p]||new THREE.RenderableLine;p++;s=Ha;s.v1.positionScreen.copy(ca);s.v2.positionScreen.copy(I);s.z=Math.max(ca.z,I.z);s.material=O.material;u.elements.push(s)}}}}}d=0;for(za=u.sprites.length;d0&&B.z<1){D=y[A]=y[A]||new THREE.RenderableParticle;A++;w=D;w.x=B.x/B.w;w.y=B.y/B.w;w.z=B.z;w.rotation=O.rotation.z;w.scale.x=O.scale.x*Math.abs(w.x-(B.x+e.projectionMatrix.elements[0])/(B.w+e.projectionMatrix.elements[12]));w.scale.y=O.scale.y*Math.abs(w.y-(B.y+e.projectionMatrix.elements[5])/(B.w+e.projectionMatrix.elements[13]));w.material=O.material;u.elements.push(w)}}}f&&u.elements.sort(b);return u}};
-THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1};
-THREE.Quaternion.prototype={constructor:THREE.Quaternion,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w;return this},setFromEuler:function(a){var b=Math.PI/360,c=a.x*b,d=a.y*b,e=a.z*b,a=Math.cos(d),d=Math.sin(d),b=Math.cos(-e),e=Math.sin(-e),f=Math.cos(c),c=Math.sin(c),h=a*b,i=d*e;this.w=h*f-i*c;this.x=h*c+i*f;this.y=d*b*f+a*e*c;this.z=a*e*f-d*b*c;return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);
-this.x=a.x*d;this.y=a.y*d;this.z=a.z*d;this.w=Math.cos(c);return this},setFromRotationMatrix:function(a){var b=Math.pow(a.determinant(),1/3);this.w=Math.sqrt(Math.max(0,b+a.elements[0]+a.elements[5]+a.elements[10]))/2;this.x=Math.sqrt(Math.max(0,b+a.elements[0]-a.elements[5]-a.elements[10]))/2;this.y=Math.sqrt(Math.max(0,b-a.elements[0]+a.elements[5]-a.elements[10]))/2;this.z=Math.sqrt(Math.max(0,b-a.elements[0]-a.elements[5]+a.elements[10]))/2;this.x=a.elements[6]-a.elements[9]<0?-Math.abs(this.x):
-Math.abs(this.x);this.y=a.elements[8]-a.elements[2]<0?-Math.abs(this.y):Math.abs(this.y);this.z=a.elements[1]-a.elements[4]<0?-Math.abs(this.z):Math.abs(this.z);this.normalize();return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x=this.x*-1;this.y=this.y*-1;this.z=this.z*-1;return this},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a=
-Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);if(a===0)this.w=this.z=this.y=this.x=0;else{a=1/a;this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a}return this},multiply:function(a,b){this.x=a.x*b.w+a.y*b.z-a.z*b.y+a.w*b.x;this.y=-a.x*b.z+a.y*b.w+a.z*b.x+a.w*b.y;this.z=a.x*b.y-a.y*b.x+a.z*b.w+a.w*b.z;this.w=-a.x*b.x-a.y*b.y-a.z*b.z+a.w*b.w;return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,f=a.x,h=a.y,i=a.z,a=a.w;this.x=b*a+e*f+c*i-d*h;this.y=
-c*a+e*h+d*f-b*i;this.z=d*a+e*i+b*h-c*f;this.w=e*a-b*f-c*h-d*i;return this},multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,e=a.z,f=this.x,h=this.y,i=this.z,l=this.w,k=l*c+h*e-i*d,j=l*d+i*c-f*e,m=l*e+f*d-h*c,c=-f*c-h*d-i*e;b.x=k*l+c*-f+j*-i-m*-h;b.y=j*l+c*-h+m*-f-k*-i;b.z=m*l+c*-i+k*-h-j*-f;return b},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}};
-THREE.Quaternion.slerp=function(a,b,c,d){var e=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(e<0){c.w=-b.w;c.x=-b.x;c.y=-b.y;c.z=-b.z;e=-e}else c.copy(b);if(Math.abs(e)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var f=Math.acos(e),e=Math.sqrt(1-e*e);if(Math.abs(e)<0.001){c.w=0.5*(a.w+b.w);c.x=0.5*(a.x+b.x);c.y=0.5*(a.y+b.y);c.z=0.5*(a.z+b.z);return c}b=Math.sin((1-d)*f)/e;d=Math.sin(d*f)/e;c.w=a.w*b+c.w*d;c.x=a.x*b+c.x*d;c.y=a.y*b+c.y*d;c.z=a.z*b+c.z*d;return c};THREE.Vertex=function(){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.")};
-THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=f;this.centroid=new THREE.Vector3};
-THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;b0){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d
-c.x)c.x=a.x;if(a.yc.y)c.y=a.y;if(a.zc.z)c.z=a.z}}else{this.boundingBox.min.set(0,0,0);this.boundingBox.max.set(0,0,0)}},computeBoundingSphere:function(){if(!this.boundingSphere)this.boundingSphere={radius:0};for(var a,b=0,c=0,d=this.vertices.length;cb&&(b=a)}this.boundingSphere.radius=b},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,h,i;f=0;for(h=this.vertices.length;f0;a--)if(d.indexOf(e["abcd"[a]])!=a){d.splice(a,1);this.faces[f]=new THREE.Face3(d[0],d[1],d[2]);e=0;for(d=this.faceVertexUvs.length;e<
-d;e++)(i=this.faceVertexUvs[e][f])&&i.splice(a,1);break}}}c=this.vertices.length-b.length;this.vertices=b;return c}};THREE.GeometryCount=0;
-THREE.Spline=function(a){function b(a,b,c,d,e,f,h){a=(c-a)*0.5;d=(d-b)*0.5;return(2*(b-c)+a+d)*h+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,h,i,l,k,j,m,n;this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:
-f+2;k=this.points[c[0]];j=this.points[c[1]];m=this.points[c[2]];n=this.points[c[3]];i=h*h;l=h*i;d.x=b(k.x,j.x,m.x,n.x,h,i,l);d.y=b(k.y,j.y,m.y,n.y,h,i,l);d.z=b(k.z,j.z,m.z,n.z,h,i,l);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a1){a.matrixWorldInverse.getInverse(a.matrixWorld);a=a.matrixWorldInverse;a=-(a.elements[2]*this.matrixWorld.elements[12]+a.elements[6]*this.matrixWorld.elements[13]+a.elements[10]*this.matrixWorld.elements[14]+a.elements[14]);this.LODs[0].object3D.visible=true;for(var b=1;b=this.LODs[b].visibleAtDistance){this.LODs[b-1].object3D.visible=false;this.LODs[b].object3D.visible=true}else break;for(;b 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngle[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif",
-lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nlVector = normalize( lVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - mPosition.xyz ) );\nif ( spotEffect > spotLightAngle[ i ] ) {\nspotEffect = pow( spotEffect, spotLightExponent[ i ] );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif",
-lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvarying vec3 vWorldPosition;\n#endif",lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvWorldPosition = mPosition.xyz;\n#endif",
-lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngle[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",
-lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngle[ i ] ) {\nspotEffect = pow( spotEffect, spotLightExponent[ i ] );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif",
-color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n#endif",skinning_vertex:"#ifdef USE_SKINNING\ngl_Position = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;\ngl_Position += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;\ngl_Position = projectionMatrix * modelViewMatrix * gl_Position;\n#endif",
-morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( morphed, 1.0 );\n#endif",
-default_vertex:"#ifndef USE_MORPHTARGETS\n#ifndef USE_SKINNING\ngl_Position = projectionMatrix * mvPosition;\n#endif\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\nvec3 transformedNormal = normalMatrix * morphedNormal;\n#else\nvec3 transformedNormal = normalMatrix * normal;\n#endif",
-shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#ifdef SHADOWMAP_SOFT\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif",
-shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n#ifdef USE_MORPHTARGETS\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( morphed, 1.0 );\n#else\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( position, 1.0 );\n#endif\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",
-linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"};
-THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b=0)return a.geometry.materials[b.materialIndex]}function d(a){return a instanceof THREE.MeshBasicMaterial&&!a.envMap||a instanceof THREE.MeshDepthMaterial?false:a&&a.shading!==void 0&&a.shading===THREE.SmoothShading?THREE.SmoothShading:THREE.FlatShading}function e(a){return a.map||a.lightMap||a instanceof THREE.ShaderMaterial?true:false}function f(a,b,c){var d,e,f,h,i=a.vertices;h=i.length;
-var k=a.colors,j=k.length,l=a.__vertexArray,n=a.__colorArray,o=a.__sortArray,m=a.verticesNeedUpdate,p=a.colorsNeedUpdate,s=a.__webglCustomAttributesList;if(c.sortParticles){Ub.copy(qb);Ub.multiplySelf(c.matrixWorld);for(d=0;d0};this.setSize=
-function(a,b){H.width=a;H.height=b;this.setViewport(0,0,H.width,H.height)};this.setViewport=function(a,b,c,d){Eb=a;Fb=b;Xb=c;Gb=d;g.viewport(Eb,Fb,Xb,Gb)};this.setScissor=function(a,b,c,d){g.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?g.enable(g.SCISSOR_TEST):g.disable(g.SCISSOR_TEST)};this.setClearColorHex=function(a,b){ba.setHex(a);ja=b;g.clearColor(ba.r,ba.g,ba.b,ja)};this.setClearColor=function(a,b){ba.copy(a);ja=b;g.clearColor(ba.r,ba.g,ba.b,ja)};this.getClearColor=function(){return ba};
-this.getClearAlpha=function(){return ja};this.clear=function(a,b,c){var d=0;if(a===void 0||a)d=d|g.COLOR_BUFFER_BIT;if(b===void 0||b)d=d|g.DEPTH_BUFFER_BIT;if(c===void 0||c)d=d|g.STENCIL_BUFFER_BIT;g.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};this.deallocateObject=function(a){if(a.__webglInit){a.__webglInit=
-false;delete a._modelViewMatrix;delete a._normalMatrix;delete a._normalMatrixArray;delete a._modelViewMatrixArray;delete a._objectMatrixArray;if(a instanceof THREE.Mesh)for(var b in a.geometry.geometryGroups){var c=a.geometry.geometryGroups[b];g.deleteBuffer(c.__webglVertexBuffer);g.deleteBuffer(c.__webglNormalBuffer);g.deleteBuffer(c.__webglTangentBuffer);g.deleteBuffer(c.__webglColorBuffer);g.deleteBuffer(c.__webglUVBuffer);g.deleteBuffer(c.__webglUV2Buffer);g.deleteBuffer(c.__webglSkinVertexABuffer);
-g.deleteBuffer(c.__webglSkinVertexBBuffer);g.deleteBuffer(c.__webglSkinIndicesBuffer);g.deleteBuffer(c.__webglSkinWeightsBuffer);g.deleteBuffer(c.__webglFaceBuffer);g.deleteBuffer(c.__webglLineBuffer);var d=void 0,e=void 0;if(c.numMorphTargets){d=0;for(e=c.numMorphTargets;d=
-0&&e.vertexNormalBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexNormalBuffer);g.vertexAttribPointer(a.normal,e.vertexNormalBuffer.itemSize,g.FLOAT,false,0,f[d].index*12)}if(a.uv>=0&&e.vertexUvBuffer)if(e.vertexUvBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexUvBuffer);g.vertexAttribPointer(a.uv,e.vertexUvBuffer.itemSize,g.FLOAT,false,0,f[d].index*8);g.enableVertexAttribArray(a.uv)}else g.disableVertexAttribArray(a.uv);if(a.color>=0&&e.vertexColorBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexColorBuffer);
-g.vertexAttribPointer(a.color,e.vertexColorBuffer.itemSize,g.FLOAT,false,0,f[d].index*16)}g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.vertexIndexBuffer)}g.drawElements(g.TRIANGLES,f[d].count,g.UNSIGNED_SHORT,f[d].start*2);D.info.render.calls++;D.info.render.vertices=D.info.render.vertices+f[d].count;D.info.render.faces=D.info.render.faces+f[d].count/3}}}};this.renderBuffer=function(a,b,c,d,e,f){if(d.visible!==false){var h,i,c=o(a,b,c,d,f),b=c.attributes,a=false,c=e.id*16777215+c.id*2+(d.wireframe?1:0);
-if(c!==R){R=c;a=true}if(!d.morphTargets&&b.position>=0){if(a){g.bindBuffer(g.ARRAY_BUFFER,e.__webglVertexBuffer);g.vertexAttribPointer(b.position,3,g.FLOAT,false,0,0)}}else if(f.morphTargetBase){c=d.program.attributes;if(f.morphTargetBase!==-1){g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]);g.vertexAttribPointer(c.position,3,g.FLOAT,false,0,0)}else if(c.position>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglVertexBuffer);g.vertexAttribPointer(c.position,3,g.FLOAT,false,0,
-0)}if(f.morphTargetForcedOrder.length){h=0;var k=f.morphTargetForcedOrder;for(i=f.morphTargetInfluences;hj){l=n;j=i[l]}g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[l]);g.vertexAttribPointer(c["morphTarget"+h],3,g.FLOAT,false,0,0);if(d.morphNormals){g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[l]);g.vertexAttribPointer(c["morphNormal"+h],3,g.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[h]=j;k[l]=1;j=-1;h++}}d.program.uniforms.morphTargetInfluences!==
-null&&g.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList){h=0;for(i=e.__webglCustomAttributesList.length;h=0){g.bindBuffer(g.ARRAY_BUFFER,c.buffer);g.vertexAttribPointer(b[c.buffer.belongsToAttribute],c.size,g.FLOAT,false,0,0)}}}if(b.color>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglColorBuffer);g.vertexAttribPointer(b.color,3,g.FLOAT,false,0,0)}if(b.normal>=
-0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglNormalBuffer);g.vertexAttribPointer(b.normal,3,g.FLOAT,false,0,0)}if(b.tangent>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglTangentBuffer);g.vertexAttribPointer(b.tangent,4,g.FLOAT,false,0,0)}if(b.uv>=0)if(e.__webglUVBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.__webglUVBuffer);g.vertexAttribPointer(b.uv,2,g.FLOAT,false,0,0);g.enableVertexAttribArray(b.uv)}else g.disableVertexAttribArray(b.uv);if(b.uv2>=0)if(e.__webglUV2Buffer){g.bindBuffer(g.ARRAY_BUFFER,e.__webglUV2Buffer);
-g.vertexAttribPointer(b.uv2,2,g.FLOAT,false,0,0);g.enableVertexAttribArray(b.uv2)}else g.disableVertexAttribArray(b.uv2);if(d.skinning&&b.skinVertexA>=0&&b.skinVertexB>=0&&b.skinIndex>=0&&b.skinWeight>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinVertexABuffer);g.vertexAttribPointer(b.skinVertexA,4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinVertexBBuffer);g.vertexAttribPointer(b.skinVertexB,4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinIndicesBuffer);g.vertexAttribPointer(b.skinIndex,
-4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinWeightsBuffer);g.vertexAttribPointer(b.skinWeight,4,g.FLOAT,false,0,0)}}if(f instanceof THREE.Mesh){if(d.wireframe){d=d.wireframeLinewidth;if(d!==Db){g.lineWidth(d);Db=d}a&&g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer);g.drawElements(g.LINES,e.__webglLineCount,g.UNSIGNED_SHORT,0)}else{a&&g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer);g.drawElements(g.TRIANGLES,e.__webglFaceCount,g.UNSIGNED_SHORT,0)}D.info.render.calls++;
-D.info.render.vertices=D.info.render.vertices+e.__webglFaceCount;D.info.render.faces=D.info.render.faces+e.__webglFaceCount/3}else if(f instanceof THREE.Line){f=f.type===THREE.LineStrip?g.LINE_STRIP:g.LINES;d=d.linewidth;if(d!==Db){g.lineWidth(d);Db=d}g.drawArrays(f,0,e.__webglLineCount);D.info.render.calls++}}};this.render=function(a,b,c,d){var e,f,j,n,m=a.__lights,o=a.fog;$=-1;rb=true;if(b.parent===void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(b)}this.autoUpdateScene&&
-a.updateMatrixWorld();if(!b._viewMatrixArray)b._viewMatrixArray=new Float32Array(16);if(!b._projectionMatrixArray)b._projectionMatrixArray=new Float32Array(16);b.matrixWorldInverse.getInverse(b.matrixWorld);b.matrixWorldInverse.flattenToArray(b._viewMatrixArray);b.projectionMatrix.flattenToArray(b._projectionMatrixArray);qb.multiply(b.projectionMatrix,b.matrixWorldInverse);Yb.setFromMatrix(qb);this.autoUpdateObjects&&this.initWebGLObjects(a);i(this.renderPluginsPre,a,b);D.info.render.calls=0;D.info.render.vertices=
-0;D.info.render.faces=0;D.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);n=a.__webglObjects;d=0;for(e=n.length;d=0){w=u.geometry.materials[w];
-if(w.transparent){q.transparent=w;q.opaque=null}else{q.opaque=w;q.transparent=null}}}else if(w)if(w.transparent){q.transparent=w;q.opaque=null}else{q.opaque=w;q.transparent=null}f.render=true;if(this.sortObjects)if(j.renderDepth)f.z=j.renderDepth;else{Ra.copy(j.matrixWorld.getPosition());qb.multiplyVector3(Ra);f.z=Ra.z}}}this.sortObjects&&n.sort(h);n=a.__webglObjectsImmediate;d=0;for(e=n.length;d65535){H[A].counter=H[A].counter+1;B=H[A].hash+"_"+H[A].counter;q.geometryGroups[B]===void 0&&(q.geometryGroups[B]={faces3:[],faces4:[],materialIndex:w,vertices:0,numMorphTargets:K,numMorphNormals:Y})}u instanceof THREE.Face3?q.geometryGroups[B].faces3.push(p):q.geometryGroups[B].faces4.push(p);q.geometryGroups[B].vertices=
-q.geometryGroups[B].vertices+y}q.geometryGroupsList=[];var J=void 0;for(J in q.geometryGroups){q.geometryGroups[J].id=Z++;q.geometryGroupsList.push(q.geometryGroups[J])}}for(k in l.geometryGroups){o=l.geometryGroups[k];if(!o.__webglVertexBuffer){var N=o;N.__webglVertexBuffer=g.createBuffer();N.__webglNormalBuffer=g.createBuffer();N.__webglTangentBuffer=g.createBuffer();N.__webglColorBuffer=g.createBuffer();N.__webglUVBuffer=g.createBuffer();N.__webglUV2Buffer=g.createBuffer();N.__webglSkinVertexABuffer=
-g.createBuffer();N.__webglSkinVertexBBuffer=g.createBuffer();N.__webglSkinIndicesBuffer=g.createBuffer();N.__webglSkinWeightsBuffer=g.createBuffer();N.__webglFaceBuffer=g.createBuffer();N.__webglLineBuffer=g.createBuffer();var O=void 0,R=void 0;if(N.numMorphTargets){N.__webglMorphTargetsBuffers=[];O=0;for(R=N.numMorphTargets;O0||ja.faceVertexUvs.length>0)I.__uvArray=new Float32Array(Q*2);if(ja.faceUvs.length>1||ja.faceVertexUvs.length>
-1)I.__uv2Array=new Float32Array(Q*2)}if(ba.geometry.skinWeights.length&&ba.geometry.skinIndices.length){I.__skinVertexAArray=new Float32Array(Q*4);I.__skinVertexBArray=new Float32Array(Q*4);I.__skinIndexArray=new Float32Array(Q*4);I.__skinWeightArray=new Float32Array(Q*4)}I.__faceArray=new Uint16Array(za*3);I.__lineArray=new Uint16Array(pa*2);var sa=void 0,Ca=void 0;if(I.numMorphTargets){I.__morphTargetsArrays=[];sa=0;for(Ca=I.numMorphTargets;sa=0;nc--)Fb[nc].object===Xb&&Fb.splice(nc,1);mc.__webglActive=false;a.__objectsRemoved.splice(0,1)}for(var Gb=0,Yb=a.__webglObjects.length;Gb0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinVertexABuffer);g.bufferData(g.ARRAY_BUFFER,ea,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinVertexBBuffer);g.bufferData(g.ARRAY_BUFFER,fa,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinIndicesBuffer);g.bufferData(g.ARRAY_BUFFER,ga,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinWeightsBuffer);g.bufferData(g.ARRAY_BUFFER,ha,Ia)}}if(Pc&&Ac){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglColorBuffer);g.bufferData(g.ARRAY_BUFFER,va,Ia)}}if(Oc&&Ba.hasTangents){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglUVBuffer);g.bufferData(g.ARRAY_BUFFER,fc,Ia)}}if(Jc&&Fc&&Wb){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglUV2Buffer);g.bufferData(g.ARRAY_BUFFER,gc,Ia)}}if(yc){v=0;for(C=T.length;v0?"#define VERTEX_TEXTURES":"",D.gammaInput?"#define GAMMA_INPUT":"",D.gammaOutput?"#define GAMMA_OUTPUT":"",D.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,c.map?"#define USE_MAP":
-"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?
-"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
-j=["precision "+B+" float;","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",D.gammaInput?"#define GAMMA_INPUT":"",D.gammaOutput?"#define GAMMA_OUTPUT":"",D.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",c.map?"#define USE_MAP":
-"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");
-g.attachShader(s,q("fragment",j+m));g.attachShader(s,q("vertex",d+k));g.linkProgram(s);g.getProgramParameter(s,g.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+g.getProgramParameter(s,g.VALIDATE_STATUS)+", gl error ["+g.getError()+"]");s.uniforms={};s.attributes={};var u,d=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","boneGlobalMatrices","morphTargetInfluences"];for(u in i)d.push(u);u=d;d=0;for(i=u.length;d=0&&g.enableVertexAttribArray(p.position);
-p.color>=0&&g.enableVertexAttribArray(p.color);p.normal>=0&&g.enableVertexAttribArray(p.normal);p.tangent>=0&&g.enableVertexAttribArray(p.tangent);if(a.skinning&&p.skinVertexA>=0&&p.skinVertexB>=0&&p.skinIndex>=0&&p.skinWeight>=0){g.enableVertexAttribArray(p.skinVertexA);g.enableVertexAttribArray(p.skinVertexB);g.enableVertexAttribArray(p.skinIndex);g.enableVertexAttribArray(p.skinWeight)}if(a.attributes)for(f in a.attributes)p[f]!==void 0&&p[f]>=0&&g.enableVertexAttribArray(p[f]);if(a.morphTargets){a.numSupportedMorphTargets=
-0;s="morphTarget";for(f=0;f=0){g.enableVertexAttribArray(p[u]);a.numSupportedMorphTargets++}}}if(a.morphNormals){a.numSupportedMorphNormals=0;s="morphNormal";for(f=0;f=0){g.enableVertexAttribArray(p[u]);a.numSupportedMorphNormals++}}}a.uniformsList=[];for(e in a.uniforms)a.uniformsList.push([a.uniforms[e],e])};this.setFaceCulling=function(a,b){if(a){!b||b==="ccw"?g.frontFace(g.CCW):g.frontFace(g.CW);a==="back"?g.cullFace(g.BACK):
-a==="front"?g.cullFace(g.FRONT):g.cullFace(g.FRONT_AND_BACK);g.enable(g.CULL_FACE)}else g.disable(g.CULL_FACE)};this.setObjectFaces=function(a){if(Q!==a.doubleSided){a.doubleSided?g.disable(g.CULL_FACE):g.enable(g.CULL_FACE);Q=a.doubleSided}if(pa!==a.flipSided){a.flipSided?g.frontFace(g.CW):g.frontFace(g.CCW);pa=a.flipSided}};this.setDepthTest=function(a){if(La!==a){a?g.enable(g.DEPTH_TEST):g.disable(g.DEPTH_TEST);La=a}};this.setDepthWrite=function(a){if(Oa!==a){g.depthMask(a);Oa=a}};this.setBlending=
-function(a,b,c,d){if(a!==O){switch(a){case THREE.NoBlending:g.disable(g.BLEND);break;case THREE.AdditiveBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.SRC_ALPHA,g.ONE);break;case THREE.SubtractiveBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.ZERO,g.ONE_MINUS_SRC_COLOR);break;case THREE.MultiplyBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.ZERO,g.SRC_COLOR);break;case THREE.CustomBlending:g.enable(g.BLEND);break;default:g.enable(g.BLEND);
-g.blendEquationSeparate(g.FUNC_ADD,g.FUNC_ADD);g.blendFuncSeparate(g.SRC_ALPHA,g.ONE_MINUS_SRC_ALPHA,g.ONE,g.ONE_MINUS_SRC_ALPHA)}O=a}if(a===THREE.CustomBlending){if(b!==sa){g.blendEquation(u(b));sa=b}if(c!==Ga||d!==Ha){g.blendFunc(u(c),u(d));Ga=c;Ha=d}}else Ha=Ga=sa=null};this.setTexture=function(a,b){if(a.needsUpdate){if(!a.__webglInit){a.__webglInit=true;a.__webglTexture=g.createTexture();D.info.memory.textures++}g.activeTexture(g.TEXTURE0+b);g.bindTexture(g.TEXTURE_2D,a.__webglTexture);g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
-a.premultiplyAlpha);var c=a.image,d=(c.width&c.width-1)===0&&(c.height&c.height-1)===0,e=u(a.format),f=u(a.type);w(g.TEXTURE_2D,a,d);a instanceof THREE.DataTexture?g.texImage2D(g.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data):g.texImage2D(g.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&g.generateMipmap(g.TEXTURE_2D);a.needsUpdate=false;if(a.onUpdate)a.onUpdate()}else{g.activeTexture(g.TEXTURE0+b);g.bindTexture(g.TEXTURE_2D,a.__webglTexture)}};this.setRenderTarget=function(a){var b=a instanceof
-THREE.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){if(a.depthBuffer===void 0)a.depthBuffer=true;if(a.stencilBuffer===void 0)a.stencilBuffer=true;a.__webglTexture=g.createTexture();var c=(a.width&a.width-1)===0&&(a.height&a.height-1)===0,d=u(a.format),e=u(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];g.bindTexture(g.TEXTURE_CUBE_MAP,a.__webglTexture);w(g.TEXTURE_CUBE_MAP,a,c);for(var f=0;f<6;f++){a.__webglFramebuffer[f]=g.createFramebuffer();a.__webglRenderbuffer[f]=g.createRenderbuffer();
-g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var h=a,i=g.TEXTURE_CUBE_MAP_POSITIVE_X+f;g.bindFramebuffer(g.FRAMEBUFFER,a.__webglFramebuffer[f]);g.framebufferTexture2D(g.FRAMEBUFFER,g.COLOR_ATTACHMENT0,i,h.__webglTexture,0);A(a.__webglRenderbuffer[f],a)}c&&g.generateMipmap(g.TEXTURE_CUBE_MAP)}else{a.__webglFramebuffer=g.createFramebuffer();a.__webglRenderbuffer=g.createRenderbuffer();g.bindTexture(g.TEXTURE_2D,a.__webglTexture);w(g.TEXTURE_2D,a,c);g.texImage2D(g.TEXTURE_2D,
-0,d,a.width,a.height,0,d,e,null);d=g.TEXTURE_2D;g.bindFramebuffer(g.FRAMEBUFFER,a.__webglFramebuffer);g.framebufferTexture2D(g.FRAMEBUFFER,g.COLOR_ATTACHMENT0,d,a.__webglTexture,0);A(a.__webglRenderbuffer,a);c&&g.generateMipmap(g.TEXTURE_2D)}b?g.bindTexture(g.TEXTURE_CUBE_MAP,null):g.bindTexture(g.TEXTURE_2D,null);g.bindRenderbuffer(g.RENDERBUFFER,null);g.bindFramebuffer(g.FRAMEBUFFER,null)}if(a){b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer;c=a.width;a=a.height;e=d=0}else{b=null;
-c=Xb;a=Gb;d=Eb;e=Fb}if(b!==Da){g.bindFramebuffer(g.FRAMEBUFFER,b);g.viewport(d,e,c,a);Da=b}jc=c;kc=a}};
-THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=c.wrapS!==void 0?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=c.wrapT!==void 0?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=c.magFilter!==void 0?c.magFilter:THREE.LinearFilter;this.minFilter=c.minFilter!==void 0?c.minFilter:THREE.LinearMipMapLinearFilter;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=c.format!==void 0?c.format:THREE.RGBAFormat;this.type=c.type!==void 0?c.type:
-THREE.UnsignedByteType;this.depthBuffer=c.depthBuffer!==void 0?c.depthBuffer:true;this.stencilBuffer=c.stencilBuffer!==void 0?c.stencilBuffer:true;this.generateMipmaps=true};
-THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;return a};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};
-THREE.WebGLRenderTargetCube.prototype=new THREE.WebGLRenderTarget;THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube;THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=true};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};
-THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null};
-THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null};
-THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null};
-THREE.GeometryUtils={merge:function(a,b){for(var c,d,e=a.vertices.length,f=b instanceof THREE.Mesh?b.geometry:b,h=a.vertices,i=f.vertices,l=a.faces,k=f.faces,j=a.faceVertexUvs[0],m=f.faceVertexUvs[0],n={},o=0;o1){d=1-d;e=1-e}f=1-d-e;h.copy(a);h.multiplyScalar(d);i.copy(b);i.multiplyScalar(e);h.addSelf(i);i.copy(c);i.multiplyScalar(f);h.addSelf(i);return h},randomPointInFace:function(a,b,c){var d,e,f;if(a instanceof
-THREE.Face3){d=b.vertices[a.a];e=b.vertices[a.b];f=b.vertices[a.c];return THREE.GeometryUtils.randomPointInTriangle(d,e,f)}if(a instanceof THREE.Face4){d=b.vertices[a.a];e=b.vertices[a.b];f=b.vertices[a.c];var b=b.vertices[a.d],h;if(c)if(a._area1&&a._area2){c=a._area1;h=a._area2}else{c=THREE.GeometryUtils.triangleArea(d,e,b);h=THREE.GeometryUtils.triangleArea(e,f,b);a._area1=c;a._area2=h}else{c=THREE.GeometryUtils.triangleArea(d,e,b);h=THREE.GeometryUtils.triangleArea(e,f,b)}return THREE.GeometryUtils.random()*
-(c+h)a?b(c,e-1):k[e]
-b||s>b||n>b){l=a.vertices.length;y=e.clone();u=e.clone();if(o>=s&&o>=n){k=k.clone();k.lerpSelf(j,0.5);y.a=f;y.b=l;y.c=i;u.a=l;u.b=h;u.c=i;if(e.vertexNormals.length===3){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[1],0.5);y.vertexNormals[1].copy(f);u.vertexNormals[0].copy(f)}if(e.vertexColors.length===3){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[1],0.5);y.vertexColors[1].copy(f);u.vertexColors[0].copy(f)}e=0}else if(s>=o&&s>=n){k=j.clone();k.lerpSelf(m,0.5);y.a=f;y.b=h;y.c=
-l;u.a=l;u.b=i;u.c=f;if(e.vertexNormals.length===3){f=e.vertexNormals[1].clone();f.lerpSelf(e.vertexNormals[2],0.5);y.vertexNormals[2].copy(f);u.vertexNormals[0].copy(f);u.vertexNormals[1].copy(e.vertexNormals[2]);u.vertexNormals[2].copy(e.vertexNormals[0])}if(e.vertexColors.length===3){f=e.vertexColors[1].clone();f.lerpSelf(e.vertexColors[2],0.5);y.vertexColors[2].copy(f);u.vertexColors[0].copy(f);u.vertexColors[1].copy(e.vertexColors[2]);u.vertexColors[2].copy(e.vertexColors[0])}e=1}else{k=k.clone();
-k.lerpSelf(m,0.5);y.a=f;y.b=h;y.c=l;u.a=l;u.b=h;u.c=i;if(e.vertexNormals.length===3){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[2],0.5);y.vertexNormals[2].copy(f);u.vertexNormals[0].copy(f)}if(e.vertexColors.length===3){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[2],0.5);y.vertexColors[2].copy(f);u.vertexColors[0].copy(f)}e=2}H.push(y,u);a.vertices.push(k);f=0;for(h=a.faceVertexUvs.length;fb||s>b||p>b||q>b){w=a.vertices.length;A=a.vertices.length+1;y=e.clone();u=e.clone();if(o>=s&&o>=p&&o>=q||p>=s&&p>=o&&p>=q){o=k.clone();o.lerpSelf(j,0.5);j=m.clone();j.lerpSelf(n,0.5);y.a=f;y.b=w;y.c=A;y.d=l;u.a=w;u.b=h;u.c=i;u.d=A;if(e.vertexNormals.length===4){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[1],0.5);h=e.vertexNormals[2].clone();h.lerpSelf(e.vertexNormals[3],0.5);y.vertexNormals[1].copy(f);
-y.vertexNormals[2].copy(h);u.vertexNormals[0].copy(f);u.vertexNormals[3].copy(h)}if(e.vertexColors.length===4){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[1],0.5);h=e.vertexColors[2].clone();h.lerpSelf(e.vertexColors[3],0.5);y.vertexColors[1].copy(f);y.vertexColors[2].copy(h);u.vertexColors[0].copy(f);u.vertexColors[3].copy(h)}e=0}else{o=j.clone();o.lerpSelf(m,0.5);j=n.clone();j.lerpSelf(k,0.5);y.a=f;y.b=h;y.c=w;y.d=A;u.a=A;u.b=w;u.c=i;u.d=l;if(e.vertexNormals.length===4){f=e.vertexNormals[1].clone();
-f.lerpSelf(e.vertexNormals[2],0.5);h=e.vertexNormals[3].clone();h.lerpSelf(e.vertexNormals[0],0.5);y.vertexNormals[2].copy(f);y.vertexNormals[3].copy(h);u.vertexNormals[0].copy(h);u.vertexNormals[1].copy(f)}if(e.vertexColors.length===4){f=e.vertexColors[1].clone();f.lerpSelf(e.vertexColors[2],0.5);h=e.vertexColors[3].clone();h.lerpSelf(e.vertexColors[0],0.5);y.vertexColors[2].copy(f);y.vertexColors[3].copy(h);u.vertexColors[0].copy(h);u.vertexColors[1].copy(f)}e=1}H.push(y,u);a.vertices.push(o,j);
-f=0;for(h=a.faceVertexUvs.length;fe-1?e-1:m+1,s=j-1<0?0:j-1,p=j+1>d-1?d-1:j+1,q=[],w=[0,0,i[(m*d+j)*4]/255*b];q.push([-1,0,i[(m*d+s)*4]/255*b]);q.push([-1,-1,i[(n*d+s)*4]/255*b]);q.push([0,
--1,i[(n*d+j)*4]/255*b]);q.push([1,-1,i[(n*d+p)*4]/255*b]);q.push([1,0,i[(m*d+p)*4]/255*b]);q.push([1,1,i[(o*d+p)*4]/255*b]);q.push([0,1,i[(o*d+j)*4]/255*b]);q.push([-1,1,i[(o*d+s)*4]/255*b]);n=[];s=q.length;for(o=0;o 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;",
-THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec3 pointVector = normalize( vPointLight[ i ].xyz );\nfloat pointDistance = vPointLight[ i ].w;\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;\nif ( enableReflection ) {\nvec3 wPos = cameraPosition - vViewPosition;\nvec3 vReflect = reflect( normalize( wPos ), normal );\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}",
-THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;",
-THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvViewPosition = -mvPosition.xyz;\nvNormal = normalMatrix * normal;\nvTangent = normalMatrix * tangent.xyz;\nvBinormal = cross( vNormal, vTangent ) * tangent.w;\nvUv = uv * uRepeat + uOffset;\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#ifdef VERTEX_TEXTURES\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\nvec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;\ngl_Position = projectionMatrix * displacedPosition;\n#else\ngl_Position = projectionMatrix * mvPosition;\n#endif",
-THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:1,texture:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );\n}"}}});
-THREE.BufferGeometry=function(){this.id=THREE.GeometryCount++;this.vertexColorArray=this.vertexUvArray=this.vertexNormalArray=this.vertexPositionArray=this.vertexIndexArray=this.vertexColorBuffer=this.vertexUvBuffer=this.vertexNormalBuffer=this.vertexPositionBuffer=this.vertexIndexBuffer=null;this.dynamic=false;this.boundingSphere=this.boundingBox=null;this.morphTargets=[]};THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,computeBoundingBox:function(){},computeBoundingSphere:function(){}};
-THREE.CubeGeometry=function(a,b,c,d,e,f,h,i){function l(a,b,c,h,i,j,l,n){var m,o=d||1,p=e||1,q=i/2,g=j/2,s=k.vertices.length;if(a==="x"&&b==="y"||a==="y"&&b==="x")m="z";else if(a==="x"&&b==="z"||a==="z"&&b==="x"){m="y";p=f||1}else if(a==="z"&&b==="y"||a==="y"&&b==="z"){m="x";o=f||1}var w=o+1,y=p+1,A=i/o,R=j/p,J=new THREE.Vector3;J[m]=l>0?1:-1;for(i=0;i0){this.vertices.push(new THREE.Vector3(0,
-h,0));for(i=0;i0){this.vertices.push(new THREE.Vector3(0,-h,0));for(i=0;i 0) {
- return result.invalidAttrs;
- }
- }
- };
- };
-
- // Helper to mix in validation on a model
- var bindModel = function(view, model, options) {
- _.extend(model, mixin(view, options));
- };
-
- // Removes the methods added to a model
- var unbindModel = function(model) {
- delete model.validate;
- delete model.preValidate;
- delete model.isValid;
- };
-
- // Mix in validation on a model whenever a model is
- // added to a collection
- var collectionAdd = function(model) {
- bindModel(this.view, model, this.options);
- };
-
- // Remove validation from a model whenever a model is
- // removed from a collection
- var collectionRemove = function(model) {
- unbindModel(model);
- };
-
- // Returns the public methods on Backbone.Validation
- return {
-
- // Current version of the library
- version: '0.9.1',
-
- // Called to configure the default options
- configure: function(options) {
- _.extend(defaultOptions, options);
- },
-
- // Hooks up validation on a view with a model
- // or collection
- bind: function(view, options) {
- options = _.extend({}, defaultOptions, defaultCallbacks, options);
-
- var model = options.model || view.model,
- collection = options.collection || view.collection;
-
- if(typeof model === 'undefined' && typeof collection === 'undefined'){
- throw 'Before you execute the binding your view must have a model or a collection.\n' +
- 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.';
- }
-
- if(model) {
- bindModel(view, model, options);
- }
- else if(collection) {
- collection.each(function(model){
- bindModel(view, model, options);
- });
- collection.bind('add', collectionAdd, {view: view, options: options});
- collection.bind('remove', collectionRemove);
- }
- },
-
- // Removes validation from a view with a model
- // or collection
- unbind: function(view, options) {
- options = _.extend({}, options);
- var model = options.model || view.model,
- collection = options.collection || view.collection;
-
- if(model) {
- unbindModel(model);
- }
- else if(collection) {
- collection.each(function(model){
- unbindModel(model);
- });
- collection.unbind('add', collectionAdd);
- collection.unbind('remove', collectionRemove);
- }
- },
-
- // Used to extend the Backbone.Model.prototype
- // with validation
- mixin: mixin(null, defaultOptions)
- };
- }());
-
-
- // Callbacks
- // ---------
-
- var defaultCallbacks = Validation.callbacks = {
-
- // Gets called when a previously invalid field in the
- // view becomes valid. Removes any error message.
- // Should be overridden with custom functionality.
- valid: function(view, attr, selector) {
- view.$('[' + selector + '~="' + attr + '"]')
- .removeClass('invalid')
- .removeAttr('data-error');
- },
-
- // Gets called when a field in the view becomes invalid.
- // Adds a error message.
- // Should be overridden with custom functionality.
- invalid: function(view, attr, error, selector) {
- view.$('[' + selector + '~="' + attr + '"]')
- .addClass('invalid')
- .attr('data-error', error);
- }
- };
-
-
- // Patterns
- // --------
-
- var defaultPatterns = Validation.patterns = {
- // Matches any digit(s) (i.e. 0-9)
- digits: /^\d+$/,
-
- // Matches any number (e.g. 100.000)
- number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,
-
- // Matches a valid email address (e.g. mail@example.com)
- email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,
-
- // Mathes any valid url (e.g. http://www.xample.com)
- url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
- };
-
-
- // Error messages
- // --------------
-
- // Error message for the build in validators.
- // {x} gets swapped out with arguments form the validator.
- var defaultMessages = Validation.messages = {
- required: '{0} is required',
- acceptance: '{0} must be accepted',
- min: '{0} must be greater than or equal to {1}',
- max: '{0} must be less than or equal to {1}',
- range: '{0} must be between {1} and {2}',
- length: '{0} must be {1} characters',
- minLength: '{0} must be at least {1} characters',
- maxLength: '{0} must be at most {1} characters',
- rangeLength: '{0} must be between {1} and {2} characters',
- oneOf: '{0} must be one of: {1}',
- equalTo: '{0} must be the same as {1}',
- digits: '{0} must only contain digits',
- number: '{0} must be a number',
- email: '{0} must be a valid email',
- url: '{0} must be a valid url',
- inlinePattern: '{0} is invalid'
- };
-
- // Label formatters
- // ----------------
-
- // Label formatters are used to convert the attribute name
- // to a more human friendly label when using the built in
- // error messages.
- // Configure which one to use with a call to
- //
- // Backbone.Validation.configure({
- // labelFormatter: 'label'
- // });
- var defaultLabelFormatters = Validation.labelFormatters = {
-
- // Returns the attribute name with applying any formatting
- none: function(attrName) {
- return attrName;
- },
-
- // Converts attributeName or attribute_name to Attribute name
- sentenceCase: function(attrName) {
- return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
- return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
- }).replace(/_/g, ' ');
- },
-
- // Looks for a label configured on the model and returns it
- //
- // var Model = Backbone.Model.extend({
- // validation: {
- // someAttribute: {
- // required: true
- // }
- // },
- //
- // labels: {
- // someAttribute: 'Custom label'
- // }
- // });
- label: function(attrName, model) {
- return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model);
- }
- };
-
-
- // Built in validators
- // -------------------
-
- var defaultValidators = Validation.validators = (function(){
- // Use native trim when defined
- var trim = String.prototype.trim ?
- function(text) {
- return text === null ? '' : String.prototype.trim.call(text);
- } :
- function(text) {
- var trimLeft = /^\s+/,
- trimRight = /\s+$/;
-
- return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, '');
- };
-
- // Determines whether or not a value is a number
- var isNumber = function(value){
- return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
- };
-
- // Determines whether or not a value is empty
- var hasValue = function(value) {
- return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
- };
-
- return {
- // Function validator
- // Lets you implement a custom function used for validation
- fn: function(value, attr, fn, model, computed) {
- if(_.isString(fn)){
- fn = model[fn];
- }
- return fn.call(model, value, attr, computed);
- },
-
- // Required validator
- // Validates if the attribute is required or not
- // This can be specified as either a boolean value or a function that returns a boolean value
- required: function(value, attr, required, model, computed) {
- var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required;
- if(!isRequired && !hasValue(value)) {
- return false; // overrides all other validators
- }
- if (isRequired && !hasValue(value)) {
- return this.format(defaultMessages.required, this.formatLabel(attr, model));
- }
- },
-
- // Acceptance validator
- // Validates that something has to be accepted, e.g. terms of use
- // `true` or 'true' are valid
- acceptance: function(value, attr, accept, model) {
- if(value !== 'true' && (!_.isBoolean(value) || value === false)) {
- return this.format(defaultMessages.acceptance, this.formatLabel(attr, model));
- }
- },
-
- // Min validator
- // Validates that the value has to be a number and equal to or greater than
- // the min value specified
- min: function(value, attr, minValue, model) {
- if (!isNumber(value) || value < minValue) {
- return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue);
- }
- },
-
- // Max validator
- // Validates that the value has to be a number and equal to or less than
- // the max value specified
- max: function(value, attr, maxValue, model) {
- if (!isNumber(value) || value > maxValue) {
- return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue);
- }
- },
-
- // Range validator
- // Validates that the value has to be a number and equal to or between
- // the two numbers specified
- range: function(value, attr, range, model) {
- if(!isNumber(value) || value < range[0] || value > range[1]) {
- return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]);
- }
- },
-
- // Length validator
- // Validates that the value has to be a string with length equal to
- // the length value specified
- length: function(value, attr, length, model) {
- if (!_.isString(value) || value.length !== length) {
- return this.format(defaultMessages.length, this.formatLabel(attr, model), length);
- }
- },
-
- // Min length validator
- // Validates that the value has to be a string with length equal to or greater than
- // the min length value specified
- minLength: function(value, attr, minLength, model) {
- if (!_.isString(value) || value.length < minLength) {
- return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength);
- }
- },
-
- // Max length validator
- // Validates that the value has to be a string with length equal to or less than
- // the max length value specified
- maxLength: function(value, attr, maxLength, model) {
- if (!_.isString(value) || value.length > maxLength) {
- return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength);
- }
- },
-
- // Range length validator
- // Validates that the value has to be a string and equal to or between
- // the two numbers specified
- rangeLength: function(value, attr, range, model) {
- if (!_.isString(value) || value.length < range[0] || value.length > range[1]) {
- return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]);
- }
- },
-
- // One of validator
- // Validates that the value has to be equal to one of the elements in
- // the specified array. Case sensitive matching
- oneOf: function(value, attr, values, model) {
- if(!_.include(values, value)){
- return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', '));
- }
- },
-
- // Equal to validator
- // Validates that the value has to be equal to the value of the attribute
- // with the name specified
- equalTo: function(value, attr, equalTo, model, computed) {
- if(value !== computed[equalTo]) {
- return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model));
- }
- },
-
- // Pattern validator
- // Validates that the value has to match the pattern specified.
- // Can be a regular expression or the name of one of the built in patterns
- pattern: function(value, attr, pattern, model) {
- if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
- return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
- }
- }
- };
- }());
-
- // Set the correct context for all validators
- // when used from within a method validator
- _.each(defaultValidators, function(validator, key){
- defaultValidators[key] = _.bind(defaultValidators[key], _.extend({}, formatFunctions, defaultValidators));
- });
-
- return Validation;
- }(_));
- return Backbone.Validation;
-}));
\ No newline at end of file
diff --git a/client/src/js/vendor/backbone/backbone-validation.js_.js b/client/src/js/vendor/backbone/backbone-validation.js_.js
deleted file mode 100644
index 6b112dd12..000000000
--- a/client/src/js/vendor/backbone/backbone-validation.js_.js
+++ /dev/null
@@ -1,634 +0,0 @@
-// Backbone.Validation v0.9.1
-//
-// Copyright (c) 2011-2014 Thomas Pedersen
-// Distributed under MIT License
-//
-// Documentation and full license available at:
-// http://thedersen.com/projects/backbone-validation
-Backbone.Validation = (function(_){
- 'use strict';
-
- // Default options
- // ---------------
-
- var defaultOptions = {
- forceUpdate: false,
- selector: 'name',
- labelFormatter: 'sentenceCase',
- valid: Function.prototype,
- invalid: Function.prototype
- };
-
-
- // Helper functions
- // ----------------
-
- // Formatting functions used for formatting error messages
- var formatFunctions = {
- // Uses the configured label formatter to format the attribute name
- // to make it more readable for the user
- formatLabel: function(attrName, model) {
- return defaultLabelFormatters[defaultOptions.labelFormatter](attrName, model);
- },
-
- // Replaces nummeric placeholders like {0} in a string with arguments
- // passed to the function
- format: function() {
- var args = Array.prototype.slice.call(arguments),
- text = args.shift();
- return text.replace(/\{(\d+)\}/g, function(match, number) {
- return typeof args[number] !== 'undefined' ? args[number] : match;
- });
- }
- };
-
- // Flattens an object
- // eg:
- //
- // var o = {
- // address: {
- // street: 'Street',
- // zip: 1234
- // }
- // };
- //
- // becomes:
- //
- // var o = {
- // 'address.street': 'Street',
- // 'address.zip': 1234
- // };
- var flatten = function (obj, into, prefix) {
- into = into || {};
- prefix = prefix || '';
-
- _.each(obj, function(val, key) {
- if(obj.hasOwnProperty(key)) {
- if (val && typeof val === 'object' && !(
- val instanceof Array ||
- val instanceof Date ||
- val instanceof RegExp ||
- val instanceof Backbone.Model ||
- val instanceof Backbone.Collection)
- ) {
- flatten(val, into, prefix + key + '.');
- }
- else {
- into[prefix + key] = val;
- }
- }
- });
-
- return into;
- };
-
- // Validation
- // ----------
-
- var Validation = (function(){
-
- // Returns an object with undefined properties for all
- // attributes on the model that has defined one or more
- // validation rules.
- var getValidatedAttrs = function(model) {
- return _.reduce(_.keys(_.result(model, 'validation') || {}), function(memo, key) {
- memo[key] = void 0;
- return memo;
- }, {});
- };
-
- // Looks on the model for validations for a specified
- // attribute. Returns an array of any validators defined,
- // or an empty array if none is defined.
- var getValidators = function(model, attr) {
- var attrValidationSet = model.validation ? _.result(model, 'validation')[attr] || {} : {};
-
- // If the validator is a function or a string, wrap it in a function validator
- if (_.isFunction(attrValidationSet) || _.isString(attrValidationSet)) {
- attrValidationSet = {
- fn: attrValidationSet
- };
- }
-
- // Stick the validator object into an array
- if(!_.isArray(attrValidationSet)) {
- attrValidationSet = [attrValidationSet];
- }
-
- // Reduces the array of validators into a new array with objects
- // with a validation method to call, the value to validate against
- // and the specified error message, if any
- return _.reduce(attrValidationSet, function(memo, attrValidation) {
- _.each(_.without(_.keys(attrValidation), 'msg'), function(validator) {
- memo.push({
- fn: defaultValidators[validator],
- val: attrValidation[validator],
- msg: attrValidation.msg
- });
- });
- return memo;
- }, []);
- };
-
- // Validates an attribute against all validators defined
- // for that attribute. If one or more errors are found,
- // the first error message is returned.
- // If the attribute is valid, an empty string is returned.
- var validateAttr = function(model, attr, value, computed) {
- // Reduces the array of validators to an error message by
- // applying all the validators and returning the first error
- // message, if any.
- return _.reduce(getValidators(model, attr), function(memo, validator){
- // Pass the format functions plus the default
- // validators as the context to the validator
- var ctx = _.extend({}, formatFunctions, defaultValidators),
- result = validator.fn.call(ctx, value, attr, validator.val, model, computed);
-
- if(result === false || memo === false) {
- return false;
- }
- if (result && !memo) {
- return _.result(validator, 'msg') || result;
- }
- return memo;
- }, '');
- };
-
- // Loops through the model's attributes and validates them all.
- // Returns and object containing names of invalid attributes
- // as well as error messages.
- var validateModel = function(model, attrs) {
- var error,
- invalidAttrs = {},
- isValid = true,
- computed = _.clone(attrs),
- flattened = flatten(attrs);
-
- _.each(flattened, function(val, attr) {
- error = validateAttr(model, attr, val, computed);
- if (error) {
- invalidAttrs[attr] = error;
- isValid = false;
- }
- });
-
- return {
- invalidAttrs: invalidAttrs,
- isValid: isValid
- };
- };
-
- // Contains the methods that are mixed in on the model when binding
- var mixin = function(view, options) {
- return {
-
- // Check whether or not a value, or a hash of values
- // passes validation without updating the model
- preValidate: function(attr, value) {
- var self = this,
- result = {},
- error;
-
- if(_.isObject(attr)){
- _.each(attr, function(value, key) {
- error = self.preValidate(key, value);
- if(error){
- result[key] = error;
- }
- });
-
- return _.isEmpty(result) ? undefined : result;
- }
- else {
- return validateAttr(this, attr, value, _.extend({}, this.attributes));
- }
- },
-
- // Check to see if an attribute, an array of attributes or the
- // entire model is valid. Passing true will force a validation
- // of the model.
- isValid: function(option) {
- var flattened = flatten(this.attributes);
-
- if(_.isString(option)){
- return !validateAttr(this, option, flattened[option], _.extend({}, this.attributes));
- }
- if(_.isArray(option)){
- return _.reduce(option, function(memo, attr) {
- return memo && !validateAttr(this, attr, flattened[attr], _.extend({}, this.attributes));
- }, true, this);
- }
- if(option === true) {
- this.validate();
- }
- return this.validation ? this._isValid : true;
- },
-
- // This is called by Backbone when it needs to perform validation.
- // You can call it manually without any parameters to validate the
- // entire model.
- validate: function(attrs, setOptions){
- var model = this,
- validateAll = !attrs,
- opt = _.extend({}, options, setOptions),
- validatedAttrs = getValidatedAttrs(model),
- allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs),
- changedAttrs = flatten(attrs || allAttrs),
-
- result = validateModel(model, allAttrs);
-
- model._isValid = result.isValid;
-
- // After validation is performed, loop through all validated attributes
- // and call the valid callbacks so the view is updated.
- _.each(validatedAttrs, function(val, attr){
- var invalid = result.invalidAttrs.hasOwnProperty(attr);
- if(!invalid){
- opt.valid(view, attr, opt.selector);
- }
- });
-
- // After validation is performed, loop through all validated and changed attributes
- // and call the invalid callback so the view is updated.
- _.each(validatedAttrs, function(val, attr){
- var invalid = result.invalidAttrs.hasOwnProperty(attr),
- changed = changedAttrs.hasOwnProperty(attr);
-
- if(invalid && (changed || validateAll)){
- opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector);
- }
- });
-
- // Trigger validated events.
- // Need to defer this so the model is actually updated before
- // the event is triggered.
- _.defer(function() {
- model.trigger('validated', model._isValid, model, result.invalidAttrs);
- model.trigger('validated:' + (model._isValid ? 'valid' : 'invalid'), model, result.invalidAttrs);
- });
-
- // Return any error messages to Backbone, unless the forceUpdate flag is set.
- // Then we do not return anything and fools Backbone to believe the validation was
- // a success. That way Backbone will update the model regardless.
- if (!opt.forceUpdate && _.intersection(_.keys(result.invalidAttrs), _.keys(changedAttrs)).length > 0) {
- return result.invalidAttrs;
- }
- }
- };
- };
-
- // Helper to mix in validation on a model
- var bindModel = function(view, model, options) {
- _.extend(model, mixin(view, options));
- };
-
- // Removes the methods added to a model
- var unbindModel = function(model) {
- delete model.validate;
- delete model.preValidate;
- delete model.isValid;
- };
-
- // Mix in validation on a model whenever a model is
- // added to a collection
- var collectionAdd = function(model) {
- bindModel(this.view, model, this.options);
- };
-
- // Remove validation from a model whenever a model is
- // removed from a collection
- var collectionRemove = function(model) {
- unbindModel(model);
- };
-
- // Returns the public methods on Backbone.Validation
- return {
-
- // Current version of the library
- version: '0.9.1',
-
- // Called to configure the default options
- configure: function(options) {
- _.extend(defaultOptions, options);
- },
-
- // Hooks up validation on a view with a model
- // or collection
- bind: function(view, options) {
- options = _.extend({}, defaultOptions, defaultCallbacks, options);
-
- var model = options.model || view.model,
- collection = options.collection || view.collection;
-
- if(typeof model === 'undefined' && typeof collection === 'undefined'){
- throw 'Before you execute the binding your view must have a model or a collection.\n' +
- 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.';
- }
-
- if(model) {
- bindModel(view, model, options);
- }
- else if(collection) {
- collection.each(function(model){
- bindModel(view, model, options);
- });
- collection.bind('add', collectionAdd, {view: view, options: options});
- collection.bind('remove', collectionRemove);
- }
- },
-
- // Removes validation from a view with a model
- // or collection
- unbind: function(view, options) {
- options = _.extend({}, options);
- var model = options.model || view.model,
- collection = options.collection || view.collection;
-
- if(model) {
- unbindModel(model);
- }
- else if(collection) {
- collection.each(function(model){
- unbindModel(model);
- });
- collection.unbind('add', collectionAdd);
- collection.unbind('remove', collectionRemove);
- }
- },
-
- // Used to extend the Backbone.Model.prototype
- // with validation
- mixin: mixin(null, defaultOptions)
- };
- }());
-
-
- // Callbacks
- // ---------
-
- var defaultCallbacks = Validation.callbacks = {
-
- // Gets called when a previously invalid field in the
- // view becomes valid. Removes any error message.
- // Should be overridden with custom functionality.
- valid: function(view, attr, selector) {
- view.$('[' + selector + '~="' + attr + '"]')
- .removeClass('invalid')
- .removeAttr('data-error');
- },
-
- // Gets called when a field in the view becomes invalid.
- // Adds a error message.
- // Should be overridden with custom functionality.
- invalid: function(view, attr, error, selector) {
- view.$('[' + selector + '~="' + attr + '"]')
- .addClass('invalid')
- .attr('data-error', error);
- }
- };
-
-
- // Patterns
- // --------
-
- var defaultPatterns = Validation.patterns = {
- // Matches any digit(s) (i.e. 0-9)
- digits: /^\d+$/,
-
- // Matches any number (e.g. 100.000)
- number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,
-
- // Matches a valid email address (e.g. mail@example.com)
- email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,
-
- // Mathes any valid url (e.g. http://www.xample.com)
- url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
- };
-
-
- // Error messages
- // --------------
-
- // Error message for the build in validators.
- // {x} gets swapped out with arguments form the validator.
- var defaultMessages = Validation.messages = {
- required: '{0} is required',
- acceptance: '{0} must be accepted',
- min: '{0} must be greater than or equal to {1}',
- max: '{0} must be less than or equal to {1}',
- range: '{0} must be between {1} and {2}',
- length: '{0} must be {1} characters',
- minLength: '{0} must be at least {1} characters',
- maxLength: '{0} must be at most {1} characters',
- rangeLength: '{0} must be between {1} and {2} characters',
- oneOf: '{0} must be one of: {1}',
- equalTo: '{0} must be the same as {1}',
- digits: '{0} must only contain digits',
- number: '{0} must be a number',
- email: '{0} must be a valid email',
- url: '{0} must be a valid url',
- inlinePattern: '{0} is invalid'
- };
-
- // Label formatters
- // ----------------
-
- // Label formatters are used to convert the attribute name
- // to a more human friendly label when using the built in
- // error messages.
- // Configure which one to use with a call to
- //
- // Backbone.Validation.configure({
- // labelFormatter: 'label'
- // });
- var defaultLabelFormatters = Validation.labelFormatters = {
-
- // Returns the attribute name with applying any formatting
- none: function(attrName) {
- return attrName;
- },
-
- // Converts attributeName or attribute_name to Attribute name
- sentenceCase: function(attrName) {
- return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
- return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
- }).replace(/_/g, ' ');
- },
-
- // Looks for a label configured on the model and returns it
- //
- // var Model = Backbone.Model.extend({
- // validation: {
- // someAttribute: {
- // required: true
- // }
- // },
- //
- // labels: {
- // someAttribute: 'Custom label'
- // }
- // });
- label: function(attrName, model) {
- return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model);
- }
- };
-
-
- // Built in validators
- // -------------------
-
- var defaultValidators = Validation.validators = (function(){
- // Use native trim when defined
- var trim = String.prototype.trim ?
- function(text) {
- return text === null ? '' : String.prototype.trim.call(text);
- } :
- function(text) {
- var trimLeft = /^\s+/,
- trimRight = /\s+$/;
-
- return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, '');
- };
-
- // Determines whether or not a value is a number
- var isNumber = function(value){
- return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
- };
-
- // Determines whether or not a value is empty
- var hasValue = function(value) {
- return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
- };
-
- return {
- // Function validator
- // Lets you implement a custom function used for validation
- fn: function(value, attr, fn, model, computed) {
- if(_.isString(fn)){
- fn = model[fn];
- }
- return fn.call(model, value, attr, computed);
- },
-
- // Required validator
- // Validates if the attribute is required or not
- // This can be specified as either a boolean value or a function that returns a boolean value
- required: function(value, attr, required, model, computed) {
- var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required;
- if(!isRequired && !hasValue(value)) {
- return false; // overrides all other validators
- }
- if (isRequired && !hasValue(value)) {
- return this.format(defaultMessages.required, this.formatLabel(attr, model));
- }
- },
-
- // Acceptance validator
- // Validates that something has to be accepted, e.g. terms of use
- // `true` or 'true' are valid
- acceptance: function(value, attr, accept, model) {
- if(value !== 'true' && (!_.isBoolean(value) || value === false)) {
- return this.format(defaultMessages.acceptance, this.formatLabel(attr, model));
- }
- },
-
- // Min validator
- // Validates that the value has to be a number and equal to or greater than
- // the min value specified
- min: function(value, attr, minValue, model) {
- if (!isNumber(value) || value < minValue) {
- return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue);
- }
- },
-
- // Max validator
- // Validates that the value has to be a number and equal to or less than
- // the max value specified
- max: function(value, attr, maxValue, model) {
- if (!isNumber(value) || value > maxValue) {
- return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue);
- }
- },
-
- // Range validator
- // Validates that the value has to be a number and equal to or between
- // the two numbers specified
- range: function(value, attr, range, model) {
- if(!isNumber(value) || value < range[0] || value > range[1]) {
- return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]);
- }
- },
-
- // Length validator
- // Validates that the value has to be a string with length equal to
- // the length value specified
- length: function(value, attr, length, model) {
- if (!_.isString(value) || value.length !== length) {
- return this.format(defaultMessages.length, this.formatLabel(attr, model), length);
- }
- },
-
- // Min length validator
- // Validates that the value has to be a string with length equal to or greater than
- // the min length value specified
- minLength: function(value, attr, minLength, model) {
- if (!_.isString(value) || value.length < minLength) {
- return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength);
- }
- },
-
- // Max length validator
- // Validates that the value has to be a string with length equal to or less than
- // the max length value specified
- maxLength: function(value, attr, maxLength, model) {
- if (!_.isString(value) || value.length > maxLength) {
- return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength);
- }
- },
-
- // Range length validator
- // Validates that the value has to be a string and equal to or between
- // the two numbers specified
- rangeLength: function(value, attr, range, model) {
- if (!_.isString(value) || value.length < range[0] || value.length > range[1]) {
- return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]);
- }
- },
-
- // One of validator
- // Validates that the value has to be equal to one of the elements in
- // the specified array. Case sensitive matching
- oneOf: function(value, attr, values, model) {
- if(!_.include(values, value)){
- return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', '));
- }
- },
-
- // Equal to validator
- // Validates that the value has to be equal to the value of the attribute
- // with the name specified
- equalTo: function(value, attr, equalTo, model, computed) {
- if(value !== computed[equalTo]) {
- return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model));
- }
- },
-
- // Pattern validator
- // Validates that the value has to match the pattern specified.
- // Can be a regular expression or the name of one of the built in patterns
- pattern: function(value, attr, pattern, model) {
- if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
- return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
- }
- }
- };
- }());
-
- // Set the correct context for all validators
- // when used from within a method validator
- _.each(defaultValidators, function(validator, key){
- defaultValidators[key] = _.bind(defaultValidators[key], _.extend({}, formatFunctions, defaultValidators));
- });
-
- return Validation;
-}(_));
\ No newline at end of file
diff --git a/client/src/js/vendor/backbone/backbone.babysitter.js b/client/src/js/vendor/backbone/backbone.babysitter.js
deleted file mode 100644
index eeb92a2fd..000000000
--- a/client/src/js/vendor/backbone/backbone.babysitter.js
+++ /dev/null
@@ -1,190 +0,0 @@
-// Backbone.BabySitter
-// -------------------
-// v0.1.4
-//
-// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://github.com/marionettejs/backbone.babysitter
-
-(function(root, factory) {
-
- if (typeof define === 'function' && define.amd) {
- define(['backbone', 'underscore'], function(Backbone, _) {
- return factory(Backbone, _);
- });
- } else if (typeof exports !== 'undefined') {
- var Backbone = require('backbone');
- var _ = require('underscore');
- module.exports = factory(Backbone, _);
- } else {
- factory(root.Backbone, root._);
- }
-
-}(this, function(Backbone, _) {
- 'use strict';
-
- var previousChildViewContainer = Backbone.ChildViewContainer;
-
- // BabySitter.ChildViewContainer
- // -----------------------------
- //
- // Provide a container to store, retrieve and
- // shut down child views.
-
- Backbone.ChildViewContainer = (function (Backbone, _) {
-
- // Container Constructor
- // ---------------------
-
- var Container = function(views){
- this._views = {};
- this._indexByModel = {};
- this._indexByCustom = {};
- this._updateLength();
-
- _.each(views, this.add, this);
- };
-
- // Container Methods
- // -----------------
-
- _.extend(Container.prototype, {
-
- // Add a view to this container. Stores the view
- // by `cid` and makes it searchable by the model
- // cid (and model itself). Optionally specify
- // a custom key to store an retrieve the view.
- add: function(view, customIndex){
- var viewCid = view.cid;
-
- // store the view
- this._views[viewCid] = view;
-
- // index it by model
- if (view.model){
- this._indexByModel[view.model.cid] = viewCid;
- }
-
- // index by custom
- if (customIndex){
- this._indexByCustom[customIndex] = viewCid;
- }
-
- this._updateLength();
- return this;
- },
-
- // Find a view by the model that was attached to
- // it. Uses the model's `cid` to find it.
- findByModel: function(model){
- return this.findByModelCid(model.cid);
- },
-
- // Find a view by the `cid` of the model that was attached to
- // it. Uses the model's `cid` to find the view `cid` and
- // retrieve the view using it.
- findByModelCid: function(modelCid){
- var viewCid = this._indexByModel[modelCid];
- return this.findByCid(viewCid);
- },
-
- // Find a view by a custom indexer.
- findByCustom: function(index){
- var viewCid = this._indexByCustom[index];
- return this.findByCid(viewCid);
- },
-
- // Find by index. This is not guaranteed to be a
- // stable index.
- findByIndex: function(index){
- return _.values(this._views)[index];
- },
-
- // retrieve a view by its `cid` directly
- findByCid: function(cid){
- return this._views[cid];
- },
-
- // Remove a view
- remove: function(view){
- var viewCid = view.cid;
-
- // delete model index
- if (view.model){
- delete this._indexByModel[view.model.cid];
- }
-
- // delete custom index
- _.any(this._indexByCustom, function(cid, key) {
- if (cid === viewCid) {
- delete this._indexByCustom[key];
- return true;
- }
- }, this);
-
- // remove the view from the container
- delete this._views[viewCid];
-
- // update the length
- this._updateLength();
- return this;
- },
-
- // Call a method on every view in the container,
- // passing parameters to the call method one at a
- // time, like `function.call`.
- call: function(method){
- this.apply(method, _.tail(arguments));
- },
-
- // Apply a method on every view in the container,
- // passing parameters to the call method one at a
- // time, like `function.apply`.
- apply: function(method, args){
- _.each(this._views, function(view){
- if (_.isFunction(view[method])){
- view[method].apply(view, args || []);
- }
- });
- },
-
- // Update the `.length` attribute on this container
- _updateLength: function(){
- this.length = _.size(this._views);
- }
- });
-
- // Borrowing this code from Backbone.Collection:
- // http://backbonejs.org/docs/backbone.html#section-106
- //
- // Mix in methods from Underscore, for iteration, and other
- // collection related features.
- var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
- 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
- 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
- 'last', 'without', 'isEmpty', 'pluck'];
-
- _.each(methods, function(method) {
- Container.prototype[method] = function() {
- var views = _.values(this._views);
- var args = [views].concat(_.toArray(arguments));
- return _[method].apply(_, args);
- };
- });
-
- // return the public API
- return Container;
- })(Backbone, _);
-
-
- Backbone.ChildViewContainer.VERSION = '0.1.4';
-
- Backbone.ChildViewContainer.noConflict = function () {
- Backbone.ChildViewContainer = previousChildViewContainer;
- return this;
- };
-
- return Backbone.ChildViewContainer;
-
-}));
diff --git a/client/src/js/vendor/backbone/backbone.js b/client/src/js/vendor/backbone/backbone.js
deleted file mode 100644
index 24a550a0a..000000000
--- a/client/src/js/vendor/backbone/backbone.js
+++ /dev/null
@@ -1,1608 +0,0 @@
-// Backbone.js 1.1.2
-
-// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
-// Backbone may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://backbonejs.org
-
-(function(root, factory) {
-
- // Set up Backbone appropriately for the environment. Start with AMD.
- if (typeof define === 'function' && define.amd) {
- define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
- // Export global even in AMD case in case this script is loaded with
- // others that may still expect a global Backbone.
- root.Backbone = factory(root, exports, _, $);
- });
-
- // Next for Node.js or CommonJS. jQuery may not be needed as a module.
- } else if (typeof exports !== 'undefined') {
- var _ = require('underscore');
- factory(root, exports, _);
-
- // Finally, as a browser global.
- } else {
- root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
- }
-
-}(this, function(root, Backbone, _, $) {
-
- // Initial Setup
- // -------------
-
- // Save the previous value of the `Backbone` variable, so that it can be
- // restored later on, if `noConflict` is used.
- var previousBackbone = root.Backbone;
-
- // Create local references to array methods we'll want to use later.
- var array = [];
- var push = array.push;
- var slice = array.slice;
- var splice = array.splice;
-
- // Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '1.1.2';
-
- // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
- // the `$` variable.
- Backbone.$ = $;
-
- // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
- // to its previous owner. Returns a reference to this Backbone object.
- Backbone.noConflict = function() {
- root.Backbone = previousBackbone;
- return this;
- };
-
- // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
- // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
- // set a `X-Http-Method-Override` header.
- Backbone.emulateHTTP = false;
-
- // Turn on `emulateJSON` to support legacy servers that can't deal with direct
- // `application/json` requests ... will encode the body as
- // `application/x-www-form-urlencoded` instead and will send the model in a
- // form param named `model`.
- Backbone.emulateJSON = false;
-
- // Backbone.Events
- // ---------------
-
- // A module that can be mixed in to *any object* in order to provide it with
- // custom events. You may bind with `on` or remove with `off` callback
- // functions to an event; `trigger`-ing an event fires all callbacks in
- // succession.
- //
- // var object = {};
- // _.extend(object, Backbone.Events);
- // object.on('expand', function(){ alert('expanded'); });
- // object.trigger('expand');
- //
- var Events = Backbone.Events = {
-
- // Bind an event to a `callback` function. Passing `"all"` will bind
- // the callback to all events fired.
- on: function(name, callback, context) {
- if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
- this._events || (this._events = {});
- var events = this._events[name] || (this._events[name] = []);
- events.push({callback: callback, context: context, ctx: context || this});
- return this;
- },
-
- // Bind an event to only be triggered a single time. After the first time
- // the callback is invoked, it will be removed.
- once: function(name, callback, context) {
- if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
- var self = this;
- var once = _.once(function() {
- self.off(name, once);
- callback.apply(this, arguments);
- });
- once._callback = callback;
- return this.on(name, once, context);
- },
-
- // Remove one or many callbacks. If `context` is null, removes all
- // callbacks with that function. If `callback` is null, removes all
- // callbacks for the event. If `name` is null, removes all bound
- // callbacks for all events.
- off: function(name, callback, context) {
- var retain, ev, events, names, i, l, j, k;
- if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
- if (!name && !callback && !context) {
- this._events = void 0;
- return this;
- }
- names = name ? [name] : _.keys(this._events);
- for (i = 0, l = names.length; i < l; i++) {
- name = names[i];
- if (events = this._events[name]) {
- this._events[name] = retain = [];
- if (callback || context) {
- for (j = 0, k = events.length; j < k; j++) {
- ev = events[j];
- if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
- (context && context !== ev.context)) {
- retain.push(ev);
- }
- }
- }
- if (!retain.length) delete this._events[name];
- }
- }
-
- return this;
- },
-
- // Trigger one or many events, firing all bound callbacks. Callbacks are
- // passed the same arguments as `trigger` is, apart from the event name
- // (unless you're listening on `"all"`, which will cause your callback to
- // receive the true name of the event as the first argument).
- trigger: function(name) {
- if (!this._events) return this;
- var args = slice.call(arguments, 1);
- if (!eventsApi(this, 'trigger', name, args)) return this;
- var events = this._events[name];
- var allEvents = this._events.all;
- if (events) triggerEvents(events, args);
- if (allEvents) triggerEvents(allEvents, arguments);
- return this;
- },
-
- // Tell this object to stop listening to either specific events ... or
- // to every object it's currently listening to.
- stopListening: function(obj, name, callback) {
- var listeningTo = this._listeningTo;
- if (!listeningTo) return this;
- var remove = !name && !callback;
- if (!callback && typeof name === 'object') callback = this;
- if (obj) (listeningTo = {})[obj._listenId] = obj;
- for (var id in listeningTo) {
- obj = listeningTo[id];
- obj.off(name, callback, this);
- if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
- }
- return this;
- }
-
- };
-
- // Regular expression used to split event strings.
- var eventSplitter = /\s+/;
-
- // Implement fancy features of the Events API such as multiple event
- // names `"change blur"` and jQuery-style event maps `{change: action}`
- // in terms of the existing API.
- var eventsApi = function(obj, action, name, rest) {
- if (!name) return true;
-
- // Handle event maps.
- if (typeof name === 'object') {
- for (var key in name) {
- obj[action].apply(obj, [key, name[key]].concat(rest));
- }
- return false;
- }
-
- // Handle space separated event names.
- if (eventSplitter.test(name)) {
- var names = name.split(eventSplitter);
- for (var i = 0, l = names.length; i < l; i++) {
- obj[action].apply(obj, [names[i]].concat(rest));
- }
- return false;
- }
-
- return true;
- };
-
- // A difficult-to-believe, but optimized internal dispatch function for
- // triggering events. Tries to keep the usual cases speedy (most internal
- // Backbone events have 3 arguments).
- var triggerEvents = function(events, args) {
- var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
- switch (args.length) {
- case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
- case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
- case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
- case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
- default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
- }
- };
-
- var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
-
- // Inversion-of-control versions of `on` and `once`. Tell *this* object to
- // listen to an event in another object ... keeping track of what it's
- // listening to.
- _.each(listenMethods, function(implementation, method) {
- Events[method] = function(obj, name, callback) {
- var listeningTo = this._listeningTo || (this._listeningTo = {});
- var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
- listeningTo[id] = obj;
- if (!callback && typeof name === 'object') callback = this;
- obj[implementation](name, callback, this);
- return this;
- };
- });
-
- // Aliases for backwards compatibility.
- Events.bind = Events.on;
- Events.unbind = Events.off;
-
- // Allow the `Backbone` object to serve as a global event bus, for folks who
- // want global "pubsub" in a convenient place.
- _.extend(Backbone, Events);
-
- // Backbone.Model
- // --------------
-
- // Backbone **Models** are the basic data object in the framework --
- // frequently representing a row in a table in a database on your server.
- // A discrete chunk of data and a bunch of useful, related methods for
- // performing computations and transformations on that data.
-
- // Create a new model with the specified attributes. A client id (`cid`)
- // is automatically generated and assigned for you.
- var Model = Backbone.Model = function(attributes, options) {
- var attrs = attributes || {};
- options || (options = {});
- this.cid = _.uniqueId('c');
- this.attributes = {};
- if (options.collection) this.collection = options.collection;
- if (options.parse) attrs = this.parse(attrs, options) || {};
- attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
- this.set(attrs, options);
- this.changed = {};
- this.initialize.apply(this, arguments);
- };
-
- // Attach all inheritable methods to the Model prototype.
- _.extend(Model.prototype, Events, {
-
- // A hash of attributes whose current and previous value differ.
- changed: null,
-
- // The value returned during the last failed validation.
- validationError: null,
-
- // The default name for the JSON `id` attribute is `"id"`. MongoDB and
- // CouchDB users may want to set this to `"_id"`.
- idAttribute: 'id',
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // Return a copy of the model's `attributes` object.
- toJSON: function(options) {
- return _.clone(this.attributes);
- },
-
- // Proxy `Backbone.sync` by default -- but override this if you need
- // custom syncing semantics for *this* particular model.
- sync: function() {
- return Backbone.sync.apply(this, arguments);
- },
-
- // Get the value of an attribute.
- get: function(attr) {
- return this.attributes[attr];
- },
-
- // Get the HTML-escaped value of an attribute.
- escape: function(attr) {
- return _.escape(this.get(attr));
- },
-
- // Returns `true` if the attribute contains a value that is not null
- // or undefined.
- has: function(attr) {
- return this.get(attr) != null;
- },
-
- // Set a hash of model attributes on the object, firing `"change"`. This is
- // the core primitive operation of a model, updating the data and notifying
- // anyone who needs to know about the change in state. The heart of the beast.
- set: function(key, val, options) {
- var attr, attrs, unset, changes, silent, changing, prev, current;
- if (key == null) return this;
-
- // Handle both `"key", value` and `{key: value}` -style arguments.
- if (typeof key === 'object') {
- attrs = key;
- options = val;
- } else {
- (attrs = {})[key] = val;
- }
-
- options || (options = {});
-
- // Run validation.
- if (!this._validate(attrs, options)) return false;
-
- // Extract attributes and options.
- unset = options.unset;
- silent = options.silent;
- changes = [];
- changing = this._changing;
- this._changing = true;
-
- if (!changing) {
- this._previousAttributes = _.clone(this.attributes);
- this.changed = {};
- }
- current = this.attributes, prev = this._previousAttributes;
-
- // Check for changes of `id`.
- if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
-
- // For each `set` attribute, update or delete the current value.
- for (attr in attrs) {
- val = attrs[attr];
- if (!_.isEqual(current[attr], val)) changes.push(attr);
- if (!_.isEqual(prev[attr], val)) {
- this.changed[attr] = val;
- } else {
- delete this.changed[attr];
- }
- unset ? delete current[attr] : current[attr] = val;
- }
-
- // Trigger all relevant attribute changes.
- if (!silent) {
- if (changes.length) this._pending = options;
- for (var i = 0, l = changes.length; i < l; i++) {
- this.trigger('change:' + changes[i], this, current[changes[i]], options);
- }
- }
-
- // You might be wondering why there's a `while` loop here. Changes can
- // be recursively nested within `"change"` events.
- if (changing) return this;
- if (!silent) {
- while (this._pending) {
- options = this._pending;
- this._pending = false;
- this.trigger('change', this, options);
- }
- }
- this._pending = false;
- this._changing = false;
- return this;
- },
-
- // Remove an attribute from the model, firing `"change"`. `unset` is a noop
- // if the attribute doesn't exist.
- unset: function(attr, options) {
- return this.set(attr, void 0, _.extend({}, options, {unset: true}));
- },
-
- // Clear all attributes on the model, firing `"change"`.
- clear: function(options) {
- var attrs = {};
- for (var key in this.attributes) attrs[key] = void 0;
- return this.set(attrs, _.extend({}, options, {unset: true}));
- },
-
- // Determine if the model has changed since the last `"change"` event.
- // If you specify an attribute name, determine if that attribute has changed.
- hasChanged: function(attr) {
- if (attr == null) return !_.isEmpty(this.changed);
- return _.has(this.changed, attr);
- },
-
- // Return an object containing all the attributes that have changed, or
- // false if there are no changed attributes. Useful for determining what
- // parts of a view need to be updated and/or what attributes need to be
- // persisted to the server. Unset attributes will be set to undefined.
- // You can also pass an attributes object to diff against the model,
- // determining if there *would be* a change.
- changedAttributes: function(diff) {
- if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
- var val, changed = false;
- var old = this._changing ? this._previousAttributes : this.attributes;
- for (var attr in diff) {
- if (_.isEqual(old[attr], (val = diff[attr]))) continue;
- (changed || (changed = {}))[attr] = val;
- }
- return changed;
- },
-
- // Get the previous value of an attribute, recorded at the time the last
- // `"change"` event was fired.
- previous: function(attr) {
- if (attr == null || !this._previousAttributes) return null;
- return this._previousAttributes[attr];
- },
-
- // Get all of the attributes of the model at the time of the previous
- // `"change"` event.
- previousAttributes: function() {
- return _.clone(this._previousAttributes);
- },
-
- // Fetch the model from the server. If the server's representation of the
- // model differs from its current attributes, they will be overridden,
- // triggering a `"change"` event.
- fetch: function(options) {
- options = options ? _.clone(options) : {};
- if (options.parse === void 0) options.parse = true;
- var model = this;
- var success = options.success;
- options.success = function(resp) {
- if (!model.set(model.parse(resp, options), options)) return false;
- if (success) success(model, resp, options);
- model.trigger('sync', model, resp, options);
- };
- wrapError(this, options);
- return this.sync('read', this, options);
- },
-
- // Set a hash of model attributes, and sync the model to the server.
- // If the server returns an attributes hash that differs, the model's
- // state will be `set` again.
- save: function(key, val, options) {
- var attrs, method, xhr, attributes = this.attributes;
-
- // Handle both `"key", value` and `{key: value}` -style arguments.
- if (key == null || typeof key === 'object') {
- attrs = key;
- options = val;
- } else {
- (attrs = {})[key] = val;
- }
-
- options = _.extend({validate: true}, options);
-
- // If we're not waiting and attributes exist, save acts as
- // `set(attr).save(null, opts)` with validation. Otherwise, check if
- // the model will be valid when the attributes, if any, are set.
- if (attrs && !options.wait) {
- if (!this.set(attrs, options)) return false;
- } else {
- if (!this._validate(attrs, options)) return false;
- }
-
- // Set temporary attributes if `{wait: true}`.
- if (attrs && options.wait) {
- this.attributes = _.extend({}, attributes, attrs);
- }
-
- // After a successful server-side save, the client is (optionally)
- // updated with the server-side state.
- if (options.parse === void 0) options.parse = true;
- var model = this;
- var success = options.success;
- options.success = function(resp) {
- // Ensure attributes are restored during synchronous saves.
- model.attributes = attributes;
- var serverAttrs = model.parse(resp, options);
- if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
- if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
- return false;
- }
- if (success) success(model, resp, options);
- model.trigger('sync', model, resp, options);
- };
- wrapError(this, options);
-
- method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
- if (method === 'patch') options.attrs = attrs;
- xhr = this.sync(method, this, options);
-
- // Restore attributes.
- if (attrs && options.wait) this.attributes = attributes;
-
- return xhr;
- },
-
- // Destroy this model on the server if it was already persisted.
- // Optimistically removes the model from its collection, if it has one.
- // If `wait: true` is passed, waits for the server to respond before removal.
- destroy: function(options) {
- options = options ? _.clone(options) : {};
- var model = this;
- var success = options.success;
-
- var destroy = function() {
- model.trigger('destroy', model, model.collection, options);
- };
-
- options.success = function(resp) {
- if (options.wait || model.isNew()) destroy();
- if (success) success(model, resp, options);
- if (!model.isNew()) model.trigger('sync', model, resp, options);
- };
-
- if (this.isNew()) {
- options.success();
- return false;
- }
- wrapError(this, options);
-
- var xhr = this.sync('delete', this, options);
- if (!options.wait) destroy();
- return xhr;
- },
-
- // Default URL for the model's representation on the server -- if you're
- // using Backbone's restful methods, override this to change the endpoint
- // that will be called.
- url: function() {
- var base =
- _.result(this, 'urlRoot') ||
- _.result(this.collection, 'url') ||
- urlError();
- if (this.isNew()) return base;
- return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
- },
-
- // **parse** converts a response into the hash of attributes to be `set` on
- // the model. The default implementation is just to pass the response along.
- parse: function(resp, options) {
- return resp;
- },
-
- // Create a new model with identical attributes to this one.
- clone: function() {
- return new this.constructor(this.attributes);
- },
-
- // A model is new if it has never been saved to the server, and lacks an id.
- isNew: function() {
- return !this.has(this.idAttribute);
- },
-
- // Check if the model is currently in a valid state.
- isValid: function(options) {
- return this._validate({}, _.extend(options || {}, { validate: true }));
- },
-
- // Run validation against the next complete set of model attributes,
- // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
- _validate: function(attrs, options) {
- if (!options.validate || !this.validate) return true;
- attrs = _.extend({}, this.attributes, attrs);
- var error = this.validationError = this.validate(attrs, options) || null;
- if (!error) return true;
- this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
- return false;
- }
-
- });
-
- // Underscore methods that we want to implement on the Model.
- var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
-
- // Mix in each Underscore method as a proxy to `Model#attributes`.
- _.each(modelMethods, function(method) {
- Model.prototype[method] = function() {
- var args = slice.call(arguments);
- args.unshift(this.attributes);
- return _[method].apply(_, args);
- };
- });
-
- // Backbone.Collection
- // -------------------
-
- // If models tend to represent a single row of data, a Backbone Collection is
- // more analagous to a table full of data ... or a small slice or page of that
- // table, or a collection of rows that belong together for a particular reason
- // -- all of the messages in this particular folder, all of the documents
- // belonging to this particular author, and so on. Collections maintain
- // indexes of their models, both in order, and for lookup by `id`.
-
- // Create a new **Collection**, perhaps to contain a specific type of `model`.
- // If a `comparator` is specified, the Collection will maintain
- // its models in sort order, as they're added and removed.
- var Collection = Backbone.Collection = function(models, options) {
- options || (options = {});
- if (options.model) this.model = options.model;
- if (options.comparator !== void 0) this.comparator = options.comparator;
- this._reset();
- this.initialize.apply(this, arguments);
- if (models) this.reset(models, _.extend({silent: true}, options));
- };
-
- // Default options for `Collection#set`.
- var setOptions = {add: true, remove: true, merge: true};
- var addOptions = {add: true, remove: false};
-
- // Define the Collection's inheritable methods.
- _.extend(Collection.prototype, Events, {
-
- // The default model for a collection is just a **Backbone.Model**.
- // This should be overridden in most cases.
- model: Model,
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // The JSON representation of a Collection is an array of the
- // models' attributes.
- toJSON: function(options) {
- return this.map(function(model){ return model.toJSON(options); });
- },
-
- // Proxy `Backbone.sync` by default.
- sync: function() {
- return Backbone.sync.apply(this, arguments);
- },
-
- // Add a model, or list of models to the set.
- add: function(models, options) {
- return this.set(models, _.extend({merge: false}, options, addOptions));
- },
-
- // Remove a model, or a list of models from the set.
- remove: function(models, options) {
- var singular = !_.isArray(models);
- models = singular ? [models] : _.clone(models);
- options || (options = {});
- var i, l, index, model;
- for (i = 0, l = models.length; i < l; i++) {
- model = models[i] = this.get(models[i]);
- if (!model) continue;
- delete this._byId[model.id];
- delete this._byId[model.cid];
- index = this.indexOf(model);
- this.models.splice(index, 1);
- this.length--;
- if (!options.silent) {
- options.index = index;
- model.trigger('remove', model, this, options);
- }
- this._removeReference(model, options);
- }
- return singular ? models[0] : models;
- },
-
- // Update a collection by `set`-ing a new list of models, adding new ones,
- // removing models that are no longer present, and merging models that
- // already exist in the collection, as necessary. Similar to **Model#set**,
- // the core operation for updating the data contained by the collection.
- set: function(models, options) {
- options = _.defaults({}, options, setOptions);
- if (options.parse) models = this.parse(models, options);
- var singular = !_.isArray(models);
- models = singular ? (models ? [models] : []) : _.clone(models);
- var i, l, id, model, attrs, existing, sort;
- var at = options.at;
- var targetModel = this.model;
- var sortable = this.comparator && (at == null) && options.sort !== false;
- var sortAttr = _.isString(this.comparator) ? this.comparator : null;
- var toAdd = [], toRemove = [], modelMap = {};
- var add = options.add, merge = options.merge, remove = options.remove;
- var order = !sortable && add && remove ? [] : false;
-
- // Turn bare objects into model references, and prevent invalid models
- // from being added.
- for (i = 0, l = models.length; i < l; i++) {
- attrs = models[i] || {};
- if (attrs instanceof Model) {
- id = model = attrs;
- } else {
- id = attrs[targetModel.prototype.idAttribute || 'id'];
- }
-
- // If a duplicate is found, prevent it from being added and
- // optionally merge it into the existing model.
- if (existing = this.get(id)) {
- if (remove) modelMap[existing.cid] = true;
- if (merge) {
- attrs = attrs === model ? model.attributes : attrs;
- if (options.parse) attrs = existing.parse(attrs, options);
- existing.set(attrs, options);
- if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
- }
- models[i] = existing;
-
- // If this is a new, valid model, push it to the `toAdd` list.
- } else if (add) {
- model = models[i] = this._prepareModel(attrs, options);
- if (!model) continue;
- toAdd.push(model);
- this._addReference(model, options);
- }
-
- // Do not add multiple models with the same `id`.
- model = existing || model;
- if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
- modelMap[model.id] = true;
- }
-
- // Remove nonexistent models if appropriate.
- if (remove) {
- for (i = 0, l = this.length; i < l; ++i) {
- if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
- }
- if (toRemove.length) this.remove(toRemove, options);
- }
-
- // See if sorting is needed, update `length` and splice in new models.
- if (toAdd.length || (order && order.length)) {
- if (sortable) sort = true;
- this.length += toAdd.length;
- if (at != null) {
- for (i = 0, l = toAdd.length; i < l; i++) {
- this.models.splice(at + i, 0, toAdd[i]);
- }
- } else {
- if (order) this.models.length = 0;
- var orderedModels = order || toAdd;
- for (i = 0, l = orderedModels.length; i < l; i++) {
- this.models.push(orderedModels[i]);
- }
- }
- }
-
- // Silently sort the collection if appropriate.
- if (sort) this.sort({silent: true});
-
- // Unless silenced, it's time to fire all appropriate add/sort events.
- if (!options.silent) {
- for (i = 0, l = toAdd.length; i < l; i++) {
- (model = toAdd[i]).trigger('add', model, this, options);
- }
- if (sort || (order && order.length)) this.trigger('sort', this, options);
- }
-
- // Return the added (or merged) model (or models).
- return singular ? models[0] : models;
- },
-
- // When you have more items than you want to add or remove individually,
- // you can reset the entire set with a new list of models, without firing
- // any granular `add` or `remove` events. Fires `reset` when finished.
- // Useful for bulk operations and optimizations.
- reset: function(models, options) {
- options || (options = {});
- for (var i = 0, l = this.models.length; i < l; i++) {
- this._removeReference(this.models[i], options);
- }
- options.previousModels = this.models;
- this._reset();
- models = this.add(models, _.extend({silent: true}, options));
- if (!options.silent) this.trigger('reset', this, options);
- return models;
- },
-
- // Add a model to the end of the collection.
- push: function(model, options) {
- return this.add(model, _.extend({at: this.length}, options));
- },
-
- // Remove a model from the end of the collection.
- pop: function(options) {
- var model = this.at(this.length - 1);
- this.remove(model, options);
- return model;
- },
-
- // Add a model to the beginning of the collection.
- unshift: function(model, options) {
- return this.add(model, _.extend({at: 0}, options));
- },
-
- // Remove a model from the beginning of the collection.
- shift: function(options) {
- var model = this.at(0);
- this.remove(model, options);
- return model;
- },
-
- // Slice out a sub-array of models from the collection.
- slice: function() {
- return slice.apply(this.models, arguments);
- },
-
- // Get a model from the set by id.
- get: function(obj) {
- if (obj == null) return void 0;
- return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
- },
-
- // Get the model at the given index.
- at: function(index) {
- return this.models[index];
- },
-
- // Return models with matching attributes. Useful for simple cases of
- // `filter`.
- where: function(attrs, first) {
- if (_.isEmpty(attrs)) return first ? void 0 : [];
- return this[first ? 'find' : 'filter'](function(model) {
- for (var key in attrs) {
- if (attrs[key] !== model.get(key)) return false;
- }
- return true;
- });
- },
-
- // Return the first model with matching attributes. Useful for simple cases
- // of `find`.
- findWhere: function(attrs) {
- return this.where(attrs, true);
- },
-
- // Force the collection to re-sort itself. You don't need to call this under
- // normal circumstances, as the set will maintain sort order as each item
- // is added.
- sort: function(options) {
- if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
- options || (options = {});
-
- // Run sort based on type of `comparator`.
- if (_.isString(this.comparator) || this.comparator.length === 1) {
- this.models = this.sortBy(this.comparator, this);
- } else {
- this.models.sort(_.bind(this.comparator, this));
- }
-
- if (!options.silent) this.trigger('sort', this, options);
- return this;
- },
-
- // Pluck an attribute from each model in the collection.
- pluck: function(attr) {
- return _.invoke(this.models, 'get', attr);
- },
-
- // Fetch the default set of models for this collection, resetting the
- // collection when they arrive. If `reset: true` is passed, the response
- // data will be passed through the `reset` method instead of `set`.
- fetch: function(options) {
- options = options ? _.clone(options) : {};
- if (options.parse === void 0) options.parse = true;
- var success = options.success;
- var collection = this;
- options.success = function(resp) {
- var method = options.reset ? 'reset' : 'set';
- collection[method](resp, options);
- if (success) success(collection, resp, options);
- collection.trigger('sync', collection, resp, options);
- };
- wrapError(this, options);
- return this.sync('read', this, options);
- },
-
- // Create a new instance of a model in this collection. Add the model to the
- // collection immediately, unless `wait: true` is passed, in which case we
- // wait for the server to agree.
- create: function(model, options) {
- options = options ? _.clone(options) : {};
- if (!(model = this._prepareModel(model, options))) return false;
- if (!options.wait) this.add(model, options);
- var collection = this;
- var success = options.success;
- options.success = function(model, resp) {
- if (options.wait) collection.add(model, options);
- if (success) success(model, resp, options);
- };
- model.save(null, options);
- return model;
- },
-
- // **parse** converts a response into a list of models to be added to the
- // collection. The default implementation is just to pass it through.
- parse: function(resp, options) {
- return resp;
- },
-
- // Create a new collection with an identical list of models as this one.
- clone: function() {
- return new this.constructor(this.models);
- },
-
- // Private method to reset all internal state. Called when the collection
- // is first initialized or reset.
- _reset: function() {
- this.length = 0;
- this.models = [];
- this._byId = {};
- },
-
- // Prepare a hash of attributes (or other model) to be added to this
- // collection.
- _prepareModel: function(attrs, options) {
- if (attrs instanceof Model) return attrs;
- options = options ? _.clone(options) : {};
- options.collection = this;
- var model = new this.model(attrs, options);
- if (!model.validationError) return model;
- this.trigger('invalid', this, model.validationError, options);
- return false;
- },
-
- // Internal method to create a model's ties to a collection.
- _addReference: function(model, options) {
- this._byId[model.cid] = model;
- if (model.id != null) this._byId[model.id] = model;
- if (!model.collection) model.collection = this;
- model.on('all', this._onModelEvent, this);
- },
-
- // Internal method to sever a model's ties to a collection.
- _removeReference: function(model, options) {
- if (this === model.collection) delete model.collection;
- model.off('all', this._onModelEvent, this);
- },
-
- // Internal method called every time a model in the set fires an event.
- // Sets need to update their indexes when models change ids. All other
- // events simply proxy through. "add" and "remove" events that originate
- // in other collections are ignored.
- _onModelEvent: function(event, model, collection, options) {
- if ((event === 'add' || event === 'remove') && collection !== this) return;
- if (event === 'destroy') this.remove(model, options);
- if (model && event === 'change:' + model.idAttribute) {
- delete this._byId[model.previous(model.idAttribute)];
- if (model.id != null) this._byId[model.id] = model;
- }
- this.trigger.apply(this, arguments);
- }
-
- });
-
- // Underscore methods that we want to implement on the Collection.
- // 90% of the core usefulness of Backbone Collections is actually implemented
- // right here:
- var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
- 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
- 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
- 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
- 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
- 'lastIndexOf', 'isEmpty', 'chain', 'sample'];
-
- // Mix in each Underscore method as a proxy to `Collection#models`.
- _.each(methods, function(method) {
- Collection.prototype[method] = function() {
- var args = slice.call(arguments);
- args.unshift(this.models);
- return _[method].apply(_, args);
- };
- });
-
- // Underscore methods that take a property name as an argument.
- var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
-
- // Use attributes instead of properties.
- _.each(attributeMethods, function(method) {
- Collection.prototype[method] = function(value, context) {
- var iterator = _.isFunction(value) ? value : function(model) {
- return model.get(value);
- };
- return _[method](this.models, iterator, context);
- };
- });
-
- // Backbone.View
- // -------------
-
- // Backbone Views are almost more convention than they are actual code. A View
- // is simply a JavaScript object that represents a logical chunk of UI in the
- // DOM. This might be a single item, an entire list, a sidebar or panel, or
- // even the surrounding frame which wraps your whole app. Defining a chunk of
- // UI as a **View** allows you to define your DOM events declaratively, without
- // having to worry about render order ... and makes it easy for the view to
- // react to specific changes in the state of your models.
-
- // Creating a Backbone.View creates its initial element outside of the DOM,
- // if an existing element is not provided...
- var View = Backbone.View = function(options) {
- this.cid = _.uniqueId('view');
- options || (options = {});
- _.extend(this, _.pick(options, viewOptions));
- this._ensureElement();
- this.initialize.apply(this, arguments);
- this.delegateEvents();
- };
-
- // Cached regex to split keys for `delegate`.
- var delegateEventSplitter = /^(\S+)\s*(.*)$/;
-
- // List of view options to be merged as properties.
- var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
-
- // Set up all inheritable **Backbone.View** properties and methods.
- _.extend(View.prototype, Events, {
-
- // The default `tagName` of a View's element is `"div"`.
- tagName: 'div',
-
- // jQuery delegate for element lookup, scoped to DOM elements within the
- // current view. This should be preferred to global lookups where possible.
- $: function(selector) {
- return this.$el.find(selector);
- },
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // **render** is the core function that your view should override, in order
- // to populate its element (`this.el`), with the appropriate HTML. The
- // convention is for **render** to always return `this`.
- render: function() {
- return this;
- },
-
- // Remove this view by taking the element out of the DOM, and removing any
- // applicable Backbone.Events listeners.
- remove: function() {
- this.$el.remove();
- this.stopListening();
- return this;
- },
-
- // Change the view's element (`this.el` property), including event
- // re-delegation.
- setElement: function(element, delegate) {
- if (this.$el) this.undelegateEvents();
- this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
- this.el = this.$el[0];
- if (delegate !== false) this.delegateEvents();
- return this;
- },
-
- // Set callbacks, where `this.events` is a hash of
- //
- // *{"event selector": "callback"}*
- //
- // {
- // 'mousedown .title': 'edit',
- // 'click .button': 'save',
- // 'click .open': function(e) { ... }
- // }
- //
- // pairs. Callbacks will be bound to the view, with `this` set properly.
- // Uses event delegation for efficiency.
- // Omitting the selector binds the event to `this.el`.
- // This only works for delegate-able events: not `focus`, `blur`, and
- // not `change`, `submit`, and `reset` in Internet Explorer.
- delegateEvents: function(events) {
- if (!(events || (events = _.result(this, 'events')))) return this;
- this.undelegateEvents();
- for (var key in events) {
- var method = events[key];
- if (!_.isFunction(method)) method = this[events[key]];
- if (!method) continue;
-
- var match = key.match(delegateEventSplitter);
- var eventName = match[1], selector = match[2];
- method = _.bind(method, this);
- eventName += '.delegateEvents' + this.cid;
- if (selector === '') {
- this.$el.on(eventName, method);
- } else {
- this.$el.on(eventName, selector, method);
- }
- }
- return this;
- },
-
- // Clears all callbacks previously bound to the view with `delegateEvents`.
- // You usually don't need to use this, but may wish to if you have multiple
- // Backbone views attached to the same DOM element.
- undelegateEvents: function() {
- this.$el.off('.delegateEvents' + this.cid);
- return this;
- },
-
- // Ensure that the View has a DOM element to render into.
- // If `this.el` is a string, pass it through `$()`, take the first
- // matching element, and re-assign it to `el`. Otherwise, create
- // an element from the `id`, `className` and `tagName` properties.
- _ensureElement: function() {
- if (!this.el) {
- var attrs = _.extend({}, _.result(this, 'attributes'));
- if (this.id) attrs.id = _.result(this, 'id');
- if (this.className) attrs['class'] = _.result(this, 'className');
- var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
- this.setElement($el, false);
- } else {
- this.setElement(_.result(this, 'el'), false);
- }
- }
-
- });
-
- // Backbone.sync
- // -------------
-
- // Override this function to change the manner in which Backbone persists
- // models to the server. You will be passed the type of request, and the
- // model in question. By default, makes a RESTful Ajax request
- // to the model's `url()`. Some possible customizations could be:
- //
- // * Use `setTimeout` to batch rapid-fire updates into a single request.
- // * Send up the models as XML instead of JSON.
- // * Persist models via WebSockets instead of Ajax.
- //
- // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
- // as `POST`, with a `_method` parameter containing the true HTTP method,
- // as well as all requests with the body as `application/x-www-form-urlencoded`
- // instead of `application/json` with the model in a param named `model`.
- // Useful when interfacing with server-side languages like **PHP** that make
- // it difficult to read the body of `PUT` requests.
- Backbone.sync = function(method, model, options) {
- var type = methodMap[method];
-
- // Default options, unless specified.
- _.defaults(options || (options = {}), {
- emulateHTTP: Backbone.emulateHTTP,
- emulateJSON: Backbone.emulateJSON
- });
-
- // Default JSON-request options.
- var params = {type: type, dataType: 'json'};
-
- // Ensure that we have a URL.
- if (!options.url) {
- params.url = _.result(model, 'url') || urlError();
- }
-
- // Ensure that we have the appropriate request data.
- if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
- params.contentType = 'application/json';
- params.data = JSON.stringify(options.attrs || model.toJSON(options));
- }
-
- // For older servers, emulate JSON by encoding the request into an HTML-form.
- if (options.emulateJSON) {
- params.contentType = 'application/x-www-form-urlencoded';
- params.data = params.data ? {model: params.data} : {};
- }
-
- // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
- // And an `X-HTTP-Method-Override` header.
- if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
- params.type = 'POST';
- if (options.emulateJSON) params.data._method = type;
- var beforeSend = options.beforeSend;
- options.beforeSend = function(xhr) {
- xhr.setRequestHeader('X-HTTP-Method-Override', type);
- if (beforeSend) return beforeSend.apply(this, arguments);
- };
- }
-
- // Don't process data on a non-GET request.
- if (params.type !== 'GET' && !options.emulateJSON) {
- params.processData = false;
- }
-
- // If we're sending a `PATCH` request, and we're in an old Internet Explorer
- // that still has ActiveX enabled by default, override jQuery to use that
- // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
- if (params.type === 'PATCH' && noXhrPatch) {
- params.xhr = function() {
- return new ActiveXObject("Microsoft.XMLHTTP");
- };
- }
-
- // Make the request, allowing the user to override any Ajax options.
- var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
- model.trigger('request', model, xhr, options);
- return xhr;
- };
-
- var noXhrPatch =
- typeof window !== 'undefined' && !!window.ActiveXObject &&
- !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
-
- // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
- var methodMap = {
- 'create': 'POST',
- 'update': 'PUT',
- 'patch': 'PATCH',
- 'delete': 'DELETE',
- 'read': 'GET'
- };
-
- // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
- // Override this if you'd like to use a different library.
- Backbone.ajax = function() {
- return Backbone.$.ajax.apply(Backbone.$, arguments);
- };
-
- // Backbone.Router
- // ---------------
-
- // Routers map faux-URLs to actions, and fire events when routes are
- // matched. Creating a new one sets its `routes` hash, if not set statically.
- var Router = Backbone.Router = function(options) {
- options || (options = {});
- if (options.routes) this.routes = options.routes;
- this._bindRoutes();
- this.initialize.apply(this, arguments);
- };
-
- // Cached regular expressions for matching named param parts and splatted
- // parts of route strings.
- var optionalParam = /\((.*?)\)/g;
- var namedParam = /(\(\?)?:\w+/g;
- var splatParam = /\*\w+/g;
- var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
-
- // Set up all inheritable **Backbone.Router** properties and methods.
- _.extend(Router.prototype, Events, {
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // Manually bind a single named route to a callback. For example:
- //
- // this.route('search/:query/p:num', 'search', function(query, num) {
- // ...
- // });
- //
- route: function(route, name, callback) {
- if (!_.isRegExp(route)) route = this._routeToRegExp(route);
- if (_.isFunction(name)) {
- callback = name;
- name = '';
- }
- if (!callback) callback = this[name];
- var router = this;
- Backbone.history.route(route, function(fragment) {
- var args = router._extractParameters(route, fragment);
- router.execute(callback, args);
- router.trigger.apply(router, ['route:' + name].concat(args));
- router.trigger('route', name, args);
- Backbone.history.trigger('route', router, name, args);
- });
- return this;
- },
-
- // Execute a route handler with the provided parameters. This is an
- // excellent place to do pre-route setup or post-route cleanup.
- execute: function(callback, args) {
- if (callback) callback.apply(this, args);
- },
-
- // Simple proxy to `Backbone.history` to save a fragment into the history.
- navigate: function(fragment, options) {
- Backbone.history.navigate(fragment, options);
- return this;
- },
-
- // Bind all defined routes to `Backbone.history`. We have to reverse the
- // order of the routes here to support behavior where the most general
- // routes can be defined at the bottom of the route map.
- _bindRoutes: function() {
- if (!this.routes) return;
- this.routes = _.result(this, 'routes');
- var route, routes = _.keys(this.routes);
- while ((route = routes.pop()) != null) {
- this.route(route, this.routes[route]);
- }
- },
-
- // Convert a route string into a regular expression, suitable for matching
- // against the current location hash.
- _routeToRegExp: function(route) {
- route = route.replace(escapeRegExp, '\\$&')
- .replace(optionalParam, '(?:$1)?')
- .replace(namedParam, function(match, optional) {
- return optional ? match : '([^/?]+)';
- })
- .replace(splatParam, '([^?]*?)');
- return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
- },
-
- // Given a route, and a URL fragment that it matches, return the array of
- // extracted decoded parameters. Empty or unmatched parameters will be
- // treated as `null` to normalize cross-browser behavior.
- _extractParameters: function(route, fragment) {
- var params = route.exec(fragment).slice(1);
- return _.map(params, function(param, i) {
- // Don't decode the search params.
- if (i === params.length - 1) return param || null;
- return param ? decodeURIComponent(param) : null;
- });
- }
-
- });
-
- // Backbone.History
- // ----------------
-
- // Handles cross-browser history management, based on either
- // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
- // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
- // and URL fragments. If the browser supports neither (old IE, natch),
- // falls back to polling.
- var History = Backbone.History = function() {
- this.handlers = [];
- _.bindAll(this, 'checkUrl');
-
- // Ensure that `History` can be used outside of the browser.
- if (typeof window !== 'undefined') {
- this.location = window.location;
- this.history = window.history;
- }
- };
-
- // Cached regex for stripping a leading hash/slash and trailing space.
- var routeStripper = /^[#\/]|\s+$/g;
-
- // Cached regex for stripping leading and trailing slashes.
- var rootStripper = /^\/+|\/+$/g;
-
- // Cached regex for detecting MSIE.
- var isExplorer = /msie [\w.]+/;
-
- // Cached regex for removing a trailing slash.
- var trailingSlash = /\/$/;
-
- // Cached regex for stripping urls of hash.
- var pathStripper = /#.*$/;
-
- // Has the history handling already been started?
- History.started = false;
-
- // Set up all inheritable **Backbone.History** properties and methods.
- _.extend(History.prototype, Events, {
-
- // The default interval to poll for hash changes, if necessary, is
- // twenty times a second.
- interval: 50,
-
- // Are we at the app root?
- atRoot: function() {
- return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
- },
-
- // Gets the true hash value. Cannot use location.hash directly due to bug
- // in Firefox where location.hash will always be decoded.
- getHash: function(window) {
- var match = (window || this).location.href.match(/#(.*)$/);
- return match ? match[1] : '';
- },
-
- // Get the cross-browser normalized URL fragment, either from the URL,
- // the hash, or the override.
- getFragment: function(fragment, forcePushState) {
- if (fragment == null) {
- if (this._hasPushState || !this._wantsHashChange || forcePushState) {
- fragment = decodeURI(this.location.pathname + this.location.search);
- var root = this.root.replace(trailingSlash, '');
- if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
- } else {
- fragment = this.getHash();
- }
- }
- return fragment.replace(routeStripper, '');
- },
-
- // Start the hash change handling, returning `true` if the current URL matches
- // an existing route, and `false` otherwise.
- start: function(options) {
- if (History.started) throw new Error("Backbone.history has already been started");
- History.started = true;
-
- // Figure out the initial configuration. Do we need an iframe?
- // Is pushState desired ... is it available?
- this.options = _.extend({root: '/'}, this.options, options);
- this.root = this.options.root;
- this._wantsHashChange = this.options.hashChange !== false;
- this._wantsPushState = !!this.options.pushState;
- this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
- var fragment = this.getFragment();
- var docMode = document.documentMode;
- var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
-
- // Normalize root to always include a leading and trailing slash.
- this.root = ('/' + this.root + '/').replace(rootStripper, '/');
-
- if (oldIE && this._wantsHashChange) {
- var frame = Backbone.$('