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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 Z`oH@t|Ln8>|5^UC@4$cE@5g>^`)^we#C!k% literal 0 HcmV?d00001 diff --git a/plugins/Sidebar/media/Class.coffee b/plugins/Sidebar/media/Class.coffee new file mode 100644 index 00000000..d62ab25c --- /dev/null +++ b/plugins/Sidebar/media/Class.coffee @@ -0,0 +1,23 @@ +class Class + trace: true + + log: (args...) -> + 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