From 42da429414b23c16b4b6307dd08213fb0692cc5d Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 27 Apr 2017 12:01:37 -0700
Subject: [PATCH 1/8] Fix NetworkTexture self possibly being null when
 attempting request

---
 .../model-networking/src/model-networking/TextureCache.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 55704236e3..c2d947baab 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -394,12 +394,17 @@ void NetworkTexture::startRequestForNextMipLevel() {
     }
 
     if (_ktxResourceState == WAITING_FOR_MIP_REQUEST) {
+        auto self = _self.lock();
+        if (!self) {
+            return;
+        }
+
         _ktxResourceState = PENDING_MIP_REQUEST;
 
         init();
         setLoadPriority(this, -static_cast<int>(_originalKtxDescriptor->header.numberOfMipmapLevels) + _lowestKnownPopulatedMip);
         _url.setFragment(QString::number(_lowestKnownPopulatedMip - 1));
-        TextureCache::attemptRequest(_self);
+        TextureCache::attemptRequest(self);
     }
 }
 

From 149f87e734e454d09c3754e4a35058d8c18e9b2d Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 27 Apr 2017 12:01:55 -0700
Subject: [PATCH 2/8] Fix style in NetworkTexture

---
 .../src/model-networking/TextureCache.cpp            | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index c2d947baab..680550d9a1 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -473,19 +473,16 @@ void NetworkTexture::ktxMipRequestFinished() {
                 texture->assignStoredMip(_ktxMipLevelRangeInFlight.first,
                     _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
                 _lowestKnownPopulatedMip = _textureSource->getGPUTexture()->minAvailableMipLevel();
-            }
-            else {
+            } else {
                 qWarning(networking) << "Trying to update mips but texture is null";
             }
             finishedLoading(true);
             _ktxResourceState = WAITING_FOR_MIP_REQUEST;
-        }
-        else {
+        } else {
             finishedLoading(false);
             if (handleFailedRequest(_ktxMipRequest->getResult())) {
                 _ktxResourceState = PENDING_MIP_REQUEST;
-            }
-            else {
+            } else {
                 qWarning(networking) << "Failed to load mip: " << _url;
                 _ktxResourceState = FAILED_TO_LOAD;
             }
@@ -497,8 +494,7 @@ void NetworkTexture::ktxMipRequestFinished() {
         if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) {
             startRequestForNextMipLevel();
         }
-    }
-    else {
+    } else {
         qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState;
     }
 }

From d8e4604b18ccdcf3d8c714ff1a265fc49321d1a0 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 27 Apr 2017 13:03:04 -0700
Subject: [PATCH 3/8] Fix gpu access of ktx file not being thread-safe

---
 libraries/gpu/src/gpu/Texture.h       | 8 ++++----
 libraries/gpu/src/gpu/Texture_ktx.cpp | 5 +++--
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h
index 9b23b4e695..3b8ae508eb 100755
--- a/libraries/gpu/src/gpu/Texture.h
+++ b/libraries/gpu/src/gpu/Texture.h
@@ -324,11 +324,11 @@ public:
         void reset() override { }
 
     protected:
-        std::shared_ptr<storage::FileStorage> maybeOpenFile();
+        std::shared_ptr<storage::FileStorage> maybeOpenFile() const;
 
-        std::mutex _cacheFileCreateMutex;
-        std::mutex _cacheFileWriteMutex;
-        std::weak_ptr<storage::FileStorage> _cacheFile;
+        mutable std::mutex _cacheFileCreateMutex;
+        mutable std::mutex _cacheFileWriteMutex;
+        mutable std::weak_ptr<storage::FileStorage> _cacheFile;
 
         std::string _filename;
         std::atomic<uint8_t> _minMipLevelAvailable;
diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp
index efff6c7afe..d2f93c0036 100644
--- a/libraries/gpu/src/gpu/Texture_ktx.cpp
+++ b/libraries/gpu/src/gpu/Texture_ktx.cpp
@@ -128,7 +128,7 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
     }
 }
 
-std::shared_ptr<storage::FileStorage> KtxStorage::maybeOpenFile() {
+std::shared_ptr<storage::FileStorage> KtxStorage::maybeOpenFile() const {
     std::shared_ptr<storage::FileStorage> file = _cacheFile.lock();
     if (file) {
         return file;
@@ -154,7 +154,8 @@ PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
     auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face);
     auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
     if (faceSize != 0 && faceOffset != 0) {
-        result = std::make_shared<storage::FileStorage>(_filename.c_str())->createView(faceSize, faceOffset)->toMemoryStorage();
+        auto file = maybeOpenFile();
+        result = file->createView(faceSize, faceOffset)->toMemoryStorage();
     }
     return result;
 }

From 4b0bd80c270254ead7f22ffe09934a9f99bfff6d Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 27 Apr 2017 13:03:42 -0700
Subject: [PATCH 4/8] Fix NetworkTexture not cleaning itself up on destruction

---
 .../src/model-networking/TextureCache.cpp        | 16 ++++++++++++++++
 .../src/model-networking/TextureCache.h          |  1 +
 libraries/networking/src/ResourceCache.h         |  2 +-
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 680550d9a1..7aee95c758 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -330,6 +330,22 @@ private:
     int _maxNumPixels;
 };
 
+NetworkTexture::~NetworkTexture() {
+    if (_ktxHeaderRequest || _ktxMipRequest) {
+        if (_ktxHeaderRequest) {
+            _ktxHeaderRequest->disconnect(this);
+            _ktxHeaderRequest->deleteLater();
+            _ktxHeaderRequest = nullptr;
+        }
+        if (_ktxMipRequest) {
+            _ktxMipRequest->disconnect(this);
+            _ktxMipRequest->deleteLater();
+            _ktxMipRequest = nullptr;
+        }
+        ResourceCache::requestCompleted(_self);
+    }
+}
+
 const uint16_t NetworkTexture::NULL_MIP_LEVEL = std::numeric_limits<uint16_t>::max();
 void NetworkTexture::makeRequest() {
     if (!_sourceIsKTX) {
diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h
index 1e61b9ecee..c7a7799216 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.h
+++ b/libraries/model-networking/src/model-networking/TextureCache.h
@@ -46,6 +46,7 @@ class NetworkTexture : public Resource, public Texture {
 
 public:
     NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels);
+    ~NetworkTexture() override;
 
     QString getType() const override { return "NetworkTexture"; }
 
diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h
index d4c7d63ee5..51c8d8554a 100644
--- a/libraries/networking/src/ResourceCache.h
+++ b/libraries/networking/src/ResourceCache.h
@@ -344,7 +344,7 @@ class Resource : public QObject {
 public:
     
     Resource(const QUrl& url);
-    ~Resource();
+    virtual ~Resource();
 
     virtual QString getType() const { return "Resource"; }
     

From 2faa8fb671508dcf85841ba82a3fd6b0bfd1fe99 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 27 Apr 2017 14:01:55 -0700
Subject: [PATCH 5/8] Fix ResourceCache warning on OSX

---
 .../model-networking/src/model-networking/TextureCache.cpp      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 7aee95c758..12ec6eca24 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -342,7 +342,7 @@ NetworkTexture::~NetworkTexture() {
             _ktxMipRequest->deleteLater();
             _ktxMipRequest = nullptr;
         }
-        ResourceCache::requestCompleted(_self);
+        TextureCache::requestCompleted(_self);
     }
 }
 

From eed4da3570833de3667d7f41931d505921f1cf98 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Tue, 2 May 2017 15:36:38 -0700
Subject: [PATCH 6/8] some cleanups, delete far-grabs during transition to
 near-grab rather than set ttl to zero

---
 .../system/controllers/handControllerGrab.js  | 95 +++++++------------
 1 file changed, 36 insertions(+), 59 deletions(-)

diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index ec70b0b1c8..33fd2b8fd9 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -14,7 +14,7 @@
 
 /* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
     Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
-   setGrabCommunications, Menu, HMD, isInEditMode */
+   setGrabCommunications, Menu, HMD, isInEditMode, AvatarManager */
 /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
 
 (function() { // BEGIN LOCAL_SCOPE
@@ -75,7 +75,6 @@ var WEB_TOUCH_Y_OFFSET = 0.05; // how far forward (or back with a negative numbe
 //
 // distant manipulation
 //
-var linearTimeScale = 0;
 var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object
 var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
 var DISTANCE_HOLDING_UNITY_MASS = 1200; //  The mass at which the distance holding action timeframe is unmodified
@@ -155,7 +154,6 @@ var INCHES_TO_METERS = 1.0 / 39.3701;
 
 // these control how long an abandoned pointer line or action will hang around
 var ACTION_TTL = 15; // seconds
-var ACTION_TTL_ZERO = 0; // seconds
 var ACTION_TTL_REFRESH = 5;
 var PICKS_PER_SECOND_PER_HAND = 60;
 var MSECS_PER_SEC = 1000.0;
@@ -193,7 +191,6 @@ var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
 var holdEnabled = true;
 var nearGrabEnabled = true;
 var farGrabEnabled = true;
-var farToNearGrab = false;
 var myAvatarScalingEnabled = true;
 var objectScalingEnabled = true;
 var mostRecentSearchingHand = RIGHT_HAND;
@@ -300,14 +297,13 @@ function getFingerWorldLocation(hand) {
 // Object assign  polyfill
 if (typeof Object.assign != 'function') {
     Object.assign = function(target, varArgs) {
-        'use strict';
-        if (target == null) {
+        if (target === null) {
             throw new TypeError('Cannot convert undefined or null to object');
         }
         var to = Object(target);
         for (var index = 1; index < arguments.length; index++) {
             var nextSource = arguments[index];
-            if (nextSource != null) {
+            if (nextSource !== null) {
                 for (var nextKey in nextSource) {
                     if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
                         to[nextKey] = nextSource[nextKey];
@@ -801,7 +797,7 @@ function calculateNearestStylusTarget(stylusTargets) {
     }
 
     return nearestStylusTarget;
-};
+}
 
 // EntityPropertiesCache is a helper class that contains a cache of entity properties.
 // the hope is to prevent excess calls to Entity.getEntityProperties()
@@ -1229,8 +1225,9 @@ function MyController(hand) {
              newState !== STATE_OVERLAY_LASER_TOUCHING)) {
             return;
         }
-        setGrabCommunications((newState === STATE_DISTANCE_HOLDING) || (newState === STATE_DISTANCE_ROTATING)
-            || (newState === STATE_NEAR_GRABBING));
+        setGrabCommunications((newState === STATE_DISTANCE_HOLDING) ||
+                              (newState === STATE_DISTANCE_ROTATING) ||
+                              (newState === STATE_NEAR_GRABBING));
         if (WANT_DEBUG || WANT_DEBUG_STATE) {
             var oldStateName = stateToName(this.state);
             var newStateName = stateToName(newState);
@@ -1428,7 +1425,7 @@ function MyController(hand) {
         if (PICK_WITH_HAND_RAY) {
             this.overlayLineOff();
         }
-    }
+    };
 
     this.otherGrabbingLineOn = function(avatarPosition, entityPosition, color) {
         if (this.otherGrabbingLine === null) {
@@ -1641,11 +1638,6 @@ function MyController(hand) {
 
         var tipPosition = this.stylusTip.position;
 
-        var candidates = {
-            entities: [],
-            overlays: []
-        };
-
         // build list of stylus targets, near the stylusTip
         var stylusTargets = [];
         var candidateEntities = Entities.findEntities(tipPosition, WEB_DISPLAY_STYLUS_DISTANCE);
@@ -1972,9 +1964,10 @@ function MyController(hand) {
         var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
 
         var otherHandControllerState = this.getOtherHandController().state;
-        var okToEquipFromOtherHand = ((otherHandControllerState === STATE_NEAR_GRABBING
-            || otherHandControllerState === STATE_DISTANCE_HOLDING || otherHandControllerState === STATE_DISTANCE_ROTATING)
-            && this.getOtherHandController().grabbedThingID === hotspot.entityID);
+        var okToEquipFromOtherHand = ((otherHandControllerState === STATE_NEAR_GRABBING ||
+                                       otherHandControllerState === STATE_DISTANCE_HOLDING ||
+                                       otherHandControllerState === STATE_DISTANCE_ROTATING) &&
+                                      this.getOtherHandController().grabbedThingID === hotspot.entityID);
         var hasParent = true;
         if (props.parentID === NULL_UUID) {
             hasParent = false;
@@ -1999,7 +1992,7 @@ function MyController(hand) {
             return entityProps.cloneable;
         }
         return false;
-    }
+    };
     this.entityIsGrabbable = function(entityID) {
         var grabbableProps = entityPropertiesCache.getGrabbableProps(entityID);
         var props = entityPropertiesCache.getProps(entityID);
@@ -2346,7 +2339,7 @@ function MyController(hand) {
                 this.otherGrabbingLineOff();
             } else if (this.otherGrabbingUUID !== null) {
                 if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) {
-                    var avatar = AvatarList.getAvatar(this.otherGrabbingUUID);
+                    var avatar = AvatarManager.getAvatar(this.otherGrabbingUUID);
                     var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 };  // Up from hips and in front of avatar.
                     var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR));
                     var finishPisition = Vec3.sum(rayPickInfo.properties.position,  // Entity's centroid.
@@ -2720,7 +2713,8 @@ function MyController(hand) {
 
         var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
 
-        var candidateHotSpotEntities = Entities.findEntities(controllerLocation.position,MAX_FAR_TO_NEAR_EQUIP_HOTSPOT_RADIUS);
+        var candidateHotSpotEntities =
+            Entities.findEntities(controllerLocation.position,MAX_FAR_TO_NEAR_EQUIP_HOTSPOT_RADIUS);
         entityPropertiesCache.addEntities(candidateHotSpotEntities);
 
         var potentialEquipHotspot = this.chooseBestEquipHotspotForFarToNearEquip(candidateHotSpotEntities);
@@ -2730,40 +2724,23 @@ function MyController(hand) {
                 this.grabbedThingID = potentialEquipHotspot.entityID;
                 this.grabbedIsOverlay = false;
 
-                var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
-                    targetPosition: newTargetPosition,
-                    linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
-                    targetRotation: this.currentObjectRotation,
-                    angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
-                    ttl: ACTION_TTL_ZERO
-                });
-                
-                if (success) {
-                    this.actionTimeout = now + (ACTION_TTL_ZERO * MSECS_PER_SEC);
-                } else {
-                    print("continueDistanceHolding -- updateAction failed");
-                }
+                Entities.deleteAction(this.grabbedThingID, this.actionID);
+                this.actionID = null;
+
                 this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedThingID).name + "'");
                 return;
              }
         }
         var rayPositionOnEntity = Vec3.subtract(grabbedProperties.position, this.offsetPosition);
         //Far to Near Grab: If object is draw by user inside FAR_TO_NEAR_GRAB_MAX_DISTANCE, grab it
-        if (this.entityIsFarToNearGrabbable(rayPositionOnEntity, controllerLocation.position, FAR_TO_NEAR_GRAB_MAX_DISTANCE)) {
+        if (this.entityIsFarToNearGrabbable(rayPositionOnEntity,
+                                            controllerLocation.position,
+                                            FAR_TO_NEAR_GRAB_MAX_DISTANCE)) {
             this.farToNearGrab = true;
 
-            var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
-                targetPosition: newTargetPosition,
-                linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
-                targetRotation: this.currentObjectRotation,
-                angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
-                ttl: ACTION_TTL_ZERO  // Overriding ACTION_TTL,Assign ACTION_TTL_ZERO so that the object is dropped down immediately after the trigger is released.
-            });
-            if (success) {
-                this.actionTimeout = now + (ACTION_TTL_ZERO * MSECS_PER_SEC);
-            } else {
-                print("continueDistanceHolding -- updateAction failed");
-            }
+            Entities.deleteAction(this.grabbedThingID, this.actionID);
+            this.actionID = null;
+
             this.setState(STATE_NEAR_GRABBING , "near grab entity '" + this.grabbedThingID + "'");
             return;
         }
@@ -2844,7 +2821,7 @@ function MyController(hand) {
             COLORS_GRAB_DISTANCE_HOLD, this.grabbedThingID);
 
         this.previousWorldControllerRotation = worldControllerRotation;
-    }
+    };
 
     this.setupHoldAction = function() {
         this.actionID = Entities.addAction("hold", this.grabbedThingID, {
@@ -3043,15 +3020,14 @@ function MyController(hand) {
                             var worldEntities = Entities.findEntities(MyAvatar.position, 50);
                             var count = 0;
                             worldEntities.forEach(function(item) {
-                                var item = Entities.getEntityProperties(item, ["name"]);
-                                if (item.name.indexOf('-clone-' + grabbedProperties.id) !== -1) {
+                                var itemWE = Entities.getEntityProperties(itemWE, ["name"]);
+                                if (itemWE.name.indexOf('-clone-' + grabbedProperties.id) !== -1) {
                                     count++;
                                 }
-                            })
+                            });
 
                             var limit = grabInfo.cloneLimit ? grabInfo.cloneLimit : 0;
                             if (count >= limit && limit !== 0) {
-                                delete limit;
                                 return;
                             }
 
@@ -3067,7 +3043,7 @@ function MyController(hand) {
                             delete cUserData.grabbableKey.cloneable;
                             delete cUserData.grabbableKey.cloneDynamic;
                             delete cUserData.grabbableKey.cloneLimit;
-                            delete cProperties.id
+                            delete cProperties.id;
 
                             cProperties.dynamic = dynamic;
                             cProperties.locked = false;
@@ -3133,7 +3109,7 @@ function MyController(hand) {
             _this.currentAngularVelocity = ZERO_VEC;
 
             _this.prevDropDetected = false;
-        }
+        };
 
         if (isClone) {
             // 100 ms seems to be sufficient time to force the check even occur after the object has been initialized.
@@ -3149,7 +3125,6 @@ function MyController(hand) {
         var ttl = ACTION_TTL;
 
         if (this.farToNearGrab) {
-            ttl = ACTION_TTL_ZERO; // farToNearGrab - Assign ACTION_TTL_ZERO so that, the object is dropped down immediately after the trigger is released.
             if(!this.triggerClicked){
                this.farToNearGrab = false;
             }
@@ -3322,7 +3297,7 @@ function MyController(hand) {
             this.maybeScale(props);
         }
 
-        if (this.actionID && this.actionTimeout - now < ttl * MSECS_PER_SEC) {
+        if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) {
             // if less than a 5 seconds left, refresh the actions ttl
             var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
                 hand: this.hand === RIGHT_HAND ? "right" : "left",
@@ -3761,10 +3736,12 @@ function MyController(hand) {
         var TABLET_MAX_TOUCH_DISTANCE = 0.01;
 
         if (this.stylusTarget) {
-            if (this.stylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE && this.stylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE) {
+            if (this.stylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE &&
+                this.stylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE) {
                 var POINTER_PRESS_TO_MOVE_DELAY = 0.33; // seconds
                 if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY ||
-                    distance2D(this.stylusTarget.position2D, this.touchingEnterStylusTarget.position2D) > this.deadspotRadius) {
+                    distance2D(this.stylusTarget.position2D,
+                               this.touchingEnterStylusTarget.position2D) > this.deadspotRadius) {
                     sendTouchMoveEventToStylusTarget(this.hand, this.stylusTarget);
                     this.deadspotExpired = true;
                 }

From f1170dc17dbd7ead1a8c0353ed2268e93ad04340 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Tue, 2 May 2017 15:48:12 -0700
Subject: [PATCH 7/8] AvatarList not AvatarManager

---
 scripts/system/controllers/handControllerGrab.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index 33fd2b8fd9..15aa52b5c0 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -14,7 +14,7 @@
 
 /* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
     Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
-   setGrabCommunications, Menu, HMD, isInEditMode, AvatarManager */
+   setGrabCommunications, Menu, HMD, isInEditMode, AvatarList */
 /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
 
 (function() { // BEGIN LOCAL_SCOPE
@@ -2339,7 +2339,7 @@ function MyController(hand) {
                 this.otherGrabbingLineOff();
             } else if (this.otherGrabbingUUID !== null) {
                 if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) {
-                    var avatar = AvatarManager.getAvatar(this.otherGrabbingUUID);
+                    var avatar = AvatarList.getAvatar(this.otherGrabbingUUID);
                     var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 };  // Up from hips and in front of avatar.
                     var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR));
                     var finishPisition = Vec3.sum(rayPickInfo.properties.position,  // Entity's centroid.

From 0cd0e46ca5a42835d6e9bb742cf917d7417c1bca Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Tue, 2 May 2017 16:20:59 -0700
Subject: [PATCH 8/8] make clone work again

---
 scripts/system/controllers/handControllerGrab.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index 15aa52b5c0..db0840b078 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -3020,7 +3020,7 @@ function MyController(hand) {
                             var worldEntities = Entities.findEntities(MyAvatar.position, 50);
                             var count = 0;
                             worldEntities.forEach(function(item) {
-                                var itemWE = Entities.getEntityProperties(itemWE, ["name"]);
+                                var itemWE = Entities.getEntityProperties(item, ["name"]);
                                 if (itemWE.name.indexOf('-clone-' + grabbedProperties.id) !== -1) {
                                     count++;
                                 }