From b83d6ba2ffc446db49823fc3aeb53a35bb75afa8 Mon Sep 17 00:00:00 2001 From: HelloZeroNet Date: Sun, 16 Aug 2015 11:51:00 +0200 Subject: [PATCH] Version 0.3.2, rev351, Sidebar to display site infos an modify settings, Per-site upload/download bytes statistics, Deny different origin media requests, Allow 10sec to finish query modifications, Websocket display errors to client instead of disconnecting, Allow specify notification id to server-side messages, Track every command response time --- README.md | 13 +- plugins/Sidebar/SidebarPlugin.py | 407 ++++ plugins/Sidebar/__init__.py | 1 + plugins/Sidebar/maxminddb/__init__.py | 46 + plugins/Sidebar/maxminddb/compat.py | 28 + plugins/Sidebar/maxminddb/const.py | 7 + plugins/Sidebar/maxminddb/decoder.py | 173 ++ plugins/Sidebar/maxminddb/errors.py | 11 + .../Sidebar/maxminddb/extension/maxminddb.c | 570 +++++ plugins/Sidebar/maxminddb/file.py | 65 + plugins/Sidebar/maxminddb/ipaddr.py | 1897 +++++++++++++++++ plugins/Sidebar/maxminddb/reader.py | 221 ++ plugins/Sidebar/media-globe/Detector.js | 60 + plugins/Sidebar/media-globe/Tween.js | 12 + plugins/Sidebar/media-globe/all.js | 1333 ++++++++++++ plugins/Sidebar/media-globe/globe.js | 424 ++++ plugins/Sidebar/media-globe/three.min.js | 814 +++++++ plugins/Sidebar/media-globe/world.jpg | Bin 0 -> 94795 bytes plugins/Sidebar/media/Class.coffee | 23 + plugins/Sidebar/media/Scrollable.js | 89 + plugins/Sidebar/media/Scrollbable.css | 44 + plugins/Sidebar/media/Sidebar.coffee | 318 +++ plugins/Sidebar/media/Sidebar.css | 96 + plugins/Sidebar/media/all.css | 150 ++ plugins/Sidebar/media/all.js | 882 ++++++++ plugins/Sidebar/media/morphdom.js | 340 +++ plugins/Stats/StatsPlugin.py | 4 +- plugins/Zeroname/UiRequestPlugin.py | 3 + src/Config.py | 4 +- src/Connection/Connection.py | 3 + src/Db/Db.py | 4 +- src/File/FileRequest.py | 21 +- src/Peer/Peer.py | 2 + src/Site/Site.py | 13 +- src/Site/SiteStorage.py | 5 + src/Ui/UiWebsocket.py | 24 +- src/Ui/media/Wrapper.coffee | 8 +- src/Ui/media/Wrapper.css | 6 +- src/Ui/media/all.css | 6 +- src/Ui/media/all.js | 12 +- src/Ui/media/img/loading-circle.gif | Bin 0 -> 2346 bytes src/Ui/media/img/loading.gif | Bin 0 -> 723 bytes src/util/RateLimit.py | 4 +- 43 files changed, 8104 insertions(+), 39 deletions(-) create mode 100644 plugins/Sidebar/SidebarPlugin.py create mode 100644 plugins/Sidebar/__init__.py create mode 100644 plugins/Sidebar/maxminddb/__init__.py create mode 100644 plugins/Sidebar/maxminddb/compat.py create mode 100644 plugins/Sidebar/maxminddb/const.py create mode 100644 plugins/Sidebar/maxminddb/decoder.py create mode 100644 plugins/Sidebar/maxminddb/errors.py create mode 100644 plugins/Sidebar/maxminddb/extension/maxminddb.c create mode 100644 plugins/Sidebar/maxminddb/file.py create mode 100644 plugins/Sidebar/maxminddb/ipaddr.py create mode 100644 plugins/Sidebar/maxminddb/reader.py create mode 100644 plugins/Sidebar/media-globe/Detector.js create mode 100644 plugins/Sidebar/media-globe/Tween.js create mode 100644 plugins/Sidebar/media-globe/all.js create mode 100644 plugins/Sidebar/media-globe/globe.js create mode 100644 plugins/Sidebar/media-globe/three.min.js create mode 100644 plugins/Sidebar/media-globe/world.jpg create mode 100644 plugins/Sidebar/media/Class.coffee create mode 100644 plugins/Sidebar/media/Scrollable.js create mode 100644 plugins/Sidebar/media/Scrollbable.css create mode 100644 plugins/Sidebar/media/Sidebar.coffee create mode 100644 plugins/Sidebar/media/Sidebar.css create mode 100644 plugins/Sidebar/media/all.css create mode 100644 plugins/Sidebar/media/all.js create mode 100644 plugins/Sidebar/media/morphdom.js create mode 100644 src/Ui/media/img/loading-circle.gif create mode 100644 src/Ui/media/img/loading.gif diff --git a/README.md b/README.md index fc8eee00..cc9095f1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network - http:// * Real-time updated sites * Namecoin .bit domains support * Easy to setup: unpack & run - * Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) + * Clone websites in one click + * Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) based authorization: Your account is protected by same cryptography as your Bitcoin wallet * Built-in SQL server with P2P data synchronization: Allows easier site development and faster page load times * Tor network support @@ -26,12 +27,12 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network - http:// * Automatic, uPnP port opening * Plugin for multiuser (openproxy) support * Works with any browser/OS - + ## How does it work? * After starting `zeronet.py` you will be able to visit zeronet sites using - `http://127.0.0.1:43110/{zeronet_address}` (eg. + `http://127.0.0.1:43110/{zeronet_address}` (eg. `http://127.0.0.1:43110/1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr`). * When you visit a new zeronet site, it tries to find peers using the BitTorrent network so it can download the site files (html, css, js...) from them. @@ -82,7 +83,7 @@ It downloads the latest version of ZeroNet then starts it automatically. #### Debian * `sudo apt-get update` -* `sudo apt-get install msgpack-python python-gevent` +* `sudo apt-get install msgpack-python python-gevent` * `wget https://github.com/HelloZeroNet/ZeroNet/archive/master.tar.gz` * `tar xvpfz master.tar.gz` * `cd ZeroNet-master` @@ -91,7 +92,7 @@ It downloads the latest version of ZeroNet then starts it automatically. #### Other Linux or without root access * Check your python version using `python --version` if the returned version is not `Python 2.7.X` then try `python2` or `python2.7` command and use it from now -* `wget https://bootstrap.pypa.io/get-pip.py` +* `wget https://bootstrap.pypa.io/get-pip.py` * `python get-pip.py --user gevent msgpack-python` * Start with `python zeronet.py` @@ -101,7 +102,7 @@ It downloads the latest version of ZeroNet then starts it automatically. * `brew install python` * `pip install gevent msgpack-python` * [Download](https://github.com/HelloZeroNet/ZeroNet/archive/master.zip), Unpack, run `python zeronet.py` - + ### Vagrant * `vagrant up` diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py new file mode 100644 index 00000000..bde16359 --- /dev/null +++ b/plugins/Sidebar/SidebarPlugin.py @@ -0,0 +1,407 @@ +import re +import os +import cgi +import sys +import math +import time +try: + import cStringIO as StringIO +except: + import StringIO + + +from Config import config +from Plugin import PluginManager +from Debug import Debug + +plugin_dir = "plugins/Sidebar" +media_dir = plugin_dir + "/media" +sys.path.append(plugin_dir) # To able to load geoip lib + +loc_cache = {} + + +@PluginManager.registerTo("UiRequest") +class UiRequestPlugin(object): + # Inject our resources to end of original file streams + def actionUiMedia(self, path): + if path == "/uimedia/all.js" or path == "/uimedia/all.css": + # First yield the original file and header + body_generator = super(UiRequestPlugin, self).actionUiMedia(path) + for part in body_generator: + yield part + + # Append our media file to the end + ext = re.match(".*(js|css)$", path).group(1) + plugin_media_file = "%s/all.%s" % (media_dir, ext) + if config.debug: + # If debugging merge *.css to all.css and *.js to all.js + from Debug import DebugMedia + DebugMedia.merge(plugin_media_file) + for part in self.actionFile(plugin_media_file, send_header=False): + yield part + elif path.startswith("/uimedia/globe/"): # Serve WebGL globe files + file_name = re.match(".*/(.*)", path).group(1) + plugin_media_file = "%s-globe/%s" % (media_dir, file_name) + if config.debug and path.endswith("all.js"): + # If debugging merge *.css to all.css and *.js to all.js + from Debug import DebugMedia + DebugMedia.merge(plugin_media_file) + for part in self.actionFile(plugin_media_file): + yield part + else: + for part in super(UiRequestPlugin, self).actionUiMedia(path): + yield part + + +@PluginManager.registerTo("UiWebsocket") +class UiWebsocketPlugin(object): + + def sidebarRenderPeerStats(self, body, site): + connected = len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]) + connectable = len([peer_id for peer_id in site.peers.keys() if not peer_id.endswith(":0")]) + peers_total = len(site.peers) + if peers_total: + percent_connected = float(connected) / peers_total + percent_connectable = float(connectable) / peers_total + else: + percent_connectable = percent_connected = 0 + body.append(""" +
  • + + + +
  • + """.format(**locals())) + + def sidebarRenderTransferStats(self, body, site): + recv = float(site.settings.get("bytes_recv", 0)) / 1024 / 1024 + sent = float(site.settings.get("bytes_sent", 0)) / 1024 / 1024 + transfer_total = recv + sent + if transfer_total: + percent_recv = recv / transfer_total + percent_sent = sent / transfer_total + else: + percent_recv = 0.5 + percent_sent = 0.5 + body.append(""" +
  • + + + +
  • + """.format(**locals())) + + def sidebarRenderFileStats(self, body, site): + body.append("
  • ") + + def getFreeSpace(self): + free_space = 0 + if "statvfs" in dir(os): # Unix + statvfs = os.statvfs(config.data_dir) + free_space = statvfs.f_frsize * statvfs.f_bavail + else: # Windows + try: + import ctypes + free_space_pointer = ctypes.c_ulonglong(0) + ctypes.windll.kernel32.GetDiskFreeSpaceExW( + ctypes.c_wchar_p(config.data_dir), None, None, ctypes.pointer(free_space_pointer) + ) + free_space = free_space_pointer.value + except Exception, err: + self.log.debug("GetFreeSpace error: %s" % err) + return free_space + + def sidebarRenderSizeLimit(self, body, site): + free_space = self.getFreeSpace() / 1024 / 1024 + size = float(site.settings["size"]) / 1024 / 1024 + size_limit = site.getSizeLimit() + percent_used = size / size_limit + body.append(""" +
  • + + MB + Set +
  • + """.format(**locals())) + + def sidebarRenderDbOptions(self, body, site): + if not site.storage.db: + return False + + inner_path = site.storage.getInnerPath(site.storage.db.db_path) + size = float(site.storage.getSize(inner_path)) / 1024 + body.append(""" +
  • + + + +
  • + """.format(**locals())) + + def sidebarRenderIdentity(self, body, site): + auth_address = self.user.getAuthAddress(self.site.address) + body.append(""" +
  • + + {auth_address} + Change +
  • + """.format(**locals())) + + def sidebarRenderOwnedCheckbox(self, body, site): + if self.site.settings["own"]: + checked = "checked='checked'" + else: + checked = "" + + body.append(""" +

    Owned site settings

    +
    + """.format(**locals())) + + def sidebarRenderOwnSettings(self, body, site): + title = cgi.escape(site.content_manager.contents["content.json"]["title"], True) + description = cgi.escape(site.content_manager.contents["content.json"]["description"], True) + privatekey = cgi.escape(self.user.getSiteData(site.address, create=False).get("privatekey", "")) + + body.append(""" +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + Save site settings +
  • + """.format(**locals())) + + def sidebarRenderContents(self, body, site): + body.append(""" +
  • + + + › + Sign + Publish +
  • + """) + + def actionSidebarGetHtmlTag(self, to): + site = self.site + + body = [] + + body.append("
    ") + body.append("

    %s

    " % site.content_manager.contents["content.json"]["title"]) + + body.append("
    ") + + body.append("") + body.append("
    ") + + self.response(to, "".join(body)) + + def downloadGeoLiteDb(self, db_path): + import urllib + import gzip + import shutil + + self.log.info("Downloading GeoLite2 City database...") + self.cmd("notification", ["geolite-info", "Downloading GeoLite2 City database (one time only, ~15MB)...", 0]) + try: + # Download + file = urllib.urlopen("http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz") + data = StringIO.StringIO() + while True: + buff = file.read(1024 * 16) + if not buff: + break + data.write(buff) + self.log.info("GeoLite2 City database downloaded (%s bytes), unpacking..." % data.tell()) + data.seek(0) + + # Unpack + with gzip.GzipFile(fileobj=data) as gzip_file: + shutil.copyfileobj(gzip_file, open(db_path, "wb")) + + self.cmd("notification", ["geolite-done", "GeoLite2 City database downloaded!", 5000]) + time.sleep(2) # Wait for notify animation + except Exception, err: + self.cmd("notification", ["geolite-error", "GeoLite2 City database download error: %s!" % err, 0]) + raise err + + def actionSidebarGetPeers(self, to): + permissions = self.getPermissions(to) + if "ADMIN" not in permissions: + return self.response(to, "You don't have permission to run this command") + try: + import maxminddb + db_path = config.data_dir + '/GeoLite2-City.mmdb' + if not os.path.isfile(db_path): + self.downloadGeoLiteDb(db_path) + geodb = maxminddb.open_database(db_path) + + peers = self.site.peers.values() + # Find avg ping + ping_times = [ + peer.connection.last_ping_delay + for peer in peers + if peer.connection and peer.connection.last_ping_delay and peer.connection.last_ping_delay + ] + if ping_times: + ping_avg = sum(ping_times) / float(len(ping_times)) + else: + ping_avg = 0 + # Place bars + globe_data = [] + placed = {} # Already placed bars here + for peer in peers: + # Height of bar + if peer.connection and peer.connection.last_ping_delay: + ping = min(0.20, math.log(1 + peer.connection.last_ping_delay / ping_avg, 300)) + else: + ping = -0.03 + + # Query and cache location + if peer.ip in loc_cache: + loc = loc_cache[peer.ip] + else: + loc = geodb.get(peer.ip) + loc_cache[peer.ip] = loc + if not loc: + continue + + # Create position array + lat, lon = (loc["location"]["latitude"], loc["location"]["longitude"]) + latlon = "%s,%s" % (lat, lon) + if latlon in placed: # Dont place more than 1 bar to same place, fake repos using ip address last two part + lat += float(128 - int(peer.ip.split(".")[-2])) / 50 + lon += float(128 - int(peer.ip.split(".")[-1])) / 50 + latlon = "%s,%s" % (lat, lon) + placed[latlon] = True + + globe_data += (lat, lon, ping) + # Append myself + loc = geodb.get(config.ip_external) + if loc: + lat, lon = (loc["location"]["latitude"], loc["location"]["longitude"]) + globe_data += (lat, lon, -0.135) + + self.response(to, globe_data) + except Exception, err: + self.log.debug("sidebarGetPeers error: %s" % Debug.formatException(err)) + self.response(to, {"error": err}) + + def actionSiteSetOwned(self, to, owned): + permissions = self.getPermissions(to) + if "ADMIN" not in permissions: + return self.response(to, "You don't have permission to run this command") + self.site.settings["own"] = bool(owned) diff --git a/plugins/Sidebar/__init__.py b/plugins/Sidebar/__init__.py new file mode 100644 index 00000000..8b61cb4a --- /dev/null +++ b/plugins/Sidebar/__init__.py @@ -0,0 +1 @@ +import SidebarPlugin \ No newline at end of file diff --git a/plugins/Sidebar/maxminddb/__init__.py b/plugins/Sidebar/maxminddb/__init__.py new file mode 100644 index 00000000..fc28186b --- /dev/null +++ b/plugins/Sidebar/maxminddb/__init__.py @@ -0,0 +1,46 @@ +# pylint:disable=C0111 +import os + +import maxminddb.reader + +try: + import maxminddb.extension +except ImportError: + maxminddb.extension = None + +from maxminddb.const import (MODE_AUTO, MODE_MMAP, MODE_MMAP_EXT, MODE_FILE, + MODE_MEMORY) +from maxminddb.decoder import InvalidDatabaseError + + +def open_database(database, mode=MODE_AUTO): + """Open a Maxmind DB database + + Arguments: + database -- A path to a valid MaxMind DB file such as a GeoIP2 + database file. + mode -- mode to open the database with. Valid mode are: + * MODE_MMAP_EXT - use the C extension with memory map. + * MODE_MMAP - read from memory map. Pure Python. + * MODE_FILE - read database as standard file. Pure Python. + * MODE_MEMORY - load database into memory. Pure Python. + * MODE_AUTO - tries MODE_MMAP_EXT, MODE_MMAP, MODE_FILE in that + order. Default mode. + """ + if (mode == MODE_AUTO and maxminddb.extension and + hasattr(maxminddb.extension, 'Reader')) or mode == MODE_MMAP_EXT: + return maxminddb.extension.Reader(database) + elif mode in (MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY): + return maxminddb.reader.Reader(database, mode) + raise ValueError('Unsupported open mode: {0}'.format(mode)) + + +def Reader(database): # pylint: disable=invalid-name + """This exists for backwards compatibility. Use open_database instead""" + return open_database(database) + +__title__ = 'maxminddb' +__version__ = '1.2.0' +__author__ = 'Gregory Oschwald' +__license__ = 'Apache License, Version 2.0' +__copyright__ = 'Copyright 2014 Maxmind, Inc.' diff --git a/plugins/Sidebar/maxminddb/compat.py b/plugins/Sidebar/maxminddb/compat.py new file mode 100644 index 00000000..14c98832 --- /dev/null +++ b/plugins/Sidebar/maxminddb/compat.py @@ -0,0 +1,28 @@ +import sys + +# pylint: skip-file + +if sys.version_info[0] == 2: + import ipaddr as ipaddress # pylint:disable=F0401 + ipaddress.ip_address = ipaddress.IPAddress + + int_from_byte = ord + + FileNotFoundError = IOError + + def int_from_bytes(b): + if b: + return int(b.encode("hex"), 16) + return 0 + + byte_from_int = chr +else: + import ipaddress # pylint:disable=F0401 + + int_from_byte = lambda x: x + + FileNotFoundError = FileNotFoundError + + int_from_bytes = lambda x: int.from_bytes(x, 'big') + + byte_from_int = lambda x: bytes([x]) diff --git a/plugins/Sidebar/maxminddb/const.py b/plugins/Sidebar/maxminddb/const.py new file mode 100644 index 00000000..59ea84b6 --- /dev/null +++ b/plugins/Sidebar/maxminddb/const.py @@ -0,0 +1,7 @@ +"""Constants used in the API""" + +MODE_AUTO = 0 +MODE_MMAP_EXT = 1 +MODE_MMAP = 2 +MODE_FILE = 4 +MODE_MEMORY = 8 diff --git a/plugins/Sidebar/maxminddb/decoder.py b/plugins/Sidebar/maxminddb/decoder.py new file mode 100644 index 00000000..1b8f0711 --- /dev/null +++ b/plugins/Sidebar/maxminddb/decoder.py @@ -0,0 +1,173 @@ +""" +maxminddb.decoder +~~~~~~~~~~~~~~~~~ + +This package contains code for decoding the MaxMind DB data section. + +""" +from __future__ import unicode_literals + +import struct + +from maxminddb.compat import byte_from_int, int_from_bytes +from maxminddb.errors import InvalidDatabaseError + + +class Decoder(object): # pylint: disable=too-few-public-methods + + """Decoder for the data section of the MaxMind DB""" + + def __init__(self, database_buffer, pointer_base=0, pointer_test=False): + """Created a Decoder for a MaxMind DB + + Arguments: + database_buffer -- an mmap'd MaxMind DB file. + pointer_base -- the base number to use when decoding a pointer + pointer_test -- used for internal unit testing of pointer code + """ + self._pointer_test = pointer_test + self._buffer = database_buffer + self._pointer_base = pointer_base + + def _decode_array(self, size, offset): + array = [] + for _ in range(size): + (value, offset) = self.decode(offset) + array.append(value) + return array, offset + + def _decode_boolean(self, size, offset): + return size != 0, offset + + def _decode_bytes(self, size, offset): + new_offset = offset + size + return self._buffer[offset:new_offset], new_offset + + # pylint: disable=no-self-argument + # |-> I am open to better ways of doing this as long as it doesn't involve + # lots of code duplication. + def _decode_packed_type(type_code, type_size, pad=False): + # pylint: disable=protected-access, missing-docstring + def unpack_type(self, size, offset): + if not pad: + self._verify_size(size, type_size) + new_offset = offset + type_size + packed_bytes = self._buffer[offset:new_offset] + if pad: + packed_bytes = packed_bytes.rjust(type_size, b'\x00') + (value,) = struct.unpack(type_code, packed_bytes) + return value, new_offset + return unpack_type + + def _decode_map(self, size, offset): + container = {} + for _ in range(size): + (key, offset) = self.decode(offset) + (value, offset) = self.decode(offset) + container[key] = value + return container, offset + + _pointer_value_offset = { + 1: 0, + 2: 2048, + 3: 526336, + 4: 0, + } + + def _decode_pointer(self, size, offset): + pointer_size = ((size >> 3) & 0x3) + 1 + new_offset = offset + pointer_size + pointer_bytes = self._buffer[offset:new_offset] + packed = pointer_bytes if pointer_size == 4 else struct.pack( + b'!c', byte_from_int(size & 0x7)) + pointer_bytes + unpacked = int_from_bytes(packed) + pointer = unpacked + self._pointer_base + \ + self._pointer_value_offset[pointer_size] + if self._pointer_test: + return pointer, new_offset + (value, _) = self.decode(pointer) + return value, new_offset + + def _decode_uint(self, size, offset): + new_offset = offset + size + uint_bytes = self._buffer[offset:new_offset] + return int_from_bytes(uint_bytes), new_offset + + def _decode_utf8_string(self, size, offset): + new_offset = offset + size + return self._buffer[offset:new_offset].decode('utf-8'), new_offset + + _type_decoder = { + 1: _decode_pointer, + 2: _decode_utf8_string, + 3: _decode_packed_type(b'!d', 8), # double, + 4: _decode_bytes, + 5: _decode_uint, # uint16 + 6: _decode_uint, # uint32 + 7: _decode_map, + 8: _decode_packed_type(b'!i', 4, pad=True), # int32 + 9: _decode_uint, # uint64 + 10: _decode_uint, # uint128 + 11: _decode_array, + 14: _decode_boolean, + 15: _decode_packed_type(b'!f', 4), # float, + } + + def decode(self, offset): + """Decode a section of the data section starting at offset + + Arguments: + offset -- the location of the data structure to decode + """ + new_offset = offset + 1 + (ctrl_byte,) = struct.unpack(b'!B', self._buffer[offset:new_offset]) + type_num = ctrl_byte >> 5 + # Extended type + if not type_num: + (type_num, new_offset) = self._read_extended(new_offset) + + if not type_num in self._type_decoder: + raise InvalidDatabaseError('Unexpected type number ({type}) ' + 'encountered'.format(type=type_num)) + + (size, new_offset) = self._size_from_ctrl_byte( + ctrl_byte, new_offset, type_num) + return self._type_decoder[type_num](self, size, new_offset) + + def _read_extended(self, offset): + (next_byte,) = struct.unpack(b'!B', self._buffer[offset:offset + 1]) + type_num = next_byte + 7 + if type_num < 7: + raise InvalidDatabaseError( + 'Something went horribly wrong in the decoder. An ' + 'extended type resolved to a type number < 8 ' + '({type})'.format(type=type_num)) + return type_num, offset + 1 + + def _verify_size(self, expected, actual): + if expected != actual: + raise InvalidDatabaseError( + 'The MaxMind DB file\'s data section contains bad data ' + '(unknown data type or corrupt data)' + ) + + def _size_from_ctrl_byte(self, ctrl_byte, offset, type_num): + size = ctrl_byte & 0x1f + if type_num == 1: + return size, offset + bytes_to_read = 0 if size < 29 else size - 28 + + new_offset = offset + bytes_to_read + size_bytes = self._buffer[offset:new_offset] + + # Using unpack rather than int_from_bytes as it is about 200 lookups + # per second faster here. + if size == 29: + size = 29 + struct.unpack(b'!B', size_bytes)[0] + elif size == 30: + size = 285 + struct.unpack(b'!H', size_bytes)[0] + elif size > 30: + size = struct.unpack( + b'!I', size_bytes.rjust(4, b'\x00'))[0] + 65821 + + return size, new_offset diff --git a/plugins/Sidebar/maxminddb/errors.py b/plugins/Sidebar/maxminddb/errors.py new file mode 100644 index 00000000..f04ff028 --- /dev/null +++ b/plugins/Sidebar/maxminddb/errors.py @@ -0,0 +1,11 @@ +""" +maxminddb.errors +~~~~~~~~~~~~~~~~ + +This module contains custom errors for the MaxMind DB reader +""" + + +class InvalidDatabaseError(RuntimeError): + + """This error is thrown when unexpected data is found in the database.""" diff --git a/plugins/Sidebar/maxminddb/extension/maxminddb.c b/plugins/Sidebar/maxminddb/extension/maxminddb.c new file mode 100644 index 00000000..9e4d45e2 --- /dev/null +++ b/plugins/Sidebar/maxminddb/extension/maxminddb.c @@ -0,0 +1,570 @@ +#include +#include +#include "structmember.h" + +#define __STDC_FORMAT_MACROS +#include + +static PyTypeObject Reader_Type; +static PyTypeObject Metadata_Type; +static PyObject *MaxMindDB_error; + +typedef struct { + PyObject_HEAD /* no semicolon */ + MMDB_s *mmdb; +} Reader_obj; + +typedef struct { + PyObject_HEAD /* no semicolon */ + PyObject *binary_format_major_version; + PyObject *binary_format_minor_version; + PyObject *build_epoch; + PyObject *database_type; + PyObject *description; + PyObject *ip_version; + PyObject *languages; + PyObject *node_count; + PyObject *record_size; +} Metadata_obj; + +static PyObject *from_entry_data_list(MMDB_entry_data_list_s **entry_data_list); +static PyObject *from_map(MMDB_entry_data_list_s **entry_data_list); +static PyObject *from_array(MMDB_entry_data_list_s **entry_data_list); +static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list); + +#if PY_MAJOR_VERSION >= 3 + #define MOD_INIT(name) PyMODINIT_FUNC PyInit_ ## name(void) + #define RETURN_MOD_INIT(m) return (m) + #define FILE_NOT_FOUND_ERROR PyExc_FileNotFoundError +#else + #define MOD_INIT(name) PyMODINIT_FUNC init ## name(void) + #define RETURN_MOD_INIT(m) return + #define PyInt_FromLong PyLong_FromLong + #define FILE_NOT_FOUND_ERROR PyExc_IOError +#endif + +#ifdef __GNUC__ + # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#else + # define UNUSED(x) UNUSED_ ## x +#endif + +static int Reader_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + char *filename; + int mode = 0; + + static char *kwlist[] = {"database", "mode", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &filename, &mode)) { + return -1; + } + + if (mode != 0 && mode != 1) { + PyErr_Format(PyExc_ValueError, "Unsupported open mode (%i). Only " + "MODE_AUTO and MODE_MMAP_EXT are supported by this extension.", + mode); + return -1; + } + + if (0 != access(filename, R_OK)) { + PyErr_Format(FILE_NOT_FOUND_ERROR, + "No such file or directory: '%s'", + filename); + return -1; + } + + MMDB_s *mmdb = (MMDB_s *)malloc(sizeof(MMDB_s)); + if (NULL == mmdb) { + PyErr_NoMemory(); + return -1; + } + + Reader_obj *mmdb_obj = (Reader_obj *)self; + if (!mmdb_obj) { + free(mmdb); + PyErr_NoMemory(); + return -1; + } + + uint16_t status = MMDB_open(filename, MMDB_MODE_MMAP, mmdb); + + if (MMDB_SUCCESS != status) { + free(mmdb); + PyErr_Format( + MaxMindDB_error, + "Error opening database file (%s). Is this a valid MaxMind DB file?", + filename + ); + return -1; + } + + mmdb_obj->mmdb = mmdb; + return 0; +} + +static PyObject *Reader_get(PyObject *self, PyObject *args) +{ + char *ip_address = NULL; + + Reader_obj *mmdb_obj = (Reader_obj *)self; + if (!PyArg_ParseTuple(args, "s", &ip_address)) { + return NULL; + } + + MMDB_s *mmdb = mmdb_obj->mmdb; + + if (NULL == mmdb) { + PyErr_SetString(PyExc_ValueError, + "Attempt to read from a closed MaxMind DB."); + return NULL; + } + + int gai_error = 0; + int mmdb_error = MMDB_SUCCESS; + MMDB_lookup_result_s result = + MMDB_lookup_string(mmdb, ip_address, &gai_error, + &mmdb_error); + + if (0 != gai_error) { + PyErr_Format(PyExc_ValueError, + "'%s' does not appear to be an IPv4 or IPv6 address.", + ip_address); + return NULL; + } + + if (MMDB_SUCCESS != mmdb_error) { + PyObject *exception; + if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) { + exception = PyExc_ValueError; + } else { + exception = MaxMindDB_error; + } + PyErr_Format(exception, "Error looking up %s. %s", + ip_address, MMDB_strerror(mmdb_error)); + return NULL; + } + + if (!result.found_entry) { + Py_RETURN_NONE; + } + + MMDB_entry_data_list_s *entry_data_list = NULL; + int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); + if (MMDB_SUCCESS != status) { + PyErr_Format(MaxMindDB_error, + "Error while looking up data for %s. %s", + ip_address, MMDB_strerror(status)); + MMDB_free_entry_data_list(entry_data_list); + return NULL; + } + + MMDB_entry_data_list_s *original_entry_data_list = entry_data_list; + PyObject *py_obj = from_entry_data_list(&entry_data_list); + MMDB_free_entry_data_list(original_entry_data_list); + return py_obj; +} + +static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args)) +{ + Reader_obj *mmdb_obj = (Reader_obj *)self; + + if (NULL == mmdb_obj->mmdb) { + PyErr_SetString(PyExc_IOError, + "Attempt to read from a closed MaxMind DB."); + return NULL; + } + + MMDB_entry_data_list_s *entry_data_list; + MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list); + MMDB_entry_data_list_s *original_entry_data_list = entry_data_list; + + PyObject *metadata_dict = from_entry_data_list(&entry_data_list); + MMDB_free_entry_data_list(original_entry_data_list); + if (NULL == metadata_dict || !PyDict_Check(metadata_dict)) { + PyErr_SetString(MaxMindDB_error, + "Error decoding metadata."); + return NULL; + } + + PyObject *args = PyTuple_New(0); + if (NULL == args) { + Py_DECREF(metadata_dict); + return NULL; + } + + PyObject *metadata = PyObject_Call((PyObject *)&Metadata_Type, args, + metadata_dict); + + Py_DECREF(metadata_dict); + return metadata; +} + +static PyObject *Reader_close(PyObject *self, PyObject *UNUSED(args)) +{ + Reader_obj *mmdb_obj = (Reader_obj *)self; + + if (NULL != mmdb_obj->mmdb) { + MMDB_close(mmdb_obj->mmdb); + free(mmdb_obj->mmdb); + mmdb_obj->mmdb = NULL; + } + + Py_RETURN_NONE; +} + +static void Reader_dealloc(PyObject *self) +{ + Reader_obj *obj = (Reader_obj *)self; + if (NULL != obj->mmdb) { + Reader_close(self, NULL); + } + + PyObject_Del(self); +} + +static int Metadata_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + + PyObject + *binary_format_major_version, + *binary_format_minor_version, + *build_epoch, + *database_type, + *description, + *ip_version, + *languages, + *node_count, + *record_size; + + static char *kwlist[] = { + "binary_format_major_version", + "binary_format_minor_version", + "build_epoch", + "database_type", + "description", + "ip_version", + "languages", + "node_count", + "record_size", + NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, + &binary_format_major_version, + &binary_format_minor_version, + &build_epoch, + &database_type, + &description, + &ip_version, + &languages, + &node_count, + &record_size)) { + return -1; + } + + Metadata_obj *obj = (Metadata_obj *)self; + + obj->binary_format_major_version = binary_format_major_version; + obj->binary_format_minor_version = binary_format_minor_version; + obj->build_epoch = build_epoch; + obj->database_type = database_type; + obj->description = description; + obj->ip_version = ip_version; + obj->languages = languages; + obj->node_count = node_count; + obj->record_size = record_size; + + Py_INCREF(obj->binary_format_major_version); + Py_INCREF(obj->binary_format_minor_version); + Py_INCREF(obj->build_epoch); + Py_INCREF(obj->database_type); + Py_INCREF(obj->description); + Py_INCREF(obj->ip_version); + Py_INCREF(obj->languages); + Py_INCREF(obj->node_count); + Py_INCREF(obj->record_size); + + return 0; +} + +static void Metadata_dealloc(PyObject *self) +{ + Metadata_obj *obj = (Metadata_obj *)self; + Py_DECREF(obj->binary_format_major_version); + Py_DECREF(obj->binary_format_minor_version); + Py_DECREF(obj->build_epoch); + Py_DECREF(obj->database_type); + Py_DECREF(obj->description); + Py_DECREF(obj->ip_version); + Py_DECREF(obj->languages); + Py_DECREF(obj->node_count); + Py_DECREF(obj->record_size); + PyObject_Del(self); +} + +static PyObject *from_entry_data_list(MMDB_entry_data_list_s **entry_data_list) +{ + if (NULL == entry_data_list || NULL == *entry_data_list) { + PyErr_SetString( + MaxMindDB_error, + "Error while looking up data. Your database may be corrupt or you have found a bug in libmaxminddb." + ); + return NULL; + } + + switch ((*entry_data_list)->entry_data.type) { + case MMDB_DATA_TYPE_MAP: + return from_map(entry_data_list); + case MMDB_DATA_TYPE_ARRAY: + return from_array(entry_data_list); + case MMDB_DATA_TYPE_UTF8_STRING: + return PyUnicode_FromStringAndSize( + (*entry_data_list)->entry_data.utf8_string, + (*entry_data_list)->entry_data.data_size + ); + case MMDB_DATA_TYPE_BYTES: + return PyByteArray_FromStringAndSize( + (const char *)(*entry_data_list)->entry_data.bytes, + (Py_ssize_t)(*entry_data_list)->entry_data.data_size); + case MMDB_DATA_TYPE_DOUBLE: + return PyFloat_FromDouble((*entry_data_list)->entry_data.double_value); + case MMDB_DATA_TYPE_FLOAT: + return PyFloat_FromDouble((*entry_data_list)->entry_data.float_value); + case MMDB_DATA_TYPE_UINT16: + return PyLong_FromLong( (*entry_data_list)->entry_data.uint16); + case MMDB_DATA_TYPE_UINT32: + return PyLong_FromLong((*entry_data_list)->entry_data.uint32); + case MMDB_DATA_TYPE_BOOLEAN: + return PyBool_FromLong((*entry_data_list)->entry_data.boolean); + case MMDB_DATA_TYPE_UINT64: + return PyLong_FromUnsignedLongLong( + (*entry_data_list)->entry_data.uint64); + case MMDB_DATA_TYPE_UINT128: + return from_uint128(*entry_data_list); + case MMDB_DATA_TYPE_INT32: + return PyLong_FromLong((*entry_data_list)->entry_data.int32); + default: + PyErr_Format(MaxMindDB_error, + "Invalid data type arguments: %d", + (*entry_data_list)->entry_data.type); + return NULL; + } + return NULL; +} + +static PyObject *from_map(MMDB_entry_data_list_s **entry_data_list) +{ + PyObject *py_obj = PyDict_New(); + if (NULL == py_obj) { + PyErr_NoMemory(); + return NULL; + } + + const uint32_t map_size = (*entry_data_list)->entry_data.data_size; + + uint i; + // entry_data_list cannot start out NULL (see from_entry_data_list). We + // check it in the loop because it may become NULL. + // coverity[check_after_deref] + for (i = 0; i < map_size && entry_data_list; i++) { + *entry_data_list = (*entry_data_list)->next; + + PyObject *key = PyUnicode_FromStringAndSize( + (char *)(*entry_data_list)->entry_data.utf8_string, + (*entry_data_list)->entry_data.data_size + ); + + *entry_data_list = (*entry_data_list)->next; + + PyObject *value = from_entry_data_list(entry_data_list); + if (NULL == value) { + Py_DECREF(key); + Py_DECREF(py_obj); + return NULL; + } + PyDict_SetItem(py_obj, key, value); + Py_DECREF(value); + Py_DECREF(key); + } + + return py_obj; +} + +static PyObject *from_array(MMDB_entry_data_list_s **entry_data_list) +{ + const uint32_t size = (*entry_data_list)->entry_data.data_size; + + PyObject *py_obj = PyList_New(size); + if (NULL == py_obj) { + PyErr_NoMemory(); + return NULL; + } + + uint i; + // entry_data_list cannot start out NULL (see from_entry_data_list). We + // check it in the loop because it may become NULL. + // coverity[check_after_deref] + for (i = 0; i < size && entry_data_list; i++) { + *entry_data_list = (*entry_data_list)->next; + PyObject *value = from_entry_data_list(entry_data_list); + if (NULL == value) { + Py_DECREF(py_obj); + return NULL; + } + // PyList_SetItem 'steals' the reference + PyList_SetItem(py_obj, i, value); + } + return py_obj; +} + +static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list) +{ + uint64_t high = 0; + uint64_t low = 0; +#if MMDB_UINT128_IS_BYTE_ARRAY + int i; + for (i = 0; i < 8; i++) { + high = (high << 8) | entry_data_list->entry_data.uint128[i]; + } + + for (i = 8; i < 16; i++) { + low = (low << 8) | entry_data_list->entry_data.uint128[i]; + } +#else + high = entry_data_list->entry_data.uint128 >> 64; + low = (uint64_t)entry_data_list->entry_data.uint128; +#endif + + char *num_str = malloc(33); + if (NULL == num_str) { + PyErr_NoMemory(); + return NULL; + } + + snprintf(num_str, 33, "%016" PRIX64 "%016" PRIX64, high, low); + + PyObject *py_obj = PyLong_FromString(num_str, NULL, 16); + + free(num_str); + return py_obj; +} + +static PyMethodDef Reader_methods[] = { + { "get", Reader_get, METH_VARARGS, + "Get record for IP address" }, + { "metadata", Reader_metadata, METH_NOARGS, + "Returns metadata object for database" }, + { "close", Reader_close, METH_NOARGS, "Closes database"}, + { NULL, NULL, 0, NULL } +}; + +static PyTypeObject Reader_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_basicsize = sizeof(Reader_obj), + .tp_dealloc = Reader_dealloc, + .tp_doc = "Reader object", + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = Reader_methods, + .tp_name = "Reader", + .tp_init = Reader_init, +}; + +static PyMethodDef Metadata_methods[] = { + { NULL, NULL, 0, NULL } +}; + +/* *INDENT-OFF* */ +static PyMemberDef Metadata_members[] = { + { "binary_format_major_version", T_OBJECT, offsetof( + Metadata_obj, binary_format_major_version), READONLY, NULL }, + { "binary_format_minor_version", T_OBJECT, offsetof( + Metadata_obj, binary_format_minor_version), READONLY, NULL }, + { "build_epoch", T_OBJECT, offsetof(Metadata_obj, build_epoch), + READONLY, NULL }, + { "database_type", T_OBJECT, offsetof(Metadata_obj, database_type), + READONLY, NULL }, + { "description", T_OBJECT, offsetof(Metadata_obj, description), + READONLY, NULL }, + { "ip_version", T_OBJECT, offsetof(Metadata_obj, ip_version), + READONLY, NULL }, + { "languages", T_OBJECT, offsetof(Metadata_obj, languages), READONLY, + NULL }, + { "node_count", T_OBJECT, offsetof(Metadata_obj, node_count), + READONLY, NULL }, + { "record_size", T_OBJECT, offsetof(Metadata_obj, record_size), + READONLY, NULL }, + { NULL, 0, 0, 0, NULL } +}; +/* *INDENT-ON* */ + +static PyTypeObject Metadata_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_basicsize = sizeof(Metadata_obj), + .tp_dealloc = Metadata_dealloc, + .tp_doc = "Metadata object", + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_members = Metadata_members, + .tp_methods = Metadata_methods, + .tp_name = "Metadata", + .tp_init = Metadata_init +}; + +static PyMethodDef MaxMindDB_methods[] = { + { NULL, NULL, 0, NULL } +}; + + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef MaxMindDB_module = { + PyModuleDef_HEAD_INIT, + .m_name = "extension", + .m_doc = "This is a C extension to read MaxMind DB file format", + .m_methods = MaxMindDB_methods, +}; +#endif + +MOD_INIT(extension){ + PyObject *m; + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&MaxMindDB_module); +#else + m = Py_InitModule("extension", MaxMindDB_methods); +#endif + + if (!m) { + RETURN_MOD_INIT(NULL); + } + + Reader_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&Reader_Type)) { + RETURN_MOD_INIT(NULL); + } + Py_INCREF(&Reader_Type); + PyModule_AddObject(m, "Reader", (PyObject *)&Reader_Type); + + Metadata_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&Metadata_Type)) { + RETURN_MOD_INIT(NULL); + } + PyModule_AddObject(m, "extension", (PyObject *)&Metadata_Type); + + PyObject* error_mod = PyImport_ImportModule("maxminddb.errors"); + if (error_mod == NULL) { + RETURN_MOD_INIT(NULL); + } + + MaxMindDB_error = PyObject_GetAttrString(error_mod, "InvalidDatabaseError"); + Py_DECREF(error_mod); + + if (MaxMindDB_error == NULL) { + RETURN_MOD_INIT(NULL); + } + + Py_INCREF(MaxMindDB_error); + + /* We primarily add it to the module for backwards compatibility */ + PyModule_AddObject(m, "InvalidDatabaseError", MaxMindDB_error); + + RETURN_MOD_INIT(m); +} diff --git a/plugins/Sidebar/maxminddb/file.py b/plugins/Sidebar/maxminddb/file.py new file mode 100644 index 00000000..3460893e --- /dev/null +++ b/plugins/Sidebar/maxminddb/file.py @@ -0,0 +1,65 @@ +"""For internal use only. It provides a slice-like file reader.""" + +import os + +try: + from multiprocessing import Lock +except ImportError: + from threading import Lock + + +class FileBuffer(object): + + """A slice-able file reader""" + + def __init__(self, database): + self._handle = open(database, 'rb') + self._size = os.fstat(self._handle.fileno()).st_size + if not hasattr(os, 'pread'): + self._lock = Lock() + + def __getitem__(self, key): + if isinstance(key, slice): + return self._read(key.stop - key.start, key.start) + elif isinstance(key, int): + return self._read(1, key) + else: + raise TypeError("Invalid argument type.") + + def rfind(self, needle, start): + """Reverse find needle from start""" + pos = self._read(self._size - start - 1, start).rfind(needle) + if pos == -1: + return pos + return start + pos + + def size(self): + """Size of file""" + return self._size + + def close(self): + """Close file""" + self._handle.close() + + if hasattr(os, 'pread'): + + def _read(self, buffersize, offset): + """read that uses pread""" + # pylint: disable=no-member + return os.pread(self._handle.fileno(), buffersize, offset) + + else: + + def _read(self, buffersize, offset): + """read with a lock + + This lock is necessary as after a fork, the different processes + will share the same file table entry, even if we dup the fd, and + as such the same offsets. There does not appear to be a way to + duplicate the file table entry and we cannot re-open based on the + original path as that file may have replaced with another or + unlinked. + """ + with self._lock: + self._handle.seek(offset) + return self._handle.read(buffersize) diff --git a/plugins/Sidebar/maxminddb/ipaddr.py b/plugins/Sidebar/maxminddb/ipaddr.py new file mode 100644 index 00000000..ad27ae9d --- /dev/null +++ b/plugins/Sidebar/maxminddb/ipaddr.py @@ -0,0 +1,1897 @@ +#!/usr/bin/python +# +# Copyright 2007 Google Inc. +# Licensed to PSF under a Contributor Agreement. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""A fast, lightweight IPv4/IPv6 manipulation library in Python. + +This library is used to create/poke/manipulate IPv4 and IPv6 addresses +and networks. + +""" + +__version__ = '2.1.10' + +import struct + +IPV4LENGTH = 32 +IPV6LENGTH = 128 + + +class AddressValueError(ValueError): + """A Value Error related to the address.""" + + +class NetmaskValueError(ValueError): + """A Value Error related to the netmask.""" + + +def IPAddress(address, version=None): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + version: An Integer, 4 or 6. If set, don't try to automatically + determine what the IP address type is. important for things + like IPAddress(1), which could be IPv4, '0.0.0.1', or IPv6, + '::1'. + + Returns: + An IPv4Address or IPv6Address object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. + + """ + if version: + if version == 4: + return IPv4Address(address) + elif version == 6: + return IPv6Address(address) + + try: + return IPv4Address(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Address(address) + except (AddressValueError, NetmaskValueError): + pass + + raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % + address) + + +def IPNetwork(address, version=None, strict=False): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + version: An Integer, if set, don't try to automatically + determine what the IP address type is. important for things + like IPNetwork(1), which could be IPv4, '0.0.0.1/32', or IPv6, + '::1/128'. + + Returns: + An IPv4Network or IPv6Network object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. Or if a strict network was requested and a strict + network wasn't given. + + """ + if version: + if version == 4: + return IPv4Network(address, strict) + elif version == 6: + return IPv6Network(address, strict) + + try: + return IPv4Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % + address) + + +def v4_int_to_packed(address): + """The binary representation of this address. + + Args: + address: An integer representation of an IPv4 IP address. + + Returns: + The binary representation of this address. + + Raises: + ValueError: If the integer is too large to be an IPv4 IP + address. + """ + if address > _BaseV4._ALL_ONES: + raise ValueError('Address too large for IPv4') + return Bytes(struct.pack('!I', address)) + + +def v6_int_to_packed(address): + """The binary representation of this address. + + Args: + address: An integer representation of an IPv4 IP address. + + Returns: + The binary representation of this address. + """ + return Bytes(struct.pack('!QQ', address >> 64, address & (2**64 - 1))) + + +def _find_address_range(addresses): + """Find a sequence of addresses. + + Args: + addresses: a list of IPv4 or IPv6 addresses. + + Returns: + A tuple containing the first and last IP addresses in the sequence. + + """ + first = last = addresses[0] + for ip in addresses[1:]: + if ip._ip == last._ip + 1: + last = ip + else: + break + return (first, last) + +def _get_prefix_length(number1, number2, bits): + """Get the number of leading bits that are same for two numbers. + + Args: + number1: an integer. + number2: another integer. + bits: the maximum number of bits to compare. + + Returns: + The number of leading bits that are the same for two numbers. + + """ + for i in range(bits): + if number1 >> i == number2 >> i: + return bits - i + return 0 + +def _count_righthand_zero_bits(number, bits): + """Count the number of zero bits on the right hand side. + + Args: + number: an integer. + bits: maximum number of bits to count. + + Returns: + The number of zero bits on the right hand side of the number. + + """ + if number == 0: + return bits + for i in range(bits): + if (number >> i) % 2: + return i + +def summarize_address_range(first, last): + """Summarize a network range given the first and last IP addresses. + + Example: + >>> summarize_address_range(IPv4Address('1.1.1.0'), + IPv4Address('1.1.1.130')) + [IPv4Network('1.1.1.0/25'), IPv4Network('1.1.1.128/31'), + IPv4Network('1.1.1.130/32')] + + Args: + first: the first IPv4Address or IPv6Address in the range. + last: the last IPv4Address or IPv6Address in the range. + + Returns: + The address range collapsed to a list of IPv4Network's or + IPv6Network's. + + Raise: + TypeError: + If the first and last objects are not IP addresses. + If the first and last objects are not the same version. + ValueError: + If the last object is not greater than the first. + If the version is not 4 or 6. + + """ + if not (isinstance(first, _BaseIP) and isinstance(last, _BaseIP)): + raise TypeError('first and last must be IP addresses, not networks') + if first.version != last.version: + raise TypeError("%s and %s are not of the same version" % ( + str(first), str(last))) + if first > last: + raise ValueError('last IP address must be greater than first') + + networks = [] + + if first.version == 4: + ip = IPv4Network + elif first.version == 6: + ip = IPv6Network + else: + raise ValueError('unknown IP version') + + ip_bits = first._max_prefixlen + first_int = first._ip + last_int = last._ip + while first_int <= last_int: + nbits = _count_righthand_zero_bits(first_int, ip_bits) + current = None + while nbits >= 0: + addend = 2**nbits - 1 + current = first_int + addend + nbits -= 1 + if current <= last_int: + break + prefix = _get_prefix_length(first_int, current, ip_bits) + net = ip('%s/%d' % (str(first), prefix)) + networks.append(net) + if current == ip._ALL_ONES: + break + first_int = current + 1 + first = IPAddress(first_int, version=first._version) + return networks + +def _collapse_address_list_recursive(addresses): + """Loops through the addresses, collapsing concurrent netblocks. + + Example: + + ip1 = IPv4Network('1.1.0.0/24') + ip2 = IPv4Network('1.1.1.0/24') + ip3 = IPv4Network('1.1.2.0/24') + ip4 = IPv4Network('1.1.3.0/24') + ip5 = IPv4Network('1.1.4.0/24') + ip6 = IPv4Network('1.1.0.1/22') + + _collapse_address_list_recursive([ip1, ip2, ip3, ip4, ip5, ip6]) -> + [IPv4Network('1.1.0.0/22'), IPv4Network('1.1.4.0/24')] + + This shouldn't be called directly; it is called via + collapse_address_list([]). + + Args: + addresses: A list of IPv4Network's or IPv6Network's + + Returns: + A list of IPv4Network's or IPv6Network's depending on what we were + passed. + + """ + ret_array = [] + optimized = False + + for cur_addr in addresses: + if not ret_array: + ret_array.append(cur_addr) + continue + if cur_addr in ret_array[-1]: + optimized = True + elif cur_addr == ret_array[-1].supernet().subnet()[1]: + ret_array.append(ret_array.pop().supernet()) + optimized = True + else: + ret_array.append(cur_addr) + + if optimized: + return _collapse_address_list_recursive(ret_array) + + return ret_array + + +def collapse_address_list(addresses): + """Collapse a list of IP objects. + + Example: + collapse_address_list([IPv4('1.1.0.0/24'), IPv4('1.1.1.0/24')]) -> + [IPv4('1.1.0.0/23')] + + Args: + addresses: A list of IPv4Network or IPv6Network objects. + + Returns: + A list of IPv4Network or IPv6Network objects depending on what we + were passed. + + Raises: + TypeError: If passed a list of mixed version objects. + + """ + i = 0 + addrs = [] + ips = [] + nets = [] + + # split IP addresses and networks + for ip in addresses: + if isinstance(ip, _BaseIP): + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + str(ip), str(ips[-1]))) + ips.append(ip) + elif ip._prefixlen == ip._max_prefixlen: + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + str(ip), str(ips[-1]))) + ips.append(ip.ip) + else: + if nets and nets[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + str(ip), str(ips[-1]))) + nets.append(ip) + + # sort and dedup + ips = sorted(set(ips)) + nets = sorted(set(nets)) + + while i < len(ips): + (first, last) = _find_address_range(ips[i:]) + i = ips.index(last) + 1 + addrs.extend(summarize_address_range(first, last)) + + return _collapse_address_list_recursive(sorted( + addrs + nets, key=_BaseNet._get_networks_key)) + +# backwards compatibility +CollapseAddrList = collapse_address_list + +# We need to distinguish between the string and packed-bytes representations +# of an IP address. For example, b'0::1' is the IPv4 address 48.58.58.49, +# while '0::1' is an IPv6 address. +# +# In Python 3, the native 'bytes' type already provides this functionality, +# so we use it directly. For earlier implementations where bytes is not a +# distinct type, we create a subclass of str to serve as a tag. +# +# Usage example (Python 2): +# ip = ipaddr.IPAddress(ipaddr.Bytes('xxxx')) +# +# Usage example (Python 3): +# ip = ipaddr.IPAddress(b'xxxx') +try: + if bytes is str: + raise TypeError("bytes is not a distinct type") + Bytes = bytes +except (NameError, TypeError): + class Bytes(str): + def __repr__(self): + return 'Bytes(%s)' % str.__repr__(self) + +def get_mixed_type_key(obj): + """Return a key suitable for sorting between networks and addresses. + + Address and Network objects are not sortable by default; they're + fundamentally different so the expression + + IPv4Address('1.1.1.1') <= IPv4Network('1.1.1.1/24') + + doesn't make any sense. There are some times however, where you may wish + to have ipaddr sort these for you anyway. If you need to do this, you + can use this function as the key= argument to sorted(). + + Args: + obj: either a Network or Address object. + Returns: + appropriate key. + + """ + if isinstance(obj, _BaseNet): + return obj._get_networks_key() + elif isinstance(obj, _BaseIP): + return obj._get_address_key() + return NotImplemented + +class _IPAddrBase(object): + + """The mother class.""" + + def __index__(self): + return self._ip + + def __int__(self): + return self._ip + + def __hex__(self): + return hex(self._ip) + + @property + def exploded(self): + """Return the longhand version of the IP address as a string.""" + return self._explode_shorthand_ip_string() + + @property + def compressed(self): + """Return the shorthand version of the IP address as a string.""" + return str(self) + + +class _BaseIP(_IPAddrBase): + + """A generic IP object. + + This IP class contains the version independent methods which are + used by single IP addresses. + + """ + + def __eq__(self, other): + try: + return (self._ip == other._ip + and self._version == other._version) + except AttributeError: + return NotImplemented + + def __ne__(self, other): + eq = self.__eq__(other) + if eq is NotImplemented: + return NotImplemented + return not eq + + def __le__(self, other): + gt = self.__gt__(other) + if gt is NotImplemented: + return NotImplemented + return not gt + + def __ge__(self, other): + lt = self.__lt__(other) + if lt is NotImplemented: + return NotImplemented + return not lt + + def __lt__(self, other): + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + str(self), str(other))) + if not isinstance(other, _BaseIP): + raise TypeError('%s and %s are not of the same type' % ( + str(self), str(other))) + if self._ip != other._ip: + return self._ip < other._ip + return False + + def __gt__(self, other): + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + str(self), str(other))) + if not isinstance(other, _BaseIP): + raise TypeError('%s and %s are not of the same type' % ( + str(self), str(other))) + if self._ip != other._ip: + return self._ip > other._ip + return False + + # Shorthand for Integer addition and subtraction. This is not + # meant to ever support addition/subtraction of addresses. + def __add__(self, other): + if not isinstance(other, int): + return NotImplemented + return IPAddress(int(self) + other, version=self._version) + + def __sub__(self, other): + if not isinstance(other, int): + return NotImplemented + return IPAddress(int(self) - other, version=self._version) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, str(self)) + + def __str__(self): + return '%s' % self._string_from_ip_int(self._ip) + + def __hash__(self): + return hash(hex(long(self._ip))) + + def _get_address_key(self): + return (self._version, self) + + @property + def version(self): + raise NotImplementedError('BaseIP has no version') + + +class _BaseNet(_IPAddrBase): + + """A generic IP object. + + This IP class contains the version independent methods which are + used by networks. + + """ + + def __init__(self, address): + self._cache = {} + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, str(self)) + + def iterhosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the network + or broadcast addresses. + + """ + cur = int(self.network) + 1 + bcast = int(self.broadcast) - 1 + while cur <= bcast: + cur += 1 + yield IPAddress(cur - 1, version=self._version) + + def __iter__(self): + cur = int(self.network) + bcast = int(self.broadcast) + while cur <= bcast: + cur += 1 + yield IPAddress(cur - 1, version=self._version) + + def __getitem__(self, n): + network = int(self.network) + broadcast = int(self.broadcast) + if n >= 0: + if network + n > broadcast: + raise IndexError + return IPAddress(network + n, version=self._version) + else: + n += 1 + if broadcast + n < network: + raise IndexError + return IPAddress(broadcast + n, version=self._version) + + def __lt__(self, other): + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + str(self), str(other))) + if not isinstance(other, _BaseNet): + raise TypeError('%s and %s are not of the same type' % ( + str(self), str(other))) + if self.network != other.network: + return self.network < other.network + if self.netmask != other.netmask: + return self.netmask < other.netmask + return False + + def __gt__(self, other): + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + str(self), str(other))) + if not isinstance(other, _BaseNet): + raise TypeError('%s and %s are not of the same type' % ( + str(self), str(other))) + if self.network != other.network: + return self.network > other.network + if self.netmask != other.netmask: + return self.netmask > other.netmask + return False + + def __le__(self, other): + gt = self.__gt__(other) + if gt is NotImplemented: + return NotImplemented + return not gt + + def __ge__(self, other): + lt = self.__lt__(other) + if lt is NotImplemented: + return NotImplemented + return not lt + + def __eq__(self, other): + try: + return (self._version == other._version + and self.network == other.network + and int(self.netmask) == int(other.netmask)) + except AttributeError: + if isinstance(other, _BaseIP): + return (self._version == other._version + and self._ip == other._ip) + + def __ne__(self, other): + eq = self.__eq__(other) + if eq is NotImplemented: + return NotImplemented + return not eq + + def __str__(self): + return '%s/%s' % (str(self.ip), + str(self._prefixlen)) + + def __hash__(self): + return hash(int(self.network) ^ int(self.netmask)) + + def __contains__(self, other): + # always false if one is v4 and the other is v6. + if self._version != other._version: + return False + # dealing with another network. + if isinstance(other, _BaseNet): + return (self.network <= other.network and + self.broadcast >= other.broadcast) + # dealing with another address + else: + return (int(self.network) <= int(other._ip) <= + int(self.broadcast)) + + def overlaps(self, other): + """Tell if self is partly contained in other.""" + return self.network in other or self.broadcast in other or ( + other.network in self or other.broadcast in self) + + @property + def network(self): + x = self._cache.get('network') + if x is None: + x = IPAddress(self._ip & int(self.netmask), version=self._version) + self._cache['network'] = x + return x + + @property + def broadcast(self): + x = self._cache.get('broadcast') + if x is None: + x = IPAddress(self._ip | int(self.hostmask), version=self._version) + self._cache['broadcast'] = x + return x + + @property + def hostmask(self): + x = self._cache.get('hostmask') + if x is None: + x = IPAddress(int(self.netmask) ^ self._ALL_ONES, + version=self._version) + self._cache['hostmask'] = x + return x + + @property + def with_prefixlen(self): + return '%s/%d' % (str(self.ip), self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (str(self.ip), str(self.netmask)) + + @property + def with_hostmask(self): + return '%s/%s' % (str(self.ip), str(self.hostmask)) + + @property + def numhosts(self): + """Number of hosts in the current subnet.""" + return int(self.broadcast) - int(self.network) + 1 + + @property + def version(self): + raise NotImplementedError('BaseNet has no version') + + @property + def prefixlen(self): + return self._prefixlen + + def address_exclude(self, other): + """Remove an address from a larger block. + + For example: + + addr1 = IPNetwork('10.1.1.0/24') + addr2 = IPNetwork('10.1.1.0/26') + addr1.address_exclude(addr2) = + [IPNetwork('10.1.1.64/26'), IPNetwork('10.1.1.128/25')] + + or IPv6: + + addr1 = IPNetwork('::1/32') + addr2 = IPNetwork('::1/128') + addr1.address_exclude(addr2) = [IPNetwork('::0/128'), + IPNetwork('::2/127'), + IPNetwork('::4/126'), + IPNetwork('::8/125'), + ... + IPNetwork('0:0:8000::/33')] + + Args: + other: An IPvXNetwork object of the same type. + + Returns: + A sorted list of IPvXNetwork objects addresses which is self + minus other. + + Raises: + TypeError: If self and other are of difffering address + versions, or if other is not a network object. + ValueError: If other is not completely contained by self. + + """ + if not self._version == other._version: + raise TypeError("%s and %s are not of the same version" % ( + str(self), str(other))) + + if not isinstance(other, _BaseNet): + raise TypeError("%s is not a network object" % str(other)) + + if other not in self: + raise ValueError('%s not contained in %s' % (str(other), + str(self))) + if other == self: + return [] + + ret_addrs = [] + + # Make sure we're comparing the network of other. + other = IPNetwork('%s/%s' % (str(other.network), str(other.prefixlen)), + version=other._version) + + s1, s2 = self.subnet() + while s1 != other and s2 != other: + if other in s1: + ret_addrs.append(s2) + s1, s2 = s1.subnet() + elif other in s2: + ret_addrs.append(s1) + s1, s2 = s2.subnet() + else: + # If we got here, there's a bug somewhere. + assert True == False, ('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (str(s1), str(s2), str(other))) + if s1 == other: + ret_addrs.append(s2) + elif s2 == other: + ret_addrs.append(s1) + else: + # If we got here, there's a bug somewhere. + assert True == False, ('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (str(s1), str(s2), str(other))) + + return sorted(ret_addrs, key=_BaseNet._get_networks_key) + + def compare_networks(self, other): + """Compare two IP objects. + + This is only concerned about the comparison of the integer + representation of the network addresses. This means that the + host bits aren't considered at all in this method. If you want + to compare host bits, you can easily enough do a + 'HostA._ip < HostB._ip' + + Args: + other: An IP object. + + Returns: + If the IP versions of self and other are the same, returns: + + -1 if self < other: + eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24') + IPv6('1080::200C:417A') < IPv6('1080::200B:417B') + 0 if self == other + eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24') + IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96') + 1 if self > other + eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24') + IPv6('1080::1:200C:417A/112') > + IPv6('1080::0:200C:417A/112') + + If the IP versions of self and other are different, returns: + + -1 if self._version < other._version + eg: IPv4('10.0.0.1/24') < IPv6('::1/128') + 1 if self._version > other._version + eg: IPv6('::1/128') > IPv4('255.255.255.0/24') + + """ + if self._version < other._version: + return -1 + if self._version > other._version: + return 1 + # self._version == other._version below here: + if self.network < other.network: + return -1 + if self.network > other.network: + return 1 + # self.network == other.network below here: + if self.netmask < other.netmask: + return -1 + if self.netmask > other.netmask: + return 1 + # self.network == other.network and self.netmask == other.netmask + return 0 + + def _get_networks_key(self): + """Network-only key function. + + Returns an object that identifies this address' network and + netmask. This function is a suitable "key" argument for sorted() + and list.sort(). + + """ + return (self._version, self.network, self.netmask) + + def _ip_int_from_prefix(self, prefixlen=None): + """Turn the prefix length netmask into a int for comparison. + + Args: + prefixlen: An integer, the prefix length. + + Returns: + An integer. + + """ + if not prefixlen and prefixlen != 0: + prefixlen = self._prefixlen + return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) + + def _prefix_from_ip_int(self, ip_int, mask=32): + """Return prefix length from the decimal netmask. + + Args: + ip_int: An integer, the IP address. + mask: The netmask. Defaults to 32. + + Returns: + An integer, the prefix length. + + """ + while mask: + if ip_int & 1 == 1: + break + ip_int >>= 1 + mask -= 1 + + return mask + + def _ip_string_from_prefix(self, prefixlen=None): + """Turn a prefix length into a dotted decimal string. + + Args: + prefixlen: An integer, the netmask prefix length. + + Returns: + A string, the dotted decimal netmask string. + + """ + if not prefixlen: + prefixlen = self._prefixlen + return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen)) + + def iter_subnets(self, prefixlen_diff=1, new_prefix=None): + """The subnets which join to make the current subnet. + + In the case that self contains only one IP + (self._prefixlen == 32 for IPv4 or self._prefixlen == 128 + for IPv6), return a list with just ourself. + + Args: + prefixlen_diff: An integer, the amount the prefix length + should be increased by. This should not be set if + new_prefix is also set. + new_prefix: The desired new prefix length. This must be a + larger number (smaller prefix) than the existing prefix. + This should not be set if prefixlen_diff is also set. + + Returns: + An iterator of IPv(4|6) objects. + + Raises: + ValueError: The prefixlen_diff is too small or too large. + OR + prefixlen_diff and new_prefix are both set or new_prefix + is a smaller number than the current prefix (smaller + number means a larger network) + + """ + if self._prefixlen == self._max_prefixlen: + yield self + return + + if new_prefix is not None: + if new_prefix < self._prefixlen: + raise ValueError('new prefix must be longer') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = new_prefix - self._prefixlen + + if prefixlen_diff < 0: + raise ValueError('prefix length diff must be > 0') + new_prefixlen = self._prefixlen + prefixlen_diff + + if not self._is_valid_netmask(str(new_prefixlen)): + raise ValueError( + 'prefix length diff %d is invalid for netblock %s' % ( + new_prefixlen, str(self))) + + first = IPNetwork('%s/%s' % (str(self.network), + str(self._prefixlen + prefixlen_diff)), + version=self._version) + + yield first + current = first + while True: + broadcast = current.broadcast + if broadcast == self.broadcast: + return + new_addr = IPAddress(int(broadcast) + 1, version=self._version) + current = IPNetwork('%s/%s' % (str(new_addr), str(new_prefixlen)), + version=self._version) + + yield current + + def masked(self): + """Return the network object with the host bits masked out.""" + return IPNetwork('%s/%d' % (self.network, self._prefixlen), + version=self._version) + + def subnet(self, prefixlen_diff=1, new_prefix=None): + """Return a list of subnets, rather than an iterator.""" + return list(self.iter_subnets(prefixlen_diff, new_prefix)) + + def supernet(self, prefixlen_diff=1, new_prefix=None): + """The supernet containing the current network. + + Args: + prefixlen_diff: An integer, the amount the prefix length of + the network should be decreased by. For example, given a + /24 network and a prefixlen_diff of 3, a supernet with a + /21 netmask is returned. + + Returns: + An IPv4 network object. + + Raises: + ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have a + negative prefix length. + OR + If prefixlen_diff and new_prefix are both set or new_prefix is a + larger number than the current prefix (larger number means a + smaller network) + + """ + if self._prefixlen == 0: + return self + + if new_prefix is not None: + if new_prefix > self._prefixlen: + raise ValueError('new prefix must be shorter') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = self._prefixlen - new_prefix + + + if self.prefixlen - prefixlen_diff < 0: + raise ValueError( + 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % + (self.prefixlen, prefixlen_diff)) + return IPNetwork('%s/%s' % (str(self.network), + str(self.prefixlen - prefixlen_diff)), + version=self._version) + + # backwards compatibility + Subnet = subnet + Supernet = supernet + AddressExclude = address_exclude + CompareNetworks = compare_networks + Contains = __contains__ + + +class _BaseV4(object): + + """Base IPv4 object. + + The following methods are used by IPv4 objects in both single IP + addresses and networks. + + """ + + # Equivalent to 255.255.255.255 or 32 bits of 1's. + _ALL_ONES = (2**IPV4LENGTH) - 1 + _DECIMAL_DIGITS = frozenset('0123456789') + + def __init__(self, address): + self._version = 4 + self._max_prefixlen = IPV4LENGTH + + def _explode_shorthand_ip_string(self): + return str(self) + + def _ip_int_from_string(self, ip_str): + """Turn the given IP string into an integer for comparison. + + Args: + ip_str: A string, the IP ip_str. + + Returns: + The IP ip_str as an integer. + + Raises: + AddressValueError: if ip_str isn't a valid IPv4 Address. + + """ + octets = ip_str.split('.') + if len(octets) != 4: + raise AddressValueError(ip_str) + + packed_ip = 0 + for oc in octets: + try: + packed_ip = (packed_ip << 8) | self._parse_octet(oc) + except ValueError: + raise AddressValueError(ip_str) + return packed_ip + + def _parse_octet(self, octet_str): + """Convert a decimal octet into an integer. + + Args: + octet_str: A string, the number to parse. + + Returns: + The octet as an integer. + + Raises: + ValueError: if the octet isn't strictly a decimal from [0..255]. + + """ + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not self._DECIMAL_DIGITS.issuperset(octet_str): + raise ValueError + octet_int = int(octet_str, 10) + # Disallow leading zeroes, because no clear standard exists on + # whether these should be interpreted as decimal or octal. + if octet_int > 255 or (octet_str[0] == '0' and len(octet_str) > 1): + raise ValueError + return octet_int + + def _string_from_ip_int(self, ip_int): + """Turns a 32-bit integer into dotted decimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + The IP address as a string in dotted decimal notation. + + """ + octets = [] + for _ in xrange(4): + octets.insert(0, str(ip_int & 0xFF)) + ip_int >>= 8 + return '.'.join(octets) + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def packed(self): + """The binary representation of this address.""" + return v4_int_to_packed(self._ip) + + @property + def version(self): + return self._version + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within the + reserved IPv4 Network range. + + """ + return self in IPv4Network('240.0.0.0/4') + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per RFC 1918. + + """ + return (self in IPv4Network('10.0.0.0/8') or + self in IPv4Network('172.16.0.0/12') or + self in IPv4Network('192.168.0.0/16')) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is multicast. + See RFC 3171 for details. + + """ + return self in IPv4Network('224.0.0.0/4') + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 5735 3. + + """ + return self in IPv4Network('0.0.0.0') + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback per RFC 3330. + + """ + return self in IPv4Network('127.0.0.0/8') + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is link-local per RFC 3927. + + """ + return self in IPv4Network('169.254.0.0/16') + + +class IPv4Address(_BaseV4, _BaseIP): + + """Represent and manipulate single IPv4 Addresses.""" + + def __init__(self, address): + + """ + Args: + address: A string or integer representing the IP + '192.168.1.1' + + Additionally, an integer can be passed, so + IPv4Address('192.168.1.1') == IPv4Address(3232235777). + or, more generally + IPv4Address(int(IPv4Address('192.168.1.1'))) == + IPv4Address('192.168.1.1') + + Raises: + AddressValueError: If ipaddr isn't a valid IPv4 address. + + """ + _BaseV4.__init__(self, address) + + # Efficient constructor from integer. + if isinstance(address, (int, long)): + self._ip = address + if address < 0 or address > self._ALL_ONES: + raise AddressValueError(address) + return + + # Constructing from a packed address + if isinstance(address, Bytes): + try: + self._ip, = struct.unpack('!I', address) + except struct.error: + raise AddressValueError(address) # Wrong length. + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = str(address) + self._ip = self._ip_int_from_string(addr_str) + + +class IPv4Network(_BaseV4, _BaseNet): + + """This class represents and manipulates 32-bit IPv4 networks. + + Attributes: [examples for IPv4Network('1.2.3.4/27')] + ._ip: 16909060 + .ip: IPv4Address('1.2.3.4') + .network: IPv4Address('1.2.3.0') + .hostmask: IPv4Address('0.0.0.31') + .broadcast: IPv4Address('1.2.3.31') + .netmask: IPv4Address('255.255.255.224') + .prefixlen: 27 + + """ + + # the valid octets for host and netmasks. only useful for IPv4. + _valid_mask_octets = set((255, 254, 252, 248, 240, 224, 192, 128, 0)) + + def __init__(self, address, strict=False): + """Instantiate a new IPv4 network object. + + Args: + address: A string or integer representing the IP [& network]. + '192.168.1.1/24' + '192.168.1.1/255.255.255.0' + '192.168.1.1/0.0.0.255' + are all functionally the same in IPv4. Similarly, + '192.168.1.1' + '192.168.1.1/255.255.255.255' + '192.168.1.1/32' + are also functionaly equivalent. That is to say, failing to + provide a subnetmask will create an object with a mask of /32. + + If the mask (portion after the / in the argument) is given in + dotted quad form, it is treated as a netmask if it starts with a + non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it + starts with a zero field (e.g. 0.255.255.255 == /8), with the + single exception of an all-zero mask which is treated as a + netmask == /0. If no mask is given, a default of /32 is used. + + Additionally, an integer can be passed, so + IPv4Network('192.168.1.1') == IPv4Network(3232235777). + or, more generally + IPv4Network(int(IPv4Network('192.168.1.1'))) == + IPv4Network('192.168.1.1') + + strict: A boolean. If true, ensure that we have been passed + A true network address, eg, 192.168.1.0/24 and not an + IP address on a network, eg, 192.168.1.1/24. + + Raises: + AddressValueError: If ipaddr isn't a valid IPv4 address. + NetmaskValueError: If the netmask isn't valid for + an IPv4 address. + ValueError: If strict was True and a network address was not + supplied. + + """ + _BaseNet.__init__(self, address) + _BaseV4.__init__(self, address) + + # Constructing from an integer or packed bytes. + if isinstance(address, (int, long, Bytes)): + self.ip = IPv4Address(address) + self._ip = self.ip._ip + self._prefixlen = self._max_prefixlen + self.netmask = IPv4Address(self._ALL_ONES) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = str(address).split('/') + + if len(addr) > 2: + raise AddressValueError(address) + + self._ip = self._ip_int_from_string(addr[0]) + self.ip = IPv4Address(self._ip) + + if len(addr) == 2: + mask = addr[1].split('.') + if len(mask) == 4: + # We have dotted decimal netmask. + if self._is_valid_netmask(addr[1]): + self.netmask = IPv4Address(self._ip_int_from_string( + addr[1])) + elif self._is_hostmask(addr[1]): + self.netmask = IPv4Address( + self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) + else: + raise NetmaskValueError('%s is not a valid netmask' + % addr[1]) + + self._prefixlen = self._prefix_from_ip_int(int(self.netmask)) + else: + # We have a netmask in prefix length form. + if not self._is_valid_netmask(addr[1]): + raise NetmaskValueError(addr[1]) + self._prefixlen = int(addr[1]) + self.netmask = IPv4Address(self._ip_int_from_prefix( + self._prefixlen)) + else: + self._prefixlen = self._max_prefixlen + self.netmask = IPv4Address(self._ip_int_from_prefix( + self._prefixlen)) + if strict: + if self.ip != self.network: + raise ValueError('%s has host bits set' % + self.ip) + if self._prefixlen == (self._max_prefixlen - 1): + self.iterhosts = self.__iter__ + + def _is_hostmask(self, ip_str): + """Test if the IP string is a hostmask (rather than a netmask). + + Args: + ip_str: A string, the potential hostmask. + + Returns: + A boolean, True if the IP string is a hostmask. + + """ + bits = ip_str.split('.') + try: + parts = [int(x) for x in bits if int(x) in self._valid_mask_octets] + except ValueError: + return False + if len(parts) != len(bits): + return False + if parts[0] < parts[-1]: + return True + return False + + def _is_valid_netmask(self, netmask): + """Verify that the netmask is valid. + + Args: + netmask: A string, either a prefix or dotted decimal + netmask. + + Returns: + A boolean, True if the prefix represents a valid IPv4 + netmask. + + """ + mask = netmask.split('.') + if len(mask) == 4: + if [x for x in mask if int(x) not in self._valid_mask_octets]: + return False + if [y for idx, y in enumerate(mask) if idx > 0 and + y > mask[idx - 1]]: + return False + return True + try: + netmask = int(netmask) + except ValueError: + return False + return 0 <= netmask <= self._max_prefixlen + + # backwards compatibility + IsRFC1918 = lambda self: self.is_private + IsMulticast = lambda self: self.is_multicast + IsLoopback = lambda self: self.is_loopback + IsLinkLocal = lambda self: self.is_link_local + + +class _BaseV6(object): + + """Base IPv6 object. + + The following methods are used by IPv6 objects in both single IP + addresses and networks. + + """ + + _ALL_ONES = (2**IPV6LENGTH) - 1 + _HEXTET_COUNT = 8 + _HEX_DIGITS = frozenset('0123456789ABCDEFabcdef') + + def __init__(self, address): + self._version = 6 + self._max_prefixlen = IPV6LENGTH + + def _ip_int_from_string(self, ip_str): + """Turn an IPv6 ip_str into an integer. + + Args: + ip_str: A string, the IPv6 ip_str. + + Returns: + A long, the IPv6 ip_str. + + Raises: + AddressValueError: if ip_str isn't a valid IPv6 Address. + + """ + parts = ip_str.split(':') + + # An IPv6 address needs at least 2 colons (3 parts). + if len(parts) < 3: + raise AddressValueError(ip_str) + + # If the address has an IPv4-style suffix, convert it to hexadecimal. + if '.' in parts[-1]: + ipv4_int = IPv4Address(parts.pop())._ip + parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) + parts.append('%x' % (ipv4_int & 0xFFFF)) + + # An IPv6 address can't have more than 8 colons (9 parts). + if len(parts) > self._HEXTET_COUNT + 1: + raise AddressValueError(ip_str) + + # Disregarding the endpoints, find '::' with nothing in between. + # This indicates that a run of zeroes has been skipped. + try: + skip_index, = ( + [i for i in xrange(1, len(parts) - 1) if not parts[i]] or + [None]) + except ValueError: + # Can't have more than one '::' + raise AddressValueError(ip_str) + + # parts_hi is the number of parts to copy from above/before the '::' + # parts_lo is the number of parts to copy from below/after the '::' + if skip_index is not None: + # If we found a '::', then check if it also covers the endpoints. + parts_hi = skip_index + parts_lo = len(parts) - skip_index - 1 + if not parts[0]: + parts_hi -= 1 + if parts_hi: + raise AddressValueError(ip_str) # ^: requires ^:: + if not parts[-1]: + parts_lo -= 1 + if parts_lo: + raise AddressValueError(ip_str) # :$ requires ::$ + parts_skipped = self._HEXTET_COUNT - (parts_hi + parts_lo) + if parts_skipped < 1: + raise AddressValueError(ip_str) + else: + # Otherwise, allocate the entire address to parts_hi. The endpoints + # could still be empty, but _parse_hextet() will check for that. + if len(parts) != self._HEXTET_COUNT: + raise AddressValueError(ip_str) + parts_hi = len(parts) + parts_lo = 0 + parts_skipped = 0 + + try: + # Now, parse the hextets into a 128-bit integer. + ip_int = 0L + for i in xrange(parts_hi): + ip_int <<= 16 + ip_int |= self._parse_hextet(parts[i]) + ip_int <<= 16 * parts_skipped + for i in xrange(-parts_lo, 0): + ip_int <<= 16 + ip_int |= self._parse_hextet(parts[i]) + return ip_int + except ValueError: + raise AddressValueError(ip_str) + + def _parse_hextet(self, hextet_str): + """Convert an IPv6 hextet string into an integer. + + Args: + hextet_str: A string, the number to parse. + + Returns: + The hextet as an integer. + + Raises: + ValueError: if the input isn't strictly a hex number from [0..FFFF]. + + """ + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not self._HEX_DIGITS.issuperset(hextet_str): + raise ValueError + hextet_int = int(hextet_str, 16) + if hextet_int > 0xFFFF: + raise ValueError + return hextet_int + + def _compress_hextets(self, hextets): + """Compresses a list of hextets. + + Compresses a list of strings, replacing the longest continuous + sequence of "0" in the list with "" and adding empty strings at + the beginning or at the end of the string such that subsequently + calling ":".join(hextets) will produce the compressed version of + the IPv6 address. + + Args: + hextets: A list of strings, the hextets to compress. + + Returns: + A list of strings. + + """ + best_doublecolon_start = -1 + best_doublecolon_len = 0 + doublecolon_start = -1 + doublecolon_len = 0 + for index in range(len(hextets)): + if hextets[index] == '0': + doublecolon_len += 1 + if doublecolon_start == -1: + # Start of a sequence of zeros. + doublecolon_start = index + if doublecolon_len > best_doublecolon_len: + # This is the longest sequence of zeros so far. + best_doublecolon_len = doublecolon_len + best_doublecolon_start = doublecolon_start + else: + doublecolon_len = 0 + doublecolon_start = -1 + + if best_doublecolon_len > 1: + best_doublecolon_end = (best_doublecolon_start + + best_doublecolon_len) + # For zeros at the end of the address. + if best_doublecolon_end == len(hextets): + hextets += [''] + hextets[best_doublecolon_start:best_doublecolon_end] = [''] + # For zeros at the beginning of the address. + if best_doublecolon_start == 0: + hextets = [''] + hextets + + return hextets + + def _string_from_ip_int(self, ip_int=None): + """Turns a 128-bit integer into hexadecimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + A string, the hexadecimal representation of the address. + + Raises: + ValueError: The address is bigger than 128 bits of all ones. + + """ + if not ip_int and ip_int != 0: + ip_int = int(self._ip) + + if ip_int > self._ALL_ONES: + raise ValueError('IPv6 address is too large') + + hex_str = '%032x' % ip_int + hextets = [] + for x in range(0, 32, 4): + hextets.append('%x' % int(hex_str[x:x+4], 16)) + + hextets = self._compress_hextets(hextets) + return ':'.join(hextets) + + def _explode_shorthand_ip_string(self): + """Expand a shortened IPv6 address. + + Args: + ip_str: A string, the IPv6 address. + + Returns: + A string, the expanded IPv6 address. + + """ + if isinstance(self, _BaseNet): + ip_str = str(self.ip) + else: + ip_str = str(self) + + ip_int = self._ip_int_from_string(ip_str) + parts = [] + for i in xrange(self._HEXTET_COUNT): + parts.append('%04x' % (ip_int & 0xFFFF)) + ip_int >>= 16 + parts.reverse() + if isinstance(self, _BaseNet): + return '%s/%d' % (':'.join(parts), self.prefixlen) + return ':'.join(parts) + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def packed(self): + """The binary representation of this address.""" + return v6_int_to_packed(self._ip) + + @property + def version(self): + return self._version + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return self in IPv6Network('ff00::/8') + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return (self in IPv6Network('::/8') or + self in IPv6Network('100::/8') or + self in IPv6Network('200::/7') or + self in IPv6Network('400::/6') or + self in IPv6Network('800::/5') or + self in IPv6Network('1000::/4') or + self in IPv6Network('4000::/3') or + self in IPv6Network('6000::/3') or + self in IPv6Network('8000::/3') or + self in IPv6Network('A000::/3') or + self in IPv6Network('C000::/3') or + self in IPv6Network('E000::/4') or + self in IPv6Network('F000::/5') or + self in IPv6Network('F800::/6') or + self in IPv6Network('FE00::/9')) + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return self._ip == 0 and getattr(self, '_prefixlen', 128) == 128 + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return self._ip == 1 and getattr(self, '_prefixlen', 128) == 128 + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return self in IPv6Network('fe80::/10') + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return self in IPv6Network('fec0::/10') + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per RFC 4193. + + """ + return self in IPv6Network('fc00::/7') + + @property + def ipv4_mapped(self): + """Return the IPv4 mapped address. + + Returns: + If the IPv6 address is a v4 mapped address, return the + IPv4 mapped address. Return None otherwise. + + """ + if (self._ip >> 32) != 0xFFFF: + return None + return IPv4Address(self._ip & 0xFFFFFFFF) + + @property + def teredo(self): + """Tuple of embedded teredo IPs. + + Returns: + Tuple of the (server, client) IPs or None if the address + doesn't appear to be a teredo address (doesn't start with + 2001::/32) + + """ + if (self._ip >> 96) != 0x20010000: + return None + return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF), + IPv4Address(~self._ip & 0xFFFFFFFF)) + + @property + def sixtofour(self): + """Return the IPv4 6to4 embedded address. + + Returns: + The IPv4 6to4-embedded address if present or None if the + address doesn't appear to contain a 6to4 embedded address. + + """ + if (self._ip >> 112) != 0x2002: + return None + return IPv4Address((self._ip >> 80) & 0xFFFFFFFF) + + +class IPv6Address(_BaseV6, _BaseIP): + + """Represent and manipulate single IPv6 Addresses. + """ + + def __init__(self, address): + """Instantiate a new IPv6 address object. + + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv6Address('2001:4860::') == + IPv6Address(42541956101370907050197289607612071936L). + or, more generally + IPv6Address(IPv6Address('2001:4860::')._ip) == + IPv6Address('2001:4860::') + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + + """ + _BaseV6.__init__(self, address) + + # Efficient constructor from integer. + if isinstance(address, (int, long)): + self._ip = address + if address < 0 or address > self._ALL_ONES: + raise AddressValueError(address) + return + + # Constructing from a packed address + if isinstance(address, Bytes): + try: + hi, lo = struct.unpack('!QQ', address) + except struct.error: + raise AddressValueError(address) # Wrong length. + self._ip = (hi << 64) | lo + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = str(address) + if not addr_str: + raise AddressValueError('') + + self._ip = self._ip_int_from_string(addr_str) + + +class IPv6Network(_BaseV6, _BaseNet): + + """This class represents and manipulates 128-bit IPv6 networks. + + Attributes: [examples for IPv6('2001:658:22A:CAFE:200::1/64')] + .ip: IPv6Address('2001:658:22a:cafe:200::1') + .network: IPv6Address('2001:658:22a:cafe::') + .hostmask: IPv6Address('::ffff:ffff:ffff:ffff') + .broadcast: IPv6Address('2001:658:22a:cafe:ffff:ffff:ffff:ffff') + .netmask: IPv6Address('ffff:ffff:ffff:ffff::') + .prefixlen: 64 + + """ + + + def __init__(self, address, strict=False): + """Instantiate a new IPv6 Network object. + + Args: + address: A string or integer representing the IPv6 network or the IP + and prefix/netmask. + '2001:4860::/128' + '2001:4860:0000:0000:0000:0000:0000:0000/128' + '2001:4860::' + are all functionally the same in IPv6. That is to say, + failing to provide a subnetmask will create an object with + a mask of /128. + + Additionally, an integer can be passed, so + IPv6Network('2001:4860::') == + IPv6Network(42541956101370907050197289607612071936L). + or, more generally + IPv6Network(IPv6Network('2001:4860::')._ip) == + IPv6Network('2001:4860::') + + strict: A boolean. If true, ensure that we have been passed + A true network address, eg, 192.168.1.0/24 and not an + IP address on a network, eg, 192.168.1.1/24. + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + NetmaskValueError: If the netmask isn't valid for + an IPv6 address. + ValueError: If strict was True and a network address was not + supplied. + + """ + _BaseNet.__init__(self, address) + _BaseV6.__init__(self, address) + + # Constructing from an integer or packed bytes. + if isinstance(address, (int, long, Bytes)): + self.ip = IPv6Address(address) + self._ip = self.ip._ip + self._prefixlen = self._max_prefixlen + self.netmask = IPv6Address(self._ALL_ONES) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = str(address).split('/') + + if len(addr) > 2: + raise AddressValueError(address) + + self._ip = self._ip_int_from_string(addr[0]) + self.ip = IPv6Address(self._ip) + + if len(addr) == 2: + if self._is_valid_netmask(addr[1]): + self._prefixlen = int(addr[1]) + else: + raise NetmaskValueError(addr[1]) + else: + self._prefixlen = self._max_prefixlen + + self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen)) + + if strict: + if self.ip != self.network: + raise ValueError('%s has host bits set' % + self.ip) + if self._prefixlen == (self._max_prefixlen - 1): + self.iterhosts = self.__iter__ + + def _is_valid_netmask(self, prefixlen): + """Verify that the netmask/prefixlen is valid. + + Args: + prefixlen: A string, the netmask in prefix length format. + + Returns: + A boolean, True if the prefix represents a valid IPv6 + netmask. + + """ + try: + prefixlen = int(prefixlen) + except ValueError: + return False + return 0 <= prefixlen <= self._max_prefixlen + + @property + def with_netmask(self): + return self.with_prefixlen diff --git a/plugins/Sidebar/maxminddb/reader.py b/plugins/Sidebar/maxminddb/reader.py new file mode 100644 index 00000000..5ecfbdf2 --- /dev/null +++ b/plugins/Sidebar/maxminddb/reader.py @@ -0,0 +1,221 @@ +""" +maxminddb.reader +~~~~~~~~~~~~~~~~ + +This module contains the pure Python database reader and related classes. + +""" +from __future__ import unicode_literals + +try: + import mmap +except ImportError: + # pylint: disable=invalid-name + mmap = None + +import struct + +from maxminddb.compat import byte_from_int, int_from_byte, ipaddress +from maxminddb.const import MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY +from maxminddb.decoder import Decoder +from maxminddb.errors import InvalidDatabaseError +from maxminddb.file import FileBuffer + + +class Reader(object): + + """ + Instances of this class provide a reader for the MaxMind DB format. IP + addresses can be looked up using the ``get`` method. + """ + + _DATA_SECTION_SEPARATOR_SIZE = 16 + _METADATA_START_MARKER = b"\xAB\xCD\xEFMaxMind.com" + + _ipv4_start = None + + def __init__(self, database, mode=MODE_AUTO): + """Reader for the MaxMind DB file format + + Arguments: + database -- A path to a valid MaxMind DB file such as a GeoIP2 + database file. + mode -- mode to open the database with. Valid mode are: + * MODE_MMAP - read from memory map. + * MODE_FILE - read database as standard file. + * MODE_MEMORY - load database into memory. + * MODE_AUTO - tries MODE_MMAP and then MODE_FILE. Default. + """ + if (mode == MODE_AUTO and mmap) or mode == MODE_MMAP: + with open(database, 'rb') as db_file: + self._buffer = mmap.mmap( + db_file.fileno(), 0, access=mmap.ACCESS_READ) + self._buffer_size = self._buffer.size() + elif mode in (MODE_AUTO, MODE_FILE): + self._buffer = FileBuffer(database) + self._buffer_size = self._buffer.size() + elif mode == MODE_MEMORY: + with open(database, 'rb') as db_file: + self._buffer = db_file.read() + self._buffer_size = len(self._buffer) + else: + raise ValueError('Unsupported open mode ({0}). Only MODE_AUTO, ' + ' MODE_FILE, and MODE_MEMORY are support by the pure Python ' + 'Reader'.format(mode)) + + metadata_start = self._buffer.rfind(self._METADATA_START_MARKER, + max(0, self._buffer_size + - 128 * 1024)) + + if metadata_start == -1: + self.close() + raise InvalidDatabaseError('Error opening database file ({0}). ' + 'Is this a valid MaxMind DB file?' + ''.format(database)) + + metadata_start += len(self._METADATA_START_MARKER) + metadata_decoder = Decoder(self._buffer, metadata_start) + (metadata, _) = metadata_decoder.decode(metadata_start) + self._metadata = Metadata( + **metadata) # pylint: disable=bad-option-value + + self._decoder = Decoder(self._buffer, self._metadata.search_tree_size + + self._DATA_SECTION_SEPARATOR_SIZE) + + def metadata(self): + """Return the metadata associated with the MaxMind DB file""" + return self._metadata + + def get(self, ip_address): + """Return the record for the ip_address in the MaxMind DB + + + Arguments: + ip_address -- an IP address in the standard string notation + """ + address = ipaddress.ip_address(ip_address) + + if address.version == 6 and self._metadata.ip_version == 4: + raise ValueError('Error looking up {0}. You attempted to look up ' + 'an IPv6 address in an IPv4-only database.'.format( + ip_address)) + pointer = self._find_address_in_tree(address) + + return self._resolve_data_pointer(pointer) if pointer else None + + def _find_address_in_tree(self, ip_address): + packed = ip_address.packed + + bit_count = len(packed) * 8 + node = self._start_node(bit_count) + + for i in range(bit_count): + if node >= self._metadata.node_count: + break + bit = 1 & (int_from_byte(packed[i >> 3]) >> 7 - (i % 8)) + node = self._read_node(node, bit) + if node == self._metadata.node_count: + # Record is empty + return 0 + elif node > self._metadata.node_count: + return node + + raise InvalidDatabaseError('Invalid node in search tree') + + def _start_node(self, length): + if self._metadata.ip_version != 6 or length == 128: + return 0 + + # We are looking up an IPv4 address in an IPv6 tree. Skip over the + # first 96 nodes. + if self._ipv4_start: + return self._ipv4_start + + node = 0 + for _ in range(96): + if node >= self._metadata.node_count: + break + node = self._read_node(node, 0) + self._ipv4_start = node + return node + + def _read_node(self, node_number, index): + base_offset = node_number * self._metadata.node_byte_size + + record_size = self._metadata.record_size + if record_size == 24: + offset = base_offset + index * 3 + node_bytes = b'\x00' + self._buffer[offset:offset + 3] + elif record_size == 28: + (middle,) = struct.unpack( + b'!B', self._buffer[base_offset + 3:base_offset + 4]) + if index: + middle &= 0x0F + else: + middle = (0xF0 & middle) >> 4 + offset = base_offset + index * 4 + node_bytes = byte_from_int( + middle) + self._buffer[offset:offset + 3] + elif record_size == 32: + offset = base_offset + index * 4 + node_bytes = self._buffer[offset:offset + 4] + else: + raise InvalidDatabaseError( + 'Unknown record size: {0}'.format(record_size)) + return struct.unpack(b'!I', node_bytes)[0] + + def _resolve_data_pointer(self, pointer): + resolved = pointer - self._metadata.node_count + \ + self._metadata.search_tree_size + + if resolved > self._buffer_size: + raise InvalidDatabaseError( + "The MaxMind DB file's search tree is corrupt") + + (data, _) = self._decoder.decode(resolved) + return data + + def close(self): + """Closes the MaxMind DB file and returns the resources to the system""" + # pylint: disable=unidiomatic-typecheck + if type(self._buffer) not in (str, bytes): + self._buffer.close() + + +class Metadata(object): + + """Metadata for the MaxMind DB reader""" + + # pylint: disable=too-many-instance-attributes + def __init__(self, **kwargs): + """Creates new Metadata object. kwargs are key/value pairs from spec""" + # Although I could just update __dict__, that is less obvious and it + # doesn't work well with static analysis tools and some IDEs + self.node_count = kwargs['node_count'] + self.record_size = kwargs['record_size'] + self.ip_version = kwargs['ip_version'] + self.database_type = kwargs['database_type'] + self.languages = kwargs['languages'] + self.binary_format_major_version = kwargs[ + 'binary_format_major_version'] + self.binary_format_minor_version = kwargs[ + 'binary_format_minor_version'] + self.build_epoch = kwargs['build_epoch'] + self.description = kwargs['description'] + + @property + def node_byte_size(self): + """The size of a node in bytes""" + return self.record_size // 4 + + @property + def search_tree_size(self): + """The size of the search tree""" + return self.node_count * self.node_byte_size + + def __repr__(self): + args = ', '.join('%s=%r' % x for x in self.__dict__.items()) + return '{module}.{class_name}({data})'.format( + module=self.__module__, + class_name=self.__class__.__name__, + data=args) diff --git a/plugins/Sidebar/media-globe/Detector.js b/plugins/Sidebar/media-globe/Detector.js new file mode 100644 index 00000000..1c074b83 --- /dev/null +++ b/plugins/Sidebar/media-globe/Detector.js @@ -0,0 +1,60 @@ +/** + * @author alteredq / http://alteredqualia.com/ + * @author mr.doob / http://mrdoob.com/ + */ + +Detector = { + + canvas : !! window.CanvasRenderingContext2D, + webgl : ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), + workers : !! window.Worker, + fileapi : window.File && window.FileReader && window.FileList && window.Blob, + + getWebGLErrorMessage : function () { + + var domElement = document.createElement( 'div' ); + + domElement.style.fontFamily = 'monospace'; + domElement.style.fontSize = '13px'; + domElement.style.textAlign = 'center'; + domElement.style.background = '#eee'; + domElement.style.color = '#000'; + domElement.style.padding = '1em'; + domElement.style.width = '475px'; + domElement.style.margin = '5em auto 0'; + + if ( ! this.webgl ) { + + domElement.innerHTML = window.WebGLRenderingContext ? [ + 'Sorry, your graphics card doesn\'t support WebGL' + ].join( '\n' ) : [ + 'Sorry, your browser doesn\'t support WebGL
    ', + 'Please try with', + 'Chrome, ', + 'Firefox 4 or', + 'Webkit Nightly (Mac)' + ].join( '\n' ); + + } + + return domElement; + + }, + + addGetWebGLMessage : function ( parameters ) { + + var parent, id, domElement; + + parameters = parameters || {}; + + parent = parameters.parent !== undefined ? parameters.parent : document.body; + id = parameters.id !== undefined ? parameters.id : 'oldie'; + + domElement = Detector.getWebGLErrorMessage(); + domElement.id = id; + + parent.appendChild( domElement ); + + } + +}; diff --git a/plugins/Sidebar/media-globe/Tween.js b/plugins/Sidebar/media-globe/Tween.js new file mode 100644 index 00000000..bdf141ad --- /dev/null +++ b/plugins/Sidebar/media-globe/Tween.js @@ -0,0 +1,12 @@ +// Tween.js - http://github.com/sole/tween.js +var TWEEN=TWEEN||function(){var a,e,c,d,f=[];return{start:function(g){c=setInterval(this.update,1E3/(g||60))},stop:function(){clearInterval(c)},add:function(g){f.push(g)},remove:function(g){a=f.indexOf(g);a!==-1&&f.splice(a,1)},update:function(){a=0;e=f.length;for(d=(new Date).getTime();a1?1:b;i=n(b);for(h in c)a[h]=e[h]+c[h]*i;l!==null&&l.call(a,i);if(b==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a}; +TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a}; +TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1}; +TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)}; +TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d))}; +TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/d)+1}; +TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/d)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1}; +TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375}; +TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5}; diff --git a/plugins/Sidebar/media-globe/all.js b/plugins/Sidebar/media-globe/all.js new file mode 100644 index 00000000..8b6e5b6b --- /dev/null +++ b/plugins/Sidebar/media-globe/all.js @@ -0,0 +1,1333 @@ + + +/* ---- plugins/Sidebar/media-globe/Detector.js ---- */ + + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mr.doob / http://mrdoob.com/ + */ + +Detector = { + + canvas : !! window.CanvasRenderingContext2D, + webgl : ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), + workers : !! window.Worker, + fileapi : window.File && window.FileReader && window.FileList && window.Blob, + + getWebGLErrorMessage : function () { + + var domElement = document.createElement( 'div' ); + + domElement.style.fontFamily = 'monospace'; + domElement.style.fontSize = '13px'; + domElement.style.textAlign = 'center'; + domElement.style.background = '#eee'; + domElement.style.color = '#000'; + domElement.style.padding = '1em'; + domElement.style.width = '475px'; + domElement.style.margin = '5em auto 0'; + + if ( ! this.webgl ) { + + domElement.innerHTML = window.WebGLRenderingContext ? [ + 'Sorry, your graphics card doesn\'t support WebGL' + ].join( '\n' ) : [ + 'Sorry, your browser doesn\'t support WebGL
    ', + 'Please try with', + 'Chrome, ', + 'Firefox 4 or', + 'Webkit Nightly (Mac)' + ].join( '\n' ); + + } + + return domElement; + + }, + + addGetWebGLMessage : function ( parameters ) { + + var parent, id, domElement; + + parameters = parameters || {}; + + parent = parameters.parent !== undefined ? parameters.parent : document.body; + id = parameters.id !== undefined ? parameters.id : 'oldie'; + + domElement = Detector.getWebGLErrorMessage(); + domElement.id = id; + + parent.appendChild( domElement ); + + } + +}; + + + +/* ---- plugins/Sidebar/media-globe/Tween.js ---- */ + + +// Tween.js - http://github.com/sole/tween.js +var TWEEN=TWEEN||function(){var a,e,c,d,f=[];return{start:function(g){c=setInterval(this.update,1E3/(g||60))},stop:function(){clearInterval(c)},add:function(g){f.push(g)},remove:function(g){a=f.indexOf(g);a!==-1&&f.splice(a,1)},update:function(){a=0;e=f.length;for(d=(new Date).getTime();a1?1:b;i=n(b);for(h in c)a[h]=e[h]+c[h]*i;l!==null&&l.call(a,i);if(b==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a}; +TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a}; +TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1}; +TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)}; +TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d))}; +TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/d)+1}; +TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/d)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1}; +TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375}; +TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5}; + + + +/* ---- plugins/Sidebar/media-globe/globe.js ---- */ + + +/** + * dat.globe Javascript WebGL Globe Toolkit + * http://dataarts.github.com/dat.globe + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +var DAT = DAT || {}; + +DAT.Globe = function(container, opts) { + opts = opts || {}; + + var colorFn = opts.colorFn || function(x) { + var c = new THREE.Color(); + c.setHSL( ( 0.5 - (x * 2) ), Math.max(0.8, 1.0 - (x * 3)), 0.5 ); + return c; + }; + var imgDir = opts.imgDir || '/globe/'; + + var Shaders = { + 'earth' : { + uniforms: { + 'texture': { type: 't', value: null } + }, + vertexShader: [ + 'varying vec3 vNormal;', + 'varying vec2 vUv;', + 'void main() {', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + 'vNormal = normalize( normalMatrix * normal );', + 'vUv = uv;', + '}' + ].join('\n'), + fragmentShader: [ + 'uniform sampler2D texture;', + 'varying vec3 vNormal;', + 'varying vec2 vUv;', + 'void main() {', + 'vec3 diffuse = texture2D( texture, vUv ).xyz;', + 'float intensity = 1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );', + 'vec3 atmosphere = vec3( 1.0, 1.0, 1.0 ) * pow( intensity, 3.0 );', + 'gl_FragColor = vec4( diffuse + atmosphere, 1.0 );', + '}' + ].join('\n') + }, + 'atmosphere' : { + uniforms: {}, + vertexShader: [ + 'varying vec3 vNormal;', + 'void main() {', + 'vNormal = normalize( normalMatrix * normal );', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + '}' + ].join('\n'), + fragmentShader: [ + 'varying vec3 vNormal;', + 'void main() {', + 'float intensity = pow( 0.8 - dot( vNormal, vec3( 0, 0, 1.0 ) ), 12.0 );', + 'gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * intensity;', + '}' + ].join('\n') + } + }; + + var camera, scene, renderer, w, h; + var mesh, atmosphere, point, running; + + var overRenderer; + var running = true; + + var curZoomSpeed = 0; + var zoomSpeed = 50; + + var mouse = { x: 0, y: 0 }, mouseOnDown = { x: 0, y: 0 }; + var rotation = { x: 0, y: 0 }, + target = { x: Math.PI*3/2, y: Math.PI / 6.0 }, + targetOnDown = { x: 0, y: 0 }; + + var distance = 100000, distanceTarget = 100000; + var padding = 10; + var PI_HALF = Math.PI / 2; + + function init() { + + container.style.color = '#fff'; + container.style.font = '13px/20px Arial, sans-serif'; + + var shader, uniforms, material; + w = container.offsetWidth || window.innerWidth; + h = container.offsetHeight || window.innerHeight; + + camera = new THREE.PerspectiveCamera(30, w / h, 1, 10000); + camera.position.z = distance; + + scene = new THREE.Scene(); + + var geometry = new THREE.SphereGeometry(200, 40, 30); + + shader = Shaders['earth']; + uniforms = THREE.UniformsUtils.clone(shader.uniforms); + + uniforms['texture'].value = THREE.ImageUtils.loadTexture(imgDir+'world.jpg'); + + material = new THREE.ShaderMaterial({ + + uniforms: uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + + }); + + mesh = new THREE.Mesh(geometry, material); + mesh.rotation.y = Math.PI; + scene.add(mesh); + + shader = Shaders['atmosphere']; + uniforms = THREE.UniformsUtils.clone(shader.uniforms); + + material = new THREE.ShaderMaterial({ + + uniforms: uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: THREE.BackSide, + blending: THREE.AdditiveBlending, + transparent: true + + }); + + mesh = new THREE.Mesh(geometry, material); + mesh.scale.set( 1.1, 1.1, 1.1 ); + scene.add(mesh); + + geometry = new THREE.BoxGeometry(2.75, 2.75, 1); + geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,0,-0.5)); + + point = new THREE.Mesh(geometry); + + renderer = new THREE.WebGLRenderer({antialias: true}); + renderer.setSize(w, h); + renderer.setClearColor( 0x212121, 1 ); + + renderer.domElement.style.position = 'relative'; + + container.appendChild(renderer.domElement); + + container.addEventListener('mousedown', onMouseDown, false); + + container.addEventListener('mousewheel', onMouseWheel, false); + + document.addEventListener('keydown', onDocumentKeyDown, false); + + window.addEventListener('resize', onWindowResize, false); + + container.addEventListener('mouseover', function() { + overRenderer = true; + }, false); + + container.addEventListener('mouseout', function() { + overRenderer = false; + }, false); + } + + function addData(data, opts) { + var lat, lng, size, color, i, step, colorFnWrapper; + + opts.animated = opts.animated || false; + this.is_animated = opts.animated; + opts.format = opts.format || 'magnitude'; // other option is 'legend' + if (opts.format === 'magnitude') { + step = 3; + colorFnWrapper = function(data, i) { return colorFn(data[i+2]); } + } else if (opts.format === 'legend') { + step = 4; + colorFnWrapper = function(data, i) { return colorFn(data[i+3]); } + } else if (opts.format === 'peer') { + colorFnWrapper = function(data, i) { return colorFn(data[i+2]); } + } else { + throw('error: format not supported: '+opts.format); + } + + if (opts.animated) { + if (this._baseGeometry === undefined) { + this._baseGeometry = new THREE.Geometry(); + for (i = 0; i < data.length; i += step) { + lat = data[i]; + lng = data[i + 1]; +// size = data[i + 2]; + color = colorFnWrapper(data,i); + size = 0; + addPoint(lat, lng, size, color, this._baseGeometry); + } + } + if(this._morphTargetId === undefined) { + this._morphTargetId = 0; + } else { + this._morphTargetId += 1; + } + opts.name = opts.name || 'morphTarget'+this._morphTargetId; + } + var subgeo = new THREE.Geometry(); + for (i = 0; i < data.length; i += step) { + lat = data[i]; + lng = data[i + 1]; + color = colorFnWrapper(data,i); + size = data[i + 2]; + size = size*200; + addPoint(lat, lng, size, color, subgeo); + } + if (opts.animated) { + this._baseGeometry.morphTargets.push({'name': opts.name, vertices: subgeo.vertices}); + } else { + this._baseGeometry = subgeo; + } + + }; + + function createPoints() { + if (this._baseGeometry !== undefined) { + if (this.is_animated === false) { + this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ + color: 0xffffff, + vertexColors: THREE.FaceColors, + morphTargets: false + })); + } else { + if (this._baseGeometry.morphTargets.length < 8) { + console.log('t l',this._baseGeometry.morphTargets.length); + var padding = 8-this._baseGeometry.morphTargets.length; + console.log('padding', padding); + for(var i=0; i<=padding; i++) { + console.log('padding',i); + this._baseGeometry.morphTargets.push({'name': 'morphPadding'+i, vertices: this._baseGeometry.vertices}); + } + } + this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ + color: 0xffffff, + vertexColors: THREE.FaceColors, + morphTargets: true + })); + } + scene.add(this.points); + } + } + + function addPoint(lat, lng, size, color, subgeo) { + + var phi = (90 - lat) * Math.PI / 180; + var theta = (180 - lng) * Math.PI / 180; + + point.position.x = 200 * Math.sin(phi) * Math.cos(theta); + point.position.y = 200 * Math.cos(phi); + point.position.z = 200 * Math.sin(phi) * Math.sin(theta); + + point.lookAt(mesh.position); + + point.scale.z = Math.max( size, 0.1 ); // avoid non-invertible matrix + point.updateMatrix(); + + for (var i = 0; i < point.geometry.faces.length; i++) { + + point.geometry.faces[i].color = color; + + } + if(point.matrixAutoUpdate){ + point.updateMatrix(); + } + subgeo.merge(point.geometry, point.matrix); + } + + function onMouseDown(event) { + event.preventDefault(); + + container.addEventListener('mousemove', onMouseMove, false); + container.addEventListener('mouseup', onMouseUp, false); + container.addEventListener('mouseout', onMouseOut, false); + + mouseOnDown.x = - event.clientX; + mouseOnDown.y = event.clientY; + + targetOnDown.x = target.x; + targetOnDown.y = target.y; + + container.style.cursor = 'move'; + } + + function onMouseMove(event) { + mouse.x = - event.clientX; + mouse.y = event.clientY; + + var zoomDamp = distance/1000; + + target.x = targetOnDown.x + (mouse.x - mouseOnDown.x) * 0.005 * zoomDamp; + target.y = targetOnDown.y + (mouse.y - mouseOnDown.y) * 0.005 * zoomDamp; + + target.y = target.y > PI_HALF ? PI_HALF : target.y; + target.y = target.y < - PI_HALF ? - PI_HALF : target.y; + } + + function onMouseUp(event) { + container.removeEventListener('mousemove', onMouseMove, false); + container.removeEventListener('mouseup', onMouseUp, false); + container.removeEventListener('mouseout', onMouseOut, false); + container.style.cursor = 'auto'; + } + + function onMouseOut(event) { + container.removeEventListener('mousemove', onMouseMove, false); + container.removeEventListener('mouseup', onMouseUp, false); + container.removeEventListener('mouseout', onMouseOut, false); + } + + function onMouseWheel(event) { + event.preventDefault(); + if (overRenderer) { + zoom(event.wheelDeltaY * 0.3); + } + return false; + } + + function onDocumentKeyDown(event) { + switch (event.keyCode) { + case 38: + zoom(100); + event.preventDefault(); + break; + case 40: + zoom(-100); + event.preventDefault(); + break; + } + } + + function onWindowResize( event ) { + camera.aspect = container.offsetWidth / container.offsetHeight; + camera.updateProjectionMatrix(); + renderer.setSize( container.offsetWidth, container.offsetHeight ); + } + + function zoom(delta) { + distanceTarget -= delta; + distanceTarget = distanceTarget > 855 ? 855 : distanceTarget; + distanceTarget = distanceTarget < 350 ? 350 : distanceTarget; + } + + function animate() { + if (!running) return + requestAnimationFrame(animate); + render(); + } + + function render() { + zoom(curZoomSpeed); + + rotation.x += (target.x - rotation.x) * 0.1; + rotation.y += (target.y - rotation.y) * 0.1; + distance += (distanceTarget - distance) * 0.3; + + camera.position.x = distance * Math.sin(rotation.x) * Math.cos(rotation.y); + camera.position.y = distance * Math.sin(rotation.y); + camera.position.z = distance * Math.cos(rotation.x) * Math.cos(rotation.y); + + camera.lookAt(mesh.position); + + renderer.render(scene, camera); + } + + function unload() { + running = false + container.removeEventListener('mousedown', onMouseDown, false); + container.removeEventListener('mousewheel', onMouseWheel, false); + document.removeEventListener('keydown', onDocumentKeyDown, false); + window.removeEventListener('resize', onWindowResize, false); + + } + + init(); + this.animate = animate; + this.unload = unload; + + + this.__defineGetter__('time', function() { + return this._time || 0; + }); + + this.__defineSetter__('time', function(t) { + var validMorphs = []; + var morphDict = this.points.morphTargetDictionary; + for(var k in morphDict) { + if(k.indexOf('morphPadding') < 0) { + validMorphs.push(morphDict[k]); + } + } + validMorphs.sort(); + var l = validMorphs.length-1; + var scaledt = t*l+1; + var index = Math.floor(scaledt); + for (i=0;i= 0) { + this.points.morphTargetInfluences[lastIndex] = 1 - leftover; + } + this.points.morphTargetInfluences[index] = leftover; + this._time = t; + }); + + this.addData = addData; + this.createPoints = createPoints; + this.renderer = renderer; + this.scene = scene; + + return this; + +}; + + + + +/* ---- plugins/Sidebar/media-globe/three.min.js ---- */ + + +// threejs.org/license +'use strict';var THREE={REVISION:"69"};"object"===typeof module&&(module.exports=THREE);void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a};b=.5>=c?c*(1+b):c+b-c*b;c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= +Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r;this.g= +a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<< +8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f,f=.5>=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(cf&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y= +.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;this.normalize();return this}}(),inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*= +-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},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=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this}, +multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,k=b._z,n=b._w;this._x=c*n+f*g+d*k-e*h;this._y=d*n+f*h+e*g-c*k;this._z=e*n+f*k+c*h-d*g;this._w=f*n-c*g-d*h-e*k;this.onChangeCallback();return this},multiplyVector3:function(a){console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."); +return a.applyQuaternion(this)},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),k=Math.sqrt(1-g*g);if(.001>Math.abs(k))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;g=Math.sin((1-b)*h)/k;h= +Math.sin(b*h)/k;this._w=f*g+this._w*h;this._x=c*g+this._x*h;this._y=d*g+this._y*h;this._z=e*g+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback= +a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};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},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, +b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this}, +roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},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.x*this.x+this.y*this.y)},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){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},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},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y= +a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a;return function(b){!1===b instanceof THREE.Euler&&console.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),applyMatrix3:function(a){var b=this.x, +c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z= +(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,n=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-n*-f;this.y=k*a+b*-f+n*-e-h*-g;this.z=n*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(),unproject:function(){var a;return function(b){void 0=== +a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},min:function(a){this.x> +a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3,b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a, +b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z); +return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},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.x*this.x+this.y*this.y+this.z*this.z)},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){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/ +b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this}, +projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length()); +return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(a,b){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")}, +getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a, +b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},setFromMatrixScale: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;return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x=== +this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},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=void 0!==d?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},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x; +case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this}, +addVectors: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},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors: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},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b= +this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this}, +setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var n=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+n-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;n=(n+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>n?.01>e?(b=0,d=c=.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):h>n?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h), +b=d/c,d=k/c):.01>n?(c=b=.707106781,d=0):(d=Math.sqrt(n),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+n-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);this.wb.w&&(this.w=b.w);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w); +return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w); +return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())}, +setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]= +this.z;a[b+3]=this.w;return a},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; +THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order},set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},copy:function(a){this._x= +a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b){var c=THREE.Math.clamp,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[1],k=d[5],n=d[9],p=d[2],q=d[6],d=d[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(c(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-n,d),this._z=Math.atan2(-f,e)):(this._x=Math.atan2(q,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-c(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(g,d),this._z=Math.atan2(h,k)):(this._y= +Math.atan2(-p,e),this._z=0)):"ZXY"===b?(this._x=Math.asin(c(q,-1,1)),.99999>Math.abs(q)?(this._y=Math.atan2(-p,d),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,e))):"ZYX"===b?(this._y=Math.asin(-c(p,-1,1)),.99999>Math.abs(p)?(this._x=Math.atan2(q,d),this._z=Math.atan2(h,e)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(c(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-n,k),this._y=Math.atan2(-p,e)):(this._x=0,this._y=Math.atan2(g,d))):"XZY"===b?(this._z=Math.asin(-c(f, +-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(q,k),this._y=Math.atan2(g,e)):(this._x=Math.atan2(-n,d),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;this.onChangeCallback();return this},setFromQuaternion:function(a,b,c){var d=THREE.Math.clamp,e=a.x*a.x,f=a.y*a.y,g=a.z*a.z,h=a.w*a.w;b=b||this._order;"XYZ"===b?(this._x=Math.atan2(2*(a.x*a.w-a.y*a.z),h-e-f+g),this._y=Math.asin(d(2*(a.x*a.z+a.y*a.w),-1,1)),this._z=Math.atan2(2*(a.z*a.w-a.x* +a.y),h+e-f-g)):"YXZ"===b?(this._x=Math.asin(d(2*(a.x*a.w-a.y*a.z),-1,1)),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h-e-f+g),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h-e+f-g)):"ZXY"===b?(this._x=Math.asin(d(2*(a.x*a.w+a.y*a.z),-1,1)),this._y=Math.atan2(2*(a.y*a.w-a.z*a.x),h-e-f+g),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),h-e+f-g)):"ZYX"===b?(this._x=Math.atan2(2*(a.x*a.w+a.z*a.y),h-e-f+g),this._y=Math.asin(d(2*(a.y*a.w-a.x*a.z),-1,1)),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h+e-f-g)):"YZX"===b?(this._x=Math.atan2(2* +(a.x*a.w-a.z*a.y),h-e+f-g),this._y=Math.atan2(2*(a.y*a.w-a.x*a.z),h+e-f-g),this._z=Math.asin(d(2*(a.x*a.y+a.z*a.w),-1,1))):"XZY"===b?(this._x=Math.atan2(2*(a.x*a.w+a.y*a.z),h-e+f-g),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h+e-f-g),this._z=Math.asin(d(2*(a.z*a.w-a.x*a.y),-1,1))):console.warn("THREE.Euler: .setFromQuaternion() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this); +this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(){return[this._x,this._y,this._z,this._order]},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Euler(this._x,this._y,this._z,this._order)}}; +THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, +b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); +this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; +THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector2).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.y +this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&& +a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; +THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector3).set((a.x-this.min.x)/(this.max.x- +this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= +new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y, +this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a); +this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(){this.elements=new Float32Array([1,0,0,0,1,0,0,0,1]);0this.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,n=1/k;b.elements[0]*=c;b.elements[1]*= +c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=n;b.elements[9]*=n;b.elements[10]*=n;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRad(.5*a)); +var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,k=c-d,n=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/n;g[14]=-((f+e)/n);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){return(new THREE.Matrix4).fromArray(this.elements)}}; +THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; +THREE.Ray.prototype={constructor:THREE.Ray,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new THREE.Vector3;c.subVectors(a,this.origin); +var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(a,b,c,d){var e=a.clone().add(b).multiplyScalar(.5),f=b.clone().sub(a).normalize(),g=.5*a.distanceTo(b),h= +this.origin.clone().sub(e);a=-this.direction.dot(f);b=h.dot(this.direction);var k=-h.dot(f),n=h.lengthSq(),p=Math.abs(1-a*a),q,m;0<=p?(h=a*k-b,q=a*b-k,m=g*p,0<=h?q>=-m?q<=m?(g=1/p,h*=g,q*=g,a=h*(h+a*q+2*b)+q*(a*h+q+2*k)+n):(q=g,h=Math.max(0,-(a*q+b)),a=-h*h+q*(q+2*k)+n):(q=-g,h=Math.max(0,-(a*q+b)),a=-h*h+q*(q+2*k)+n):q<=-m?(h=Math.max(0,-(-a*g+b)),q=0f)return null;f=Math.sqrt(f-e);e=d-f; +d+=f;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new THREE.Vector3; +return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g;d=1/this.direction.x;f=1/this.direction.y;g=1/this.direction.z;var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=f?(e=(a.min.y-h.y)*f,f*=a.max.y-h.y):(e=(a.max.y-h.y)*f,f*=a.min.y-h.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(fg||e>d)return null;if(e>c||c!== +c)c=e;if(gd?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a));if(0>g||e+g>f)return null; +e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new THREE.Ray).copy(this)}};THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; +THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,g=b.length;f=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= +this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius); +return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}}; +THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; +THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],n=c[7],p=c[8],q=c[9],m=c[10],r=c[11],t=c[12],s=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,n-g,r-p,c-t).normalize();b[1].setComponents(f+ +a,n+g,r+p,c+t).normalize();b[2].setComponents(f+d,n+h,r+q,c+s).normalize();b[3].setComponents(f-d,n-h,r-q,c-s).normalize();b[4].setComponents(f-e,n-k,r-m,c-u).normalize();b[5].setComponents(f+e,n+k,r+m,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes, +c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0g&&0>f)return!1}return!0}}(), +containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, +c);return this}}(),copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, +b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start);a=this.distanceToPoint(a.end);return 0>b&&0a&&0f||1e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(){var a=Math.PI/180;return function(b){return b*a}}(),radToDeg:function(){var a= +180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a}}; +THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,n,p,q,m;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;n=this.points[c[0]];p=this.points[c[1]];q=this.points[c[2]];m=this.points[c[3]];h=g*g;k=g*h;d.x=b(n.x,p.x,q.x,m.x,g,h,k);d.y=b(n.y,p.y,q.y,m.y,g,h,k);d.z=b(n.z,p.z,q.z,m.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a=b.x+b.y}}(); +THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| +new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}, +clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; +THREE.Clock.prototype={constructor:THREE.Clock,start:function(){this.oldTime=this.startTime=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now(), +a=.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){}; +THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a].indexOf(b)&& +c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners[a];if(void 0!==c){var d=c.indexOf(b);-1!==d&&c.splice(d,1)}}},dispatchEvent:function(a){if(void 0!==this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;for(var c=[],d=b.length,e=0;eza?-1:1;h[4*a]=la.x;h[4*a+1]=la.y;h[4*a+2]=la.z;h[4*a+3]=Ga}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array, +e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],n=[],p=0;ps;s++)t=a[3*c+s],-1==m[t]?(q[2*s]=t,q[2*s+1]=-1,p++):m[t]k.index+b)for(k={start:f,count:0,index:g},h.push(k),p=0;6>p;p+=2)s=q[p+1],-1p;p+=2)t=q[p],s=q[p+1],-1===s&&(s=g++),m[t]=s,r[s]=t,e[f++]=s-k.index,k.count++}this.reorderBuffers(e,r,g);return this.offsets=h},merge:function(){console.log("BufferGeometry.merge(): TODO")},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;ed?-1:1,e.vertexTangents[c]=new THREE.Vector4(w.x,w.y,w.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;cd;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;ca.opacity)h.transparent=a.transparent;void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"=== +a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorAmbient&&(h.ambient=e(a.colorAmbient));a.colorEmissive&&(h.emissive=e(a.colorEmissive));a.transparency&&(h.opacity=a.transparency);a.specularCoef&&(h.shininess=a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap, +a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&& +b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormal?(g=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(g.uniforms),k.tNormal.value=h.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),h.map&&(k.tDiffuse.value=h.map,k.enableDiffuse.value=!0),h.specularMap&&(k.tSpecular.value=h.specularMap,k.enableSpecular.value=!0),h.lightMap&&(k.tAO.value=h.lightMap, +k.enableAO.value=!0),k.diffuse.value.setHex(h.color),k.specular.value.setHex(h.specular),k.ambient.value.setHex(h.ambient),k.shininess.value=h.shininess,void 0!==h.opacity&&(k.opacity.value=h.opacity),g=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:k,lights:!0,fog:!0}),h.transparent&&(g.transparent=!0)):g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}}; +THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;bg;g++)m=y[k++],v=u[2*m],m=u[2*m+1],v=new THREE.Vector2(v,m),2!==g&&c.faceVertexUvs[d][h].push(v),0!==g&&c.faceVertexUvs[d][h+1].push(v);q&&(q=3*y[k++],r.normal.set(G[q++],G[q++],G[q]),s.normal.copy(r.normal));if(t)for(d=0;4>d;d++)q=3*y[k++],t=new THREE.Vector3(G[q++], +G[q++],G[q]),2!==d&&r.vertexNormals.push(t),0!==d&&s.vertexNormals.push(t);p&&(p=y[k++],p=w[p],r.color.setHex(p),s.color.setHex(p));if(b)for(d=0;4>d;d++)p=y[k++],p=w[p],2!==d&&r.vertexColors.push(new THREE.Color(p)),0!==d&&s.vertexColors.push(new THREE.Color(p));c.faces.push(r);c.faces.push(s)}else{r=new THREE.Face3;r.a=y[k++];r.b=y[k++];r.c=y[k++];h&&(h=y[k++],r.materialIndex=h);h=c.faces.length;if(d)for(d=0;dg;g++)m=y[k++],v=u[2*m],m=u[2*m+1], +v=new THREE.Vector2(v,m),c.faceVertexUvs[d][h].push(v);q&&(q=3*y[k++],r.normal.set(G[q++],G[q++],G[q]));if(t)for(d=0;3>d;d++)q=3*y[k++],t=new THREE.Vector3(G[q++],G[q++],G[q]),r.vertexNormals.push(t);p&&(p=y[k++],r.color.setHex(w[p]));if(b)for(d=0;3>d;d++)p=y[k++],r.vertexColors.push(new THREE.Color(w[p]));c.faces.push(r)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;dthis.opacity&&(a.opacity=this.opacity);!1!==this.transparent&&(a.transparent=this.transparent);!1!==this.wireframe&&(a.wireframe=this.wireframe);return a},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor= +this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0; +THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.type="LineBasicMaterial";this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.type="LineDashedMaterial";this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineDashedMaterial.prototype.clone=function(){var a=new THREE.LineDashedMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.scale=this.scale;a.dashSize=this.dashSize;a.gapSize=this.gapSize;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.type="MeshBasicMaterial";this.color=new THREE.Color(16777215);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphTargets=this.skinning=!1;this.setValues(a)}; +THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshBasicMaterial.prototype.clone=function(){var a=new THREE.MeshBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap; +a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;return a}; +THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.type="MeshLambertMaterial";this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth= +1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog; +a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.type="MeshPhongMaterial";this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.wrapAround=this.metal=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.envMap=this.alphaMap=this.specularMap=null;this.combine= +THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale); +a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.type="MeshDepthMaterial";this.wireframe=this.morphTargets=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a}; +THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.shading=THREE.FlatShading;this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MeshFaceMaterial";this.materials=a instanceof Array?a:[]}; +THREE.MeshFaceMaterial.prototype={constructor:THREE.MeshFaceMaterial,toJSON:function(){for(var a={metadata:{version:4.2,type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type,materials:[]},b=0,c=this.materials.length;bf)){var m=b.origin.distanceTo(n);md.far||e.push({distance:m,point:k.clone().applyMatrix4(this.matrixWorld),face:null,faceIndex:null,object:this})}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.mode));THREE.Object3D.prototype.clone.call(this,a);return a}; +THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); +THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0g.far||h.push({distance:x,point:K,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(s=p.position.array,t=k=0,w=s.length;k +g.far||h.push({distance:x,point:K,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(t=this.material instanceof THREE.MeshFaceMaterial,s=!0===t?this.material.materials:null,r=g.precision,u=k.vertices,v=0,y=k.faces.length;vg.far||h.push({distance:x,point:K,face:G,faceIndex:v,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype); +THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256h.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=(c.end-c.start)/b*1E3,this.time=0):console.warn("animation["+a+"] undefined")}; +THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& +(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; +THREE.MorphAnimMesh.prototype.interpolateTargets=function(a,b,c){for(var d=this.morphTargetInfluences,e=0,f=d.length;e=this.objects[d].distance)this.objects[d-1].object.visible=!1,this.objects[d].object.visible=!0;else break;for(;dthis.scale.x||c.push({distance:d,point:this.position,face:null,object:this})}}();THREE.Sprite.prototype.clone=function(a){void 0===a&&(a=new THREE.Sprite(this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Particle=THREE.Sprite; +THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype); +THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; +THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a dashSize ) {\n\t\tdiscard;\n\t}\n\tgl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment, +"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment, +"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\n\tgl_FragColor = vec4( vec3( color ), opacity );\n}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvNormal = normalize( normalMatrix * normal );", +THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i", +value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},diffuse:{type:"c",value:new THREE.Color(16777215)}, +specular:{type:"c",value:new THREE.Color(1118481)},ambient:{type:"c",value:new THREE.Color(16777215)},shininess:{type:"f",value:30},opacity:{type:"f",value:1},useRefract:{type:"i",value:0},refractionRatio:{type:"f",value:.98},reflectivity:{type:"f",value:.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 ambient;\nuniform vec3 diffuse;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float refractionRatio;\nuniform float reflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\n\tuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\tgl_FragColor = vec4( vec3( 1.0 ), opacity );\n\tvec3 specularTex = vec3( 1.0 );\n\tvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\n\tnormalTex.xy *= uNormalScale;\n\tnormalTex = normalize( normalTex );\n\tif( enableDiffuse ) {\n\t\t#ifdef GAMMA_INPUT\n\t\t\tvec4 texelColor = texture2D( tDiffuse, vUv );\n\t\t\ttexelColor.xyz *= texelColor.xyz;\n\t\t\tgl_FragColor = gl_FragColor * texelColor;\n\t\t#else\n\t\t\tgl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n\t\t#endif\n\t}\n\tif( enableAO ) {\n\t\t#ifdef GAMMA_INPUT\n\t\t\tvec4 aoColor = texture2D( tAO, vUv );\n\t\t\taoColor.xyz *= aoColor.xyz;\n\t\t\tgl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n\t\t#else\n\t\t\tgl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n\t\t#endif\n\t}", +THREE.ShaderChunk.alphatest_fragment,"\tif( enableSpecular )\n\t\tspecularTex = texture2D( tSpecular, vUv ).xyz;\n\tmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\n\tvec3 finalNormal = tsb * normalTex;\n\t#ifdef FLIP_SIDED\n\t\tfinalNormal = -finalNormal;\n\t#endif\n\tvec3 normal = normalize( finalNormal );\n\tvec3 viewPosition = normalize( vViewPosition );\n\t#if MAX_POINT_LIGHTS > 0\n\t\tvec3 pointDiffuse = vec3( 0.0 );\n\t\tvec3 pointSpecular = vec3( 0.0 );\n\t\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\t\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\t\tvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\n\t\t\tfloat pointDistance = 1.0;\n\t\t\tif ( pointLightDistance[ i ] > 0.0 )\n\t\t\t\tpointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\n\t\t\tpointVector = normalize( pointVector );\n\t\t\t#ifdef WRAP_AROUND\n\t\t\t\tfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\n\t\t\t\tfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\n\t\t\t\tvec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\t\t\t#else\n\t\t\t\tfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n\t\t\t#endif\n\t\t\tpointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;\n\t\t\tvec3 pointHalfVector = normalize( pointVector + viewPosition );\n\t\t\tfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n\t\t\tfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( pointVector, pointHalfVector ), 0.0 ), 5.0 );\n\t\t\tpointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n\t\t}\n\t#endif\n\t#if MAX_SPOT_LIGHTS > 0\n\t\tvec3 spotDiffuse = vec3( 0.0 );\n\t\tvec3 spotSpecular = vec3( 0.0 );\n\t\tfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\t\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\t\tvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\n\t\t\tfloat spotDistance = 1.0;\n\t\t\tif ( spotLightDistance[ i ] > 0.0 )\n\t\t\t\tspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\n\t\t\tspotVector = normalize( spotVector );\n\t\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\t\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\t\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\t\t\t\t#ifdef WRAP_AROUND\n\t\t\t\t\tfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\n\t\t\t\t\tfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\n\t\t\t\t\tvec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\t\t\t\t#else\n\t\t\t\t\tfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n\t\t\t\t#endif\n\t\t\t\tspotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;\n\t\t\t\tvec3 spotHalfVector = normalize( spotVector + viewPosition );\n\t\t\t\tfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n\t\t\t\tfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\t\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( spotVector, spotHalfVector ), 0.0 ), 5.0 );\n\t\t\t\tspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n\t\t\t}\n\t\t}\n\t#endif\n\t#if MAX_DIR_LIGHTS > 0\n\t\tvec3 dirDiffuse = vec3( 0.0 );\n\t\tvec3 dirSpecular = vec3( 0.0 );\n\t\tfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\n\t\t\tvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\n\t\t\tvec3 dirVector = normalize( lDirection.xyz );\n\t\t\t#ifdef WRAP_AROUND\n\t\t\t\tfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\n\t\t\t\tfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\n\t\t\t\tvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n\t\t\t#else\n\t\t\t\tfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n\t\t\t#endif\n\t\t\tdirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;\n\t\t\tvec3 dirHalfVector = normalize( dirVector + viewPosition );\n\t\t\tfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n\t\t\tfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n\t\t\tdirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\t\t}\n\t#endif\n\t#if MAX_HEMI_LIGHTS > 0\n\t\tvec3 hemiDiffuse = vec3( 0.0 );\n\t\tvec3 hemiSpecular = vec3( 0.0 );\n\t\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\t\t\tvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\n\t\t\tvec3 lVector = normalize( lDirection.xyz );\n\t\t\tfloat dotProduct = dot( normal, lVector );\n\t\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\t\t\tvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\t\t\themiDiffuse += diffuse * hemiColor;\n\t\t\tvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n\t\t\tfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n\t\t\tfloat hemiSpecularWeightSky = specularTex.r * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\t\t\tvec3 lVectorGround = -lVector;\n\t\t\tvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n\t\t\tfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n\t\t\tfloat hemiSpecularWeightGround = specularTex.r * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\t\t\tfloat dotProductGround = dot( normal, lVectorGround );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n\t\t\tvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n\t\t\themiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\t\t}\n\t#endif\n\tvec3 totalDiffuse = vec3( 0.0 );\n\tvec3 totalSpecular = vec3( 0.0 );\n\t#if MAX_DIR_LIGHTS > 0\n\t\ttotalDiffuse += dirDiffuse;\n\t\ttotalSpecular += dirSpecular;\n\t#endif\n\t#if MAX_HEMI_LIGHTS > 0\n\t\ttotalDiffuse += hemiDiffuse;\n\t\ttotalSpecular += hemiSpecular;\n\t#endif\n\t#if MAX_POINT_LIGHTS > 0\n\t\ttotalDiffuse += pointDiffuse;\n\t\ttotalSpecular += pointSpecular;\n\t#endif\n\t#if MAX_SPOT_LIGHTS > 0\n\t\ttotalDiffuse += spotDiffuse;\n\t\ttotalSpecular += spotSpecular;\n\t#endif\n\t#ifdef METAL\n\t\tgl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );\n\t#else\n\t\tgl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n\t#endif\n\tif ( enableReflection ) {\n\t\tvec3 vReflect;\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tif ( useRefract ) {\n\t\t\tvReflect = refract( cameraToVertex, normal, refractionRatio );\n\t\t} else {\n\t\t\tvReflect = reflect( cameraToVertex, normal );\n\t\t}\n\t\tvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n\t\t#ifdef GAMMA_INPUT\n\t\t\tcubeColor.xyz *= cubeColor.xyz;\n\t\t#endif\n\t\tgl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );\n\t}", +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;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\n\tuniform sampler2D tDisplacement;\n\tuniform float uDisplacementScale;\n\tuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"\t#ifdef USE_SKINNING\n\t\tvNormal = normalize( normalMatrix * skinnedNormal.xyz );\n\t\tvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\n\t\tvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n\t#else\n\t\tvNormal = normalize( normalMatrix * normal );\n\t\tvTangent = normalize( normalMatrix * tangent.xyz );\n\t#endif\n\tvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\n\tvUv = uv * uRepeat + uOffset;\n\tvec3 displacedPosition;\n\t#ifdef VERTEX_TEXTURES\n\t\tif ( enableDisplacement ) {\n\t\t\tvec3 dv = texture2D( tDisplacement, uv ).xyz;\n\t\t\tfloat df = uDisplacementScale * dv.x + uDisplacementBias;\n\t\t\tdisplacedPosition = position + normalize( normal ) * df;\n\t\t} else {\n\t\t\t#ifdef USE_SKINNING\n\t\t\t\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\t\t\t\tvec4 skinned = vec4( 0.0 );\n\t\t\t\tskinned += boneMatX * skinVertex * skinWeight.x;\n\t\t\t\tskinned += boneMatY * skinVertex * skinWeight.y;\n\t\t\t\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\t\t\t\tskinned += boneMatW * skinVertex * skinWeight.w;\n\t\t\t\tskinned = bindMatrixInverse * skinned;\n\t\t\t\tdisplacedPosition = skinned.xyz;\n\t\t\t#else\n\t\t\t\tdisplacedPosition = position;\n\t\t\t#endif\n\t\t}\n\t#else\n\t\t#ifdef USE_SKINNING\n\t\t\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\t\t\tvec4 skinned = vec4( 0.0 );\n\t\t\tskinned += boneMatX * skinVertex * skinWeight.x;\n\t\t\tskinned += boneMatY * skinVertex * skinWeight.y;\n\t\t\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\t\t\tskinned += boneMatW * skinVertex * skinWeight.w;\n\t\t\tskinned = bindMatrixInverse * skinned;\n\t\t\tdisplacedPosition = skinned.xyz;\n\t\t#else\n\t\t\tdisplacedPosition = position;\n\t\t#endif\n\t#endif\n\tvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\n\tvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk.logdepthbuf_vertex,"\tvWorldPosition = worldPosition.xyz;\n\tvViewPosition = -mvPosition.xyz;\n\t#ifdef USE_SHADOWMAP\n\t\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\t\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\t\t}\n\t#endif\n}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\tvWorldPosition = worldPosition.xyz;\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", +THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex, +"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {", +THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}}; +THREE.WebGLRenderer=function(a){function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a.attributes){void 0===b.__webglCustomAttributesList&&(b.__webglCustomAttributesList=[]);for(var d in a.attributes){var e=a.attributes[d];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var f=1;"v2"===e.type?f=2:"v3"===e.type?f=3:"v4"===e.type?f=4:"c"===e.type&&(f=3);e.size=f;e.array=new Float32Array(c*f);e.buffer=l.createBuffer();e.buffer.belongsToAttribute=d;e.needsUpdate= +!0}b.__webglCustomAttributesList.push(e)}}}function c(a,b){var c=b.geometry,e=a.faces3,f=3*e.length,g=1*e.length,h=3*e.length,e=d(b,a);a.__vertexArray=new Float32Array(3*f);a.__normalArray=new Float32Array(3*f);a.__colorArray=new Float32Array(3*f);a.__uvArray=new Float32Array(2*f);1Aa;Aa++)Cb=ma[Aa],Ta[Sa]=Cb.x,Ta[Sa+1]=Cb.y,Ta[Sa+2]=Cb.z,Sa+=3;else for(Aa=0;3>Aa;Aa++)Ta[Sa]=pa.x,Ta[Sa+1]=pa.y,Ta[Sa+2]=pa.z,Sa+=3;l.bindBuffer(l.ARRAY_BUFFER,C.__webglNormalBuffer);l.bufferData(l.ARRAY_BUFFER, +Ta,S)}if(Kc&&ua){M=0;for(ea=N.length;MAa;Aa++)Oa=hb[Aa],sb[qb]=Oa.x,sb[qb+1]=Oa.y,qb+=2;0Aa;Aa++)Qb=za[Aa],fb[rb]=Qb.x,fb[rb+1]=Qb.y,rb+=2;0h&&(f[v].counter+=1,k=f[v].hash+"_"+f[v].counter,k in r||(p={id:rc++, +faces3:[],materialIndex:v,vertices:0,numMorphTargets:m,numMorphNormals:n},r[k]=p,q.push(p)));r[k].faces3.push(t);r[k].vertices+=3}a[g]=q;d.groupsNeedUpdate=!1}a=xb[d.id];g=0;for(e=a.length;gDa;Da++)kb[Da]=!J.autoScaleCubemaps||Ob||Tb?Tb?ua.image[Da].image:ua.image[Da]:R(ua.image[Da],$c);var ka=kb[0],Zb=THREE.Math.isPowerOfTwo(ka.width)&&THREE.Math.isPowerOfTwo(ka.height),ab=Q(ua.format),Fb=Q(ua.type);F(l.TEXTURE_CUBE_MAP,ua,Zb);for(Da=0;6>Da;Da++)if(Ob)for(var gb,$b=kb[Da].mipmaps,ga=0,Xb=$b.length;ga=Oc&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+ +Oc);dc+=1;return a}function x(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getNormalMatrix(a._modelViewMatrix)}function D(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function E(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function A(a){a!==Pc&&(l.lineWidth(a),Pc=a)}function B(a,b,c){Qc!==a&&(a?l.enable(l.POLYGON_OFFSET_FILL):l.disable(l.POLYGON_OFFSET_FILL),Qc=a);!a||Rc===b&&Sc===c||(l.polygonOffset(b,c),Rc=b,Sc=c)}function F(a,b,c){c? +(l.texParameteri(a,l.TEXTURE_WRAP_S,Q(b.wrapS)),l.texParameteri(a,l.TEXTURE_WRAP_T,Q(b.wrapT)),l.texParameteri(a,l.TEXTURE_MAG_FILTER,Q(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,Q(b.minFilter))):(l.texParameteri(a,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_MAG_FILTER,T(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,T(b.minFilter)));(c=pa.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&(1b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.log("THREE.WebGLRenderer:",a,"is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height+ +".");return d}return a}function H(a,b){l.bindRenderbuffer(l.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_COMPONENT16,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT,l.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_STENCIL,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a)):l.renderbufferStorage(l.RENDERBUFFER,l.RGBA4,b.width, +b.height)}function C(a){a instanceof THREE.WebGLRenderTargetCube?(l.bindTexture(l.TEXTURE_CUBE_MAP,a.__webglTexture),l.generateMipmap(l.TEXTURE_CUBE_MAP),l.bindTexture(l.TEXTURE_CUBE_MAP,null)):(l.bindTexture(l.TEXTURE_2D,a.__webglTexture),l.generateMipmap(l.TEXTURE_2D),l.bindTexture(l.TEXTURE_2D,null))}function T(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?l.NEAREST:l.LINEAR}function Q(a){var b;if(a===THREE.RepeatWrapping)return l.REPEAT; +if(a===THREE.ClampToEdgeWrapping)return l.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return l.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return l.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return l.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return l.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return l.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return l.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return l.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return l.UNSIGNED_BYTE; +if(a===THREE.UnsignedShort4444Type)return l.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return l.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return l.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return l.BYTE;if(a===THREE.ShortType)return l.SHORT;if(a===THREE.UnsignedShortType)return l.UNSIGNED_SHORT;if(a===THREE.IntType)return l.INT;if(a===THREE.UnsignedIntType)return l.UNSIGNED_INT;if(a===THREE.FloatType)return l.FLOAT;if(a===THREE.AlphaFormat)return l.ALPHA;if(a===THREE.RGBFormat)return l.RGB; +if(a===THREE.RGBAFormat)return l.RGBA;if(a===THREE.LuminanceFormat)return l.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return l.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return l.FUNC_ADD;if(a===THREE.SubtractEquation)return l.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return l.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return l.ZERO;if(a===THREE.OneFactor)return l.ONE;if(a===THREE.SrcColorFactor)return l.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return l.ONE_MINUS_SRC_COLOR;if(a=== +THREE.SrcAlphaFactor)return l.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return l.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return l.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return l.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return l.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return l.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return l.SRC_ALPHA_SATURATE;b=pa.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT; +if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=pa.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; +if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=pa.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var O=void 0!==a.canvas?a.canvas:document.createElement("canvas"),S=void 0!==a.context?a.context:null,X=void 0!==a.precision?a.precision:"highp",Y=void 0!==a.alpha?a.alpha:!1,la=void 0!==a.depth?a.depth:!0,ma=void 0!==a.stencil? +a.stencil:!0,ya=void 0!==a.antialias?a.antialias:!1,P=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,Ga=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,Fa=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,za=new THREE.Color(0),bb=0,cb=[],ob={},jb=[],Jb=[],Ib=[],yb=[],Ra=[];this.domElement=O;this.context=null;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==self.devicePixelRatio?self.devicePixelRatio:1;this.sortObjects=this.autoClearStencil= +this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=this.gammaOutput=this.gammaInput=!1;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var J=this,hb=[],tc=null,Tc=null,Kb=-1,Oa=-1,ec=null,dc=0,Lb=-1,Mb=-1,pb=-1,Nb=-1,Ob=-1, +Xb=-1,Yb=-1,nb=-1,Qc=null,Rc=null,Sc=null,Pc=null,Pb=0,kc=0,lc=O.width,mc=O.height,Uc=0,Vc=0,wb=new Uint8Array(16),ib=new Uint8Array(16),Ec=new THREE.Frustum,Ac=new THREE.Matrix4,Gc=new THREE.Matrix4,Na=new THREE.Vector3,sa=new THREE.Vector3,fc=!0,Mc={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[]},hemi:{length:0,skyColors:[],groundColors:[], +positions:[]}},l;try{var Wc={alpha:Y,depth:la,stencil:ma,antialias:ya,premultipliedAlpha:P,preserveDrawingBuffer:Ga};l=S||O.getContext("webgl",Wc)||O.getContext("experimental-webgl",Wc);if(null===l){if(null!==O.getContext("webgl"))throw"Error creating WebGL context with your selected attributes.";throw"Error creating WebGL context.";}}catch(ad){console.error(ad)}void 0===l.getShaderPrecisionFormat&&(l.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var pa=new THREE.WebGLExtensions(l); +pa.get("OES_texture_float");pa.get("OES_texture_float_linear");pa.get("OES_standard_derivatives");Fa&&pa.get("EXT_frag_depth");l.clearColor(0,0,0,1);l.clearDepth(1);l.clearStencil(0);l.enable(l.DEPTH_TEST);l.depthFunc(l.LEQUAL);l.frontFace(l.CCW);l.cullFace(l.BACK);l.enable(l.CULL_FACE);l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.SRC_ALPHA,l.ONE_MINUS_SRC_ALPHA);l.viewport(Pb,kc,lc,mc);l.clearColor(za.r,za.g,za.b,bb);this.context=l;var Oc=l.getParameter(l.MAX_TEXTURE_IMAGE_UNITS), +bd=l.getParameter(l.MAX_VERTEX_TEXTURE_IMAGE_UNITS),cd=l.getParameter(l.MAX_TEXTURE_SIZE),$c=l.getParameter(l.MAX_CUBE_MAP_TEXTURE_SIZE),sc=0b;b++)l.deleteFramebuffer(a.__webglFramebuffer[b]),l.deleteRenderbuffer(a.__webglRenderbuffer[b]); +else l.deleteFramebuffer(a.__webglFramebuffer),l.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}J.info.memory.textures--},Dc=function(a){a=a.target;a.removeEventListener("dispose",Dc);Cc(a)},Yc=function(a){for(var b="__webglVertexBuffer __webglNormalBuffer __webglTangentBuffer __webglColorBuffer __webglUVBuffer __webglUV2Buffer __webglSkinIndicesBuffer __webglSkinWeightsBuffer __webglFaceBuffer __webglLineBuffer __webglLineDistanceBuffer".split(" "), +c=0,d=b.length;cd.numSupportedMorphTargets?(n.sort(p),n.length=d.numSupportedMorphTargets):n.length>d.numSupportedMorphNormals?n.sort(p):0===n.length&&n.push([0, +0]);for(m=0;mf;f++){a.__webglFramebuffer[f]=l.createFramebuffer();a.__webglRenderbuffer[f]=l.createRenderbuffer();l.texImage2D(l.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=l.TEXTURE_CUBE_MAP_POSITIVE_X+f;l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer[f]);l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,h,g.__webglTexture,0);H(a.__webglRenderbuffer[f],a)}c&&l.generateMipmap(l.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer= +l.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:l.createRenderbuffer(),l.bindTexture(l.TEXTURE_2D,a.__webglTexture),F(l.TEXTURE_2D,a,c),l.texImage2D(l.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=l.TEXTURE_2D,l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer),l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT, +l.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a.__webglRenderbuffer):H(a.__webglRenderbuffer,a),c&&l.generateMipmap(l.TEXTURE_2D);b?l.bindTexture(l.TEXTURE_CUBE_MAP,null):l.bindTexture(l.TEXTURE_2D,null);l.bindRenderbuffer(l.RENDERBUFFER,null);l.bindFramebuffer(l.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=lc,a=mc, +d=Pb,e=kc);b!==Tc&&(l.bindFramebuffer(l.FRAMEBUFFER,b),l.viewport(d,e,c,a),Tc=b);Uc=c;Vc=a};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}}; +THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: +THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; +THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){this.width=a;this.height=b},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.anisotropy=this.anisotropy;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;a.generateMipmaps=this.generateMipmaps; +a.shareDepthFrom=this.shareDepthFrom;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype); +THREE.WebGLExtensions=function(a){var b={};this.get=function(c){if(void 0!==b[c])return b[c];var d;switch(c){case "OES_texture_float":d=a.getExtension("OES_texture_float");break;case "OES_texture_float_linear":d=a.getExtension("OES_texture_float_linear");break;case "OES_standard_derivatives":d=a.getExtension("OES_standard_derivatives");break;case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic"); +break;case "WEBGL_compressed_texture_s3tc":d=a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;case "OES_element_index_uint":d=a.getExtension("OES_element_index_uint");break;case "EXT_blend_minmax":d=a.getExtension("EXT_blend_minmax");break; +case "EXT_frag_depth":d=a.getExtension("EXT_frag_depth")}null===d&&console.log("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}}; +THREE.WebGLProgram=function(){var a=0;return function(b,c,d,e){var f=b.context,g=d.defines,h=d.__webglShader.uniforms,k=d.attributes,n=d.__webglShader.vertexShader,p=d.__webglShader.fragmentShader,q=d.index0AttributeName;void 0===q&&!0===e.morphTargets&&(q="position");var m="SHADOWMAP_TYPE_BASIC";e.shadowMapType===THREE.PCFShadowMap?m="SHADOWMAP_TYPE_PCF":e.shadowMapType===THREE.PCFSoftShadowMap&&(m="SHADOWMAP_TYPE_PCF_SOFT");var r,t;r=[];for(var s in g)t=g[s],!1!==t&&(t="#define "+s+" "+t,r.push(t)); +r=r.join("\n");g=f.createProgram();d instanceof THREE.RawShaderMaterial?b=d="":(d=["precision "+e.precision+" float;","precision "+e.precision+" int;",r,e.supportsVertexTextures?"#define VERTEX_TEXTURES":"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"","#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,"#define MAX_BONES "+ +e.maxBones,e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.skinning?"#define USE_SKINNING":"",e.useVertexTexture?"#define BONE_TEXTURE":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals?"#define USE_MORPHNORMALS":"",e.wrapAround?"#define WRAP_AROUND": +"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.sizeAttenuation?"#define USE_SIZEATTENUATION":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;\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\n\tattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\n\tattribute vec3 morphTarget0;\n\tattribute vec3 morphTarget1;\n\tattribute vec3 morphTarget2;\n\tattribute vec3 morphTarget3;\n\t#ifdef USE_MORPHNORMALS\n\t\tattribute vec3 morphNormal0;\n\t\tattribute vec3 morphNormal1;\n\t\tattribute vec3 morphNormal2;\n\t\tattribute vec3 morphNormal3;\n\t#else\n\t\tattribute vec3 morphTarget4;\n\t\tattribute vec3 morphTarget5;\n\t\tattribute vec3 morphTarget6;\n\t\tattribute vec3 morphTarget7;\n\t#endif\n#endif\n#ifdef USE_SKINNING\n\tattribute vec4 skinIndex;\n\tattribute vec4 skinWeight;\n#endif\n"].join("\n"), +b=["precision "+e.precision+" float;","precision "+e.precision+" int;",e.bumpMap||e.normalMap?"#extension GL_OES_standard_derivatives : enable":"",r,"#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,e.alphaTest?"#define ALPHATEST "+e.alphaTest:"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"",e.useFog&&e.fog?"#define USE_FOG": +"",e.useFog&&e.fogExp?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.metal?"#define METAL":"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP": +"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n"));n=new THREE.WebGLShader(f,f.VERTEX_SHADER,d+n);p=new THREE.WebGLShader(f,f.FRAGMENT_SHADER,b+p);f.attachShader(g,n);f.attachShader(g,p);void 0!==q&&f.bindAttribLocation(g,0,q);f.linkProgram(g);!1===f.getProgramParameter(g,f.LINK_STATUS)&&(console.error("THREE.WebGLProgram: Could not initialise shader."), +console.error("gl.VALIDATE_STATUS",f.getProgramParameter(g,f.VALIDATE_STATUS)),console.error("gl.getError()",f.getError()));""!==f.getProgramInfoLog(g)&&console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",f.getProgramInfoLog(g));f.deleteShader(n);f.deleteShader(p);q="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences bindMatrix bindMatrixInverse".split(" ");e.useVertexTexture?(q.push("boneTexture"),q.push("boneTextureWidth"),q.push("boneTextureHeight")): +q.push("boneGlobalMatrices");e.logarithmicDepthBuffer&&q.push("logDepthBufFC");for(var u in h)q.push(u);h=q;u={};q=0;for(b=h.length;qT;T++)F[T]=new THREE.Vector3,A[T]=new THREE.Vector3;F=B.shadowCascadeNearZ[C];B=B.shadowCascadeFarZ[C];A[0].set(-1,-1,F);A[1].set(1,-1,F);A[2].set(-1,1,F);A[3].set(1,1,F);A[4].set(-1,-1,B);A[5].set(1,-1,B);A[6].set(-1,1,B);A[7].set(1,1,B);H.originalCamera=v;A=new THREE.Gyroscope;A.position.copy(x.shadowCascadeOffset);A.add(H);A.add(H.target);v.add(A);x.shadowCascadeArray[E]=H;console.log("Created virtualLight",H)}C= +x;F=E;B=C.shadowCascadeArray[F];B.position.copy(C.position);B.target.position.copy(C.target.position);B.lookAt(B.target);B.shadowCameraVisible=C.shadowCameraVisible;B.shadowDarkness=C.shadowDarkness;B.shadowBias=C.shadowCascadeBias[F];A=C.shadowCascadeNearZ[F];C=C.shadowCascadeFarZ[F];B=B.pointsFrustum;B[0].z=A;B[1].z=A;B[2].z=A;B[3].z=A;B[4].z=C;B[5].z=C;B[6].z=C;B[7].z=C;R[D]=H;D++}else R[D]=x,D++;u=0;for(K=R.length;uC;C++)F=B[C],F.copy(A[C]),F.unproject(E),F.applyMatrix4(D.matrixWorldInverse),F.xr.x&&(r.x=F.x),F.yr.y&&(r.y=F.y),F.zr.z&&(r.z=F.z);D.left=m.x;D.right=r.x;D.top=r.y;D.bottom=m.y;D.updateProjectionMatrix()}D=x.shadowMap;A=x.shadowMatrix;E=x.shadowCamera;E.position.setFromMatrixPosition(x.matrixWorld);t.setFromMatrixPosition(x.target.matrixWorld);E.lookAt(t);E.updateMatrixWorld();E.matrixWorldInverse.getInverse(E.matrixWorld);x.cameraHelper&& +(x.cameraHelper.visible=x.shadowCameraVisible);x.shadowCameraVisible&&x.cameraHelper.update();A.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);A.multiply(E.projectionMatrix);A.multiply(E.matrixWorldInverse);q.multiplyMatrices(E.projectionMatrix,E.matrixWorldInverse);p.setFromMatrix(q);a.setRenderTarget(D);a.clear();s.length=0;e(c,c,E);x=0;for(D=s.length;x 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); +w.compileShader(R);w.compileShader(H);w.attachShader(F,R);w.attachShader(F,H);w.linkProgram(F);D=F;v=w.getAttribLocation(D,"position");y=w.getAttribLocation(D,"uv");c=w.getUniformLocation(D,"uvOffset");d=w.getUniformLocation(D,"uvScale");e=w.getUniformLocation(D,"rotation");f=w.getUniformLocation(D,"scale");g=w.getUniformLocation(D,"color");h=w.getUniformLocation(D,"map");k=w.getUniformLocation(D,"opacity");n=w.getUniformLocation(D,"modelViewMatrix");p=w.getUniformLocation(D,"projectionMatrix");q= +w.getUniformLocation(D,"fogType");m=w.getUniformLocation(D,"fogDensity");r=w.getUniformLocation(D,"fogNear");t=w.getUniformLocation(D,"fogFar");s=w.getUniformLocation(D,"fogColor");u=w.getUniformLocation(D,"alphaTest");F=document.createElement("canvas");F.width=8;F.height=8;R=F.getContext("2d");R.fillStyle="white";R.fillRect(0,0,8,8);E=new THREE.Texture(F);E.needsUpdate=!0}w.useProgram(D);w.enableVertexAttribArray(v);w.enableVertexAttribArray(y);w.disable(w.CULL_FACE);w.enable(w.BLEND);w.bindBuffer(w.ARRAY_BUFFER, +K);w.vertexAttribPointer(v,2,w.FLOAT,!1,16,0);w.vertexAttribPointer(y,2,w.FLOAT,!1,16,8);w.bindBuffer(w.ELEMENT_ARRAY_BUFFER,x);w.uniformMatrix4fv(p,!1,B.projectionMatrix.elements);w.activeTexture(w.TEXTURE0);w.uniform1i(h,0);R=F=0;(H=A.fog)?(w.uniform3f(s,H.color.r,H.color.g,H.color.b),H instanceof THREE.Fog?(w.uniform1f(r,H.near),w.uniform1f(t,H.far),w.uniform1i(q,1),R=F=1):H instanceof THREE.FogExp2&&(w.uniform1f(m,H.density),w.uniform1i(q,2),R=F=2)):(w.uniform1i(q,0),R=F=0);for(var H=0,C=b.length;H< +C;H++){var T=b[H];T._modelViewMatrix.multiplyMatrices(B.matrixWorldInverse,T.matrixWorld);T.z=null===T.renderDepth?-T._modelViewMatrix.elements[14]:T.renderDepth}b.sort(G);for(var Q=[],H=0,C=b.length;Hq-1?0:q-1,r=q+1>e-1?e-1:q+1,t=0>p-1?0:p-1,s=p+1>d-1?d-1:p+1,u=[],v=[0,0,h[4*(q*d+p)]/255*b];u.push([-1,0,h[4*(q*d+t)]/255*b]);u.push([-1,-1,h[4*(m*d+t)]/255*b]);u.push([0,-1,h[4*(m*d+p)]/255*b]);u.push([1,-1,h[4*(m*d+s)]/255*b]);u.push([1,0,h[4*(q*d+s)]/255*b]);u.push([1,1,h[4*(r*d+s)]/255*b]);u.push([0,1,h[4*(r*d+p)]/255* +b]);u.push([-1,1,h[4*(r*d+t)]/255*b]);m=[];t=u.length;for(r=0;re)return null;var f=[],g=[],h=[],k,n,p;if(0=q--){console.log("Warning, unable to triangulate polygon!");break}k=n;e<=k&&(k=0);n=k+1;e<=n&&(n=0);p=n+1;e<=p&&(p=0);var m;a:{var r=m=void 0,t=void 0,s=void 0,u=void 0,v=void 0,y=void 0,G=void 0,w=void 0, +r=a[g[k]].x,t=a[g[k]].y,s=a[g[n]].x,u=a[g[n]].y,v=a[g[p]].x,y=a[g[p]].y;if(1E-10>(s-r)*(y-t)-(u-t)*(v-r))m=!1;else{var K=void 0,x=void 0,D=void 0,E=void 0,A=void 0,B=void 0,F=void 0,R=void 0,H=void 0,C=void 0,H=R=F=w=G=void 0,K=v-s,x=y-u,D=r-v,E=t-y,A=s-r,B=u-t;for(m=0;mk)g=d+1;else if(0b&&(b=0);1=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; +THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=h.x:h.xc?c=h.y:h.yd?d=h.z:h.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;cm&&(g=b[f],k=-k,h=b[e],m=-m),!(a.yh.y))if(a.y==g.y){if(a.x==g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0==e)return!0;0>e||(d=!d)}}else if(a.y==g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<= +h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;bE||E>D)return[];k=n*p-k*q;if(0>k||k>D)return[]}else{if(0d?[]:k==d?f?[]:[g]:a<=d?[g,h]: +[g,n]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1; +d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;cC){console.log("Infinite Loop! Holes left:"+ +n.length+", Probably Hole outside Shape!");break}for(q=B;qh;h++)n=k[h].x+":"+k[h].y, +n=p[n],void 0!==n&&(k[h]=n);return q.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a, +b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()}; +THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return b}; +THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=new THREE.Vector2;b.x=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);return b.normalize()};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype); +THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)};THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b}; +THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.getPoint=function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector2;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);return c}; +THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype); +THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);a=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;b=new THREE.Vector2;b.x=this.aX+this.xRadius*Math.cos(a);b.y=this.aY+this.yRadius*Math.sin(a);return b};THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype); +THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);b.z=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return b}); +THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b.y=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b.z=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return b}); +THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector3;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);c.z=THREE.Curve.Utils.interpolate(d.z,e.z,f.z,b.z,a);return c}); +THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-0;var c=Math.floor(a);a-=c;var c=c+(0a.hierarchy[b].keys[c].time&&(a.hierarchy[b].keys[c].time= +0),void 0!==a.hierarchy[b].keys[c].rot&&!(a.hierarchy[b].keys[c].rot instanceof THREE.Quaternion)){var d=a.hierarchy[b].keys[c].rot;a.hierarchy[b].keys[c].rot=(new THREE.Quaternion).fromArray(d)}if(a.hierarchy[b].keys.length&&void 0!==a.hierarchy[b].keys[0].morphTargets){d={};for(c=0;cd;d++){for(var e=this.keyTypes[d],f=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(e,a,1);g.timef.index;)f=g,g=this.getNextKeyWith(e,a,g.index+1);c.prevKey[e]=f;c.nextKey[e]=g}}}; +THREE.Animation.prototype.resetBlendWeights=function(){for(var a=0,b=this.hierarchy.length;aa.length-2?q:q+1;c[3]=q>a.length-3?q:q+2;q=a[c[0]];r=a[c[1]];t=a[c[2]];s=a[c[3]];c=e*e;m=e*c;d[0]=f(q[0],r[0],t[0],s[0],e,c,m);d[1]=f(q[1],r[1],t[1],s[1],e,c,m);d[2]=f(q[2],r[2],t[2],s[2],e,c,m);return d},f=function(a,b,c,d,e,f,m){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*m+ +(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)if(this.loop)this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset();else{this.stop();return}f=0;for(var h=this.hierarchy.length;fq;q++){var m=this.keyTypes[q],r=n.prevKey[m],t=n.nextKey[m]; +if(0this.timeScale&&r.time>=this.currentTime){r=this.data.hierarchy[f].keys[0];for(t=this.getNextKeyWith(m,f,1);t.timer.index;)r=t,t=this.getNextKeyWith(m,f,t.index+1);n.prevKey[m]=r;n.nextKey[m]=t}k.matrixAutoUpdate=!0;k.matrixWorldNeedsUpdate=!0;var s=(this.currentTime-r.time)/(t.time-r.time),u=r[m],v=t[m];0>s&&(s=0);1a&&(this.currentTime%=a);this.currentTime=Math.min(this.currentTime,a);a=0;for(var b=this.hierarchy.length;af.index;)f=g,g=e[f.index+1];d.prevKey= +f;d.nextKey=g}g.time>=this.currentTime?f.interpolate(g,this.currentTime):f.interpolate(g,g.time);this.data.hierarchy[a].node.updateMatrix();c.matrixWorldNeedsUpdate=!0}}}};THREE.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;cthis.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);c=this.duration/this.frames;var d=Math.floor(this.currentTime/c);d!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[d]= +0,a=b,b=d);this.mesh.morphTargetInfluences[d]=this.currentTime%c/c;this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[d]}}}()}; +THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,s){var u,v=h.widthSegments,y=h.heightSegments,G=e/2,w=f/2,K=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)u="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)u="y",y=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)u="x",v=h.depthSegments;var x=v+1,D=y+1,E=e/v,A=f/y,B=new THREE.Vector3;B[u]=0=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10d?-1E-10>f&&(a=!0):Math.sign(e)== +Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(P=a.length;0<=--P;){c=P;d=P-1;0>d&&(d=a.length-1);for(var e=0,f=r+2*p,e=0;eMath.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y, +1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===a instanceof Array&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cc&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5, +a.y));return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,n=0,p=a.length;nr&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));n=0;for(p=this.vertices.length;nc.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}(); +THREE.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,a,1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)}; +THREE.BoxHelper=function(a){var b=new THREE.BufferGeometry;b.addAttribute("position",new THREE.BufferAttribute(new Float32Array(72),3));THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces);void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype); +THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.geometry.attributes.position.array;d[0]=b.x;d[1]=b.y;d[2]=b.z;d[3]=c.x;d[4]=b.y;d[5]=b.z;d[6]=c.x;d[7]=b.y;d[8]=b.z;d[9]=c.x;d[10]=c.y;d[11]=b.z;d[12]=c.x;d[13]=c.y;d[14]=b.z;d[15]=b.x;d[16]=c.y;d[17]=b.z;d[18]=b.x;d[19]=c.y;d[20]=b.z;d[21]=b.x;d[22]=b.y;d[23]=b.z;d[24]=b.x;d[25]=b.y;d[26]=c.z;d[27]=c.x;d[28]=b.y;d[29]=c.z;d[30]=c.x;d[31]=b.y; +d[32]=c.z;d[33]=c.x;d[34]=c.y;d[35]=c.z;d[36]=c.x;d[37]=c.y;d[38]=c.z;d[39]=b.x;d[40]=c.y;d[41]=c.z;d[42]=b.x;d[43]=c.y;d[44]=c.z;d[45]=b.x;d[46]=b.y;d[47]=c.z;d[48]=b.x;d[49]=b.y;d[50]=b.z;d[51]=b.x;d[52]=b.y;d[53]=c.z;d[54]=c.x;d[55]=b.y;d[56]=b.z;d[57]=c.x;d[58]=b.y;d[59]=c.z;d[60]=c.x;d[61]=c.y;d[62]=b.z;d[63]=c.x;d[64]=c.y;d[65]=c.z;d[66]=b.x;d[67]=c.y;d[68]=b.z;d[69]=b.x;d[70]=c.y;d[71]=c.z;this.geometry.attributes.position.needsUpdate=!0;this.geometry.computeBoundingSphere();this.matrix=a.matrixWorld; +this.matrixAutoUpdate=!1};THREE.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)}; +THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200); +b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}; +THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); +THREE.CameraHelper.prototype.update=function(){var a,b,c=new THREE.Vector3,d=new THREE.Camera,e=function(e,g,h,k){c.set(g,h,k).unproject(d);e=b[e];if(void 0!==e)for(g=0,h=e.length;gt;t++){d[0]=r[g[t]];d[1]=r[g[(t+1)%3]];d.sort(f);var s=d.toString();void 0===e[s]?(e[s]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[s].face2=q}d=new Float32Array(6*p);f=0;for(s in e)if(g=e[s],void 0===g.face2|| +.9999>k[g.face1].normal.dot(k[g.face2].normal))p=n[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=n[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype); +THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=new THREE.Geometry;c=0;for(var e=this.object.geometry.faces.length;cb;b++)a.faces[b].color=this.colors[4>b?0:1];b=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(a,b);this.add(this.lightSphere); +this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; +THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}(); +THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()}; +THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}; +THREE.SkeletonHelper=function(a){this.bones=this.getBoneList(a);for(var b=new THREE.Geometry,c=0;cs;s++){d[0]=t[g[s]];d[1]=t[g[(s+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);m=0;for(r=p;ms;s++)p= +k[q[2*m+s]],g=6*m+3*s,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;r=a.geometry.attributes.index.array;n=a.geometry.drawcalls;p=0;0===n.length&&(n=[{count:r.length,index:0,start:0}]);for(var q=new Uint32Array(2*r.length),t=0,v=n.length;ts;s++)d[0]= +g+r[m+s],d[1]=g+r[m+(s+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);m=0;for(r=p;ms;s++)g=6*m+3*s,p=3*q[2*m+s],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),m=0,r=q;ms;s++)g=18*m+6*s,q=9*m+3*s,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*m+(s+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d, +3))}THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(a){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype); +THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype); +THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)}; +THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;fh.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c}; +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; +THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; +f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}}; diff --git a/plugins/Sidebar/media-globe/globe.js b/plugins/Sidebar/media-globe/globe.js new file mode 100644 index 00000000..a6ed358a --- /dev/null +++ b/plugins/Sidebar/media-globe/globe.js @@ -0,0 +1,424 @@ +/** + * dat.globe Javascript WebGL Globe Toolkit + * http://dataarts.github.com/dat.globe + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +var DAT = DAT || {}; + +DAT.Globe = function(container, opts) { + opts = opts || {}; + + var colorFn = opts.colorFn || function(x) { + var c = new THREE.Color(); + c.setHSL( ( 0.5 - (x * 2) ), Math.max(0.8, 1.0 - (x * 3)), 0.5 ); + return c; + }; + var imgDir = opts.imgDir || '/globe/'; + + var Shaders = { + 'earth' : { + uniforms: { + 'texture': { type: 't', value: null } + }, + vertexShader: [ + 'varying vec3 vNormal;', + 'varying vec2 vUv;', + 'void main() {', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + 'vNormal = normalize( normalMatrix * normal );', + 'vUv = uv;', + '}' + ].join('\n'), + fragmentShader: [ + 'uniform sampler2D texture;', + 'varying vec3 vNormal;', + 'varying vec2 vUv;', + 'void main() {', + 'vec3 diffuse = texture2D( texture, vUv ).xyz;', + 'float intensity = 1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );', + 'vec3 atmosphere = vec3( 1.0, 1.0, 1.0 ) * pow( intensity, 3.0 );', + 'gl_FragColor = vec4( diffuse + atmosphere, 1.0 );', + '}' + ].join('\n') + }, + 'atmosphere' : { + uniforms: {}, + vertexShader: [ + 'varying vec3 vNormal;', + 'void main() {', + 'vNormal = normalize( normalMatrix * normal );', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + '}' + ].join('\n'), + fragmentShader: [ + 'varying vec3 vNormal;', + 'void main() {', + 'float intensity = pow( 0.8 - dot( vNormal, vec3( 0, 0, 1.0 ) ), 12.0 );', + 'gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * intensity;', + '}' + ].join('\n') + } + }; + + var camera, scene, renderer, w, h; + var mesh, atmosphere, point, running; + + var overRenderer; + var running = true; + + var curZoomSpeed = 0; + var zoomSpeed = 50; + + var mouse = { x: 0, y: 0 }, mouseOnDown = { x: 0, y: 0 }; + var rotation = { x: 0, y: 0 }, + target = { x: Math.PI*3/2, y: Math.PI / 6.0 }, + targetOnDown = { x: 0, y: 0 }; + + var distance = 100000, distanceTarget = 100000; + var padding = 10; + var PI_HALF = Math.PI / 2; + + function init() { + + container.style.color = '#fff'; + container.style.font = '13px/20px Arial, sans-serif'; + + var shader, uniforms, material; + w = container.offsetWidth || window.innerWidth; + h = container.offsetHeight || window.innerHeight; + + camera = new THREE.PerspectiveCamera(30, w / h, 1, 10000); + camera.position.z = distance; + + scene = new THREE.Scene(); + + var geometry = new THREE.SphereGeometry(200, 40, 30); + + shader = Shaders['earth']; + uniforms = THREE.UniformsUtils.clone(shader.uniforms); + + uniforms['texture'].value = THREE.ImageUtils.loadTexture(imgDir+'world.jpg'); + + material = new THREE.ShaderMaterial({ + + uniforms: uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + + }); + + mesh = new THREE.Mesh(geometry, material); + mesh.rotation.y = Math.PI; + scene.add(mesh); + + shader = Shaders['atmosphere']; + uniforms = THREE.UniformsUtils.clone(shader.uniforms); + + material = new THREE.ShaderMaterial({ + + uniforms: uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: THREE.BackSide, + blending: THREE.AdditiveBlending, + transparent: true + + }); + + mesh = new THREE.Mesh(geometry, material); + mesh.scale.set( 1.1, 1.1, 1.1 ); + scene.add(mesh); + + geometry = new THREE.BoxGeometry(2.75, 2.75, 1); + geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,0,-0.5)); + + point = new THREE.Mesh(geometry); + + renderer = new THREE.WebGLRenderer({antialias: true}); + renderer.setSize(w, h); + renderer.setClearColor( 0x212121, 1 ); + + renderer.domElement.style.position = 'relative'; + + container.appendChild(renderer.domElement); + + container.addEventListener('mousedown', onMouseDown, false); + + container.addEventListener('mousewheel', onMouseWheel, false); + + document.addEventListener('keydown', onDocumentKeyDown, false); + + window.addEventListener('resize', onWindowResize, false); + + container.addEventListener('mouseover', function() { + overRenderer = true; + }, false); + + container.addEventListener('mouseout', function() { + overRenderer = false; + }, false); + } + + function addData(data, opts) { + var lat, lng, size, color, i, step, colorFnWrapper; + + opts.animated = opts.animated || false; + this.is_animated = opts.animated; + opts.format = opts.format || 'magnitude'; // other option is 'legend' + if (opts.format === 'magnitude') { + step = 3; + colorFnWrapper = function(data, i) { return colorFn(data[i+2]); } + } else if (opts.format === 'legend') { + step = 4; + colorFnWrapper = function(data, i) { return colorFn(data[i+3]); } + } else if (opts.format === 'peer') { + colorFnWrapper = function(data, i) { return colorFn(data[i+2]); } + } else { + throw('error: format not supported: '+opts.format); + } + + if (opts.animated) { + if (this._baseGeometry === undefined) { + this._baseGeometry = new THREE.Geometry(); + for (i = 0; i < data.length; i += step) { + lat = data[i]; + lng = data[i + 1]; +// size = data[i + 2]; + color = colorFnWrapper(data,i); + size = 0; + addPoint(lat, lng, size, color, this._baseGeometry); + } + } + if(this._morphTargetId === undefined) { + this._morphTargetId = 0; + } else { + this._morphTargetId += 1; + } + opts.name = opts.name || 'morphTarget'+this._morphTargetId; + } + var subgeo = new THREE.Geometry(); + for (i = 0; i < data.length; i += step) { + lat = data[i]; + lng = data[i + 1]; + color = colorFnWrapper(data,i); + size = data[i + 2]; + size = size*200; + addPoint(lat, lng, size, color, subgeo); + } + if (opts.animated) { + this._baseGeometry.morphTargets.push({'name': opts.name, vertices: subgeo.vertices}); + } else { + this._baseGeometry = subgeo; + } + + }; + + function createPoints() { + if (this._baseGeometry !== undefined) { + if (this.is_animated === false) { + this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ + color: 0xffffff, + vertexColors: THREE.FaceColors, + morphTargets: false + })); + } else { + if (this._baseGeometry.morphTargets.length < 8) { + console.log('t l',this._baseGeometry.morphTargets.length); + var padding = 8-this._baseGeometry.morphTargets.length; + console.log('padding', padding); + for(var i=0; i<=padding; i++) { + console.log('padding',i); + this._baseGeometry.morphTargets.push({'name': 'morphPadding'+i, vertices: this._baseGeometry.vertices}); + } + } + this.points = new THREE.Mesh(this._baseGeometry, new THREE.MeshBasicMaterial({ + color: 0xffffff, + vertexColors: THREE.FaceColors, + morphTargets: true + })); + } + scene.add(this.points); + } + } + + function addPoint(lat, lng, size, color, subgeo) { + + var phi = (90 - lat) * Math.PI / 180; + var theta = (180 - lng) * Math.PI / 180; + + point.position.x = 200 * Math.sin(phi) * Math.cos(theta); + point.position.y = 200 * Math.cos(phi); + point.position.z = 200 * Math.sin(phi) * Math.sin(theta); + + point.lookAt(mesh.position); + + point.scale.z = Math.max( size, 0.1 ); // avoid non-invertible matrix + point.updateMatrix(); + + for (var i = 0; i < point.geometry.faces.length; i++) { + + point.geometry.faces[i].color = color; + + } + if(point.matrixAutoUpdate){ + point.updateMatrix(); + } + subgeo.merge(point.geometry, point.matrix); + } + + function onMouseDown(event) { + event.preventDefault(); + + container.addEventListener('mousemove', onMouseMove, false); + container.addEventListener('mouseup', onMouseUp, false); + container.addEventListener('mouseout', onMouseOut, false); + + mouseOnDown.x = - event.clientX; + mouseOnDown.y = event.clientY; + + targetOnDown.x = target.x; + targetOnDown.y = target.y; + + container.style.cursor = 'move'; + } + + function onMouseMove(event) { + mouse.x = - event.clientX; + mouse.y = event.clientY; + + var zoomDamp = distance/1000; + + target.x = targetOnDown.x + (mouse.x - mouseOnDown.x) * 0.005 * zoomDamp; + target.y = targetOnDown.y + (mouse.y - mouseOnDown.y) * 0.005 * zoomDamp; + + target.y = target.y > PI_HALF ? PI_HALF : target.y; + target.y = target.y < - PI_HALF ? - PI_HALF : target.y; + } + + function onMouseUp(event) { + container.removeEventListener('mousemove', onMouseMove, false); + container.removeEventListener('mouseup', onMouseUp, false); + container.removeEventListener('mouseout', onMouseOut, false); + container.style.cursor = 'auto'; + } + + function onMouseOut(event) { + container.removeEventListener('mousemove', onMouseMove, false); + container.removeEventListener('mouseup', onMouseUp, false); + container.removeEventListener('mouseout', onMouseOut, false); + } + + function onMouseWheel(event) { + event.preventDefault(); + if (overRenderer) { + zoom(event.wheelDeltaY * 0.3); + } + return false; + } + + function onDocumentKeyDown(event) { + switch (event.keyCode) { + case 38: + zoom(100); + event.preventDefault(); + break; + case 40: + zoom(-100); + event.preventDefault(); + break; + } + } + + function onWindowResize( event ) { + camera.aspect = container.offsetWidth / container.offsetHeight; + camera.updateProjectionMatrix(); + renderer.setSize( container.offsetWidth, container.offsetHeight ); + } + + function zoom(delta) { + distanceTarget -= delta; + distanceTarget = distanceTarget > 855 ? 855 : distanceTarget; + distanceTarget = distanceTarget < 350 ? 350 : distanceTarget; + } + + function animate() { + if (!running) return + requestAnimationFrame(animate); + render(); + } + + function render() { + zoom(curZoomSpeed); + + rotation.x += (target.x - rotation.x) * 0.1; + rotation.y += (target.y - rotation.y) * 0.1; + distance += (distanceTarget - distance) * 0.3; + + camera.position.x = distance * Math.sin(rotation.x) * Math.cos(rotation.y); + camera.position.y = distance * Math.sin(rotation.y); + camera.position.z = distance * Math.cos(rotation.x) * Math.cos(rotation.y); + + camera.lookAt(mesh.position); + + renderer.render(scene, camera); + } + + function unload() { + running = false + container.removeEventListener('mousedown', onMouseDown, false); + container.removeEventListener('mousewheel', onMouseWheel, false); + document.removeEventListener('keydown', onDocumentKeyDown, false); + window.removeEventListener('resize', onWindowResize, false); + + } + + init(); + this.animate = animate; + this.unload = unload; + + + this.__defineGetter__('time', function() { + return this._time || 0; + }); + + this.__defineSetter__('time', function(t) { + var validMorphs = []; + var morphDict = this.points.morphTargetDictionary; + for(var k in morphDict) { + if(k.indexOf('morphPadding') < 0) { + validMorphs.push(morphDict[k]); + } + } + validMorphs.sort(); + var l = validMorphs.length-1; + var scaledt = t*l+1; + var index = Math.floor(scaledt); + for (i=0;i= 0) { + this.points.morphTargetInfluences[lastIndex] = 1 - leftover; + } + this.points.morphTargetInfluences[index] = leftover; + this._time = t; + }); + + this.addData = addData; + this.createPoints = createPoints; + this.renderer = renderer; + this.scene = scene; + + return this; + +}; + diff --git a/plugins/Sidebar/media-globe/three.min.js b/plugins/Sidebar/media-globe/three.min.js new file mode 100644 index 00000000..a88b4afa --- /dev/null +++ b/plugins/Sidebar/media-globe/three.min.js @@ -0,0 +1,814 @@ +// threejs.org/license +'use strict';var THREE={REVISION:"69"};"object"===typeof module&&(module.exports=THREE);void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a};b=.5>=c?c*(1+b):c+b-c*b;c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= +Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r;this.g= +a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<< +8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f,f=.5>=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(cf&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y= +.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;this.normalize();return this}}(),inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*= +-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},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=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this}, +multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,k=b._z,n=b._w;this._x=c*n+f*g+d*k-e*h;this._y=d*n+f*h+e*g-c*k;this._z=e*n+f*k+c*h-d*g;this._w=f*n-c*g-d*h-e*k;this.onChangeCallback();return this},multiplyVector3:function(a){console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."); +return a.applyQuaternion(this)},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),k=Math.sqrt(1-g*g);if(.001>Math.abs(k))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;g=Math.sin((1-b)*h)/k;h= +Math.sin(b*h)/k;this._w=f*g+this._w*h;this._x=c*g+this._x*h;this._y=d*g+this._y*h;this._z=e*g+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback= +a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};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},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, +b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this}, +roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},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.x*this.x+this.y*this.y)},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){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},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},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y= +a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a;return function(b){!1===b instanceof THREE.Euler&&console.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),applyMatrix3:function(a){var b=this.x, +c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z= +(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,n=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-n*-f;this.y=k*a+b*-f+n*-e-h*-g;this.z=n*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(),unproject:function(){var a;return function(b){void 0=== +a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},min:function(a){this.x> +a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3,b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a, +b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z); +return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},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.x*this.x+this.y*this.y+this.z*this.z)},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){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/ +b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this}, +projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length()); +return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(a,b){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")}, +getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a, +b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},setFromMatrixScale: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;return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x=== +this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},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=void 0!==d?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},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x; +case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this}, +addVectors: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},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors: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},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b= +this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this}, +setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var n=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+n-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;n=(n+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>n?.01>e?(b=0,d=c=.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):h>n?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h), +b=d/c,d=k/c):.01>n?(c=b=.707106781,d=0):(d=Math.sqrt(n),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+n-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);this.wb.w&&(this.w=b.w);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w); +return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w); +return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())}, +setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]= +this.z;a[b+3]=this.w;return a},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; +THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order},set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},copy:function(a){this._x= +a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b){var c=THREE.Math.clamp,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[1],k=d[5],n=d[9],p=d[2],q=d[6],d=d[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(c(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-n,d),this._z=Math.atan2(-f,e)):(this._x=Math.atan2(q,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-c(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(g,d),this._z=Math.atan2(h,k)):(this._y= +Math.atan2(-p,e),this._z=0)):"ZXY"===b?(this._x=Math.asin(c(q,-1,1)),.99999>Math.abs(q)?(this._y=Math.atan2(-p,d),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,e))):"ZYX"===b?(this._y=Math.asin(-c(p,-1,1)),.99999>Math.abs(p)?(this._x=Math.atan2(q,d),this._z=Math.atan2(h,e)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(c(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-n,k),this._y=Math.atan2(-p,e)):(this._x=0,this._y=Math.atan2(g,d))):"XZY"===b?(this._z=Math.asin(-c(f, +-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(q,k),this._y=Math.atan2(g,e)):(this._x=Math.atan2(-n,d),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;this.onChangeCallback();return this},setFromQuaternion:function(a,b,c){var d=THREE.Math.clamp,e=a.x*a.x,f=a.y*a.y,g=a.z*a.z,h=a.w*a.w;b=b||this._order;"XYZ"===b?(this._x=Math.atan2(2*(a.x*a.w-a.y*a.z),h-e-f+g),this._y=Math.asin(d(2*(a.x*a.z+a.y*a.w),-1,1)),this._z=Math.atan2(2*(a.z*a.w-a.x* +a.y),h+e-f-g)):"YXZ"===b?(this._x=Math.asin(d(2*(a.x*a.w-a.y*a.z),-1,1)),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h-e-f+g),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h-e+f-g)):"ZXY"===b?(this._x=Math.asin(d(2*(a.x*a.w+a.y*a.z),-1,1)),this._y=Math.atan2(2*(a.y*a.w-a.z*a.x),h-e-f+g),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),h-e+f-g)):"ZYX"===b?(this._x=Math.atan2(2*(a.x*a.w+a.z*a.y),h-e-f+g),this._y=Math.asin(d(2*(a.y*a.w-a.x*a.z),-1,1)),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h+e-f-g)):"YZX"===b?(this._x=Math.atan2(2* +(a.x*a.w-a.z*a.y),h-e+f-g),this._y=Math.atan2(2*(a.y*a.w-a.x*a.z),h+e-f-g),this._z=Math.asin(d(2*(a.x*a.y+a.z*a.w),-1,1))):"XZY"===b?(this._x=Math.atan2(2*(a.x*a.w+a.y*a.z),h-e+f-g),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h+e-f-g),this._z=Math.asin(d(2*(a.z*a.w-a.x*a.y),-1,1))):console.warn("THREE.Euler: .setFromQuaternion() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this); +this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(){return[this._x,this._y,this._z,this._order]},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Euler(this._x,this._y,this._z,this._order)}}; +THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, +b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); +this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; +THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector2).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.y +this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&& +a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; +THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector3).set((a.x-this.min.x)/(this.max.x- +this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= +new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y, +this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a); +this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(){this.elements=new Float32Array([1,0,0,0,1,0,0,0,1]);0this.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,n=1/k;b.elements[0]*=c;b.elements[1]*= +c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=n;b.elements[9]*=n;b.elements[10]*=n;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRad(.5*a)); +var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,k=c-d,n=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/n;g[14]=-((f+e)/n);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){return(new THREE.Matrix4).fromArray(this.elements)}}; +THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; +THREE.Ray.prototype={constructor:THREE.Ray,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new THREE.Vector3;c.subVectors(a,this.origin); +var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(a,b,c,d){var e=a.clone().add(b).multiplyScalar(.5),f=b.clone().sub(a).normalize(),g=.5*a.distanceTo(b),h= +this.origin.clone().sub(e);a=-this.direction.dot(f);b=h.dot(this.direction);var k=-h.dot(f),n=h.lengthSq(),p=Math.abs(1-a*a),q,m;0<=p?(h=a*k-b,q=a*b-k,m=g*p,0<=h?q>=-m?q<=m?(g=1/p,h*=g,q*=g,a=h*(h+a*q+2*b)+q*(a*h+q+2*k)+n):(q=g,h=Math.max(0,-(a*q+b)),a=-h*h+q*(q+2*k)+n):(q=-g,h=Math.max(0,-(a*q+b)),a=-h*h+q*(q+2*k)+n):q<=-m?(h=Math.max(0,-(-a*g+b)),q=0f)return null;f=Math.sqrt(f-e);e=d-f; +d+=f;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new THREE.Vector3; +return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g;d=1/this.direction.x;f=1/this.direction.y;g=1/this.direction.z;var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=f?(e=(a.min.y-h.y)*f,f*=a.max.y-h.y):(e=(a.max.y-h.y)*f,f*=a.min.y-h.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(fg||e>d)return null;if(e>c||c!== +c)c=e;if(gd?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a));if(0>g||e+g>f)return null; +e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new THREE.Ray).copy(this)}};THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; +THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,g=b.length;f=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= +this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius); +return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}}; +THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; +THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],n=c[7],p=c[8],q=c[9],m=c[10],r=c[11],t=c[12],s=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,n-g,r-p,c-t).normalize();b[1].setComponents(f+ +a,n+g,r+p,c+t).normalize();b[2].setComponents(f+d,n+h,r+q,c+s).normalize();b[3].setComponents(f-d,n-h,r-q,c-s).normalize();b[4].setComponents(f-e,n-k,r-m,c-u).normalize();b[5].setComponents(f+e,n+k,r+m,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes, +c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0g&&0>f)return!1}return!0}}(), +containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, +c);return this}}(),copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, +b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start);a=this.distanceToPoint(a.end);return 0>b&&0a&&0f||1e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(){var a=Math.PI/180;return function(b){return b*a}}(),radToDeg:function(){var a= +180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a}}; +THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,n,p,q,m;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;n=this.points[c[0]];p=this.points[c[1]];q=this.points[c[2]];m=this.points[c[3]];h=g*g;k=g*h;d.x=b(n.x,p.x,q.x,m.x,g,h,k);d.y=b(n.y,p.y,q.y,m.y,g,h,k);d.z=b(n.z,p.z,q.z,m.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a=b.x+b.y}}(); +THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| +new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}, +clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; +THREE.Clock.prototype={constructor:THREE.Clock,start:function(){this.oldTime=this.startTime=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now(), +a=.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){}; +THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a].indexOf(b)&& +c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners[a];if(void 0!==c){var d=c.indexOf(b);-1!==d&&c.splice(d,1)}}},dispatchEvent:function(a){if(void 0!==this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;for(var c=[],d=b.length,e=0;eza?-1:1;h[4*a]=la.x;h[4*a+1]=la.y;h[4*a+2]=la.z;h[4*a+3]=Ga}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array, +e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],n=[],p=0;ps;s++)t=a[3*c+s],-1==m[t]?(q[2*s]=t,q[2*s+1]=-1,p++):m[t]k.index+b)for(k={start:f,count:0,index:g},h.push(k),p=0;6>p;p+=2)s=q[p+1],-1p;p+=2)t=q[p],s=q[p+1],-1===s&&(s=g++),m[t]=s,r[s]=t,e[f++]=s-k.index,k.count++}this.reorderBuffers(e,r,g);return this.offsets=h},merge:function(){console.log("BufferGeometry.merge(): TODO")},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;ed?-1:1,e.vertexTangents[c]=new THREE.Vector4(w.x,w.y,w.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;cd;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;ca.opacity)h.transparent=a.transparent;void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"=== +a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorAmbient&&(h.ambient=e(a.colorAmbient));a.colorEmissive&&(h.emissive=e(a.colorEmissive));a.transparency&&(h.opacity=a.transparency);a.specularCoef&&(h.shininess=a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap, +a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&& +b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormal?(g=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(g.uniforms),k.tNormal.value=h.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),h.map&&(k.tDiffuse.value=h.map,k.enableDiffuse.value=!0),h.specularMap&&(k.tSpecular.value=h.specularMap,k.enableSpecular.value=!0),h.lightMap&&(k.tAO.value=h.lightMap, +k.enableAO.value=!0),k.diffuse.value.setHex(h.color),k.specular.value.setHex(h.specular),k.ambient.value.setHex(h.ambient),k.shininess.value=h.shininess,void 0!==h.opacity&&(k.opacity.value=h.opacity),g=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:k,lights:!0,fog:!0}),h.transparent&&(g.transparent=!0)):g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}}; +THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;bg;g++)m=y[k++],v=u[2*m],m=u[2*m+1],v=new THREE.Vector2(v,m),2!==g&&c.faceVertexUvs[d][h].push(v),0!==g&&c.faceVertexUvs[d][h+1].push(v);q&&(q=3*y[k++],r.normal.set(G[q++],G[q++],G[q]),s.normal.copy(r.normal));if(t)for(d=0;4>d;d++)q=3*y[k++],t=new THREE.Vector3(G[q++], +G[q++],G[q]),2!==d&&r.vertexNormals.push(t),0!==d&&s.vertexNormals.push(t);p&&(p=y[k++],p=w[p],r.color.setHex(p),s.color.setHex(p));if(b)for(d=0;4>d;d++)p=y[k++],p=w[p],2!==d&&r.vertexColors.push(new THREE.Color(p)),0!==d&&s.vertexColors.push(new THREE.Color(p));c.faces.push(r);c.faces.push(s)}else{r=new THREE.Face3;r.a=y[k++];r.b=y[k++];r.c=y[k++];h&&(h=y[k++],r.materialIndex=h);h=c.faces.length;if(d)for(d=0;dg;g++)m=y[k++],v=u[2*m],m=u[2*m+1], +v=new THREE.Vector2(v,m),c.faceVertexUvs[d][h].push(v);q&&(q=3*y[k++],r.normal.set(G[q++],G[q++],G[q]));if(t)for(d=0;3>d;d++)q=3*y[k++],t=new THREE.Vector3(G[q++],G[q++],G[q]),r.vertexNormals.push(t);p&&(p=y[k++],r.color.setHex(w[p]));if(b)for(d=0;3>d;d++)p=y[k++],r.vertexColors.push(new THREE.Color(w[p]));c.faces.push(r)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;dthis.opacity&&(a.opacity=this.opacity);!1!==this.transparent&&(a.transparent=this.transparent);!1!==this.wireframe&&(a.wireframe=this.wireframe);return a},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor= +this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0; +THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.type="LineBasicMaterial";this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.type="LineDashedMaterial";this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineDashedMaterial.prototype.clone=function(){var a=new THREE.LineDashedMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.scale=this.scale;a.dashSize=this.dashSize;a.gapSize=this.gapSize;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.type="MeshBasicMaterial";this.color=new THREE.Color(16777215);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphTargets=this.skinning=!1;this.setValues(a)}; +THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshBasicMaterial.prototype.clone=function(){var a=new THREE.MeshBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap; +a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;return a}; +THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.type="MeshLambertMaterial";this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth= +1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog; +a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.type="MeshPhongMaterial";this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.wrapAround=this.metal=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.envMap=this.alphaMap=this.specularMap=null;this.combine= +THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale); +a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.type="MeshDepthMaterial";this.wireframe=this.morphTargets=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a}; +THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.shading=THREE.FlatShading;this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MeshFaceMaterial";this.materials=a instanceof Array?a:[]}; +THREE.MeshFaceMaterial.prototype={constructor:THREE.MeshFaceMaterial,toJSON:function(){for(var a={metadata:{version:4.2,type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type,materials:[]},b=0,c=this.materials.length;bf)){var m=b.origin.distanceTo(n);md.far||e.push({distance:m,point:k.clone().applyMatrix4(this.matrixWorld),face:null,faceIndex:null,object:this})}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.mode));THREE.Object3D.prototype.clone.call(this,a);return a}; +THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); +THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0g.far||h.push({distance:x,point:K,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(s=p.position.array,t=k=0,w=s.length;k +g.far||h.push({distance:x,point:K,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(t=this.material instanceof THREE.MeshFaceMaterial,s=!0===t?this.material.materials:null,r=g.precision,u=k.vertices,v=0,y=k.faces.length;vg.far||h.push({distance:x,point:K,face:G,faceIndex:v,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype); +THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256h.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=(c.end-c.start)/b*1E3,this.time=0):console.warn("animation["+a+"] undefined")}; +THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& +(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; +THREE.MorphAnimMesh.prototype.interpolateTargets=function(a,b,c){for(var d=this.morphTargetInfluences,e=0,f=d.length;e=this.objects[d].distance)this.objects[d-1].object.visible=!1,this.objects[d].object.visible=!0;else break;for(;dthis.scale.x||c.push({distance:d,point:this.position,face:null,object:this})}}();THREE.Sprite.prototype.clone=function(a){void 0===a&&(a=new THREE.Sprite(this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Particle=THREE.Sprite; +THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype); +THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; +THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a dashSize ) {\n\t\tdiscard;\n\t}\n\tgl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment, +"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment, +"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\n\tgl_FragColor = vec4( vec3( color ), opacity );\n}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvNormal = normalize( normalMatrix * normal );", +THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i", +value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},diffuse:{type:"c",value:new THREE.Color(16777215)}, +specular:{type:"c",value:new THREE.Color(1118481)},ambient:{type:"c",value:new THREE.Color(16777215)},shininess:{type:"f",value:30},opacity:{type:"f",value:1},useRefract:{type:"i",value:0},refractionRatio:{type:"f",value:.98},reflectivity:{type:"f",value:.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 ambient;\nuniform vec3 diffuse;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float refractionRatio;\nuniform float reflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\n\tuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\tgl_FragColor = vec4( vec3( 1.0 ), opacity );\n\tvec3 specularTex = vec3( 1.0 );\n\tvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\n\tnormalTex.xy *= uNormalScale;\n\tnormalTex = normalize( normalTex );\n\tif( enableDiffuse ) {\n\t\t#ifdef GAMMA_INPUT\n\t\t\tvec4 texelColor = texture2D( tDiffuse, vUv );\n\t\t\ttexelColor.xyz *= texelColor.xyz;\n\t\t\tgl_FragColor = gl_FragColor * texelColor;\n\t\t#else\n\t\t\tgl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n\t\t#endif\n\t}\n\tif( enableAO ) {\n\t\t#ifdef GAMMA_INPUT\n\t\t\tvec4 aoColor = texture2D( tAO, vUv );\n\t\t\taoColor.xyz *= aoColor.xyz;\n\t\t\tgl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n\t\t#else\n\t\t\tgl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n\t\t#endif\n\t}", +THREE.ShaderChunk.alphatest_fragment,"\tif( enableSpecular )\n\t\tspecularTex = texture2D( tSpecular, vUv ).xyz;\n\tmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\n\tvec3 finalNormal = tsb * normalTex;\n\t#ifdef FLIP_SIDED\n\t\tfinalNormal = -finalNormal;\n\t#endif\n\tvec3 normal = normalize( finalNormal );\n\tvec3 viewPosition = normalize( vViewPosition );\n\t#if MAX_POINT_LIGHTS > 0\n\t\tvec3 pointDiffuse = vec3( 0.0 );\n\t\tvec3 pointSpecular = vec3( 0.0 );\n\t\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\t\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\t\tvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\n\t\t\tfloat pointDistance = 1.0;\n\t\t\tif ( pointLightDistance[ i ] > 0.0 )\n\t\t\t\tpointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\n\t\t\tpointVector = normalize( pointVector );\n\t\t\t#ifdef WRAP_AROUND\n\t\t\t\tfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\n\t\t\t\tfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\n\t\t\t\tvec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\t\t\t#else\n\t\t\t\tfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n\t\t\t#endif\n\t\t\tpointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;\n\t\t\tvec3 pointHalfVector = normalize( pointVector + viewPosition );\n\t\t\tfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n\t\t\tfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( pointVector, pointHalfVector ), 0.0 ), 5.0 );\n\t\t\tpointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n\t\t}\n\t#endif\n\t#if MAX_SPOT_LIGHTS > 0\n\t\tvec3 spotDiffuse = vec3( 0.0 );\n\t\tvec3 spotSpecular = vec3( 0.0 );\n\t\tfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\t\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\t\tvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\n\t\t\tfloat spotDistance = 1.0;\n\t\t\tif ( spotLightDistance[ i ] > 0.0 )\n\t\t\t\tspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\n\t\t\tspotVector = normalize( spotVector );\n\t\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\t\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\t\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\t\t\t\t#ifdef WRAP_AROUND\n\t\t\t\t\tfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\n\t\t\t\t\tfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\n\t\t\t\t\tvec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\t\t\t\t#else\n\t\t\t\t\tfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n\t\t\t\t#endif\n\t\t\t\tspotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;\n\t\t\t\tvec3 spotHalfVector = normalize( spotVector + viewPosition );\n\t\t\t\tfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n\t\t\t\tfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\t\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( spotVector, spotHalfVector ), 0.0 ), 5.0 );\n\t\t\t\tspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n\t\t\t}\n\t\t}\n\t#endif\n\t#if MAX_DIR_LIGHTS > 0\n\t\tvec3 dirDiffuse = vec3( 0.0 );\n\t\tvec3 dirSpecular = vec3( 0.0 );\n\t\tfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\n\t\t\tvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\n\t\t\tvec3 dirVector = normalize( lDirection.xyz );\n\t\t\t#ifdef WRAP_AROUND\n\t\t\t\tfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\n\t\t\t\tfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\n\t\t\t\tvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n\t\t\t#else\n\t\t\t\tfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n\t\t\t#endif\n\t\t\tdirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;\n\t\t\tvec3 dirHalfVector = normalize( dirVector + viewPosition );\n\t\t\tfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n\t\t\tfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n\t\t\tdirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\t\t}\n\t#endif\n\t#if MAX_HEMI_LIGHTS > 0\n\t\tvec3 hemiDiffuse = vec3( 0.0 );\n\t\tvec3 hemiSpecular = vec3( 0.0 );\n\t\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\t\t\tvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\n\t\t\tvec3 lVector = normalize( lDirection.xyz );\n\t\t\tfloat dotProduct = dot( normal, lVector );\n\t\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\t\t\tvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\t\t\themiDiffuse += diffuse * hemiColor;\n\t\t\tvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n\t\t\tfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n\t\t\tfloat hemiSpecularWeightSky = specularTex.r * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\t\t\tvec3 lVectorGround = -lVector;\n\t\t\tvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n\t\t\tfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n\t\t\tfloat hemiSpecularWeightGround = specularTex.r * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\t\t\tfloat dotProductGround = dot( normal, lVectorGround );\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\t\t\tvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n\t\t\tvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n\t\t\themiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\t\t}\n\t#endif\n\tvec3 totalDiffuse = vec3( 0.0 );\n\tvec3 totalSpecular = vec3( 0.0 );\n\t#if MAX_DIR_LIGHTS > 0\n\t\ttotalDiffuse += dirDiffuse;\n\t\ttotalSpecular += dirSpecular;\n\t#endif\n\t#if MAX_HEMI_LIGHTS > 0\n\t\ttotalDiffuse += hemiDiffuse;\n\t\ttotalSpecular += hemiSpecular;\n\t#endif\n\t#if MAX_POINT_LIGHTS > 0\n\t\ttotalDiffuse += pointDiffuse;\n\t\ttotalSpecular += pointSpecular;\n\t#endif\n\t#if MAX_SPOT_LIGHTS > 0\n\t\ttotalDiffuse += spotDiffuse;\n\t\ttotalSpecular += spotSpecular;\n\t#endif\n\t#ifdef METAL\n\t\tgl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );\n\t#else\n\t\tgl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n\t#endif\n\tif ( enableReflection ) {\n\t\tvec3 vReflect;\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tif ( useRefract ) {\n\t\t\tvReflect = refract( cameraToVertex, normal, refractionRatio );\n\t\t} else {\n\t\t\tvReflect = reflect( cameraToVertex, normal );\n\t\t}\n\t\tvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n\t\t#ifdef GAMMA_INPUT\n\t\t\tcubeColor.xyz *= cubeColor.xyz;\n\t\t#endif\n\t\tgl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );\n\t}", +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;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\n\tuniform sampler2D tDisplacement;\n\tuniform float uDisplacementScale;\n\tuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"\t#ifdef USE_SKINNING\n\t\tvNormal = normalize( normalMatrix * skinnedNormal.xyz );\n\t\tvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\n\t\tvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n\t#else\n\t\tvNormal = normalize( normalMatrix * normal );\n\t\tvTangent = normalize( normalMatrix * tangent.xyz );\n\t#endif\n\tvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\n\tvUv = uv * uRepeat + uOffset;\n\tvec3 displacedPosition;\n\t#ifdef VERTEX_TEXTURES\n\t\tif ( enableDisplacement ) {\n\t\t\tvec3 dv = texture2D( tDisplacement, uv ).xyz;\n\t\t\tfloat df = uDisplacementScale * dv.x + uDisplacementBias;\n\t\t\tdisplacedPosition = position + normalize( normal ) * df;\n\t\t} else {\n\t\t\t#ifdef USE_SKINNING\n\t\t\t\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\t\t\t\tvec4 skinned = vec4( 0.0 );\n\t\t\t\tskinned += boneMatX * skinVertex * skinWeight.x;\n\t\t\t\tskinned += boneMatY * skinVertex * skinWeight.y;\n\t\t\t\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\t\t\t\tskinned += boneMatW * skinVertex * skinWeight.w;\n\t\t\t\tskinned = bindMatrixInverse * skinned;\n\t\t\t\tdisplacedPosition = skinned.xyz;\n\t\t\t#else\n\t\t\t\tdisplacedPosition = position;\n\t\t\t#endif\n\t\t}\n\t#else\n\t\t#ifdef USE_SKINNING\n\t\t\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\t\t\tvec4 skinned = vec4( 0.0 );\n\t\t\tskinned += boneMatX * skinVertex * skinWeight.x;\n\t\t\tskinned += boneMatY * skinVertex * skinWeight.y;\n\t\t\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\t\t\tskinned += boneMatW * skinVertex * skinWeight.w;\n\t\t\tskinned = bindMatrixInverse * skinned;\n\t\t\tdisplacedPosition = skinned.xyz;\n\t\t#else\n\t\t\tdisplacedPosition = position;\n\t\t#endif\n\t#endif\n\tvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\n\tvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk.logdepthbuf_vertex,"\tvWorldPosition = worldPosition.xyz;\n\tvViewPosition = -mvPosition.xyz;\n\t#ifdef USE_SHADOWMAP\n\t\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\t\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\t\t}\n\t#endif\n}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\tvWorldPosition = worldPosition.xyz;\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", +THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex, +"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {", +THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}}; +THREE.WebGLRenderer=function(a){function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a.attributes){void 0===b.__webglCustomAttributesList&&(b.__webglCustomAttributesList=[]);for(var d in a.attributes){var e=a.attributes[d];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var f=1;"v2"===e.type?f=2:"v3"===e.type?f=3:"v4"===e.type?f=4:"c"===e.type&&(f=3);e.size=f;e.array=new Float32Array(c*f);e.buffer=l.createBuffer();e.buffer.belongsToAttribute=d;e.needsUpdate= +!0}b.__webglCustomAttributesList.push(e)}}}function c(a,b){var c=b.geometry,e=a.faces3,f=3*e.length,g=1*e.length,h=3*e.length,e=d(b,a);a.__vertexArray=new Float32Array(3*f);a.__normalArray=new Float32Array(3*f);a.__colorArray=new Float32Array(3*f);a.__uvArray=new Float32Array(2*f);1Aa;Aa++)Cb=ma[Aa],Ta[Sa]=Cb.x,Ta[Sa+1]=Cb.y,Ta[Sa+2]=Cb.z,Sa+=3;else for(Aa=0;3>Aa;Aa++)Ta[Sa]=pa.x,Ta[Sa+1]=pa.y,Ta[Sa+2]=pa.z,Sa+=3;l.bindBuffer(l.ARRAY_BUFFER,C.__webglNormalBuffer);l.bufferData(l.ARRAY_BUFFER, +Ta,S)}if(Kc&&ua){M=0;for(ea=N.length;MAa;Aa++)Oa=hb[Aa],sb[qb]=Oa.x,sb[qb+1]=Oa.y,qb+=2;0Aa;Aa++)Qb=za[Aa],fb[rb]=Qb.x,fb[rb+1]=Qb.y,rb+=2;0h&&(f[v].counter+=1,k=f[v].hash+"_"+f[v].counter,k in r||(p={id:rc++, +faces3:[],materialIndex:v,vertices:0,numMorphTargets:m,numMorphNormals:n},r[k]=p,q.push(p)));r[k].faces3.push(t);r[k].vertices+=3}a[g]=q;d.groupsNeedUpdate=!1}a=xb[d.id];g=0;for(e=a.length;gDa;Da++)kb[Da]=!J.autoScaleCubemaps||Ob||Tb?Tb?ua.image[Da].image:ua.image[Da]:R(ua.image[Da],$c);var ka=kb[0],Zb=THREE.Math.isPowerOfTwo(ka.width)&&THREE.Math.isPowerOfTwo(ka.height),ab=Q(ua.format),Fb=Q(ua.type);F(l.TEXTURE_CUBE_MAP,ua,Zb);for(Da=0;6>Da;Da++)if(Ob)for(var gb,$b=kb[Da].mipmaps,ga=0,Xb=$b.length;ga=Oc&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+ +Oc);dc+=1;return a}function x(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getNormalMatrix(a._modelViewMatrix)}function D(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function E(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function A(a){a!==Pc&&(l.lineWidth(a),Pc=a)}function B(a,b,c){Qc!==a&&(a?l.enable(l.POLYGON_OFFSET_FILL):l.disable(l.POLYGON_OFFSET_FILL),Qc=a);!a||Rc===b&&Sc===c||(l.polygonOffset(b,c),Rc=b,Sc=c)}function F(a,b,c){c? +(l.texParameteri(a,l.TEXTURE_WRAP_S,Q(b.wrapS)),l.texParameteri(a,l.TEXTURE_WRAP_T,Q(b.wrapT)),l.texParameteri(a,l.TEXTURE_MAG_FILTER,Q(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,Q(b.minFilter))):(l.texParameteri(a,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_MAG_FILTER,T(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,T(b.minFilter)));(c=pa.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&(1b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.log("THREE.WebGLRenderer:",a,"is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height+ +".");return d}return a}function H(a,b){l.bindRenderbuffer(l.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_COMPONENT16,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT,l.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_STENCIL,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a)):l.renderbufferStorage(l.RENDERBUFFER,l.RGBA4,b.width, +b.height)}function C(a){a instanceof THREE.WebGLRenderTargetCube?(l.bindTexture(l.TEXTURE_CUBE_MAP,a.__webglTexture),l.generateMipmap(l.TEXTURE_CUBE_MAP),l.bindTexture(l.TEXTURE_CUBE_MAP,null)):(l.bindTexture(l.TEXTURE_2D,a.__webglTexture),l.generateMipmap(l.TEXTURE_2D),l.bindTexture(l.TEXTURE_2D,null))}function T(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?l.NEAREST:l.LINEAR}function Q(a){var b;if(a===THREE.RepeatWrapping)return l.REPEAT; +if(a===THREE.ClampToEdgeWrapping)return l.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return l.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return l.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return l.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return l.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return l.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return l.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return l.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return l.UNSIGNED_BYTE; +if(a===THREE.UnsignedShort4444Type)return l.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return l.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return l.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return l.BYTE;if(a===THREE.ShortType)return l.SHORT;if(a===THREE.UnsignedShortType)return l.UNSIGNED_SHORT;if(a===THREE.IntType)return l.INT;if(a===THREE.UnsignedIntType)return l.UNSIGNED_INT;if(a===THREE.FloatType)return l.FLOAT;if(a===THREE.AlphaFormat)return l.ALPHA;if(a===THREE.RGBFormat)return l.RGB; +if(a===THREE.RGBAFormat)return l.RGBA;if(a===THREE.LuminanceFormat)return l.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return l.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return l.FUNC_ADD;if(a===THREE.SubtractEquation)return l.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return l.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return l.ZERO;if(a===THREE.OneFactor)return l.ONE;if(a===THREE.SrcColorFactor)return l.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return l.ONE_MINUS_SRC_COLOR;if(a=== +THREE.SrcAlphaFactor)return l.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return l.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return l.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return l.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return l.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return l.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return l.SRC_ALPHA_SATURATE;b=pa.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT; +if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=pa.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; +if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=pa.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var O=void 0!==a.canvas?a.canvas:document.createElement("canvas"),S=void 0!==a.context?a.context:null,X=void 0!==a.precision?a.precision:"highp",Y=void 0!==a.alpha?a.alpha:!1,la=void 0!==a.depth?a.depth:!0,ma=void 0!==a.stencil? +a.stencil:!0,ya=void 0!==a.antialias?a.antialias:!1,P=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,Ga=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,Fa=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,za=new THREE.Color(0),bb=0,cb=[],ob={},jb=[],Jb=[],Ib=[],yb=[],Ra=[];this.domElement=O;this.context=null;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==self.devicePixelRatio?self.devicePixelRatio:1;this.sortObjects=this.autoClearStencil= +this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=this.gammaOutput=this.gammaInput=!1;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var J=this,hb=[],tc=null,Tc=null,Kb=-1,Oa=-1,ec=null,dc=0,Lb=-1,Mb=-1,pb=-1,Nb=-1,Ob=-1, +Xb=-1,Yb=-1,nb=-1,Qc=null,Rc=null,Sc=null,Pc=null,Pb=0,kc=0,lc=O.width,mc=O.height,Uc=0,Vc=0,wb=new Uint8Array(16),ib=new Uint8Array(16),Ec=new THREE.Frustum,Ac=new THREE.Matrix4,Gc=new THREE.Matrix4,Na=new THREE.Vector3,sa=new THREE.Vector3,fc=!0,Mc={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[]},hemi:{length:0,skyColors:[],groundColors:[], +positions:[]}},l;try{var Wc={alpha:Y,depth:la,stencil:ma,antialias:ya,premultipliedAlpha:P,preserveDrawingBuffer:Ga};l=S||O.getContext("webgl",Wc)||O.getContext("experimental-webgl",Wc);if(null===l){if(null!==O.getContext("webgl"))throw"Error creating WebGL context with your selected attributes.";throw"Error creating WebGL context.";}}catch(ad){console.error(ad)}void 0===l.getShaderPrecisionFormat&&(l.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var pa=new THREE.WebGLExtensions(l); +pa.get("OES_texture_float");pa.get("OES_texture_float_linear");pa.get("OES_standard_derivatives");Fa&&pa.get("EXT_frag_depth");l.clearColor(0,0,0,1);l.clearDepth(1);l.clearStencil(0);l.enable(l.DEPTH_TEST);l.depthFunc(l.LEQUAL);l.frontFace(l.CCW);l.cullFace(l.BACK);l.enable(l.CULL_FACE);l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.SRC_ALPHA,l.ONE_MINUS_SRC_ALPHA);l.viewport(Pb,kc,lc,mc);l.clearColor(za.r,za.g,za.b,bb);this.context=l;var Oc=l.getParameter(l.MAX_TEXTURE_IMAGE_UNITS), +bd=l.getParameter(l.MAX_VERTEX_TEXTURE_IMAGE_UNITS),cd=l.getParameter(l.MAX_TEXTURE_SIZE),$c=l.getParameter(l.MAX_CUBE_MAP_TEXTURE_SIZE),sc=0b;b++)l.deleteFramebuffer(a.__webglFramebuffer[b]),l.deleteRenderbuffer(a.__webglRenderbuffer[b]); +else l.deleteFramebuffer(a.__webglFramebuffer),l.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}J.info.memory.textures--},Dc=function(a){a=a.target;a.removeEventListener("dispose",Dc);Cc(a)},Yc=function(a){for(var b="__webglVertexBuffer __webglNormalBuffer __webglTangentBuffer __webglColorBuffer __webglUVBuffer __webglUV2Buffer __webglSkinIndicesBuffer __webglSkinWeightsBuffer __webglFaceBuffer __webglLineBuffer __webglLineDistanceBuffer".split(" "), +c=0,d=b.length;cd.numSupportedMorphTargets?(n.sort(p),n.length=d.numSupportedMorphTargets):n.length>d.numSupportedMorphNormals?n.sort(p):0===n.length&&n.push([0, +0]);for(m=0;mf;f++){a.__webglFramebuffer[f]=l.createFramebuffer();a.__webglRenderbuffer[f]=l.createRenderbuffer();l.texImage2D(l.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=l.TEXTURE_CUBE_MAP_POSITIVE_X+f;l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer[f]);l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,h,g.__webglTexture,0);H(a.__webglRenderbuffer[f],a)}c&&l.generateMipmap(l.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer= +l.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:l.createRenderbuffer(),l.bindTexture(l.TEXTURE_2D,a.__webglTexture),F(l.TEXTURE_2D,a,c),l.texImage2D(l.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=l.TEXTURE_2D,l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer),l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT, +l.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a.__webglRenderbuffer):H(a.__webglRenderbuffer,a),c&&l.generateMipmap(l.TEXTURE_2D);b?l.bindTexture(l.TEXTURE_CUBE_MAP,null):l.bindTexture(l.TEXTURE_2D,null);l.bindRenderbuffer(l.RENDERBUFFER,null);l.bindFramebuffer(l.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=lc,a=mc, +d=Pb,e=kc);b!==Tc&&(l.bindFramebuffer(l.FRAMEBUFFER,b),l.viewport(d,e,c,a),Tc=b);Uc=c;Vc=a};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}}; +THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: +THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; +THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){this.width=a;this.height=b},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.anisotropy=this.anisotropy;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;a.generateMipmaps=this.generateMipmaps; +a.shareDepthFrom=this.shareDepthFrom;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype); +THREE.WebGLExtensions=function(a){var b={};this.get=function(c){if(void 0!==b[c])return b[c];var d;switch(c){case "OES_texture_float":d=a.getExtension("OES_texture_float");break;case "OES_texture_float_linear":d=a.getExtension("OES_texture_float_linear");break;case "OES_standard_derivatives":d=a.getExtension("OES_standard_derivatives");break;case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic"); +break;case "WEBGL_compressed_texture_s3tc":d=a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;case "OES_element_index_uint":d=a.getExtension("OES_element_index_uint");break;case "EXT_blend_minmax":d=a.getExtension("EXT_blend_minmax");break; +case "EXT_frag_depth":d=a.getExtension("EXT_frag_depth")}null===d&&console.log("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}}; +THREE.WebGLProgram=function(){var a=0;return function(b,c,d,e){var f=b.context,g=d.defines,h=d.__webglShader.uniforms,k=d.attributes,n=d.__webglShader.vertexShader,p=d.__webglShader.fragmentShader,q=d.index0AttributeName;void 0===q&&!0===e.morphTargets&&(q="position");var m="SHADOWMAP_TYPE_BASIC";e.shadowMapType===THREE.PCFShadowMap?m="SHADOWMAP_TYPE_PCF":e.shadowMapType===THREE.PCFSoftShadowMap&&(m="SHADOWMAP_TYPE_PCF_SOFT");var r,t;r=[];for(var s in g)t=g[s],!1!==t&&(t="#define "+s+" "+t,r.push(t)); +r=r.join("\n");g=f.createProgram();d instanceof THREE.RawShaderMaterial?b=d="":(d=["precision "+e.precision+" float;","precision "+e.precision+" int;",r,e.supportsVertexTextures?"#define VERTEX_TEXTURES":"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"","#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,"#define MAX_BONES "+ +e.maxBones,e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.skinning?"#define USE_SKINNING":"",e.useVertexTexture?"#define BONE_TEXTURE":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals?"#define USE_MORPHNORMALS":"",e.wrapAround?"#define WRAP_AROUND": +"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.sizeAttenuation?"#define USE_SIZEATTENUATION":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;\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\n\tattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\n\tattribute vec3 morphTarget0;\n\tattribute vec3 morphTarget1;\n\tattribute vec3 morphTarget2;\n\tattribute vec3 morphTarget3;\n\t#ifdef USE_MORPHNORMALS\n\t\tattribute vec3 morphNormal0;\n\t\tattribute vec3 morphNormal1;\n\t\tattribute vec3 morphNormal2;\n\t\tattribute vec3 morphNormal3;\n\t#else\n\t\tattribute vec3 morphTarget4;\n\t\tattribute vec3 morphTarget5;\n\t\tattribute vec3 morphTarget6;\n\t\tattribute vec3 morphTarget7;\n\t#endif\n#endif\n#ifdef USE_SKINNING\n\tattribute vec4 skinIndex;\n\tattribute vec4 skinWeight;\n#endif\n"].join("\n"), +b=["precision "+e.precision+" float;","precision "+e.precision+" int;",e.bumpMap||e.normalMap?"#extension GL_OES_standard_derivatives : enable":"",r,"#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,e.alphaTest?"#define ALPHATEST "+e.alphaTest:"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"",e.useFog&&e.fog?"#define USE_FOG": +"",e.useFog&&e.fogExp?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.metal?"#define METAL":"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP": +"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n"));n=new THREE.WebGLShader(f,f.VERTEX_SHADER,d+n);p=new THREE.WebGLShader(f,f.FRAGMENT_SHADER,b+p);f.attachShader(g,n);f.attachShader(g,p);void 0!==q&&f.bindAttribLocation(g,0,q);f.linkProgram(g);!1===f.getProgramParameter(g,f.LINK_STATUS)&&(console.error("THREE.WebGLProgram: Could not initialise shader."), +console.error("gl.VALIDATE_STATUS",f.getProgramParameter(g,f.VALIDATE_STATUS)),console.error("gl.getError()",f.getError()));""!==f.getProgramInfoLog(g)&&console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",f.getProgramInfoLog(g));f.deleteShader(n);f.deleteShader(p);q="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences bindMatrix bindMatrixInverse".split(" ");e.useVertexTexture?(q.push("boneTexture"),q.push("boneTextureWidth"),q.push("boneTextureHeight")): +q.push("boneGlobalMatrices");e.logarithmicDepthBuffer&&q.push("logDepthBufFC");for(var u in h)q.push(u);h=q;u={};q=0;for(b=h.length;qT;T++)F[T]=new THREE.Vector3,A[T]=new THREE.Vector3;F=B.shadowCascadeNearZ[C];B=B.shadowCascadeFarZ[C];A[0].set(-1,-1,F);A[1].set(1,-1,F);A[2].set(-1,1,F);A[3].set(1,1,F);A[4].set(-1,-1,B);A[5].set(1,-1,B);A[6].set(-1,1,B);A[7].set(1,1,B);H.originalCamera=v;A=new THREE.Gyroscope;A.position.copy(x.shadowCascadeOffset);A.add(H);A.add(H.target);v.add(A);x.shadowCascadeArray[E]=H;console.log("Created virtualLight",H)}C= +x;F=E;B=C.shadowCascadeArray[F];B.position.copy(C.position);B.target.position.copy(C.target.position);B.lookAt(B.target);B.shadowCameraVisible=C.shadowCameraVisible;B.shadowDarkness=C.shadowDarkness;B.shadowBias=C.shadowCascadeBias[F];A=C.shadowCascadeNearZ[F];C=C.shadowCascadeFarZ[F];B=B.pointsFrustum;B[0].z=A;B[1].z=A;B[2].z=A;B[3].z=A;B[4].z=C;B[5].z=C;B[6].z=C;B[7].z=C;R[D]=H;D++}else R[D]=x,D++;u=0;for(K=R.length;uC;C++)F=B[C],F.copy(A[C]),F.unproject(E),F.applyMatrix4(D.matrixWorldInverse),F.xr.x&&(r.x=F.x),F.yr.y&&(r.y=F.y),F.zr.z&&(r.z=F.z);D.left=m.x;D.right=r.x;D.top=r.y;D.bottom=m.y;D.updateProjectionMatrix()}D=x.shadowMap;A=x.shadowMatrix;E=x.shadowCamera;E.position.setFromMatrixPosition(x.matrixWorld);t.setFromMatrixPosition(x.target.matrixWorld);E.lookAt(t);E.updateMatrixWorld();E.matrixWorldInverse.getInverse(E.matrixWorld);x.cameraHelper&& +(x.cameraHelper.visible=x.shadowCameraVisible);x.shadowCameraVisible&&x.cameraHelper.update();A.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);A.multiply(E.projectionMatrix);A.multiply(E.matrixWorldInverse);q.multiplyMatrices(E.projectionMatrix,E.matrixWorldInverse);p.setFromMatrix(q);a.setRenderTarget(D);a.clear();s.length=0;e(c,c,E);x=0;for(D=s.length;x 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); +w.compileShader(R);w.compileShader(H);w.attachShader(F,R);w.attachShader(F,H);w.linkProgram(F);D=F;v=w.getAttribLocation(D,"position");y=w.getAttribLocation(D,"uv");c=w.getUniformLocation(D,"uvOffset");d=w.getUniformLocation(D,"uvScale");e=w.getUniformLocation(D,"rotation");f=w.getUniformLocation(D,"scale");g=w.getUniformLocation(D,"color");h=w.getUniformLocation(D,"map");k=w.getUniformLocation(D,"opacity");n=w.getUniformLocation(D,"modelViewMatrix");p=w.getUniformLocation(D,"projectionMatrix");q= +w.getUniformLocation(D,"fogType");m=w.getUniformLocation(D,"fogDensity");r=w.getUniformLocation(D,"fogNear");t=w.getUniformLocation(D,"fogFar");s=w.getUniformLocation(D,"fogColor");u=w.getUniformLocation(D,"alphaTest");F=document.createElement("canvas");F.width=8;F.height=8;R=F.getContext("2d");R.fillStyle="white";R.fillRect(0,0,8,8);E=new THREE.Texture(F);E.needsUpdate=!0}w.useProgram(D);w.enableVertexAttribArray(v);w.enableVertexAttribArray(y);w.disable(w.CULL_FACE);w.enable(w.BLEND);w.bindBuffer(w.ARRAY_BUFFER, +K);w.vertexAttribPointer(v,2,w.FLOAT,!1,16,0);w.vertexAttribPointer(y,2,w.FLOAT,!1,16,8);w.bindBuffer(w.ELEMENT_ARRAY_BUFFER,x);w.uniformMatrix4fv(p,!1,B.projectionMatrix.elements);w.activeTexture(w.TEXTURE0);w.uniform1i(h,0);R=F=0;(H=A.fog)?(w.uniform3f(s,H.color.r,H.color.g,H.color.b),H instanceof THREE.Fog?(w.uniform1f(r,H.near),w.uniform1f(t,H.far),w.uniform1i(q,1),R=F=1):H instanceof THREE.FogExp2&&(w.uniform1f(m,H.density),w.uniform1i(q,2),R=F=2)):(w.uniform1i(q,0),R=F=0);for(var H=0,C=b.length;H< +C;H++){var T=b[H];T._modelViewMatrix.multiplyMatrices(B.matrixWorldInverse,T.matrixWorld);T.z=null===T.renderDepth?-T._modelViewMatrix.elements[14]:T.renderDepth}b.sort(G);for(var Q=[],H=0,C=b.length;Hq-1?0:q-1,r=q+1>e-1?e-1:q+1,t=0>p-1?0:p-1,s=p+1>d-1?d-1:p+1,u=[],v=[0,0,h[4*(q*d+p)]/255*b];u.push([-1,0,h[4*(q*d+t)]/255*b]);u.push([-1,-1,h[4*(m*d+t)]/255*b]);u.push([0,-1,h[4*(m*d+p)]/255*b]);u.push([1,-1,h[4*(m*d+s)]/255*b]);u.push([1,0,h[4*(q*d+s)]/255*b]);u.push([1,1,h[4*(r*d+s)]/255*b]);u.push([0,1,h[4*(r*d+p)]/255* +b]);u.push([-1,1,h[4*(r*d+t)]/255*b]);m=[];t=u.length;for(r=0;re)return null;var f=[],g=[],h=[],k,n,p;if(0=q--){console.log("Warning, unable to triangulate polygon!");break}k=n;e<=k&&(k=0);n=k+1;e<=n&&(n=0);p=n+1;e<=p&&(p=0);var m;a:{var r=m=void 0,t=void 0,s=void 0,u=void 0,v=void 0,y=void 0,G=void 0,w=void 0, +r=a[g[k]].x,t=a[g[k]].y,s=a[g[n]].x,u=a[g[n]].y,v=a[g[p]].x,y=a[g[p]].y;if(1E-10>(s-r)*(y-t)-(u-t)*(v-r))m=!1;else{var K=void 0,x=void 0,D=void 0,E=void 0,A=void 0,B=void 0,F=void 0,R=void 0,H=void 0,C=void 0,H=R=F=w=G=void 0,K=v-s,x=y-u,D=r-v,E=t-y,A=s-r,B=u-t;for(m=0;mk)g=d+1;else if(0b&&(b=0);1=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; +THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=h.x:h.xc?c=h.y:h.yd?d=h.z:h.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;cm&&(g=b[f],k=-k,h=b[e],m=-m),!(a.yh.y))if(a.y==g.y){if(a.x==g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0==e)return!0;0>e||(d=!d)}}else if(a.y==g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<= +h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;bE||E>D)return[];k=n*p-k*q;if(0>k||k>D)return[]}else{if(0d?[]:k==d?f?[]:[g]:a<=d?[g,h]: +[g,n]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1; +d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;cC){console.log("Infinite Loop! Holes left:"+ +n.length+", Probably Hole outside Shape!");break}for(q=B;qh;h++)n=k[h].x+":"+k[h].y, +n=p[n],void 0!==n&&(k[h]=n);return q.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a, +b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()}; +THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return b}; +THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=new THREE.Vector2;b.x=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);return b.normalize()};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype); +THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)};THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b}; +THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.getPoint=function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector2;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);return c}; +THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype); +THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);a=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;b=new THREE.Vector2;b.x=this.aX+this.xRadius*Math.cos(a);b.y=this.aY+this.yRadius*Math.sin(a);return b};THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype); +THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);b.z=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return b}); +THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b.y=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b.z=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return b}); +THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector3;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);c.z=THREE.Curve.Utils.interpolate(d.z,e.z,f.z,b.z,a);return c}); +THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-0;var c=Math.floor(a);a-=c;var c=c+(0a.hierarchy[b].keys[c].time&&(a.hierarchy[b].keys[c].time= +0),void 0!==a.hierarchy[b].keys[c].rot&&!(a.hierarchy[b].keys[c].rot instanceof THREE.Quaternion)){var d=a.hierarchy[b].keys[c].rot;a.hierarchy[b].keys[c].rot=(new THREE.Quaternion).fromArray(d)}if(a.hierarchy[b].keys.length&&void 0!==a.hierarchy[b].keys[0].morphTargets){d={};for(c=0;cd;d++){for(var e=this.keyTypes[d],f=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(e,a,1);g.timef.index;)f=g,g=this.getNextKeyWith(e,a,g.index+1);c.prevKey[e]=f;c.nextKey[e]=g}}}; +THREE.Animation.prototype.resetBlendWeights=function(){for(var a=0,b=this.hierarchy.length;aa.length-2?q:q+1;c[3]=q>a.length-3?q:q+2;q=a[c[0]];r=a[c[1]];t=a[c[2]];s=a[c[3]];c=e*e;m=e*c;d[0]=f(q[0],r[0],t[0],s[0],e,c,m);d[1]=f(q[1],r[1],t[1],s[1],e,c,m);d[2]=f(q[2],r[2],t[2],s[2],e,c,m);return d},f=function(a,b,c,d,e,f,m){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*m+ +(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)if(this.loop)this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset();else{this.stop();return}f=0;for(var h=this.hierarchy.length;fq;q++){var m=this.keyTypes[q],r=n.prevKey[m],t=n.nextKey[m]; +if(0this.timeScale&&r.time>=this.currentTime){r=this.data.hierarchy[f].keys[0];for(t=this.getNextKeyWith(m,f,1);t.timer.index;)r=t,t=this.getNextKeyWith(m,f,t.index+1);n.prevKey[m]=r;n.nextKey[m]=t}k.matrixAutoUpdate=!0;k.matrixWorldNeedsUpdate=!0;var s=(this.currentTime-r.time)/(t.time-r.time),u=r[m],v=t[m];0>s&&(s=0);1a&&(this.currentTime%=a);this.currentTime=Math.min(this.currentTime,a);a=0;for(var b=this.hierarchy.length;af.index;)f=g,g=e[f.index+1];d.prevKey= +f;d.nextKey=g}g.time>=this.currentTime?f.interpolate(g,this.currentTime):f.interpolate(g,g.time);this.data.hierarchy[a].node.updateMatrix();c.matrixWorldNeedsUpdate=!0}}}};THREE.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;cthis.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);c=this.duration/this.frames;var d=Math.floor(this.currentTime/c);d!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[d]= +0,a=b,b=d);this.mesh.morphTargetInfluences[d]=this.currentTime%c/c;this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[d]}}}()}; +THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,s){var u,v=h.widthSegments,y=h.heightSegments,G=e/2,w=f/2,K=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)u="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)u="y",y=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)u="x",v=h.depthSegments;var x=v+1,D=y+1,E=e/v,A=f/y,B=new THREE.Vector3;B[u]=0=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10d?-1E-10>f&&(a=!0):Math.sign(e)== +Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(P=a.length;0<=--P;){c=P;d=P-1;0>d&&(d=a.length-1);for(var e=0,f=r+2*p,e=0;eMath.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y, +1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===a instanceof Array&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cc&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5, +a.y));return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,n=0,p=a.length;nr&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));n=0;for(p=this.vertices.length;nc.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}(); +THREE.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,a,1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)}; +THREE.BoxHelper=function(a){var b=new THREE.BufferGeometry;b.addAttribute("position",new THREE.BufferAttribute(new Float32Array(72),3));THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces);void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype); +THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.geometry.attributes.position.array;d[0]=b.x;d[1]=b.y;d[2]=b.z;d[3]=c.x;d[4]=b.y;d[5]=b.z;d[6]=c.x;d[7]=b.y;d[8]=b.z;d[9]=c.x;d[10]=c.y;d[11]=b.z;d[12]=c.x;d[13]=c.y;d[14]=b.z;d[15]=b.x;d[16]=c.y;d[17]=b.z;d[18]=b.x;d[19]=c.y;d[20]=b.z;d[21]=b.x;d[22]=b.y;d[23]=b.z;d[24]=b.x;d[25]=b.y;d[26]=c.z;d[27]=c.x;d[28]=b.y;d[29]=c.z;d[30]=c.x;d[31]=b.y; +d[32]=c.z;d[33]=c.x;d[34]=c.y;d[35]=c.z;d[36]=c.x;d[37]=c.y;d[38]=c.z;d[39]=b.x;d[40]=c.y;d[41]=c.z;d[42]=b.x;d[43]=c.y;d[44]=c.z;d[45]=b.x;d[46]=b.y;d[47]=c.z;d[48]=b.x;d[49]=b.y;d[50]=b.z;d[51]=b.x;d[52]=b.y;d[53]=c.z;d[54]=c.x;d[55]=b.y;d[56]=b.z;d[57]=c.x;d[58]=b.y;d[59]=c.z;d[60]=c.x;d[61]=c.y;d[62]=b.z;d[63]=c.x;d[64]=c.y;d[65]=c.z;d[66]=b.x;d[67]=c.y;d[68]=b.z;d[69]=b.x;d[70]=c.y;d[71]=c.z;this.geometry.attributes.position.needsUpdate=!0;this.geometry.computeBoundingSphere();this.matrix=a.matrixWorld; +this.matrixAutoUpdate=!1};THREE.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)}; +THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200); +b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}; +THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); +THREE.CameraHelper.prototype.update=function(){var a,b,c=new THREE.Vector3,d=new THREE.Camera,e=function(e,g,h,k){c.set(g,h,k).unproject(d);e=b[e];if(void 0!==e)for(g=0,h=e.length;gt;t++){d[0]=r[g[t]];d[1]=r[g[(t+1)%3]];d.sort(f);var s=d.toString();void 0===e[s]?(e[s]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[s].face2=q}d=new Float32Array(6*p);f=0;for(s in e)if(g=e[s],void 0===g.face2|| +.9999>k[g.face1].normal.dot(k[g.face2].normal))p=n[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=n[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype); +THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=new THREE.Geometry;c=0;for(var e=this.object.geometry.faces.length;cb;b++)a.faces[b].color=this.colors[4>b?0:1];b=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(a,b);this.add(this.lightSphere); +this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; +THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}(); +THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()}; +THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}; +THREE.SkeletonHelper=function(a){this.bones=this.getBoneList(a);for(var b=new THREE.Geometry,c=0;cs;s++){d[0]=t[g[s]];d[1]=t[g[(s+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);m=0;for(r=p;ms;s++)p= +k[q[2*m+s]],g=6*m+3*s,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;r=a.geometry.attributes.index.array;n=a.geometry.drawcalls;p=0;0===n.length&&(n=[{count:r.length,index:0,start:0}]);for(var q=new Uint32Array(2*r.length),t=0,v=n.length;ts;s++)d[0]= +g+r[m+s],d[1]=g+r[m+(s+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);m=0;for(r=p;ms;s++)g=6*m+3*s,p=3*q[2*m+s],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),m=0,r=q;ms;s++)g=18*m+6*s,q=9*m+3*s,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*m+(s+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d, +3))}THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(a){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype); +THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype); +THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)}; +THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;fh.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c}; +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; +THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; +f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}}; diff --git a/plugins/Sidebar/media-globe/world.jpg b/plugins/Sidebar/media-globe/world.jpg new file mode 100644 index 0000000000000000000000000000000000000000..222bd939d5bf2067910ef4f9da2ea9092dfd6abb GIT binary patch literal 94795 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 + return unless @trace + return if typeof console is 'undefined' + args.unshift("[#{@.constructor.name}]") + console.log(args...) + @ + + logStart: (name, args...) -> + return unless @trace + @logtimers or= {} + @logtimers[name] = +(new Date) + @log "#{name}", args..., "(started)" if args.length > 0 + @ + + logEnd: (name, args...) -> + ms = +(new Date)-@logtimers[name] + @log "#{name}", args..., "(Done in #{ms}ms)" + @ + +window.Class = Class \ No newline at end of file diff --git a/plugins/Sidebar/media/Scrollable.js b/plugins/Sidebar/media/Scrollable.js new file mode 100644 index 00000000..9173849e --- /dev/null +++ b/plugins/Sidebar/media/Scrollable.js @@ -0,0 +1,89 @@ +/* via http://jsfiddle.net/elGrecode/00dgurnn/ */ + +window.initScrollable = function () { + + var scrollContainer = document.querySelector('.scrollable'), + scrollContentWrapper = document.querySelector('.scrollable .content-wrapper'), + scrollContent = document.querySelector('.scrollable .content'), + contentPosition = 0, + scrollerBeingDragged = false, + scroller, + topPosition, + scrollerHeight; + + function calculateScrollerHeight() { + // *Calculation of how tall scroller should be + var visibleRatio = scrollContainer.offsetHeight / scrollContentWrapper.scrollHeight; + if (visibleRatio == 1) + scroller.style.display = "none" + else + scroller.style.display = "block" + return visibleRatio * scrollContainer.offsetHeight; + } + + function moveScroller(evt) { + // Move Scroll bar to top offset + var scrollPercentage = evt.target.scrollTop / scrollContentWrapper.scrollHeight; + topPosition = scrollPercentage * (scrollContainer.offsetHeight - 5); // 5px arbitrary offset so scroll bar doesn't move too far beyond content wrapper bounding box + scroller.style.top = topPosition + 'px'; + } + + function startDrag(evt) { + normalizedPosition = evt.pageY; + contentPosition = scrollContentWrapper.scrollTop; + scrollerBeingDragged = true; + window.addEventListener('mousemove', scrollBarScroll) + } + + function stopDrag(evt) { + scrollerBeingDragged = false; + window.removeEventListener('mousemove', scrollBarScroll) + } + + function scrollBarScroll(evt) { + if (scrollerBeingDragged === true) { + var mouseDifferential = evt.pageY - normalizedPosition; + var scrollEquivalent = mouseDifferential * (scrollContentWrapper.scrollHeight / scrollContainer.offsetHeight); + scrollContentWrapper.scrollTop = contentPosition + scrollEquivalent; + } + } + + function updateHeight() { + scrollerHeight = calculateScrollerHeight()-10; + scroller.style.height = scrollerHeight + 'px'; + } + + function createScroller() { + // *Creates scroller element and appends to '.scrollable' div + // create scroller element + scroller = document.createElement("div"); + scroller.className = 'scroller'; + + // determine how big scroller should be based on content + scrollerHeight = calculateScrollerHeight()-10; + + if (scrollerHeight / scrollContainer.offsetHeight < 1){ + // *If there is a need to have scroll bar based on content size + scroller.style.height = scrollerHeight + 'px'; + + // append scroller to scrollContainer div + scrollContainer.appendChild(scroller); + + // show scroll path divot + scrollContainer.className += ' showScroll'; + + // attach related draggable listeners + scroller.addEventListener('mousedown', startDrag); + window.addEventListener('mouseup', stopDrag); + } + + } + + createScroller(); + + + // *** Listeners *** + scrollContentWrapper.addEventListener('scroll', moveScroller); + + return updateHeight +}; \ No newline at end of file diff --git a/plugins/Sidebar/media/Scrollbable.css b/plugins/Sidebar/media/Scrollbable.css new file mode 100644 index 00000000..7d69a5f3 --- /dev/null +++ b/plugins/Sidebar/media/Scrollbable.css @@ -0,0 +1,44 @@ +.scrollable { + overflow: hidden; +} + +.scrollable.showScroll::after { + position: absolute; + content: ''; + top: 5%; + right: 7px; + height: 90%; + width: 3px; + background: rgba(224, 224, 255, .3); +} + +.scrollable .content-wrapper { + width: 100%; + height: 100%; + padding-right: 50%; + overflow-y: scroll; +} +.scroller { + margin-top: 5px; + z-index: 5; + cursor: pointer; + position: absolute; + width: 7px; + border-radius: 5px; + background: #151515; + top: 0px; + left: 395px; + -webkit-transition: top .08s; + -moz-transition: top .08s; + -ms-transition: top .08s; + -o-transition: top .08s; + transition: top .08s; +} +.content { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/plugins/Sidebar/media/Sidebar.coffee b/plugins/Sidebar/media/Sidebar.coffee new file mode 100644 index 00000000..869b426f --- /dev/null +++ b/plugins/Sidebar/media/Sidebar.coffee @@ -0,0 +1,318 @@ +class Sidebar extends Class + constructor: -> + @tag = null + @container = null + @opened = false + @width = 410 + @fixbutton = $(".fixbutton") + @fixbutton_addx = 0 + @fixbutton_initx = 0 + @fixbutton_targetx = 0 + @frame = $("#inner-iframe") + @initFixbutton() + @dragStarted = 0 + @globe = null + + @original_set_site_info = wrapper.setSiteInfo # We going to override this, save the original + + # Start in opened state for debugging + if false + @startDrag() + @moved() + @fixbutton_targetx = @fixbutton_initx - @width + @stopDrag() + + + initFixbutton: -> + # Detect dragging + @fixbutton.on "mousedown", (e) => + e.preventDefault() + + # Disable previous listeners + @fixbutton.off "click" + @fixbutton.off "mousemove" + + # Make sure its not a click + @dragStarted = (+ new Date) + @fixbutton.one "mousemove", (e) => + @fixbutton_addx = @fixbutton.offset().left-e.pageX + @startDrag() + @fixbutton.parent().on "click", (e) => + @stopDrag() + @fixbutton_initx = @fixbutton.offset().left # Initial x position + + + # Start dragging the fixbutton + startDrag: -> + @log "startDrag" + @fixbutton_targetx = @fixbutton_initx # Fallback x position + + @fixbutton.addClass("dragging") + + # Fullscreen drag bg to capture mouse events over iframe + $("
    ").appendTo(document.body) + + # IE position wrap fix + if navigator.userAgent.indexOf('MSIE') != -1 or navigator.appVersion.indexOf('Trident/') > 0 + @fixbutton.css("pointer-events", "none") + + # Don't go to homepage + @fixbutton.one "click", (e) => + @stopDrag() + @fixbutton.removeClass("dragging") + if Math.abs(@fixbutton.offset().left - @fixbutton_initx) > 5 + # If moved more than some pixel the button then don't go to homepage + e.preventDefault() + + # Animate drag + @fixbutton.parents().on "mousemove", @animDrag + @fixbutton.parents().on "mousemove" ,@waitMove + + # Stop dragging listener + @fixbutton.parents().on "mouseup", (e) => + e.preventDefault() + @stopDrag() + + + # Wait for moving the fixbutton + waitMove: (e) => + if Math.abs(@fixbutton.offset().left - @fixbutton_targetx) > 10 and (+ new Date)-@dragStarted > 100 + @moved() + @fixbutton.parents().off "mousemove" ,@waitMove + + moved: -> + @log "Moved" + @createHtmltag() + $(document.body).css("perspective", "1000px").addClass("body-sidebar") + $(window).off "resize" + $(window).on "resize", => + $(document.body).css "height", $(window).height() + @scrollable() + $(window).trigger "resize" + + # Override setsiteinfo to catch changes + wrapper.setSiteInfo = (site_info) => + @setSiteInfo(site_info) + @original_set_site_info.apply(wrapper, arguments) + + setSiteInfo: (site_info) -> + @updateHtmlTag() + @displayGlobe() + + + # Create the sidebar html tag + createHtmltag: -> + if not @container + @container = $(""" + + """) + @container.appendTo(document.body) + @tag = @container.find(".sidebar") + @updateHtmlTag() + @scrollable = window.initScrollable() + + + updateHtmlTag: -> + wrapper.ws.cmd "sidebarGetHtmlTag", {}, (res) => + if @tag.find(".content").children().length == 0 # First update + @log "Creating content" + morphdom(@tag.find(".content")[0], '
    '+res+'
    ') + @scrollable() + + else # Not first update, patch the html to keep unchanged dom elements + @log "Patching content" + morphdom @tag.find(".content")[0], '
    '+res+'
    ', { + onBeforeMorphEl: (from_el, to_el) -> # Ignore globe loaded state + if from_el.className == "globe" + return false + else + return true + } + + + animDrag: (e) => + mousex = e.pageX + + overdrag = @fixbutton_initx-@width-mousex + if overdrag > 0 # Overdragged + overdrag_percent = 1+overdrag/300 + mousex = (e.pageX + (@fixbutton_initx-@width)*overdrag_percent)/(1+overdrag_percent) + targetx = @fixbutton_initx-mousex-@fixbutton_addx + + @fixbutton.offset + left: mousex+@fixbutton_addx + + if @tag + @tag.css("transform", "translateX(#{0-targetx}px)") + + # Check if opened + if (not @opened and targetx > @width/3) or (@opened and targetx > @width*0.9) + @fixbutton_targetx = @fixbutton_initx - @width # Make it opened + else + @fixbutton_targetx = @fixbutton_initx + + + # Stop dragging the fixbutton + stopDrag: -> + @fixbutton.parents().off "mousemove" + @fixbutton.off "mousemove" + @fixbutton.css("pointer-events", "") + $(".drag-bg").remove() + if not @fixbutton.hasClass("dragging") + return + @fixbutton.removeClass("dragging") + + # Move back to initial position + if @fixbutton_targetx != @fixbutton.offset().left + # Animate fixbutton + @fixbutton.stop().animate {"left": @fixbutton_targetx}, 500, "easeOutBack", => + # Switch back to auto align + if @fixbutton_targetx == @fixbutton_initx # Closed + @fixbutton.css("left", "auto") + else # Opened + @fixbutton.css("left", @fixbutton_targetx) + + $(".fixbutton-bg").trigger "mouseout" # Switch fixbutton back to normal status + + # Animate sidebar and iframe + if @fixbutton_targetx == @fixbutton_initx + # Closed + targetx = 0 + @opened = false + else + # Opened + targetx = @width + if not @opened + @onOpened() + @opened = true + + # Revent sidebar transitions + @tag.css("transition", "0.4s ease-out") + @tag.css("transform", "translateX(-#{targetx}px)").one transitionEnd, => + @tag.css("transition", "") + if not @opened + @container.remove() + @container = null + @tag.remove() + @tag = null + + # Revert body transformations + @log "stopdrag", "opened:", @opened + if not @opened + @onClosed() + + + onOpened: -> + @log "Opened" + @scrollable() + + # Re-calculate height when site admin opened or closed + @tag.find("#checkbox-owned").off("click").on "click", => + setTimeout (=> + @scrollable() + ), 300 + + # Site limit button + @tag.find("#button-sitelimit").on "click", => + wrapper.ws.cmd "siteSetLimit", $("#input-sitelimit").val(), => + wrapper.notifications.add "done-sitelimit", "done", "Site storage limit modified!", 5000 + @updateHtmlTag() + return false + + # Change identity button + @tag.find("#button-identity").on "click", => + wrapper.ws.cmd "certSelect" + return false + + # Owned checkbox + @tag.find("#checkbox-owned").on "click", => + wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")] + + # Save settings + @tag.find("#button-settings").on "click", => + wrapper.ws.cmd "fileGet", "content.json", (res) => + data = JSON.parse(res) + data["title"] = $("#settings-title").val() + data["description"] = $("#settings-description").val() + json_raw = unescape(encodeURIComponent(JSON.stringify(data, undefined, '\t'))) + wrapper.ws.cmd "fileWrite", ["content.json", btoa(json_raw)], (res) => + if res != "ok" # fileWrite failed + wrapper.notifications.add "file-write", "error", "File write error: #{res}" + else + wrapper.notifications.add "file-write", "done", "Site settings saved!", 5000 + @updateHtmlTag() + return false + + # Sign content.json + @tag.find("#button-sign").on "click", => + inner_path = @tag.find("#select-contents").val() + + if wrapper.site_info.privatekey + # Privatekey stored in users.json + wrapper.ws.cmd "siteSign", ["stored", inner_path], (res) => + wrapper.notifications.add "sign", "done", "#{inner_path} Signed!", 5000 + + else + # Ask the user for privatekey + wrapper.displayPrompt "Enter your private key:", "password", "Sign", (privatekey) => # Prompt the private key + wrapper.ws.cmd "siteSign", [privatekey, inner_path], (res) => + if res == "ok" + wrapper.notifications.add "sign", "done", "#{inner_path} Signed!", 5000 + + return false + + # Publish content.json + @tag.find("#button-publish").on "click", => + inner_path = @tag.find("#select-contents").val() + @tag.find("#button-publish").addClass "loading" + wrapper.ws.cmd "sitePublish", {"inner_path": inner_path, "sign": false}, => + @tag.find("#button-publish").removeClass "loading" + + @loadGlobe() + + + onClosed: -> + $(window).off "resize" + $(document.body).css("transition", "0.6s ease-in-out").removeClass("body-sidebar").on transitionEnd, (e) => + if e.target == document.body + $(document.body).css("height", "auto").css("perspective", "").css("transition", "").off transitionEnd + @unloadGlobe() + + # We dont need site info anymore + wrapper.setSiteInfo = @original_set_site_info + + + loadGlobe: => + if @tag.find(".globe").hasClass("loading") + setTimeout (=> + if typeof(DAT) == "undefined" # Globe script not loaded, do it first + $.getScript("/uimedia/globe/all.js", @displayGlobe) + else + @displayGlobe() + ), 600 + + + displayGlobe: => + wrapper.ws.cmd "sidebarGetPeers", [], (globe_data) => + if @globe + @globe.scene.remove(@globe.points) + @globe.addData( globe_data, {format: 'magnitude', name: "hello", animated: false} ) + @globe.createPoints() + else + @globe = new DAT.Globe( @tag.find(".globe")[0], {"imgDir": "/uimedia/globe/"} ) + @globe.addData( globe_data, {format: 'magnitude', name: "hello"} ) + @globe.createPoints() + @globe.animate() + @tag.find(".globe").removeClass("loading") + + + unloadGlobe: => + if not @globe + return false + @globe.unload() + @globe = null + + +window.sidebar = new Sidebar() +window.transitionEnd = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend' diff --git a/plugins/Sidebar/media/Sidebar.css b/plugins/Sidebar/media/Sidebar.css new file mode 100644 index 00000000..7710305a --- /dev/null +++ b/plugins/Sidebar/media/Sidebar.css @@ -0,0 +1,96 @@ +.drag-bg { width: 100%; height: 100%; position: absolute; } +.fixbutton.dragging { cursor: -webkit-grabbing; } +.fixbutton-bg:active { cursor: -webkit-grabbing; } + + +.body-sidebar { background-color: #666 !important; } +#inner-iframe { transition: 0.3s ease-in-out; transform-origin: left; backface-visibility: hidden; outline: 1px solid transparent } +.body-sidebar iframe { transform: rotateY(5deg); opacity: 0.8; pointer-events: none } /* translateX(-200px) scale(0.95)*/ + +/* SIDEBAR */ + +.sidebar-container { width: 100%; height: 100%; overflow: hidden; position: absolute; } +.sidebar { background-color: #212121; position: absolute; right: -1200px; height: 100%; width: 1200px; } /*box-shadow: inset 0px 0px 10px #000*/ +.sidebar .content { margin: 30px; font-family: "Segoe UI Light", "Segoe UI", "Helvetica Neue"; color: white; width: 375px; height: 300px; font-weight: 200 } +.sidebar h1, .sidebar h2 { font-weight: lighter; } +.sidebar .button { margin: 0px; display: inline-block; } + + +/* FIELDS */ + +.sidebar .fields { padding: 0px; list-style-type: none; width: 355px; } +.sidebar .fields > li, .sidebar .fields .settings-owned > li { margin-bottom: 30px } +.sidebar .fields > li:after, .sidebar .fields .settings-owned > li:after { clear: both; content: ''; display: block } +.sidebar .fields label { font-family: Consolas, monospace; text-transform: uppercase; font-size: 13px; color: #ACACAC; display: block; margin-bottom: 10px; } +.sidebar .fields label small { font-weight: normal; color: white; text-transform: none; } +.sidebar .fields .text { background-color: black; border: 0px; padding: 10px; color: white; border-radius: 3px; width: 250px; font-family: Consolas, monospace; } +.sidebar .fields .text.long { width: 330px; font-size: 72%; } +.sidebar .fields .disabled { color: #AAA; background-color: #3B3B3B; } +.sidebar .fields .text-num { width: 30px; text-align: right; padding-right: 30px; } +.sidebar .fields .text-post { color: white; font-family: Consolas, monospace; display: inline-block; font-size: 13px; margin-left: -25px; width: 25px; } + +/* Select */ +.sidebar .fields select { + width: 225px; background-color: #3B3B3B; color: white; font-family: Consolas, monospace; appearance: none; + padding: 5px; padding-right: 25px; border: 0px; border-radius: 3px; height: 35px; vertical-align: 1px; box-shadow: 0px 1px 2px rgba(0,0,0,0.5); +} +.sidebar .fields .select-down { margin-left: -39px; width: 34px; display: inline-block; transform: rotateZ(90deg); height: 35px; vertical-align: -8px; pointer-events: none; font-weight: bold } + +/* Checkbox */ +.sidebar .fields .checkbox { width: 50px; height: 24px; position: relative; z-index: 999; opacity: 0; } +.sidebar .fields .checkbox-skin { background-color: #CCC; width: 50px; height: 24px; border-radius: 15px; transition: all 0.3s ease-in-out; display: inline-block; margin-left: -59px; } +.sidebar .fields .checkbox-skin:before { + content: ""; position: relative; width: 20px; background-color: white; height: 20px; display: block; border-radius: 100%; margin-top: 2px; margin-left: 2px; + transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86); +} +.sidebar .fields .checkbox:checked ~ .checkbox-skin:before { margin-left: 27px; } +.sidebar .fields .checkbox:checked ~ .checkbox-skin { background-color: #2ECC71; } + +/* Fake input */ +.sidebar .input { font-size: 13px; width: 250px; display: inline-block; overflow: hidden; text-overflow: ellipsis; vertical-align: top } + +/* GRAPH */ + +.graph { padding: 0px; list-style-type: none; width: 351px; background-color: black; height: 10px; border-radius: 8px; overflow: hidden; position: relative;} +.graph li { height: 100%; position: absolute; } +.graph-stacked li { position: static; float: left; } + +.graph-legend { padding: 0px; list-style-type: none; margin-top: 13px; font-family: Consolas, "Andale Mono", monospace; font-size: 13px; text-transform: capitalize; } +.sidebar .graph-legend li { margin: 0px; margin-top: 5px; margin-left: 0px; width: 160px; float: left; position: relative; } +.sidebar .graph-legend li:nth-child(odd) { margin-right: 29px } +.graph-legend span { position: absolute; } +.graph-legend b { text-align: right; display: inline-block; width: 50px; float: right; font-weight: normal; } +.graph-legend li:before { content: '\2022'; font-size: 23px; line-height: 0px; vertical-align: -3px; margin-right: 5px; } + +/* COLORS */ + +.back-green { background-color: #2ECC71 } +.color-green:before { color: #2ECC71 } +.back-blue { background-color: #3BAFDA } +.color-blue:before { color: #3BAFDA } +.back-darkblue { background-color: #2196F3 } +.color-darkblue:before { color: #2196F3 } +.back-purple { background-color: #B10DC9 } +.color-purple:before { color: #B10DC9 } +.back-yellow { background-color: #FFDC00 } +.color-yellow:before { color: #FFDC00 } +.back-orange { background-color: #FF9800 } +.color-orange:before { color: #FF9800 } +.back-gray { background-color: #ECF0F1 } +.color-gray:before { color: #ECF0F1 } +.back-black { background-color: #34495E } +.color-black:before { color: #34495E } +.back-white { background-color: #EEE } +.color-white:before { color: #EEE } + + +/* Settings owned */ + +.owned-title { float: left } +#checkbox-owned { margin-bottom: 25px; margin-top: 26px; margin-left: 11px; } +#checkbox-owned ~ .settings-owned { opacity: 0; max-height: 0px; transition: all 0.3s linear; overflow: hidden } +#checkbox-owned:checked ~ .settings-owned { opacity: 1; max-height: 400px } + +/* Globe */ +.globe { width: 360px; height: 360px } +.globe.loading { background: url(/uimedia/img/loading-circle.gif) center center no-repeat } \ No newline at end of file diff --git a/plugins/Sidebar/media/all.css b/plugins/Sidebar/media/all.css new file mode 100644 index 00000000..76b8acdd --- /dev/null +++ b/plugins/Sidebar/media/all.css @@ -0,0 +1,150 @@ + + +/* ---- plugins/Sidebar/media/Scrollbable.css ---- */ + + +.scrollable { + overflow: hidden; +} + +.scrollable.showScroll::after { + position: absolute; + content: ''; + top: 5%; + right: 7px; + height: 90%; + width: 3px; + background: rgba(224, 224, 255, .3); +} + +.scrollable .content-wrapper { + width: 100%; + height: 100%; + padding-right: 50%; + overflow-y: scroll; +} +.scroller { + margin-top: 5px; + z-index: 5; + cursor: pointer; + position: absolute; + width: 7px; + -webkit-border-radius: 5px; -moz-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; border-radius: 5px ; + background: #151515; + top: 0px; + left: 395px; + -webkit-transition: top .08s; + -moz-transition: top .08s; + -ms-transition: top .08s; + -o-transition: top .08s; + -webkit-transition: top .08s; -moz-transition: top .08s; -o-transition: top .08s; -ms-transition: top .08s; transition: top .08s ; +} +.content { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + + +/* ---- plugins/Sidebar/media/Sidebar.css ---- */ + + +.drag-bg { width: 100%; height: 100%; position: absolute; } +.fixbutton.dragging { cursor: -webkit-grabbing; } +.fixbutton-bg:active { cursor: -webkit-grabbing; } + + +.body-sidebar { background-color: #666 !important; } +#inner-iframe { -webkit-transition: 0.3s ease-in-out; -moz-transition: 0.3s ease-in-out; -o-transition: 0.3s ease-in-out; -ms-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out ; transform-origin: left; backface-visibility: hidden; outline: 1px solid transparent } +.body-sidebar iframe { -webkit-transform: rotateY(5deg); -moz-transform: rotateY(5deg); -o-transform: rotateY(5deg); -ms-transform: rotateY(5deg); transform: rotateY(5deg) ; opacity: 0.8; pointer-events: none } /* translateX(-200px) scale(0.95)*/ + +/* SIDEBAR */ + +.sidebar-container { width: 100%; height: 100%; overflow: hidden; position: absolute; } +.sidebar { background-color: #212121; position: absolute; right: -1200px; height: 100%; width: 1200px; } /*box-shadow: inset 0px 0px 10px #000*/ +.sidebar .content { margin: 30px; font-family: "Segoe UI Light", "Segoe UI", "Helvetica Neue"; color: white; width: 375px; height: 300px; font-weight: 200 } +.sidebar h1, .sidebar h2 { font-weight: lighter; } +.sidebar .button { margin: 0px; display: inline-block; } + + +/* FIELDS */ + +.sidebar .fields { padding: 0px; list-style-type: none; width: 355px; } +.sidebar .fields > li, .sidebar .fields .settings-owned > li { margin-bottom: 30px } +.sidebar .fields > li:after, .sidebar .fields .settings-owned > li:after { clear: both; content: ''; display: block } +.sidebar .fields label { font-family: Consolas, monospace; text-transform: uppercase; font-size: 13px; color: #ACACAC; display: block; margin-bottom: 10px; } +.sidebar .fields label small { font-weight: normal; color: white; text-transform: none; } +.sidebar .fields .text { background-color: black; border: 0px; padding: 10px; color: white; -webkit-border-radius: 3px; -moz-border-radius: 3px; -o-border-radius: 3px; -ms-border-radius: 3px; border-radius: 3px ; width: 250px; font-family: Consolas, monospace; } +.sidebar .fields .text.long { width: 330px; font-size: 72%; } +.sidebar .fields .disabled { color: #AAA; background-color: #3B3B3B; } +.sidebar .fields .text-num { width: 30px; text-align: right; padding-right: 30px; } +.sidebar .fields .text-post { color: white; font-family: Consolas, monospace; display: inline-block; font-size: 13px; margin-left: -25px; width: 25px; } + +/* Select */ +.sidebar .fields select { + width: 225px; background-color: #3B3B3B; color: white; font-family: Consolas, monospace; -webkit-appearance: none; -moz-appearance: none; -o-appearance: none; -ms-appearance: none; appearance: none ; + padding: 5px; padding-right: 25px; border: 0px; -webkit-border-radius: 3px; -moz-border-radius: 3px; -o-border-radius: 3px; -ms-border-radius: 3px; border-radius: 3px ; height: 35px; vertical-align: 1px; -webkit-box-shadow: 0px 1px 2px rgba(0,0,0,0.5); -moz-box-shadow: 0px 1px 2px rgba(0,0,0,0.5); -o-box-shadow: 0px 1px 2px rgba(0,0,0,0.5); -ms-box-shadow: 0px 1px 2px rgba(0,0,0,0.5); box-shadow: 0px 1px 2px rgba(0,0,0,0.5) ; +} +.sidebar .fields .select-down { margin-left: -39px; width: 34px; display: inline-block; -webkit-transform: rotateZ(90deg); -moz-transform: rotateZ(90deg); -o-transform: rotateZ(90deg); -ms-transform: rotateZ(90deg); transform: rotateZ(90deg) ; height: 35px; vertical-align: -8px; pointer-events: none; font-weight: bold } + +/* Checkbox */ +.sidebar .fields .checkbox { width: 50px; height: 24px; position: relative; z-index: 999; opacity: 0; } +.sidebar .fields .checkbox-skin { background-color: #CCC; width: 50px; height: 24px; -webkit-border-radius: 15px; -moz-border-radius: 15px; -o-border-radius: 15px; -ms-border-radius: 15px; border-radius: 15px ; -webkit-transition: all 0.3s ease-in-out; -moz-transition: all 0.3s ease-in-out; -o-transition: all 0.3s ease-in-out; -ms-transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out ; display: inline-block; margin-left: -59px; } +.sidebar .fields .checkbox-skin:before { + content: ""; position: relative; width: 20px; background-color: white; height: 20px; display: block; -webkit-border-radius: 100%; -moz-border-radius: 100%; -o-border-radius: 100%; -ms-border-radius: 100%; border-radius: 100% ; margin-top: 2px; margin-left: 2px; + -webkit-transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86); -moz-transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86); -o-transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86); -ms-transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86); transition: all 0.5s cubic-bezier(0.785, 0.135, 0.15, 0.86) ; +} +.sidebar .fields .checkbox:checked ~ .checkbox-skin:before { margin-left: 27px; } +.sidebar .fields .checkbox:checked ~ .checkbox-skin { background-color: #2ECC71; } + +/* Fake input */ +.sidebar .input { font-size: 13px; width: 250px; display: inline-block; overflow: hidden; text-overflow: ellipsis; vertical-align: top } + +/* GRAPH */ + +.graph { padding: 0px; list-style-type: none; width: 351px; background-color: black; height: 10px; -webkit-border-radius: 8px; -moz-border-radius: 8px; -o-border-radius: 8px; -ms-border-radius: 8px; border-radius: 8px ; overflow: hidden; position: relative;} +.graph li { height: 100%; position: absolute; } +.graph-stacked li { position: static; float: left; } + +.graph-legend { padding: 0px; list-style-type: none; margin-top: 13px; font-family: Consolas, "Andale Mono", monospace; font-size: 13px; text-transform: capitalize; } +.sidebar .graph-legend li { margin: 0px; margin-top: 5px; margin-left: 0px; width: 160px; float: left; position: relative; } +.sidebar .graph-legend li:nth-child(odd) { margin-right: 29px } +.graph-legend span { position: absolute; } +.graph-legend b { text-align: right; display: inline-block; width: 50px; float: right; font-weight: normal; } +.graph-legend li:before { content: '\2022'; font-size: 23px; line-height: 0px; vertical-align: -3px; margin-right: 5px; } + +/* COLORS */ + +.back-green { background-color: #2ECC71 } +.color-green:before { color: #2ECC71 } +.back-blue { background-color: #3BAFDA } +.color-blue:before { color: #3BAFDA } +.back-darkblue { background-color: #2196F3 } +.color-darkblue:before { color: #2196F3 } +.back-purple { background-color: #B10DC9 } +.color-purple:before { color: #B10DC9 } +.back-yellow { background-color: #FFDC00 } +.color-yellow:before { color: #FFDC00 } +.back-orange { background-color: #FF9800 } +.color-orange:before { color: #FF9800 } +.back-gray { background-color: #ECF0F1 } +.color-gray:before { color: #ECF0F1 } +.back-black { background-color: #34495E } +.color-black:before { color: #34495E } +.back-white { background-color: #EEE } +.color-white:before { color: #EEE } + + +/* Settings owned */ + +.owned-title { float: left } +#checkbox-owned { margin-bottom: 25px; margin-top: 26px; margin-left: 11px; } +#checkbox-owned ~ .settings-owned { opacity: 0; max-height: 0px; -webkit-transition: all 0.3s linear; -moz-transition: all 0.3s linear; -o-transition: all 0.3s linear; -ms-transition: all 0.3s linear; transition: all 0.3s linear ; overflow: hidden } +#checkbox-owned:checked ~ .settings-owned { opacity: 1; max-height: 400px } + +/* Globe */ +.globe { width: 360px; height: 360px } +.globe.loading { background: url(/uimedia/img/loading-circle.gif) center center no-repeat } \ No newline at end of file diff --git a/plugins/Sidebar/media/all.js b/plugins/Sidebar/media/all.js new file mode 100644 index 00000000..73b73c8b --- /dev/null +++ b/plugins/Sidebar/media/all.js @@ -0,0 +1,882 @@ + + +/* ---- plugins/Sidebar/media/Class.coffee ---- */ + + +(function() { + var Class, + __slice = [].slice; + + Class = (function() { + function Class() {} + + Class.prototype.trace = true; + + Class.prototype.log = function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (!this.trace) { + return; + } + if (typeof console === 'undefined') { + return; + } + args.unshift("[" + this.constructor.name + "]"); + console.log.apply(console, args); + return this; + }; + + Class.prototype.logStart = function() { + var args, name; + name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + if (!this.trace) { + return; + } + this.logtimers || (this.logtimers = {}); + this.logtimers[name] = +(new Date); + if (args.length > 0) { + this.log.apply(this, ["" + name].concat(__slice.call(args), ["(started)"])); + } + return this; + }; + + Class.prototype.logEnd = function() { + var args, ms, name; + name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + ms = +(new Date) - this.logtimers[name]; + this.log.apply(this, ["" + name].concat(__slice.call(args), ["(Done in " + ms + "ms)"])); + return this; + }; + + return Class; + + })(); + + window.Class = Class; + +}).call(this); + + +/* ---- plugins/Sidebar/media/Scrollable.js ---- */ + + +/* via http://jsfiddle.net/elGrecode/00dgurnn/ */ + +window.initScrollable = function () { + + var scrollContainer = document.querySelector('.scrollable'), + scrollContentWrapper = document.querySelector('.scrollable .content-wrapper'), + scrollContent = document.querySelector('.scrollable .content'), + contentPosition = 0, + scrollerBeingDragged = false, + scroller, + topPosition, + scrollerHeight; + + function calculateScrollerHeight() { + // *Calculation of how tall scroller should be + var visibleRatio = scrollContainer.offsetHeight / scrollContentWrapper.scrollHeight; + if (visibleRatio == 1) + scroller.style.display = "none" + else + scroller.style.display = "block" + return visibleRatio * scrollContainer.offsetHeight; + } + + function moveScroller(evt) { + // Move Scroll bar to top offset + var scrollPercentage = evt.target.scrollTop / scrollContentWrapper.scrollHeight; + topPosition = scrollPercentage * (scrollContainer.offsetHeight - 5); // 5px arbitrary offset so scroll bar doesn't move too far beyond content wrapper bounding box + scroller.style.top = topPosition + 'px'; + } + + function startDrag(evt) { + normalizedPosition = evt.pageY; + contentPosition = scrollContentWrapper.scrollTop; + scrollerBeingDragged = true; + window.addEventListener('mousemove', scrollBarScroll) + } + + function stopDrag(evt) { + scrollerBeingDragged = false; + window.removeEventListener('mousemove', scrollBarScroll) + } + + function scrollBarScroll(evt) { + if (scrollerBeingDragged === true) { + var mouseDifferential = evt.pageY - normalizedPosition; + var scrollEquivalent = mouseDifferential * (scrollContentWrapper.scrollHeight / scrollContainer.offsetHeight); + scrollContentWrapper.scrollTop = contentPosition + scrollEquivalent; + } + } + + function updateHeight() { + scrollerHeight = calculateScrollerHeight()-10; + scroller.style.height = scrollerHeight + 'px'; + } + + function createScroller() { + // *Creates scroller element and appends to '.scrollable' div + // create scroller element + scroller = document.createElement("div"); + scroller.className = 'scroller'; + + // determine how big scroller should be based on content + scrollerHeight = calculateScrollerHeight()-10; + + if (scrollerHeight / scrollContainer.offsetHeight < 1){ + // *If there is a need to have scroll bar based on content size + scroller.style.height = scrollerHeight + 'px'; + + // append scroller to scrollContainer div + scrollContainer.appendChild(scroller); + + // show scroll path divot + scrollContainer.className += ' showScroll'; + + // attach related draggable listeners + scroller.addEventListener('mousedown', startDrag); + window.addEventListener('mouseup', stopDrag); + } + + } + + createScroller(); + + + // *** Listeners *** + scrollContentWrapper.addEventListener('scroll', moveScroller); + + return updateHeight +}; + + +/* ---- plugins/Sidebar/media/Sidebar.coffee ---- */ + + +(function() { + var Sidebar, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __hasProp = {}.hasOwnProperty; + + Sidebar = (function(_super) { + __extends(Sidebar, _super); + + function Sidebar() { + this.unloadGlobe = __bind(this.unloadGlobe, this); + this.displayGlobe = __bind(this.displayGlobe, this); + this.loadGlobe = __bind(this.loadGlobe, this); + this.animDrag = __bind(this.animDrag, this); + this.waitMove = __bind(this.waitMove, this); + this.tag = null; + this.container = null; + this.opened = false; + this.width = 410; + this.fixbutton = $(".fixbutton"); + this.fixbutton_addx = 0; + this.fixbutton_initx = 0; + this.fixbutton_targetx = 0; + this.frame = $("#inner-iframe"); + this.initFixbutton(); + this.dragStarted = 0; + this.globe = null; + this.original_set_site_info = wrapper.setSiteInfo; + if (false) { + this.startDrag(); + this.moved(); + this.fixbutton_targetx = this.fixbutton_initx - this.width; + this.stopDrag(); + } + } + + Sidebar.prototype.initFixbutton = function() { + this.fixbutton.on("mousedown", (function(_this) { + return function(e) { + e.preventDefault(); + _this.fixbutton.off("click"); + _this.fixbutton.off("mousemove"); + _this.dragStarted = +(new Date); + return _this.fixbutton.one("mousemove", function(e) { + _this.fixbutton_addx = _this.fixbutton.offset().left - e.pageX; + return _this.startDrag(); + }); + }; + })(this)); + this.fixbutton.parent().on("click", (function(_this) { + return function(e) { + return _this.stopDrag(); + }; + })(this)); + return this.fixbutton_initx = this.fixbutton.offset().left; + }; + + Sidebar.prototype.startDrag = function() { + this.log("startDrag"); + this.fixbutton_targetx = this.fixbutton_initx; + this.fixbutton.addClass("dragging"); + $("
    ").appendTo(document.body); + if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) { + this.fixbutton.css("pointer-events", "none"); + } + this.fixbutton.one("click", (function(_this) { + return function(e) { + _this.stopDrag(); + _this.fixbutton.removeClass("dragging"); + if (Math.abs(_this.fixbutton.offset().left - _this.fixbutton_initx) > 5) { + return e.preventDefault(); + } + }; + })(this)); + this.fixbutton.parents().on("mousemove", this.animDrag); + this.fixbutton.parents().on("mousemove", this.waitMove); + return this.fixbutton.parents().on("mouseup", (function(_this) { + return function(e) { + e.preventDefault(); + return _this.stopDrag(); + }; + })(this)); + }; + + Sidebar.prototype.waitMove = function(e) { + if (Math.abs(this.fixbutton.offset().left - this.fixbutton_targetx) > 10 && (+(new Date)) - this.dragStarted > 100) { + this.moved(); + return this.fixbutton.parents().off("mousemove", this.waitMove); + } + }; + + Sidebar.prototype.moved = function() { + this.log("Moved"); + this.createHtmltag(); + $(document.body).css("perspective", "1000px").addClass("body-sidebar"); + $(window).off("resize"); + $(window).on("resize", (function(_this) { + return function() { + $(document.body).css("height", $(window).height()); + return _this.scrollable(); + }; + })(this)); + $(window).trigger("resize"); + return wrapper.setSiteInfo = (function(_this) { + return function(site_info) { + _this.setSiteInfo(site_info); + return _this.original_set_site_info.apply(wrapper, arguments); + }; + })(this); + }; + + Sidebar.prototype.setSiteInfo = function(site_info) { + this.updateHtmlTag(); + return this.displayGlobe(); + }; + + Sidebar.prototype.createHtmltag = function() { + if (!this.container) { + this.container = $("
    \n
    "); + this.container.appendTo(document.body); + this.tag = this.container.find(".sidebar"); + this.updateHtmlTag(); + return this.scrollable = window.initScrollable(); + } + }; + + Sidebar.prototype.updateHtmlTag = function() { + return wrapper.ws.cmd("sidebarGetHtmlTag", {}, (function(_this) { + return function(res) { + if (_this.tag.find(".content").children().length === 0) { + _this.log("Creating content"); + morphdom(_this.tag.find(".content")[0], '
    ' + res + '
    '); + return _this.scrollable(); + } else { + _this.log("Patching content"); + return morphdom(_this.tag.find(".content")[0], '
    ' + res + '
    ', { + onBeforeMorphEl: function(from_el, to_el) { + if (from_el.className === "globe") { + return false; + } else { + return true; + } + } + }); + } + }; + })(this)); + }; + + Sidebar.prototype.animDrag = function(e) { + var mousex, overdrag, overdrag_percent, targetx; + mousex = e.pageX; + overdrag = this.fixbutton_initx - this.width - mousex; + if (overdrag > 0) { + overdrag_percent = 1 + overdrag / 300; + mousex = (e.pageX + (this.fixbutton_initx - this.width) * overdrag_percent) / (1 + overdrag_percent); + } + targetx = this.fixbutton_initx - mousex - this.fixbutton_addx; + this.fixbutton.offset({ + left: mousex + this.fixbutton_addx + }); + if (this.tag) { + this.tag.css("transform", "translateX(" + (0 - targetx) + "px)"); + } + if ((!this.opened && targetx > this.width / 3) || (this.opened && targetx > this.width * 0.9)) { + return this.fixbutton_targetx = this.fixbutton_initx - this.width; + } else { + return this.fixbutton_targetx = this.fixbutton_initx; + } + }; + + Sidebar.prototype.stopDrag = function() { + var targetx; + this.fixbutton.parents().off("mousemove"); + this.fixbutton.off("mousemove"); + this.fixbutton.css("pointer-events", ""); + $(".drag-bg").remove(); + if (!this.fixbutton.hasClass("dragging")) { + return; + } + this.fixbutton.removeClass("dragging"); + if (this.fixbutton_targetx !== this.fixbutton.offset().left) { + this.fixbutton.stop().animate({ + "left": this.fixbutton_targetx + }, 500, "easeOutBack", (function(_this) { + return function() { + if (_this.fixbutton_targetx === _this.fixbutton_initx) { + _this.fixbutton.css("left", "auto"); + } else { + _this.fixbutton.css("left", _this.fixbutton_targetx); + } + return $(".fixbutton-bg").trigger("mouseout"); + }; + })(this)); + if (this.fixbutton_targetx === this.fixbutton_initx) { + targetx = 0; + this.opened = false; + } else { + targetx = this.width; + if (!this.opened) { + this.onOpened(); + } + this.opened = true; + } + this.tag.css("transition", "0.4s ease-out"); + this.tag.css("transform", "translateX(-" + targetx + "px)").one(transitionEnd, (function(_this) { + return function() { + _this.tag.css("transition", ""); + if (!_this.opened) { + _this.container.remove(); + _this.container = null; + _this.tag.remove(); + return _this.tag = null; + } + }; + })(this)); + this.log("stopdrag", "opened:", this.opened); + if (!this.opened) { + return this.onClosed(); + } + } + }; + + Sidebar.prototype.onOpened = function() { + this.log("Opened"); + this.scrollable(); + this.tag.find("#checkbox-owned").off("click").on("click", (function(_this) { + return function() { + return setTimeout((function() { + return _this.scrollable(); + }), 300); + }; + })(this)); + this.tag.find("#button-sitelimit").on("click", (function(_this) { + return function() { + wrapper.ws.cmd("siteSetLimit", $("#input-sitelimit").val(), function() { + wrapper.notifications.add("done-sitelimit", "done", "Site storage limit modified!", 5000); + return _this.updateHtmlTag(); + }); + return false; + }; + })(this)); + this.tag.find("#button-identity").on("click", (function(_this) { + return function() { + wrapper.ws.cmd("certSelect"); + return false; + }; + })(this)); + this.tag.find("#checkbox-owned").on("click", (function(_this) { + return function() { + return wrapper.ws.cmd("siteSetOwned", [_this.tag.find("#checkbox-owned").is(":checked")]); + }; + })(this)); + this.tag.find("#button-settings").on("click", (function(_this) { + return function() { + wrapper.ws.cmd("fileGet", "content.json", function(res) { + var data, json_raw; + data = JSON.parse(res); + data["title"] = $("#settings-title").val(); + data["description"] = $("#settings-description").val(); + json_raw = unescape(encodeURIComponent(JSON.stringify(data, void 0, '\t'))); + return wrapper.ws.cmd("fileWrite", ["content.json", btoa(json_raw)], function(res) { + if (res !== "ok") { + return wrapper.notifications.add("file-write", "error", "File write error: " + res); + } else { + wrapper.notifications.add("file-write", "done", "Site settings saved!", 5000); + return _this.updateHtmlTag(); + } + }); + }); + return false; + }; + })(this)); + this.tag.find("#button-sign").on("click", (function(_this) { + return function() { + var inner_path; + inner_path = _this.tag.find("#select-contents").val(); + if (wrapper.site_info.privatekey) { + wrapper.ws.cmd("siteSign", ["stored", inner_path], function(res) { + return wrapper.notifications.add("sign", "done", inner_path + " Signed!", 5000); + }); + } else { + wrapper.displayPrompt("Enter your private key:", "password", "Sign", function(privatekey) { + return wrapper.ws.cmd("siteSign", [privatekey, inner_path], function(res) { + if (res === "ok") { + return wrapper.notifications.add("sign", "done", inner_path + " Signed!", 5000); + } + }); + }); + } + return false; + }; + })(this)); + this.tag.find("#button-publish").on("click", (function(_this) { + return function() { + var inner_path; + inner_path = _this.tag.find("#select-contents").val(); + _this.tag.find("#button-publish").addClass("loading"); + return wrapper.ws.cmd("sitePublish", { + "inner_path": inner_path, + "sign": false + }, function() { + return _this.tag.find("#button-publish").removeClass("loading"); + }); + }; + })(this)); + return this.loadGlobe(); + }; + + Sidebar.prototype.onClosed = function() { + $(window).off("resize"); + $(document.body).css("transition", "0.6s ease-in-out").removeClass("body-sidebar").on(transitionEnd, (function(_this) { + return function(e) { + if (e.target === document.body) { + $(document.body).css("height", "auto").css("perspective", "").css("transition", "").off(transitionEnd); + return _this.unloadGlobe(); + } + }; + })(this)); + return wrapper.setSiteInfo = this.original_set_site_info; + }; + + Sidebar.prototype.loadGlobe = function() { + if (this.tag.find(".globe").hasClass("loading")) { + return setTimeout(((function(_this) { + return function() { + if (typeof DAT === "undefined") { + return $.getScript("/uimedia/globe/all.js", _this.displayGlobe); + } else { + return _this.displayGlobe(); + } + }; + })(this)), 600); + } + }; + + Sidebar.prototype.displayGlobe = function() { + return wrapper.ws.cmd("sidebarGetPeers", [], (function(_this) { + return function(globe_data) { + if (_this.globe) { + _this.globe.scene.remove(_this.globe.points); + _this.globe.addData(globe_data, { + format: 'magnitude', + name: "hello", + animated: false + }); + _this.globe.createPoints(); + } else { + _this.globe = new DAT.Globe(_this.tag.find(".globe")[0], { + "imgDir": "/uimedia/globe/" + }); + _this.globe.addData(globe_data, { + format: 'magnitude', + name: "hello" + }); + _this.globe.createPoints(); + _this.globe.animate(); + } + return _this.tag.find(".globe").removeClass("loading"); + }; + })(this)); + }; + + Sidebar.prototype.unloadGlobe = function() { + if (!this.globe) { + return false; + } + this.globe.unload(); + return this.globe = null; + }; + + return Sidebar; + + })(Class); + + window.sidebar = new Sidebar(); + + window.transitionEnd = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend'; + +}).call(this); + + + +/* ---- plugins/Sidebar/media/morphdom.js ---- */ + + +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.morphdom = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o element + * since it sets the initial value. Changing the "value" + * attribute without changing the "value" property will have + * no effect since it is only used to the set the initial value. + * Similar for the "checked" attribute. + */ + /*INPUT: function(fromEl, toEl) { + fromEl.checked = toEl.checked; + fromEl.value = toEl.value; + + if (!toEl.hasAttribute('checked')) { + fromEl.removeAttribute('checked'); + } + + if (!toEl.hasAttribute('value')) { + fromEl.removeAttribute('value'); + } + }*/ +}; + +function noop() {} + +/** + * Loop over all of the attributes on the target node and make sure the + * original DOM node has the same attributes. If an attribute + * found on the original node is not on the new node then remove it from + * the original node + * @param {HTMLElement} fromNode + * @param {HTMLElement} toNode + */ +function morphAttrs(fromNode, toNode) { + var attrs = toNode.attributes; + var i; + var attr; + var attrName; + var attrValue; + var foundAttrs = {}; + + for (i=attrs.length-1; i>=0; i--) { + attr = attrs[i]; + if (attr.specified !== false) { + attrName = attr.name; + attrValue = attr.value; + foundAttrs[attrName] = true; + + if (fromNode.getAttribute(attrName) !== attrValue) { + fromNode.setAttribute(attrName, attrValue); + } + } + } + + // Delete any extra attributes found on the original DOM element that weren't + // found on the target element. + attrs = fromNode.attributes; + + for (i=attrs.length-1; i>=0; i--) { + attr = attrs[i]; + if (attr.specified !== false) { + attrName = attr.name; + if (!foundAttrs.hasOwnProperty(attrName)) { + fromNode.removeAttribute(attrName); + } + } + } +} + +/** + * Copies the children of one DOM element to another DOM element + */ +function moveChildren(from, to) { + var curChild = from.firstChild; + while(curChild) { + var nextChild = curChild.nextSibling; + to.appendChild(curChild); + curChild = nextChild; + } + return to; +} + +function morphdom(fromNode, toNode, options) { + if (!options) { + options = {}; + } + + if (typeof toNode === 'string') { + var newBodyEl = document.createElement('body'); + newBodyEl.innerHTML = toNode; + toNode = newBodyEl.childNodes[0]; + } + + var savedEls = {}; // Used to save off DOM elements with IDs + var unmatchedEls = {}; + var onNodeDiscarded = options.onNodeDiscarded || noop; + var onBeforeMorphEl = options.onBeforeMorphEl || noop; + var onBeforeMorphElChildren = options.onBeforeMorphElChildren || noop; + + function removeNodeHelper(node, nestedInSavedEl) { + var id = node.id; + // If the node has an ID then save it off since we will want + // to reuse it in case the target DOM tree has a DOM element + // with the same ID + if (id) { + savedEls[id] = node; + } else if (!nestedInSavedEl) { + // If we are not nested in a saved element then we know that this node has been + // completely discarded and will not exist in the final DOM. + onNodeDiscarded(node); + } + + if (node.nodeType === 1) { + var curChild = node.firstChild; + while(curChild) { + removeNodeHelper(curChild, nestedInSavedEl || id); + curChild = curChild.nextSibling; + } + } + } + + function walkDiscardedChildNodes(node) { + if (node.nodeType === 1) { + var curChild = node.firstChild; + while(curChild) { + + + if (!curChild.id) { + // We only want to handle nodes that don't have an ID to avoid double + // walking the same saved element. + + onNodeDiscarded(curChild); + + // Walk recursively + walkDiscardedChildNodes(curChild); + } + + curChild = curChild.nextSibling; + } + } + } + + function removeNode(node, parentNode, alreadyVisited) { + parentNode.removeChild(node); + + if (alreadyVisited) { + if (!node.id) { + onNodeDiscarded(node); + walkDiscardedChildNodes(node); + } + } else { + removeNodeHelper(node); + } + } + + function morphEl(fromNode, toNode, alreadyVisited) { + if (toNode.id) { + // If an element with an ID is being morphed then it is will be in the final + // DOM so clear it out of the saved elements collection + delete savedEls[toNode.id]; + } + + if (onBeforeMorphEl(fromNode, toNode) === false) { + return; + } + + morphAttrs(fromNode, toNode); + + if (onBeforeMorphElChildren(fromNode, toNode) === false) { + return; + } + + var curToNodeChild = toNode.firstChild; + var curFromNodeChild = fromNode.firstChild; + var curToNodeId; + + var fromNextSibling; + var toNextSibling; + var savedEl; + var unmatchedEl; + + outer: while(curToNodeChild) { + toNextSibling = curToNodeChild.nextSibling; + curToNodeId = curToNodeChild.id; + + while(curFromNodeChild) { + var curFromNodeId = curFromNodeChild.id; + fromNextSibling = curFromNodeChild.nextSibling; + + if (!alreadyVisited) { + if (curFromNodeId && (unmatchedEl = unmatchedEls[curFromNodeId])) { + unmatchedEl.parentNode.replaceChild(curFromNodeChild, unmatchedEl); + morphEl(curFromNodeChild, unmatchedEl, alreadyVisited); + curFromNodeChild = fromNextSibling; + continue; + } + } + + var curFromNodeType = curFromNodeChild.nodeType; + + if (curFromNodeType === curToNodeChild.nodeType) { + var isCompatible = false; + + if (curFromNodeType === 1) { // Both nodes being compared are Element nodes + if (curFromNodeChild.tagName === curToNodeChild.tagName) { + // We have compatible DOM elements + if (curFromNodeId || curToNodeId) { + // If either DOM element has an ID then we handle + // those differently since we want to match up + // by ID + if (curToNodeId === curFromNodeId) { + isCompatible = true; + } + } else { + isCompatible = true; + } + } + + if (isCompatible) { + // We found compatible DOM elements so add a + // task to morph the compatible DOM elements + morphEl(curFromNodeChild, curToNodeChild, alreadyVisited); + } + } else if (curFromNodeType === 3) { // Both nodes being compared are Text nodes + isCompatible = true; + curFromNodeChild.nodeValue = curToNodeChild.nodeValue; + } + + if (isCompatible) { + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + continue outer; + } + } + + // No compatible match so remove the old node from the DOM + removeNode(curFromNodeChild, fromNode, alreadyVisited); + + curFromNodeChild = fromNextSibling; + } + + if (curToNodeId) { + if ((savedEl = savedEls[curToNodeId])) { + morphEl(savedEl, curToNodeChild, true); + curToNodeChild = savedEl; // We want to append the saved element instead + } else { + // The current DOM element in the target tree has an ID + // but we did not find a match in any of the corresponding + // siblings. We just put the target element in the old DOM tree + // but if we later find an element in the old DOM tree that has + // a matching ID then we will replace the target element + // with the corresponding old element and morph the old element + unmatchedEls[curToNodeId] = curToNodeChild; + } + } + + // If we got this far then we did not find a candidate match for our "to node" + // and we exhausted all of the children "from" nodes. Therefore, we will just + // append the current "to node" to the end + fromNode.appendChild(curToNodeChild); + + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + } + + // We have processed all of the "to nodes". If curFromNodeChild is non-null then + // we still have some from nodes left over that need to be removed + while(curFromNodeChild) { + fromNextSibling = curFromNodeChild.nextSibling; + removeNode(curFromNodeChild, fromNode, alreadyVisited); + curFromNodeChild = fromNextSibling; + } + + var specialElHandler = specialElHandlers[fromNode.tagName]; + if (specialElHandler) { + specialElHandler(fromNode, toNode); + } + } + + var morphedNode = fromNode; + var morphedNodeType = morphedNode.nodeType; + var toNodeType = toNode.nodeType; + + // Handle the case where we are given two DOM nodes that are not + // compatible (e.g.
    --> or
    --> TEXT) + if (morphedNodeType === 1) { + if (toNodeType === 1) { + if (morphedNode.tagName !== toNode.tagName) { + onNodeDiscarded(fromNode); + morphedNode = moveChildren(morphedNode, document.createElement(toNode.tagName)); + } + } else { + // Going from an element node to a text node + return toNode; + } + } else if (morphedNodeType === 3) { // Text node + if (toNodeType === 3) { + morphedNode.nodeValue = toNode.nodeValue; + return morphedNode; + } else { + onNodeDiscarded(fromNode); + // Text node to something else + return toNode; + } + } + + morphEl(morphedNode, toNode, false); + + // Fire the "onNodeDiscarded" event for any saved elements + // that never found a new home in the morphed DOM + for (var savedElId in savedEls) { + if (savedEls.hasOwnProperty(savedElId)) { + var savedEl = savedEls[savedElId]; + onNodeDiscarded(savedEl); + walkDiscardedChildNodes(savedEl); + } + } + + if (morphedNode !== fromNode && fromNode.parentNode) { + fromNode.parentNode.replaceChild(morphedNode, fromNode); + } + + return morphedNode; +} + +module.exports = morphdom; +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/plugins/Sidebar/media/morphdom.js b/plugins/Sidebar/media/morphdom.js new file mode 100644 index 00000000..6829eef3 --- /dev/null +++ b/plugins/Sidebar/media/morphdom.js @@ -0,0 +1,340 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.morphdom = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o element + * since it sets the initial value. Changing the "value" + * attribute without changing the "value" property will have + * no effect since it is only used to the set the initial value. + * Similar for the "checked" attribute. + */ + /*INPUT: function(fromEl, toEl) { + fromEl.checked = toEl.checked; + fromEl.value = toEl.value; + + if (!toEl.hasAttribute('checked')) { + fromEl.removeAttribute('checked'); + } + + if (!toEl.hasAttribute('value')) { + fromEl.removeAttribute('value'); + } + }*/ +}; + +function noop() {} + +/** + * Loop over all of the attributes on the target node and make sure the + * original DOM node has the same attributes. If an attribute + * found on the original node is not on the new node then remove it from + * the original node + * @param {HTMLElement} fromNode + * @param {HTMLElement} toNode + */ +function morphAttrs(fromNode, toNode) { + var attrs = toNode.attributes; + var i; + var attr; + var attrName; + var attrValue; + var foundAttrs = {}; + + for (i=attrs.length-1; i>=0; i--) { + attr = attrs[i]; + if (attr.specified !== false) { + attrName = attr.name; + attrValue = attr.value; + foundAttrs[attrName] = true; + + if (fromNode.getAttribute(attrName) !== attrValue) { + fromNode.setAttribute(attrName, attrValue); + } + } + } + + // Delete any extra attributes found on the original DOM element that weren't + // found on the target element. + attrs = fromNode.attributes; + + for (i=attrs.length-1; i>=0; i--) { + attr = attrs[i]; + if (attr.specified !== false) { + attrName = attr.name; + if (!foundAttrs.hasOwnProperty(attrName)) { + fromNode.removeAttribute(attrName); + } + } + } +} + +/** + * Copies the children of one DOM element to another DOM element + */ +function moveChildren(from, to) { + var curChild = from.firstChild; + while(curChild) { + var nextChild = curChild.nextSibling; + to.appendChild(curChild); + curChild = nextChild; + } + return to; +} + +function morphdom(fromNode, toNode, options) { + if (!options) { + options = {}; + } + + if (typeof toNode === 'string') { + var newBodyEl = document.createElement('body'); + newBodyEl.innerHTML = toNode; + toNode = newBodyEl.childNodes[0]; + } + + var savedEls = {}; // Used to save off DOM elements with IDs + var unmatchedEls = {}; + var onNodeDiscarded = options.onNodeDiscarded || noop; + var onBeforeMorphEl = options.onBeforeMorphEl || noop; + var onBeforeMorphElChildren = options.onBeforeMorphElChildren || noop; + + function removeNodeHelper(node, nestedInSavedEl) { + var id = node.id; + // If the node has an ID then save it off since we will want + // to reuse it in case the target DOM tree has a DOM element + // with the same ID + if (id) { + savedEls[id] = node; + } else if (!nestedInSavedEl) { + // If we are not nested in a saved element then we know that this node has been + // completely discarded and will not exist in the final DOM. + onNodeDiscarded(node); + } + + if (node.nodeType === 1) { + var curChild = node.firstChild; + while(curChild) { + removeNodeHelper(curChild, nestedInSavedEl || id); + curChild = curChild.nextSibling; + } + } + } + + function walkDiscardedChildNodes(node) { + if (node.nodeType === 1) { + var curChild = node.firstChild; + while(curChild) { + + + if (!curChild.id) { + // We only want to handle nodes that don't have an ID to avoid double + // walking the same saved element. + + onNodeDiscarded(curChild); + + // Walk recursively + walkDiscardedChildNodes(curChild); + } + + curChild = curChild.nextSibling; + } + } + } + + function removeNode(node, parentNode, alreadyVisited) { + parentNode.removeChild(node); + + if (alreadyVisited) { + if (!node.id) { + onNodeDiscarded(node); + walkDiscardedChildNodes(node); + } + } else { + removeNodeHelper(node); + } + } + + function morphEl(fromNode, toNode, alreadyVisited) { + if (toNode.id) { + // If an element with an ID is being morphed then it is will be in the final + // DOM so clear it out of the saved elements collection + delete savedEls[toNode.id]; + } + + if (onBeforeMorphEl(fromNode, toNode) === false) { + return; + } + + morphAttrs(fromNode, toNode); + + if (onBeforeMorphElChildren(fromNode, toNode) === false) { + return; + } + + var curToNodeChild = toNode.firstChild; + var curFromNodeChild = fromNode.firstChild; + var curToNodeId; + + var fromNextSibling; + var toNextSibling; + var savedEl; + var unmatchedEl; + + outer: while(curToNodeChild) { + toNextSibling = curToNodeChild.nextSibling; + curToNodeId = curToNodeChild.id; + + while(curFromNodeChild) { + var curFromNodeId = curFromNodeChild.id; + fromNextSibling = curFromNodeChild.nextSibling; + + if (!alreadyVisited) { + if (curFromNodeId && (unmatchedEl = unmatchedEls[curFromNodeId])) { + unmatchedEl.parentNode.replaceChild(curFromNodeChild, unmatchedEl); + morphEl(curFromNodeChild, unmatchedEl, alreadyVisited); + curFromNodeChild = fromNextSibling; + continue; + } + } + + var curFromNodeType = curFromNodeChild.nodeType; + + if (curFromNodeType === curToNodeChild.nodeType) { + var isCompatible = false; + + if (curFromNodeType === 1) { // Both nodes being compared are Element nodes + if (curFromNodeChild.tagName === curToNodeChild.tagName) { + // We have compatible DOM elements + if (curFromNodeId || curToNodeId) { + // If either DOM element has an ID then we handle + // those differently since we want to match up + // by ID + if (curToNodeId === curFromNodeId) { + isCompatible = true; + } + } else { + isCompatible = true; + } + } + + if (isCompatible) { + // We found compatible DOM elements so add a + // task to morph the compatible DOM elements + morphEl(curFromNodeChild, curToNodeChild, alreadyVisited); + } + } else if (curFromNodeType === 3) { // Both nodes being compared are Text nodes + isCompatible = true; + curFromNodeChild.nodeValue = curToNodeChild.nodeValue; + } + + if (isCompatible) { + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + continue outer; + } + } + + // No compatible match so remove the old node from the DOM + removeNode(curFromNodeChild, fromNode, alreadyVisited); + + curFromNodeChild = fromNextSibling; + } + + if (curToNodeId) { + if ((savedEl = savedEls[curToNodeId])) { + morphEl(savedEl, curToNodeChild, true); + curToNodeChild = savedEl; // We want to append the saved element instead + } else { + // The current DOM element in the target tree has an ID + // but we did not find a match in any of the corresponding + // siblings. We just put the target element in the old DOM tree + // but if we later find an element in the old DOM tree that has + // a matching ID then we will replace the target element + // with the corresponding old element and morph the old element + unmatchedEls[curToNodeId] = curToNodeChild; + } + } + + // If we got this far then we did not find a candidate match for our "to node" + // and we exhausted all of the children "from" nodes. Therefore, we will just + // append the current "to node" to the end + fromNode.appendChild(curToNodeChild); + + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + } + + // We have processed all of the "to nodes". If curFromNodeChild is non-null then + // we still have some from nodes left over that need to be removed + while(curFromNodeChild) { + fromNextSibling = curFromNodeChild.nextSibling; + removeNode(curFromNodeChild, fromNode, alreadyVisited); + curFromNodeChild = fromNextSibling; + } + + var specialElHandler = specialElHandlers[fromNode.tagName]; + if (specialElHandler) { + specialElHandler(fromNode, toNode); + } + } + + var morphedNode = fromNode; + var morphedNodeType = morphedNode.nodeType; + var toNodeType = toNode.nodeType; + + // Handle the case where we are given two DOM nodes that are not + // compatible (e.g.
    --> or
    --> TEXT) + if (morphedNodeType === 1) { + if (toNodeType === 1) { + if (morphedNode.tagName !== toNode.tagName) { + onNodeDiscarded(fromNode); + morphedNode = moveChildren(morphedNode, document.createElement(toNode.tagName)); + } + } else { + // Going from an element node to a text node + return toNode; + } + } else if (morphedNodeType === 3) { // Text node + if (toNodeType === 3) { + morphedNode.nodeValue = toNode.nodeValue; + return morphedNode; + } else { + onNodeDiscarded(fromNode); + // Text node to something else + return toNode; + } + } + + morphEl(morphedNode, toNode, false); + + // Fire the "onNodeDiscarded" event for any saved elements + // that never found a new home in the morphed DOM + for (var savedElId in savedEls) { + if (savedEls.hasOwnProperty(savedElId)) { + var savedEl = savedEls[savedElId]; + onNodeDiscarded(savedEl); + walkDiscardedChildNodes(savedEl); + } + } + + if (morphedNode !== fromNode && fromNode.parentNode) { + fromNode.parentNode.replaceChild(morphedNode, fromNode); + } + + return morphedNode; +} + +module.exports = morphdom; +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py index 52b64266..43edefdd 100644 --- a/plugins/Stats/StatsPlugin.py +++ b/plugins/Stats/StatsPlugin.py @@ -116,7 +116,7 @@ class UiRequestPlugin(object): # Sites yield "

    Sites:" yield "" - yield "" + yield "" for site in self.server.sites.values(): yield self.formatTableRow([ ( @@ -130,6 +130,8 @@ class UiRequestPlugin(object): len(site.peers) )), ("%s", len(site.content_manager.contents)), + ("%.0fkB", site.settings.get("bytes_sent", 0) / 1024), + ("%.0fkB", site.settings.get("bytes_recv", 0) / 1024), ]) yield "
    address connected peers content.json
    address connected peers content.json out in