<commit_before>/*
 The MIT License

 Copyright (c) 2014 Gareth Clay

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

(function () {
  'use strict';
  angular.module('cblite', ['ngResource', 'ab-base64'])
    .factory('cblite', function cbliteFactory($resource, $log, $q, base64, $filter) {

      var deferredCordova = $q.defer(),
        deferredCBLiteUrl = $q.defer(),
        cbliteUrlPromise = deferredCordova.promise.then(function () { return deferredCBLiteUrl.promise; }),
        cblite;

      function deviceReady() {
        function ParsedUrl(url) {
          // Trim off the leading 'http://'
          var http = "http://",
            credentials = url.slice(http.length, url.indexOf('@')),
            basicAuthToken = base64.encode(credentials);

          $log.debug("Couchbase Lite auth token: " + basicAuthToken);

          return {
            credentials: credentials,
            basicAuthToken: basicAuthToken,
            url: url,
            urlNoCredentials: http + url.slice(http.length + credentials.length + 1) // '@' symbol
          };
        }

        function getUrl() {
          // Grab the Couchbase Lite URL via the native bridge
          if (window.cblite) {
            window.cblite.getURL(function (err, url) {
              if (err) {
                deferredCBLiteUrl.reject(err);
              } else {
                deferredCBLiteUrl.notify("Couchbase Lite is running at " + url);
                cblite = new ParsedUrl(url);
                deferredCBLiteUrl.resolve(cblite);
              }
            });
          } else {
            throw ("Couchbase Lite plugin not found.");
          }
        }

        deferredCordova.notify("Notified that Cordova is ready");
        deferredCordova.resolve();
        getUrl();
      }

      function openResource(path, paramDefaults) {
        return cbliteUrlPromise.then(
          function (parsedUrl) {
            var headers = {Authorization: 'Basic ' + parsedUrl.basicAuthToken},
              actions = {
                'get':  {method: 'GET',  headers: headers},
                'list': {method: 'GET',  headers: headers, isArray: true},
                'put':  {method: 'PUT',  headers: headers},
                'post': {method: 'POST', headers: headers}
              };

            return $resource(parsedUrl.url + path, paramDefaults, actions);
          },
          null,
          function (notification) {
            var message = "Angular Couchbase Lite: " + notification;
            $log.debug(message);
          }
        );
      }

      document.addEventListener('deviceready', deviceReady, false);

      return {
        // Couchbase Lite Server
        info: function () {
          $log.debug("Asking Couchbase Lite for server info");
          return openResource('').then(function (server) {
            return server.get().$promise;
          });
        },

        activeTasks: function () {
//          $log.debug("Asking Couchbase Lite for a list of active tasks");
          return openResource('_active_tasks').then(function (server) {
            return server.list().$promise;
          });
        },

        allDatabases: function () {
          var that = this;
//          $log.debug("Asking Couchbase Lite for list of all databases");
          return openResource('_all_dbs').then(function (allDatabases) {
            return allDatabases.list().$promise.then(function (databaseNames) {
              return databaseNames.map(function (name) {
                return that.database(name);
              });
            });
          });
        },

        userDatabases: function () {
          $log.debug("Asking Couchbase Lite for list of user databases");
          return this.allDatabases().then(function (databases) {
            return $filter('filter')(databases, function (db) { return db.slice(0, 1) !== '_'; });
          });
        },

        // Databases
        database: function (databaseName) {
          var openDatabase = openResource(':db', {db: databaseName}),
            openReplication = openResource('_replicate');

          function validateDocument(content) {
            var type = typeof content;
            switch (type) {
            case "string":
              if (typeof JSON.parse(content) !== "object") {
                throw "You can only save valid JSON strings";
              }
              break;

            case "object":
              if (content === null) {
                throw "You can't save a null document";
              }
              break;

            default:
              throw "You can't save this type: " + type;
            }
          }

          function toReplicationSpec(spec) {
            if (typeof spec === 'string') {
              spec = {
                url: spec,
                continuous: false
              };
            }
            return spec;
          }

          return {
            name: function () { return databaseName; },

            info: function () {
//              $log.debug("Asking Couchbase Lite for info about database [" + databaseName + "]");
              return openDatabase.then(function (db) {
                return db.get().$promise;
              });
            },

            checkIfExists: function () {
              $log.debug("Asking Couchbase Lite if database [" + databaseName + "] exists");
              return this.info().then(
                function () {
                  $log.debug("Couchbase Lite database '" + databaseName + "' exists");
                  return true;
                },
                function () {
                  $log.debug("Couchbase Lite database '" + databaseName + "' does not exist");
                  return false;
                }
              );
            },

            create: function () {
              $log.debug("Asking Couchbase Lite to create database [" + databaseName + "]");
              return openDatabase.then(function (db) {
                return db.put({}, null).$promise;
              });
            },

            createIfMissing: function () {
              var that = this;
              return this.info().then(
                function (info) { return info; },
                function (error) {
                  if (error.status === 404) {
                    return that.create();
                  }
                  throw "Unable to create database: " + JSON.stringify(error.data);
                }
              );
            },

            changes: function (spec) {
              $log.debug("Asking Couchbase Lite for list of changes to database [" + databaseName + "]");
              spec = angular.extend({}, spec, {db: databaseName});
              return openResource(':db/_changes', spec).then(function (db) {
                return db.get().$promise;
              });
            },

            // Documents
            document: function (id) {
              var resourceString = ':db/:doc';

              return {
                load: function (spec) {
                  spec = angular.extend({}, spec, {db: databaseName, doc: id});
                  $log.debug("Asking Couchbase Lite for document with id [" + id + "] in database [" + databaseName + "]");
                  return openResource(resourceString, spec).then(function (document) {
                    return document.get().$promise;
                  }, function (error) {
                    $log.error("Failed to load document '" + id + "': " + JSON.stringify(error));
                    throw error;
                  });
                },

                save: function (content, revision) {
                  validateDocument(content);

                  if (revision != null && angular.isDefined(revision)) {
                    content._rev = revision
                  }

                  if (/*!isLocalDocument && */!angular.isDefined(id)) {
                    // If no id has been provided, then see if we can pull one from the document
                    id = content._id;
                    if (id === null || !angular.isDefined(id)) {
                      $log.debug("Asking Couchbase Lite to save document with a database-generated id in database [" + databaseName + "]");
                      return openResource(':db', {db: databaseName}).then(function (database) {
                        var promise = database.post(content).$promise;
                        return promise.then(function (response) {
                          // Update our cached id with the one returned in the response
                          id = response.id;
                          return promise;
                        });
                      });
                    }
                  }

                  $log.debug("Asking Couchbase Lite to save document with id [" + id + "] in database [" + databaseName + "]");
                  $log.debug(JSON.stringify(content));
                  return openResource(resourceString, {db: databaseName, doc: id}).then(function (document) {
                    return document.put(content).$promise;
                  });
                }
              };
            },

            // Replication and sync
            replicateTo: function (spec) {
              spec = toReplicationSpec(spec);
              return openReplication.then(function (replication) {
                var request = {
                  source: databaseName,
                  target: spec.url,
                  continuous: spec.continuous,
                  headers: spec.headers
                };
                $log.debug('Couchbase Lite requesting replication: ' + JSON.stringify(request));
                return replication.post(request).$promise;
              });
            },

            replicateFrom: function (spec) {
              spec = toReplicationSpec(spec);
              return openReplication.then(function (replication) {
                var request = {
                  source: spec.url,
                  target: databaseName,
                  continuous: spec.continuous,
                  headers: spec.headers
                };
                $log.debug('Couchbase Lite requesting replication: ' + JSON.stringify(request));
                return replication.post(request).$promise;
              });
            },

            syncWith: function (spec) {
              var that = this,
                sync = $q.defer(),
                combinedResponse = {};

              that.replicateTo(spec).then(
                function (localToRemoteResponse) {
                  combinedResponse.localToRemote = localToRemoteResponse;

                  return that.replicateFrom(spec).then(
                    function (remoteToLocalResponse) {
                      $log.error('Couchbase Lite replication request failed: ' + JSON.stringify(remoteToLocalResponse));
                      combinedResponse.remoteToLocal = remoteToLocalResponse;
                      sync.resolve(combinedResponse);
                    },
                    function (remoteToLocalError) {
                      combinedResponse.remoteToLocal = remoteToLocalError;
                      sync.reject(combinedResponse);
                    }
                  );
                },
                function (localToRemoteError) {
                  $log.error('Couchbase Lite replication request failed: ' + JSON.stringify(localToRemoteError));
                  combinedResponse.localToRemote = localToRemoteError;
                  sync.reject(combinedResponse);
                }
              );

              return sync.promise;
            }
          };
        }
      };
    });
}());
<commit_msg>Added initial support for Design Documents and views.<commit_after>/*
 The MIT License

 Copyright (c) 2014 Gareth Clay

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

(function () {
  'use strict';
  angular.module('cblite', ['ngResource', 'ab-base64'])
    .factory('cblite', function cbliteFactory($resource, $log, $q, base64, $filter) {

      var deferredCordova = $q.defer(),
        deferredCBLiteUrl = $q.defer(),
        cbliteUrlPromise = deferredCordova.promise.then(function () { return deferredCBLiteUrl.promise; }),
        cblite;

      function deviceReady() {
        function ParsedUrl(url) {
          // Trim off the leading 'http://'
          var http = "http://",
            credentials = url.slice(http.length, url.indexOf('@')),
            basicAuthToken = base64.encode(credentials);

          $log.debug("Couchbase Lite auth token: " + basicAuthToken);

          return {
            credentials: credentials,
            basicAuthToken: basicAuthToken,
            url: url,
            urlNoCredentials: http + url.slice(http.length + credentials.length + 1) // '@' symbol
          };
        }

        function getUrl() {
          // Grab the Couchbase Lite URL via the native bridge
          if (window.cblite) {
            window.cblite.getURL(function (err, url) {
              if (err) {
                deferredCBLiteUrl.reject(err);
              } else {
                deferredCBLiteUrl.notify("Couchbase Lite is running at " + url);
                cblite = new ParsedUrl(url);
                deferredCBLiteUrl.resolve(cblite);
              }
            });
          } else {
            throw ("Couchbase Lite plugin not found.");
          }
        }

        deferredCordova.notify("Notified that Cordova is ready");
        deferredCordova.resolve();
        getUrl();
      }

      function openResource(path, paramDefaults) {
        return cbliteUrlPromise.then(
          function (parsedUrl) {
            var headers = {Authorization: 'Basic ' + parsedUrl.basicAuthToken},
              actions = {
                'get':    {method: 'GET',  headers: headers},
                'list':   {method: 'GET',  headers: headers, isArray: true},
                'put':    {method: 'PUT',  headers: headers},
                'post':   {method: 'POST', headers: headers},
                'filter': {method: 'POST', headers: headers, isArray: true}
              };

            return $resource(parsedUrl.url + path, paramDefaults, actions);
          },
          null,
          function (notification) {
            var message = "Angular Couchbase Lite: " + notification;
            $log.debug(message);
          }
        );
      }

      document.addEventListener('deviceready', deviceReady, false);

      return {
        // Couchbase Lite Server
        info: function () {
          $log.debug("Asking Couchbase Lite for server info");
          return openResource('').then(function (server) {
            return server.get().$promise;
          });
        },

        activeTasks: function () {
//          $log.debug("Asking Couchbase Lite for a list of active tasks");
          return openResource('_active_tasks').then(function (server) {
            return server.list().$promise;
          });
        },

        allDatabases: function () {
          var that = this;
//          $log.debug("Asking Couchbase Lite for list of all databases");
          return openResource('_all_dbs').then(function (allDatabases) {
            return allDatabases.list().$promise.then(function (databaseNames) {
              return databaseNames.map(function (name) {
                return that.database(name);
              });
            });
          });
        },

        userDatabases: function () {
          $log.debug("Asking Couchbase Lite for list of user databases");
          return this.allDatabases().then(function (databases) {
            return $filter('filter')(databases, function (db) { return db.slice(0, 1) !== '_'; });
          });
        },

        // Databases
        database: function (databaseName) {
          var openDatabase = openResource(':db', {db: databaseName}),
            openReplication = openResource('_replicate');

          function validateDocument(content) {
            var type = typeof content;
            switch (type) {
            case "string":
              if (typeof JSON.parse(content) !== "object") {
                throw "You can only save valid JSON strings";
              }
              break;

            case "object":
              if (content === null) {
                throw "You can't save a null document";
              }
              break;

            default:
              throw "You can't save this type: " + type;
            }
          }

          function toReplicationSpec(spec) {
            if (typeof spec === 'string') {
              spec = {
                url: spec,
                continuous: false
              };
            }
            return spec;
          }

          return {
            name: function () { return databaseName; },

            info: function () {
//              $log.debug("Asking Couchbase Lite for info about database [" + databaseName + "]");
              return openDatabase.then(function (db) {
                return db.get().$promise;
              });
            },

            checkIfExists: function () {
              $log.debug("Asking Couchbase Lite if database [" + databaseName + "] exists");
              return this.info().then(
                function () {
                  $log.debug("Couchbase Lite database '" + databaseName + "' exists");
                  return true;
                },
                function () {
                  $log.debug("Couchbase Lite database '" + databaseName + "' does not exist");
                  return false;
                }
              );
            },

            create: function () {
              $log.debug("Asking Couchbase Lite to create database [" + databaseName + "]");
              return openDatabase.then(function (db) {
                return db.put({}, null).$promise;
              });
            },

            createIfMissing: function () {
              var that = this;
              return this.info().then(
                function (info) { return info; },
                function (error) {
                  if (error.status === 404) {
                    return that.create();
                  }
                  throw "Unable to create database: " + JSON.stringify(error.data);
                }
              );
            },

            changes: function (spec) {
              $log.debug("Asking Couchbase Lite for list of changes to database [" + databaseName + "]");
              spec = angular.extend({}, spec, {db: databaseName});
              return openResource(':db/_changes', spec).then(function (db) {
                return db.get().$promise;
              });
            },

            all: function (filter) {
              $log.debug("Asking Couchbase Lite to get all documents in database [" + databaseName + "]");
              var resourceString = ':db/_all_docs';
              if (filter) {
                $log.debug(JSON.stringify(filter));
                return openResource(resourceString, {db: databaseName}).then(function (docs) {
                  return docs.filter(filter).$promise;
                });
              } else {
                return openResource(resourceString, {db: databaseName}).then(function (docs) {
                  return docs.list().$promise;
                });
              }
            },

            // Design Doc
            design: function (designId) {
              function cleanFunction(func) {
                var type = typeof func;
                switch (type) {
                case "function":
                  // stringify and scrub
                  return String(func).replace(/\s+/g, " ");

                case "string":
                  return func;

                default:
                  throw "Invalid function definition";
                }
              }

              function toDesignDoc(content) {

                validateDocument(content);
                if (typeof content == "string") {
                  content = JSON.parse(content);
                }
                if (typeof content.views != "object") {
                  throw "Design Doc is missing valid view structure";
                }
                angular.forEach(content.views, function(value, key) {
                  value.map = cleanFunction(value.map);

                  if (typeof value.reduce != "undefined") {
                    value.reduce = cleanFunction(value.reduce);
                  }

                  this[key] = value;

                }, content.views);

                if (typeof content.language == "undefined") {
                  content.language = "javascript";
                }
                return content;
              }

              var designString = ':db/_design/:designId';

              return {
                save: function (spec) {
                  spec = toDesignDoc(spec);

                  $log.debug("Asking Couchbase Lite to save design document with id [" + designId + "] in database [" + databaseName + "]");
                  $log.debug(JSON.stringify(spec));
                  return openResource(designString, {db: databaseName, designId: designId}).then(function (document) {
                    return document.put(spec).$promise;
                  });
                },
                load: function () {
                  $log.debug("Asking Couchbase Lite to load design document with id [" + designId + "] in database [" + databaseName + "]");
                  return openResource(designString, {db: databaseName, designId: designId}).then(function (document) {
                    return document.get().$promise;
                  });
                },
                view: function (id, filter) {
                  $log.debug("Asking Couchbase Lite to query view with id [" + designId + "/" + id + "] in database [" + databaseName + "]");
                  var viewString = designString + '/:id';

                  if (filter) {
                    $log.debug(JSON.stringify(filter));
                    return openResource(viewString, {db: databaseName, designId: designId, id: id}).then(function (docs) {
                      return docs.filter(filter).$promise;
                    });
                  } else {
                    return openResource(viewString, {db: databaseName, designId: designId, id: id}).then(function (docs) {
                      return docs.list().$promise;
                    });
                  }
                }
              };
            },

            // Documents
            document: function (id) {
              var resourceString = ':db/:doc';

              return {
                load: function (spec) {
                  spec = angular.extend({}, spec, {db: databaseName, doc: id});
                  $log.debug("Asking Couchbase Lite for document with id [" + id + "] in database [" + databaseName + "]");
                  return openResource(resourceString, spec).then(function (document) {
                    return document.get().$promise;
                  }, function (error) {
                    $log.error("Failed to load document '" + id + "': " + JSON.stringify(error));
                    throw error;
                  });
                },

                save: function (content, revision) {
                  validateDocument(content);

                  if (revision != null && angular.isDefined(revision)) {
                    content._rev = revision
                  }

                  if (/*!isLocalDocument && */!angular.isDefined(id)) {
                    // If no id has been provided, then see if we can pull one from the document
                    id = content._id;
                    if (id === null || !angular.isDefined(id)) {
                      $log.debug("Asking Couchbase Lite to save document with a database-generated id in database [" + databaseName + "]");
                      return openResource(':db', {db: databaseName}).then(function (database) {
                        var promise = database.post(content).$promise;
                        return promise.then(function (response) {
                          // Update our cached id with the one returned in the response
                          id = response.id;
                          return promise;
                        });
                      });
                    }
                  }

                  $log.debug("Asking Couchbase Lite to save document with id [" + id + "] in database [" + databaseName + "]");
                  $log.debug(JSON.stringify(content));
                  return openResource(resourceString, {db: databaseName, doc: id}).then(function (document) {
                    return document.put(content).$promise;
                  });
                }
              };
            },

            // Replication and sync
            replicateTo: function (spec) {
              spec = toReplicationSpec(spec);
              return openReplication.then(function (replication) {
                var request = {
                  source: databaseName,
                  target: spec.url,
                  continuous: spec.continuous,
                  headers: spec.headers
                };
                $log.debug('Couchbase Lite requesting replication: ' + JSON.stringify(request));
                return replication.post(request).$promise;
              });
            },

            replicateFrom: function (spec) {
              spec = toReplicationSpec(spec);
              return openReplication.then(function (replication) {
                var request = {
                  source: spec.url,
                  target: databaseName,
                  continuous: spec.continuous,
                  headers: spec.headers
                };
                $log.debug('Couchbase Lite requesting replication: ' + JSON.stringify(request));
                return replication.post(request).$promise;
              });
            },

            syncWith: function (spec) {
              var that = this,
                sync = $q.defer(),
                combinedResponse = {};

              that.replicateTo(spec).then(
                function (localToRemoteResponse) {
                  combinedResponse.localToRemote = localToRemoteResponse;

                  return that.replicateFrom(spec).then(
                    function (remoteToLocalResponse) {
                      $log.error('Couchbase Lite replication request failed: ' + JSON.stringify(remoteToLocalResponse));
                      combinedResponse.remoteToLocal = remoteToLocalResponse;
                      sync.resolve(combinedResponse);
                    },
                    function (remoteToLocalError) {
                      combinedResponse.remoteToLocal = remoteToLocalError;
                      sync.reject(combinedResponse);
                    }
                  );
                },
                function (localToRemoteError) {
                  $log.error('Couchbase Lite replication request failed: ' + JSON.stringify(localToRemoteError));
                  combinedResponse.localToRemote = localToRemoteError;
                  sync.reject(combinedResponse);
                }
              );

              return sync.promise;
            }
          };
        }
      };
    });
}());
<|endoftext|>


<commit_before>//
//  attachmentItemScript.js
//
//  This script is a simplified version of the original attachmentItemScript.js
//  Copyright 2017 High Fidelity, Inc.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
    var shared = Script.require('./attachmentZoneShared.js');

    var GRAB_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound1.wav'));
    var ATTACH_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound2.wav'));
    var DETACH_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound7.wav'));

    var LEFT_RIGHT_PLACEHOLDER = '[LR]';
    var ATTACH_DISTANCE = 0.35;
    var RELEASE_LIFETIME = 10;

    var TRIGGER_INTENSITY = 1.0;
    var TRIGGER_TIME = 0.2;

    var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}";

    var MESSAGE_CHANNEL_BASE = "AvatarStoreObject";
    var messageChannel;

    var _entityID;
    var _attachmentData;
    var _supportedJoints = [];
    var isAttached;

    var firstGrab = true;

    var attachDistance = HMD.active ? (MyAvatar.getHeadPosition().y - MyAvatar.getLeftHandPosition().y) / 2 : ATTACH_DISTANCE;

    function AttachableItem() {

    }

    var attachFunction = function(){
        if (HMD.active) {
            attachDistance = (MyAvatar.getHeadPosition().y - MyAvatar.getLeftHandPosition().y)/2;
            print("Avatar Scale Changed -- new attach/detach distance: " + attachDistance);
        }
    };

    AttachableItem.prototype = {
        preload : function(entityID) {
            _entityID = entityID;
            var properties = Entities.getEntityProperties(entityID, ['parentID', 'userData']);
            var userData = JSON.parse(properties.userData);
            _attachmentData = userData.Attachment;
            var _marketplaceID = userData.marketplaceID;

            if (_attachmentData.joint.indexOf(LEFT_RIGHT_PLACEHOLDER) !== -1) {
                var baseJoint = _attachmentData.joint.substring(4);
                _supportedJoints.push("Left".concat(baseJoint));
                _supportedJoints.push("Right".concat(baseJoint));
            } else {
                _supportedJoints.push(_attachmentData.joint);
            }

            isAttached = _attachmentData.attached;

            if (Entities.getNestableType(properties.parentID) !== "avatar" && !isAttached) {
                messageChannel = MESSAGE_CHANNEL_BASE + properties.parentID;
                Messages.subscribe(messageChannel);
            }

            Entities.editEntity(entityID, {marketplaceID: _marketplaceID});
            MyAvatar.scaleChanged.connect(attachFunction);
        },
        unload: function() {
            MyAvatar.scaleChanged.disconnect(attachFunction);
        },
        startNearGrab: function(entityID, args) {
            if (firstGrab) {
                if (!Entities.getEntityProperties(entityID, 'visible').visible) {
                    Entities.editEntity(entityID, {visible: true});
                }
                firstGrab = false;
            }
            if (GRAB_SOUND.downloaded) {
                Audio.playSound(GRAB_SOUND, {
                    position: MyAvatar.position,
                    volume: shared.AUDIO_VOLUME_LEVEL,
                    localOnly: true
                });
            }
            if (Entities.getEntityProperties(entityID, 'visible').visible === false) {
                Entities.editEntity(entityID, {'visible' : true});
            }
        },

        releaseGrab: function(entityID, args) {
            var hand = args[0];
            var properties = Entities.getEntityProperties(entityID, ['parentID', 'userData', 'position']);

            if (Entities.getNestableType(properties.parentID) === "entity") {
                Messages.sendMessage(messageChannel, "Removed Item :" + entityID);
                Messages.unsubscribe(messageChannel);
                Entities.editEntity(entityID, {parentID : EMPTY_PARENT_ID});
            }

            var userData = properties.userData;
            var position = properties.position;
            var attachmentData = JSON.parse(userData).Attachment;
            isAttached = attachmentData.attached;
            if (isAttached) {
                var jointPosition = (properties.parentID === MyAvatar.sessionUUID) ?
                    MyAvatar.getJointPosition(properties.parentJointIndex) :
                    AvatarList.getAvatar(properties.parentID).getJointPosition(properties.parentJointIndex);
                if (Vec3.distance(position, jointPosition) > attachDistance) {
                    var newDetachEntityProperties = Entities.getEntityProperties(entityID);
                    shared.touchJSONUserData(newDetachEntityProperties, function(userData) {
                        userData.Attachment.attached = false;
                    });
                    Entities.editEntity(_entityID, {
                        parentID: EMPTY_PARENT_ID,
                        lifetime: Entities.getEntityProperties(_entityID, 'age').age + RELEASE_LIFETIME,
                        userData: newDetachEntityProperties.userData
                    });
                    if (DETACH_SOUND.downloaded) {
                        Audio.playSound(DETACH_SOUND, {
                            position: MyAvatar.position,
                            volume: shared.AUDIO_VOLUME_LEVEL,
                            localOnly: true
                        });
                    }
                    Controller.triggerHapticPulse(TRIGGER_INTENSITY, TRIGGER_TIME, hand);
                    isAttached = false;
                }
            } else if (!isAttached) {
                _supportedJoints.forEach(function(joint) {
                    var jointPosition = MyAvatar.getJointPosition(joint);
                    if (Vec3.distance(position, jointPosition) <= attachDistance) {
                        // Check that we are not holding onto an arm attachment in a hand
                        if (joint.toLowerCase().indexOf(hand) !== -1) {
                            return;
                        }
                        var newEntityProperties = Entities.getEntityProperties(_entityID, 'userData');
                        shared.touchJSONUserData(newEntityProperties, function(userData) {
                            userData.Attachment.attached = true;
                        });
                        Entities.editEntity(_entityID, {
                            parentID: MyAvatar.sessionUUID,
                            parentJointIndex: MyAvatar.getJointIndex(joint),
                            userData: newEntityProperties.userData,
                            lifetime: -1
                        });
                        if (ATTACH_SOUND.downloaded) {
                            Audio.playSound(ATTACH_SOUND, {
                                position: MyAvatar.position,
                                volume: shared.AUDIO_VOLUME_LEVEL,
                                localOnly: true
                            });
                        }
                        isAttached = true;
                        Controller.triggerHapticPulse(TRIGGER_INTENSITY, TRIGGER_TIME, hand);
                    }
                });
            }
        }
    };
    return new AttachableItem();
});
<commit_msg>remove extra print statement<commit_after>//
//  attachmentItemScript.js
//
//  This script is a simplified version of the original attachmentItemScript.js
//  Copyright 2017 High Fidelity, Inc.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
    var shared = Script.require('./attachmentZoneShared.js');

    var GRAB_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound1.wav'));
    var ATTACH_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound2.wav'));
    var DETACH_SOUND = SoundCache.getSound(Script.resolvePath('sounds/sound7.wav'));

    var LEFT_RIGHT_PLACEHOLDER = '[LR]';
    var ATTACH_DISTANCE = 0.35;
    var RELEASE_LIFETIME = 10;

    var TRIGGER_INTENSITY = 1.0;
    var TRIGGER_TIME = 0.2;

    var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}";

    var MESSAGE_CHANNEL_BASE = "AvatarStoreObject";
    var messageChannel;

    var _entityID;
    var _attachmentData;
    var _supportedJoints = [];
    var isAttached;

    var firstGrab = true;

    var attachDistance = HMD.active ? (MyAvatar.getHeadPosition().y - MyAvatar.getLeftHandPosition().y) / 2 : ATTACH_DISTANCE;

    function AttachableItem() {

    }

    var attachFunction = function(){
        if (HMD.active) {
            attachDistance = (MyAvatar.getHeadPosition().y - MyAvatar.getLeftHandPosition().y)/2;
        }
    };

    AttachableItem.prototype = {
        preload : function(entityID) {
            _entityID = entityID;
            var properties = Entities.getEntityProperties(entityID, ['parentID', 'userData']);
            var userData = JSON.parse(properties.userData);
            _attachmentData = userData.Attachment;
            var _marketplaceID = userData.marketplaceID;

            if (_attachmentData.joint.indexOf(LEFT_RIGHT_PLACEHOLDER) !== -1) {
                var baseJoint = _attachmentData.joint.substring(4);
                _supportedJoints.push("Left".concat(baseJoint));
                _supportedJoints.push("Right".concat(baseJoint));
            } else {
                _supportedJoints.push(_attachmentData.joint);
            }

            isAttached = _attachmentData.attached;

            if (Entities.getNestableType(properties.parentID) !== "avatar" && !isAttached) {
                messageChannel = MESSAGE_CHANNEL_BASE + properties.parentID;
                Messages.subscribe(messageChannel);
            }

            Entities.editEntity(entityID, {marketplaceID: _marketplaceID});
            MyAvatar.scaleChanged.connect(attachFunction);
        },
        unload: function() {
            MyAvatar.scaleChanged.disconnect(attachFunction);
        },
        startNearGrab: function(entityID, args) {
            if (firstGrab) {
                if (!Entities.getEntityProperties(entityID, 'visible').visible) {
                    Entities.editEntity(entityID, {visible: true});
                }
                firstGrab = false;
            }
            if (GRAB_SOUND.downloaded) {
                Audio.playSound(GRAB_SOUND, {
                    position: MyAvatar.position,
                    volume: shared.AUDIO_VOLUME_LEVEL,
                    localOnly: true
                });
            }
            if (Entities.getEntityProperties(entityID, 'visible').visible === false) {
                Entities.editEntity(entityID, {'visible' : true});
            }
        },

        releaseGrab: function(entityID, args) {
            var hand = args[0];
            var properties = Entities.getEntityProperties(entityID, ['parentID', 'userData', 'position']);

            if (Entities.getNestableType(properties.parentID) === "entity") {
                Messages.sendMessage(messageChannel, "Removed Item :" + entityID);
                Messages.unsubscribe(messageChannel);
                Entities.editEntity(entityID, {parentID : EMPTY_PARENT_ID});
            }

            var userData = properties.userData;
            var position = properties.position;
            var attachmentData = JSON.parse(userData).Attachment;
            isAttached = attachmentData.attached;
            if (isAttached) {
                var jointPosition = (properties.parentID === MyAvatar.sessionUUID) ?
                    MyAvatar.getJointPosition(properties.parentJointIndex) :
                    AvatarList.getAvatar(properties.parentID).getJointPosition(properties.parentJointIndex);
                if (Vec3.distance(position, jointPosition) > attachDistance) {
                    var newDetachEntityProperties = Entities.getEntityProperties(entityID);
                    shared.touchJSONUserData(newDetachEntityProperties, function(userData) {
                        userData.Attachment.attached = false;
                    });
                    Entities.editEntity(_entityID, {
                        parentID: EMPTY_PARENT_ID,
                        lifetime: Entities.getEntityProperties(_entityID, 'age').age + RELEASE_LIFETIME,
                        userData: newDetachEntityProperties.userData
                    });
                    if (DETACH_SOUND.downloaded) {
                        Audio.playSound(DETACH_SOUND, {
                            position: MyAvatar.position,
                            volume: shared.AUDIO_VOLUME_LEVEL,
                            localOnly: true
                        });
                    }
                    Controller.triggerHapticPulse(TRIGGER_INTENSITY, TRIGGER_TIME, hand);
                    isAttached = false;
                }
            } else if (!isAttached) {
                _supportedJoints.forEach(function(joint) {
                    var jointPosition = MyAvatar.getJointPosition(joint);
                    if (Vec3.distance(position, jointPosition) <= attachDistance) {
                        // Check that we are not holding onto an arm attachment in a hand
                        if (joint.toLowerCase().indexOf(hand) !== -1) {
                            return;
                        }
                        var newEntityProperties = Entities.getEntityProperties(_entityID, 'userData');
                        shared.touchJSONUserData(newEntityProperties, function(userData) {
                            userData.Attachment.attached = true;
                        });
                        Entities.editEntity(_entityID, {
                            parentID: MyAvatar.sessionUUID,
                            parentJointIndex: MyAvatar.getJointIndex(joint),
                            userData: newEntityProperties.userData,
                            lifetime: -1
                        });
                        if (ATTACH_SOUND.downloaded) {
                            Audio.playSound(ATTACH_SOUND, {
                                position: MyAvatar.position,
                                volume: shared.AUDIO_VOLUME_LEVEL,
                                localOnly: true
                            });
                        }
                        isAttached = true;
                        Controller.triggerHapticPulse(TRIGGER_INTENSITY, TRIGGER_TIME, hand);
                    }
                });
            }
        }
    };
    return new AttachableItem();
});
<|endoftext|>


<commit_before>//
// raffleWheel.js
//
// Created by Rebecca Stankus on 07/05/2018
// Copyright High Fidelity 2018
//
// Licensed under the Apache 2.0 License
// See accompanying license file or http://apache.org/
//
/* global Avatar, AccountServices */

(function() {
    var ANGULAR_VELOCITY = {
        x: 10,
        y: 0,
        z: 0
    };
    var ANGULAR_VELOCITY_CHECK_MS = 50;
    var ANGULAR_VELOCITY_DECREMENT = 0.09;
    var CHECKING_INTERVAL_DELAY = 100;
    var USERS_ALLOWED_TO_SPIN_WHEEL = ['philip', 'ryan', 'Becky', 'MissLiviRose', 'Firebird25', 'Alan_'];
    var MAX_CHAR_PER_LINE = 9;
    var CUT_OFF_1 = 13;
    var CUT_OFF_2 = 18;
    var CUT_OFF_3 = 24;
    var CUT_OFF_4 = 32;
    var LINE_HEIGHT_1 =0.21;
    var LINE_HEIGHT_2 =0.15;
    var LINE_HEIGHT_3 =0.115;
    var LINE_HEIGHT_4 =0.075;
    var DEFAULT_LINE_HEIGHT = 0.3;

    var _this;

    function shuffle(array) {
        var currentIndex = array.length, temporaryValue, randomIndex;

        while (0 !== currentIndex) {
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
        }
        return array;
    }

    var Wheel = function() {
        _this = this;
    };

    Wheel.prototype = {
        interval: null,
        angularVelocityLimit: 10,
        nameText: null,
        avatarList: [],
        usernameList: [],
        listCounter: 0,

        preload: function(entityID) {
            _this.entityID = entityID;
            Users.usernameFromIDReply.connect(_this.usernameFromIDReply);
        },

        mousePressOnEntity: function(entityID, mouseEvent) {
            if (!mouseEvent.button === "Primary") {
                return;
            }
            var position = Entities.getEntityProperties(_this.entityID, 'position').position;
            var winnerTextEntitiesArray = Entities.findEntitiesByName("Raffle Wheel Winner", position, 1);
            print(JSON.stringify(winnerTextEntitiesArray));
            _this.usernameList = [];
            if (USERS_ALLOWED_TO_SPIN_WHEEL.indexOf(AccountServices.username) >= 0) {
                _this.angularVelocityLimit = 10;
                _this.avatarList = AvatarList.getAvatarIdentifiers();
                _this.avatarList.forEach(function(id) {
                    Users.requestUsernameFromID(id);
                });
                Entities.editEntity(_this.entityID, {
                    angularVelocity: ANGULAR_VELOCITY
                });
                Script.setTimeout(function() {
                    if (_this.interval) {
                        Script.clearInterval(_this.interval);
                    }
                    _this.interval = Script.setInterval(function() {
                        var lineHeight;
                        shuffle(_this.usernameList);
                        var currentAngularVelocity = Entities.getEntityProperties(
                            _this.entityID, 'angularVelocity').angularVelocity;
                        if (currentAngularVelocity.x <= _this.angularVelocityLimit && currentAngularVelocity.x > 0) {
                            var winner = _this.usernameList[_this.listCounter];
                            if (winner.length <= MAX_CHAR_PER_LINE) {
                                lineHeight = DEFAULT_LINE_HEIGHT;
                            } else if (winner.length <= CUT_OFF_1) {
                                lineHeight = LINE_HEIGHT_1;
                            } else if (winner.length <= CUT_OFF_2) {
                                lineHeight = LINE_HEIGHT_2;
                            } else if (winner.length <= CUT_OFF_3) {
                                lineHeight = LINE_HEIGHT_3;
                            } else if (winner.length <= CUT_OFF_4) {
                                lineHeight = LINE_HEIGHT_4;
                            } else {
                                winner = winner.slice(0, CUT_OFF_4 + 1);
                            }
                            Entities.editEntity(winnerTextEntitiesArray[0], {
                                lineHeight: lineHeight,
                                text: winner
                            });
                            _this.listCounter += 1;
                            _this.listCounter = _this.listCounter >= _this.usernameList.length ? 0 : _this.listCounter;
                            _this.angularVelocityLimit -= ANGULAR_VELOCITY_DECREMENT;
                        } else if (currentAngularVelocity.x === 0) {
                            if (_this.interval) {
                                // this print is purposely left as a backup way to see winner via logs
                                print("-------------RAFFLE WINNER IS: ", winner);
                                Script.clearInterval(_this.interval);
                            }
                        }
                    }, ANGULAR_VELOCITY_CHECK_MS);
                }, CHECKING_INTERVAL_DELAY);
            }
        },

        usernameFromIDReply: function(nodeID, userName, machineFingerprint, isAdmin) {
            _this.usernameList.push(userName);
        },

        unload: function(entityID) {
            if (_this.interval) {
                Script.clearInterval(_this.interval);
            }
        }
    };

    return new Wheel();
});
<commit_msg>Raffle Wheel...fixed error in printing winner<commit_after>//
// raffleWheel.js
//
// Created by Rebecca Stankus on 07/05/2018
// Copyright High Fidelity 2018
//
// Licensed under the Apache 2.0 License
// See accompanying license file or http://apache.org/
//
/* global Avatar, AccountServices */

(function() {
    var ANGULAR_VELOCITY = {
        x: 10,
        y: 0,
        z: 0
    };
    var ANGULAR_VELOCITY_CHECK_MS = 50;
    var ANGULAR_VELOCITY_DECREMENT = 0.09;
    var CHECKING_INTERVAL_DELAY = 100;
    var USERS_ALLOWED_TO_SPIN_WHEEL = ['philip', 'ryan', 'Becky', 'MissLiviRose', 'Firebird25', 'Alan_'];
    var MAX_CHAR_PER_LINE = 9;
    var CUT_OFF_1 = 13;
    var CUT_OFF_2 = 18;
    var CUT_OFF_3 = 24;
    var CUT_OFF_4 = 32;
    var LINE_HEIGHT_1 =0.21;
    var LINE_HEIGHT_2 =0.15;
    var LINE_HEIGHT_3 =0.115;
    var LINE_HEIGHT_4 =0.075;
    var DEFAULT_LINE_HEIGHT = 0.3;

    var _this;

    function shuffle(array) {
        var currentIndex = array.length, temporaryValue, randomIndex;

        while (0 !== currentIndex) {
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
        }
        return array;
    }

    var Wheel = function() {
        _this = this;
    };

    Wheel.prototype = {
        interval: null,
        angularVelocityLimit: 10,
        nameText: null,
        avatarList: [],
        usernameList: [],
        listCounter: 0,

        preload: function(entityID) {
            _this.entityID = entityID;
            Users.usernameFromIDReply.connect(_this.usernameFromIDReply);
        },

        mousePressOnEntity: function(entityID, mouseEvent) {
            if (!mouseEvent.button === "Primary") {
                return;
            }
            var position = Entities.getEntityProperties(_this.entityID, 'position').position;
            var winnerTextEntitiesArray = Entities.findEntitiesByName("Raffle Wheel Winner", position, 1);
            _this.usernameList = [];
            if (USERS_ALLOWED_TO_SPIN_WHEEL.indexOf(AccountServices.username) >= 0) {
                _this.angularVelocityLimit = 10;
                _this.avatarList = AvatarList.getAvatarIdentifiers();
                _this.avatarList.forEach(function(id) {
                    Users.requestUsernameFromID(id);
                });
                Entities.editEntity(_this.entityID, {
                    angularVelocity: ANGULAR_VELOCITY
                });
                Script.setTimeout(function() {
                    if (_this.interval) {
                        Script.clearInterval(_this.interval);
                    }
                    var winner;
                    _this.interval = Script.setInterval(function() {
                        var lineHeight;
                        shuffle(_this.usernameList);
                        var currentAngularVelocity = Entities.getEntityProperties(
                            _this.entityID, 'angularVelocity').angularVelocity;
                        if (currentAngularVelocity.x <= _this.angularVelocityLimit && currentAngularVelocity.x > 0) {
                            winner = _this.usernameList[_this.listCounter];
                            if (winner.length <= MAX_CHAR_PER_LINE) {
                                lineHeight = DEFAULT_LINE_HEIGHT;
                            } else if (winner.length <= CUT_OFF_1) {
                                lineHeight = LINE_HEIGHT_1;
                            } else if (winner.length <= CUT_OFF_2) {
                                lineHeight = LINE_HEIGHT_2;
                            } else if (winner.length <= CUT_OFF_3) {
                                lineHeight = LINE_HEIGHT_3;
                            } else if (winner.length <= CUT_OFF_4) {
                                lineHeight = LINE_HEIGHT_4;
                            } else {
                                winner = winner.slice(0, CUT_OFF_4 + 1);
                            }
                            Entities.editEntity(winnerTextEntitiesArray[0], {
                                lineHeight: lineHeight,
                                text: winner
                            });
                            _this.listCounter += 1;
                            _this.listCounter = _this.listCounter >= _this.usernameList.length ? 0 : _this.listCounter;
                            _this.angularVelocityLimit -= ANGULAR_VELOCITY_DECREMENT;
                        } else if (currentAngularVelocity.x === 0) {
                            if (_this.interval) {
                                // this print is purposely left as a backup way to see winner via logs
                                print("-------------RAFFLE WINNER IS: ", winner);
                                Script.clearInterval(_this.interval);
                            }
                        }
                    }, ANGULAR_VELOCITY_CHECK_MS);
                }, CHECKING_INTERVAL_DELAY);
            }
        },

        usernameFromIDReply: function(nodeID, userName, machineFingerprint, isAdmin) {
            _this.usernameList.push(userName);
        },

        unload: function(entityID) {
            if (_this.interval) {
                Script.clearInterval(_this.interval);
            }
        }
    };

    return new Wheel();
});
<|endoftext|>


<commit_before>Backbone.Syphon = (function(Backbone, $, _){
  var Syphon = {};

  // Ignore Element Types
  // --------------------

  // Tell Syphon to ignore all elements of these types. You can
  // push new types to ignore directly in to this array.
  Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"];

  // Syphon
  // ------

  // Get a JSON object that represents
  // all of the form inputs, in this view
  Syphon.serialize = function(view, options){
    var data = {};

    // Build the configuration
    var config = buildConfig(options);

    // Get all of the elements to process
    var elements = getInputElements(view, config);

    // Process all of the elements
    _.each(elements, function(el){
      var $el = $(el);
      var type = getElementType($el);

      // Get the key for the input
      var keyExtractor = config.keyExtractors.get(type);
      var key = keyExtractor($el);

      // Get the value for the input
      var inputReader = config.inputReaders.get(type);
      var value = inputReader($el);

      // Get the key assignment validator and make sure
      // it's valid before assigning the value to the key
      var validKeyAssignment = config.keyAssignmentValidators.get(type);
      if (validKeyAssignment($el, key, value)){
        var keychain = config.keySplitter(key);
        data = assignKeyValue(data, keychain, value);
      }
    });

    // Done; send back the results.
    return data;
  };

  // Use the given JSON object to populate
  // all of the form inputs, in this view
  Syphon.deserialize = function(view, data, options){
    // Build the configuration
    var config = buildConfig(options);

    // Get all of the elements to process
    var elements = getInputElements(view, config);

    // Process all of the elements
    _.each(elements, function(el){
      var $el = $(el);
      var type = getElementType($el);

      // Get the key for the input
      var keyExtractor = config.keyExtractors.get(type);
      var key = keyExtractor($el);

      // Write value to input
      var inputWriter = config.inputWriters.get(type);
      inputWriter($el, data[key]);
    });
  };

  // Helpers
  // -------

  // Retrieve all of the form inputs
  // from the view
  var getInputElements = function(view, config){
    var form = view.$el.is("form") ? view.el : view.$("form")[0];
    var elements = form.elements;

    elements = _.reject(elements, function(el){
      var reject;
      var type = getElementType(el);
      var extractor = config.keyExtractors.get(type);
      var identifier = extractor($(el));

      var foundInIgnored = _.include(config.ignoredTypes, type);
      var foundInInclude = _.include(config.include, identifier);
      var foundInExclude = _.include(config.exclude, identifier);

      if (foundInInclude){
        reject = false;
      } else {
        if (config.include){
          reject = true;
        } else {
          reject = (foundInExclude || foundInIgnored);
        }
      }

      return reject;
    });

    return elements;
  };

  // Determine what type of element this is. It
  // will either return the `type` attribute of
  // an `<input>` element, or the `tagName` of
  // the element when the element is not an `<input>`.
  var getElementType = function(el){
    var typeAttr;
    var $el = $(el);
    var tagName = $el[0].tagName;
    var type = tagName;

    if (tagName.toLowerCase() === "input"){
      typeAttr = $el.attr("type");
      if (typeAttr){
        type = typeAttr;
      } else {
        type = "text";
      }
    }

    // Always return the type as lowercase
    // so it can be matched to lowercase
    // type registrations.
    return type.toLowerCase();
  };

  // Build a configuration object and initialize
  // default values.
  var buildConfig = function(options){
    var config = _.clone(options) || {};

    config.ignoredTypes = _.clone(Syphon.ignoredTypes);
    config.inputReaders = config.inputReaders || Syphon.InputReaders;
    config.inputWriters = config.inputWriters || Syphon.InputWriters;
    config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors;
    config.keySplitter = config.keySplitter || Syphon.KeySplitter;
    config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators;

    return config;
  };

  // Assigns `value` to a parsed JSON key.
  var assignKeyValue = function(obj, keychain, value) {
    var currentObj = obj;
    var keyLength = keychain.length-1;

    // Loop through each part of the key chain
    for(var i=0; i<=keyLength; i++){
      // get the current key
      var key = keychain[i];

      if (!currentObj[key]){
        currentObj[key] = _.isArray(key) ? [] : {};
      }

      if (i === keyLength){

        // if it's the last key in the chain, assign the value directly
        if (_.isArray(currentObj[key])){
          currentObj[key].push(value);
        } else {
          currentObj[key] = value;
        }

      }

      currentObj = currentObj[key];
    }

    return obj;
  };

  return Syphon;
})(Backbone, jQuery, _);

//= backbone.syphon.typeregistry.js

//= backbone.syphon.keyextractors.js

//= backbone.syphon.inputreaders.js

//= backbone.syphon.inputwriters.js

//= backbone.syphon.keyassignmentvalidators.js

//= backbone.syphon.keysplitter.js
<commit_msg>changed assign key value to recursive method instead of loop. not sure this bought anything, though<commit_after>Backbone.Syphon = (function(Backbone, $, _){
  var Syphon = {};

  // Ignore Element Types
  // --------------------

  // Tell Syphon to ignore all elements of these types. You can
  // push new types to ignore directly in to this array.
  Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"];

  // Syphon
  // ------

  // Get a JSON object that represents
  // all of the form inputs, in this view
  Syphon.serialize = function(view, options){
    var data = {};

    // Build the configuration
    var config = buildConfig(options);

    // Get all of the elements to process
    var elements = getInputElements(view, config);

    // Process all of the elements
    _.each(elements, function(el){
      var $el = $(el);
      var type = getElementType($el);

      // Get the key for the input
      var keyExtractor = config.keyExtractors.get(type);
      var key = keyExtractor($el);

      // Get the value for the input
      var inputReader = config.inputReaders.get(type);
      var value = inputReader($el);

      // Get the key assignment validator and make sure
      // it's valid before assigning the value to the key
      var validKeyAssignment = config.keyAssignmentValidators.get(type);
      if (validKeyAssignment($el, key, value)){
        var keychain = config.keySplitter(key);
        data = assignKeyValue(data, keychain, value);
      }
    });

    // Done; send back the results.
    return data;
  };

  // Use the given JSON object to populate
  // all of the form inputs, in this view
  Syphon.deserialize = function(view, data, options){
    // Build the configuration
    var config = buildConfig(options);

    // Get all of the elements to process
    var elements = getInputElements(view, config);

    // Process all of the elements
    _.each(elements, function(el){
      var $el = $(el);
      var type = getElementType($el);

      // Get the key for the input
      var keyExtractor = config.keyExtractors.get(type);
      var key = keyExtractor($el);

      // Write value to input
      var inputWriter = config.inputWriters.get(type);
      inputWriter($el, data[key]);
    });
  };

  // Helpers
  // -------

  // Retrieve all of the form inputs
  // from the view
  var getInputElements = function(view, config){
    var form = view.$el.is("form") ? view.el : view.$("form")[0];
    var elements = form.elements;

    elements = _.reject(elements, function(el){
      var reject;
      var type = getElementType(el);
      var extractor = config.keyExtractors.get(type);
      var identifier = extractor($(el));

      var foundInIgnored = _.include(config.ignoredTypes, type);
      var foundInInclude = _.include(config.include, identifier);
      var foundInExclude = _.include(config.exclude, identifier);

      if (foundInInclude){
        reject = false;
      } else {
        if (config.include){
          reject = true;
        } else {
          reject = (foundInExclude || foundInIgnored);
        }
      }

      return reject;
    });

    return elements;
  };

  // Determine what type of element this is. It
  // will either return the `type` attribute of
  // an `<input>` element, or the `tagName` of
  // the element when the element is not an `<input>`.
  var getElementType = function(el){
    var typeAttr;
    var $el = $(el);
    var tagName = $el[0].tagName;
    var type = tagName;

    if (tagName.toLowerCase() === "input"){
      typeAttr = $el.attr("type");
      if (typeAttr){
        type = typeAttr;
      } else {
        type = "text";
      }
    }

    // Always return the type as lowercase
    // so it can be matched to lowercase
    // type registrations.
    return type.toLowerCase();
  };

  // Build a configuration object and initialize
  // default values.
  var buildConfig = function(options){
    var config = _.clone(options) || {};

    config.ignoredTypes = _.clone(Syphon.ignoredTypes);
    config.inputReaders = config.inputReaders || Syphon.InputReaders;
    config.inputWriters = config.inputWriters || Syphon.InputWriters;
    config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors;
    config.keySplitter = config.keySplitter || Syphon.KeySplitter;
    config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators;

    return config;
  };

  // Assigns `value` to a parsed JSON key.
  var assignKeyValue = function(obj, keychain, value) {
    var currentObj = obj;
    var keyLength = keychain.length-1;
    var key = keychain.shift();

    // build the current object we need to store data
    if (!currentObj[key]){
      currentObj[key] = _.isArray(key) ? [] : {};
    }

    if (keychain.length === 0){

      // if it's the last key in the chain, assign the value directly
      if (_.isArray(currentObj[key])){
        currentObj[key].push(value);
      } else {
        currentObj[key] = value;
      }

    } else {
      // recursive parsing of the array
      assignKeyValue(currentObj[key], keychain, value);
    }

    return obj;
  };

  return Syphon;
})(Backbone, jQuery, _);

//= backbone.syphon.typeregistry.js

//= backbone.syphon.keyextractors.js

//= backbone.syphon.inputreaders.js

//= backbone.syphon.inputwriters.js

//= backbone.syphon.keyassignmentvalidators.js

//= backbone.syphon.keysplitter.js
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');

var harvester = function(dirname, callback) {

  var walk = function(dir, done) {
    var results = [];
    fs.readdir(dir, function(err, list) {
      if (err) return done(err);
      var i = 0;
      (function next() {
        var file = list[i++];
        if (!file) return done(null, results);
        file = dir + '/' + file;
        fs.stat(file, function(err, stat) {
          if (stat && stat.isDirectory()) {
            walk(file, function(err, res) {
              results = results.concat(res);
              next();
            });
          } else {
            results.push(file);
            next();
          }
        });
      })();
    });
  };

  var foundItems = {};
  var foundItemsCount = 0;

  var parseFile = function(filename)
  {
    var regex = /\{t\}([^\{]+)\{\/t\}/g;
    var data = ""+fs.readFileSync(filename, 'utf8');
    var matches = data.match(regex);

    if (matches != null)
    matches.forEach(function(match){
      var string = '';
      if (match.length > 7)
        string = match.substr(3, match.length-7);
      else
        return false;

      if (typeof(foundItems[string]) == 'undefined')
      {
        foundItems[string] = '';
        foundItemsCount++;
      }
    });
  }

  var parseHTMLFile = function(filename)
  {
    var regex = /data-i18n="([^"]+)"/g;
    var data = ""+fs.readFileSync(filename, 'utf8');
    var matches = data.match(regex);

    if (matches != null)
    matches.forEach(function(match){
      var string = '';
      if (match.length > 7)
        string = match.substr(("data-i18n=\"").length, match.length-("data-i18n=\"").length-1);
      else
        return false;

      if (typeof(foundItems[string]) == 'undefined')
      {
        foundItems[string] = '';
        foundItemsCount++;
      }
    });
  }

  walk(dirname, function(err, results){

    console.log('Found '+results.length+' template files');
    if (err) throw err;
    results.forEach(function(file) {
      if (file.slice(-4) === '.tpl')
        parseFile(file);
      if (file.slice(-5) === '.html' || file.slice(-4) === '.htm')
        parseHTMLFile(file);
    });

    console.log('Found '+foundItemsCount+' i18n strings');

    callback(Object.keys(foundItems));
  });

}

var dirname = path.join(__dirname, '..', 'public');
var i18n_dirname = path.join(__dirname, '..', 'data/i18n');
harvester(dirname, function(strings){
console.log(strings);
  var i18n_files = fs.readdirSync(i18n_dirname);
  i18n_files.filter(function(file){
    if (file.slice(-5) !== '.json')
      return false;
    else
      return true;
  });

  var updatei18n = function(i18n_file, strings)
  {
    var data = {};
    try {
      data = JSON.parse(""+fs.readFileSync(path.join(i18n_dirname, i18n_file), 'utf8'));
    } catch(e) {

    }

    var newStringsCount = 0;

    strings.forEach(function(string){
      if (typeof(data[string]) == 'undefined'){
        data[string] = '';
        newStringsCount++;
      }
    });

    fs.writeFileSync(path.join(i18n_dirname, i18n_file), JSON.stringify(data, null, 2));

    console.log('Updated. Added '+newStringsCount+' new strings.');
  }

  console.log("There're "+i18n_files.length+' i18n files');
  console.log(i18n_files);
  console.log(strings);

  i18n_files.forEach(function(i18n_file){
    console.log('Updating '+i18n_file);
    updatei18n(i18n_file, strings);
  });

  console.log('Done');

});
<commit_msg>i18n parser<commit_after>var fs = require('fs');
var path = require('path');

var harvester = function(dirname, callback) {

  var walk = function(dir, done) {
    var results = [];
    fs.readdir(dir, function(err, list) {
      if (err) return done(err);
      var i = 0;
      (function next() {
        var file = list[i++];
        if (!file) return done(null, results);
        file = dir + '/' + file;
        fs.stat(file, function(err, stat) {
          if (stat && stat.isDirectory()) {
            walk(file, function(err, res) {
              results = results.concat(res);
              next();
            });
          } else {
            results.push(file);
            next();
          }
        });
      })();
    });
  };

  var foundItems = {};
  var foundItemsCount = 0;

  var parseFile = function(filename, transalateTag)
  {
    var transalateTag = transalateTag || 't';
    var regex = new RegExp("\{"+transalateTag+"\}([^\{]+)\{\/"+transalateTag+"\}", 'g');
    var data = ""+fs.readFileSync(filename, 'utf8');
    var matches = data.match(regex);

    var openingTagLength = ('{'+transalateTag+'}').length;
    var closingTag = '{/'+transalateTag+'}';
    var closingTagLength = closingTag.length;

    if (matches != null)
    matches.forEach(function(match){
      var string = '';
      if (match.length > 7)
        string = match.substr(openingTagLength, match.indexOf(closingTag)-openingTagLength);
      else
        return false;

      if (typeof(foundItems[string]) == 'undefined')
      {
        foundItems[string] = '';
        foundItemsCount++;
      }
    });
  }

  var parseHTMLFile = function(filename)
  {
    var regex = /data-i18n="([^"]+)"/g;
    var data = ""+fs.readFileSync(filename, 'utf8');
    var matches = data.match(regex);

    if (matches != null)
    matches.forEach(function(match){
      var string = '';
      if (match.length > 7)
        string = match.substr(("data-i18n=\"").length, match.length-("data-i18n=\"").length-1);
      else
        return false;

      if (typeof(foundItems[string]) == 'undefined')
      {
        foundItems[string] = '';
        foundItemsCount++;
      }
    });
  }

  walk(dirname, function(err, results){

    console.log('Found '+results.length+' files');
    if (err) throw err;

    var foundTplCount = 0;
    var foundHtmlCount = 0;
    results.forEach(function(file) {
      if (file.slice(-4) === '.tpl')
      {
        parseFile(file);
        parseFile(file, 'ts');
        foundTplCount++;
      }
      if (file.slice(-5) === '.html' || file.slice(-4) === '.htm'){
        parseHTMLFile(file);
        foundHtmlCount++;
      }
    });

    console.log('Found '+foundTplCount+' tpl files');
    console.log('Found '+foundHtmlCount+' html files');
    console.log('Found '+foundItemsCount+' i18n strings');

    callback(Object.keys(foundItems));
  });

}

var dirname = path.join(__dirname, '..', 'public');
var i18n_dirname = path.join(__dirname, '..', 'data/i18n');
harvester(dirname, function(strings){
// console.log(strings);
  var i18n_files = fs.readdirSync(i18n_dirname);
  i18n_files.filter(function(file){
    if (file.slice(-5) !== '.json')
      return false;
    else
      return true;
  });

  var updatei18n = function(i18n_file, strings)
  {
    var data = {};
    try {
      data = JSON.parse(""+fs.readFileSync(path.join(i18n_dirname, i18n_file), 'utf8'));
    } catch(e) {

    }

    var newStringsCount = 0;

    strings.forEach(function(string){
      if (typeof(data[string]) == 'undefined'){
        data[string] = '';
        newStringsCount++;
      }
    });

    fs.writeFileSync(path.join(i18n_dirname, i18n_file), JSON.stringify(data, null, 2));

    console.log('Updated. Added '+newStringsCount+' new strings.');
  }

  console.log("There're "+i18n_files.length+' i18n files');
  // console.log(i18n_files);
  // console.log(strings);

  i18n_files.forEach(function(i18n_file){
    console.log('Updating '+i18n_file);
    updatei18n(i18n_file, strings);
  });

  console.log('Done');

});
<|endoftext|>


<commit_before>import {storage, message} from 'src/helpers/chrome-api'
import defaultConfig from 'src/app-config'

// background script as transfer station
const msgChecker = /_SELF$/
message.listen((data, sender, sendResponse) => {
  if (msgChecker.test(data.msg)) {
    data.msg = data.msg.slice(0, -5)
    message.send(sender.tab.id, data, response => {
      sendResponse(response)
    })
    return true
  }

  switch (data.msg) {
    case 'CREATE_TAB':
      chrome.tabs.create({url: data.url})
      break
    case 'AUDIO_PLAY':
      let audio = new Audio(data.src)
      let timer = setTimeout(() => {
        timer = null
        sendResponse()
      }, 4000)
      audio.addEventListener('ended', () => {
        if (timer) {
          clearTimeout(timer)
          sendResponse()
        }
      })
      audio.play()
      return true
  }
})

const _dicts = {}
// dynamic load components
const _compReq = require.context('./dicts', true, /\.js$/i)
const _idChecker = /\/(\S+)\.js$/i
_compReq.keys().forEach(path => {
  let id = _idChecker.exec(path)
  if (!id) { return }
  id = id[1].toLowerCase()
  if (!defaultConfig.dicts.all[id]) { return }

  let search = _compReq(path)
  if (typeof search !== 'function') {
    search = search.default
  }
  _dicts[id] = {
    search,
    config: JSON.parse(JSON.stringify(defaultConfig))
  }
})

function setConfigs (config) {
  Object.keys(_dicts).forEach(id => {
    _dicts[id].config = JSON.parse(JSON.stringify(defaultConfig))
  })
}

storage.sync.get('config', data => {
  if (data.config) {
    setConfigs(data.config)
  }
})

storage.listen('config', changes => {
  setConfigs(changes.config.newValue)
})

message.on('FETCH_DICT_RESULT', (data, sender, sendResponse) => {
  let dict = _dicts[data.dict]
  if (!dict) {
    sendResponse({error: 'Missing Dictionary!'})
    return
  }

  function handleSuccess (result) {
    sendResponse({result, dict: data.dict})
  }

  function handleError (error) {
    sendResponse({error, dict: data.dict})
  }

  dict.search(data.text, dict.config)
    .then(handleSuccess, handleError)
    .catch(handleError)

  // keep the channel alive
  return true
})

// merge config on installed
chrome.runtime.onInstalled.addListener(({previousVersion}) => {
  let config = defaultConfig
  let [major, minor, patch] = previousVersion.split('.').map(n => Number(n))
  if (major <= 4) {
    storage.local.clear()
    storage.sync.clear()
      .then(() => {
        storage.sync.set({config})
        setConfigs(config)
      })
  }
})
<commit_msg>Fixed config update bug<commit_after>import {storage, message} from 'src/helpers/chrome-api'
import defaultConfig from 'src/app-config'

// background script as transfer station
const msgChecker = /_SELF$/
message.listen((data, sender, sendResponse) => {
  if (msgChecker.test(data.msg)) {
    data.msg = data.msg.slice(0, -5)
    message.send(sender.tab.id, data, response => {
      sendResponse(response)
    })
    return true
  }

  switch (data.msg) {
    case 'CREATE_TAB':
      chrome.tabs.create({url: data.url})
      break
    case 'AUDIO_PLAY':
      let audio = new Audio(data.src)
      let timer = setTimeout(() => {
        timer = null
        sendResponse()
      }, 4000)
      audio.addEventListener('ended', () => {
        if (timer) {
          clearTimeout(timer)
          sendResponse()
        }
      })
      audio.play()
      return true
  }
})

const _dicts = {}
// dynamic load components
const _compReq = require.context('./dicts', true, /\.js$/i)
const _idChecker = /\/(\S+)\.js$/i
_compReq.keys().forEach(path => {
  let id = _idChecker.exec(path)
  if (!id) { return }
  id = id[1].toLowerCase()
  if (!defaultConfig.dicts.all[id]) { return }

  let search = _compReq(path)
  if (typeof search !== 'function') {
    search = search.default
  }
  _dicts[id] = {
    search,
    config: JSON.parse(JSON.stringify(defaultConfig))
  }
})

function setConfigs (config) {
  Object.keys(_dicts).forEach(id => {
    _dicts[id].config = JSON.parse(JSON.stringify(config))
  })
}

storage.sync.get('config', data => {
  if (data.config) {
    setConfigs(data.config)
  }
})

storage.listen('config', changes => {
  setConfigs(changes.config.newValue)
})

message.on('FETCH_DICT_RESULT', (data, sender, sendResponse) => {
  let dict = _dicts[data.dict]
  if (!dict) {
    sendResponse({error: 'Missing Dictionary!'})
    return
  }

  function handleSuccess (result) {
    sendResponse({result, dict: data.dict})
  }

  function handleError (error) {
    sendResponse({error, dict: data.dict})
  }

  dict.search(data.text, dict.config)
    .then(handleSuccess, handleError)
    .catch(handleError)

  // keep the channel alive
  return true
})

// merge config on installed
chrome.runtime.onInstalled.addListener(({previousVersion}) => {
  let config = defaultConfig
  let [major, minor, patch] = previousVersion.split('.').map(n => Number(n))
  if (major <= 4) {
    storage.local.clear()
    storage.sync.clear()
      .then(() => {
        storage.sync.set({config})
        setConfigs(config)
      })
  }
})
<|endoftext|>


<commit_before>'use strict';

import moduleName from '../../../../Frontend/js/app/angular/name';

describe('Controllers', function() {
  let $controller;
  let $rootScope;
  let controller = null;

  beforeEach(function() {
    angular.mock.module(moduleName);
  });

  beforeEach(inject(function(_$rootScope_, _$controller_) {
    $rootScope = _$rootScope_;
    $controller = _$controller_;
  }));

  describe('SayHelloController', function() {

    it('Controller is implemented', function() {
      controller = $controller('SayHelloController', {$scope: {catchSubmit: null, name: 'test'}});

      expect(Object.keys(controller).length).toBe(2);
    });

    it('catchSubmit() method exists and executes without errors', function() {
      let actualResult = null;
      let error = null;

      try {
        actualResult = controller.catchSubmit();
      } catch (e) {
        error = e;
      }

      expect(error).toBe(null);
      expect(actualResult).toBe(undefined);
    });
  });
});
<commit_msg>Mock async calls<commit_after>'use strict';

import moduleName from '../../../../Frontend/js/app/angular/name';

describe('Controllers', function() {
  let $controller;
  let $rootScope;
  let controller = null;

  beforeEach(function() {
    angular.mock.module(moduleName);
  });

  beforeEach(inject(function(_$rootScope_, _$controller_) {
    $rootScope = _$rootScope_;
    $controller = _$controller_;
  }));

  describe('SayHelloController', function() {
    let controllerArgs = {
      $scope: {
        catchSubmit: null,
        name: 'test',
        $digest: function() {
          return 'digested';
        },
      },
    };

    it('Controller is implemented', function() {
      controller = $controller('SayHelloController', controllerArgs);

      expect(Object.keys(controller).length).toBe(2);
    });

    it('catchSubmit() method exists and executes without errors', function() {
      let actualResult = null;
      let error = null;

      controller._helloResource = {
        request: function() {
          return {
            send: function(cb) {
              return cb({data: 'data'});
            },
          };
        },
      };

      try {
        actualResult = controller.catchSubmit();
      } catch (e) {
        error = e;
      }

      expect(error).toBe(null);
      expect(actualResult).toBe(undefined);
    });
  });
});
<|endoftext|>