<commit_before>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
'use strict';

define(['angular', 'jquery'], function(angular, $) {
  var accessDeniedTemplate=
    '
Sorry, you\'re not authorized to access this.

' +
    '
' +
    '
' +
    '
If you\'re here by accident, head back to your My-UW ' +
    'homepage.
' +
    '
For help with authorization, contact the ' +
    'DoIT Help Desk.
';

  return angular.module('my-app.layout.services', [])
    .factory('layoutService',
      ['$sce', '$http', '$log', 'miscService',
      'mainService', '$sessionStorage', '$q', 'SERVICE_LOC', 'APP_FLAGS',
      function($sce, $http, $log, miscService,
        mainService, $sessionStorage, $q, SERVICE_LOC, APP_FLAGS) {

        /************************
        * NEW LAYOUT
        * To use new service layout set useNewLayout flag in override.js to true,
        * and useOldLayout to false
        ************************/

        if (APP_FLAGS.useNewLayout) {

          var getLayout = function() {
            return checkLayoutCache().then(function(data) {
              var successFn;
              var errorFn;
              var defer;

              // first, check the local storage...
              if (data) {
                defer = $q.defer();
                defer.resolve(data);
                return defer.promise;
              }

              successFn = function(result) {
                var data = formatLayoutForCache(result.data);
                storeLayoutInCache(data);
                return data;
              };

              errorFn = function(reason) {
                miscService.redirectUser(reason.status, 'layout call');
              };
            return $http.get(
                SERVICE_LOC.newLayout)
                  .then(successFn, errorFn);
            });
          };

          var addToHome = function addToHomeFunction(portlet) {
            var fname = portlet.fname;
            return getLayout().then(function(data) {
              var newLayout = data.layout.concat(fname);
              return $http({
                method: 'POST',
                url: SERVICE_LOC.newLayout,
                data: {"layout" : newLayout, "new" : false},
                dataType: 'json',
                headers : {
                  'eppn': 'pnogal@wisc.edu',
                  'Content-Type': 'application/x-www-form-urlencoded'
                }
              });
            })
          };

          var removeFromHome = function removeFromHomeFunction(fname) {
            return getLayout().then(function(data) {
              var newLayout = data.layout.filter(val => val !== fname);
              return $http({
                  method: 'POST',
                  url: SERVICE_LOC.newLayout,
                  data: {"layout" : newLayout, "new" : false},
                  dataType: 'json',
                  headers : {
                    'eppn': 'pnogal@wisc.edu',
                    'Content-Type': 'application/x-www-form-urlencoded'
                  }
              });
            })
          };

          var moveStuff = function moveStuffFunction() {
            return getLayout().then(function(data) {
              var newLayout = data.layout;
              console.log("newLayout", newLayout);
                return $http({
                  method: 'POST',
                  url: SERVICE_LOC.newLayout,
                  data: {"layout" : newLayout, "new" : false},
                  dataType: 'json',
                  headers : {
                    'eppn': 'pnogal@wisc.edu',
                    'Content-Type': 'application/x-www-form-urlencoded'
                  }
              });
            });

          };
        }

        /************************
        ** OLD LAYOUT
        ** To use old service layout set useOldLayout flag in override.js to true,
        ** and useNewLayout to false
        *************************/

        if (APP_FLAGS.useOldLayout) {
          console.log("using old layout");

          var getLayout = function() {
            return checkLayoutCache().then(function(data) {
                var successFn;
                var errorFn;
                var defer;

                // first, check the local storage...
                if (data) {
                    defer = $q.defer();
                    defer.resolve(data);
                    return defer.promise;
                }

                successFn = function(result) {
                    var data = formatLayoutForCache(result.data);
                    storeLayoutInCache(data);
                    return data;
                };

                errorFn = function(reason) {
                    miscService.redirectUser(reason.status, 'layout call');
                };

                // no caching...  request from the server
                return $http.get(
                  SERVICE_LOC.context + SERVICE_LOC.layout, {cache: true} )
                    .then(successFn, errorFn);
            });
          };

          var addToHome = function addToHomeFunction(portlet) {
              var fname = portlet.fname;
              var tabName = SERVICE_LOC.layoutTab;
              return $.ajax({
                  url: SERVICE_LOC.base + 'layout?action=addPortlet&fname=' +
                    fname + '&tabName=' + tabName,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function(request, text) {
                      $log.log('Added ' + portlet.fname + ' successfully');
                      miscService.pushGAEvent(
                        'Layout Modification', 'Add', portlet.name);
                      return true;
                  },
                  error: function(request, text, error) {
                      $log.warn('failed to add app to home.');
                      return false;
                  },
              });
          };

          var removeFromHome = function removeFromHomeFunction(fname) {
              return $.ajax({
                  url: SERVICE_LOC.base +
                    'layout?action=removeByFName&fname=' + fname,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function(request, text) {
                      $log.log('removed ' + fname + ' successfully.');
                      miscService.pushGAEvent(
                        'Layout Modification', 'Remove', fname);
                  },
                  error: function(request, text, error) {
                  },
              });
          };

          var moveStuff = function moveStuffFunction(
                index, length, sourceId, previousNodeId, nextNodeId) {
            var insertNode = function(sourceId, previousNodeId, nextNodeId) {
              var saveOrderURL = SERVICE_LOC.base +
                  'layout?action=movePortletAjax' +
                  '&sourceId=' + sourceId +
                  '&previousNodeId=' + previousNodeId +
                  '&nextNodeId=' + nextNodeId;
              $log.log(saveOrderURL);
              $.ajax({
                  url: saveOrderURL,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function() {
                    $log.log('layout move successful.');
                  },
                  error: function(request, text, error) {
                    $log.error('Error persisting move ' + saveOrderURL);
                  },
              });
            };

            insertNode(sourceId, previousNodeId, nextNodeId);
          };
        }

        var getUncachedLayout = function() {
          console.log("in getUncachedLayout");
          var successFn = function(result) {
              var data = formatLayoutForCache(result.data);
              storeLayoutInCache(data);
              return data;
          };

          var errorFn = function(reason) {
              miscService.redirectUser(reason.status, 'layout call');
          };

          // no caching...  request from the server
          return $http.get(SERVICE_LOC.context + SERVICE_LOC.layout,
            {cache: true} )
              .then(successFn, errorFn);
        };

        var addToLayoutByFname = function addToLayoutByFname(fname) {
          var tabName = SERVICE_LOC.layoutTab;
          return $.ajax({
              url: SERVICE_LOC.base + 'layout?action=addPortlet&fname=' +
                fname + '&tabName=' + tabName,
              type: 'POST',
              data: null,
              dataType: 'json',
              async: true,
              success: function() {
                  $log.log('Added ' + fname + ' successfully');
                  miscService.pushGAEvent(
                    'Layout Modification', 'Add', fname);
                  },
              error: function() {
                  $log.warn('failed to add app to home.');
                  return false;
              },
          });
        };

        var checkLayoutCache = function() {
            var userPromise = mainService.getUser();
            return userPromise.then(function(user) {
                if ($sessionStorage.sessionKey === user.sessionKey &&
                    $sessionStorage.layout) {
                  return $sessionStorage.layout;
                }

                return null;
            });
        };

        var storeLayoutInCache = function(data) {
            var userPromise = mainService.getUser();
            userPromise.then(function(user) {
                $sessionStorage.sessionKey = user.sessionKey;
                $sessionStorage.layout = data;
                return user;
            }).catch(function() {
              $log.warn('Could not getUser');
            });
        };

        var formatLayoutForCache = function(data) {
          var result = {
            'layout': [],
          };
          // layout will map to an array of objects each with an fname field.
          // those fnames represent, in order,
          // the home page content for the user
          if ($.isPlainObject(data.layout) &&
              $.isArray(data.layout.folders)) { // layout.json v1
            var folders = data.layout.folders.filter(function(el) {
              var result = false;
              if (el && SERVICE_LOC.layoutTab === el.title) {
                result = true;
              }
              return result;
            });
            if (folders && 0 < folders.length) {
              result.layout = folders[0].portlets;
            }
          } else if ( data.layout.navigation &&
              $.isPlainObject(data.layout.navigation) &&
              $.isArray(data.layout.navigation.tabs)) { // v4-3
            // var tabs will be tabs matching the layoutTab name
            // expected to be an array with length 1
            var tabs = data.layout.navigation.tabs.filter(function(el) {
              var result = false;
              if (el && SERVICE_LOC.layoutTab === el.name) {
                result = true;
              }
              return result;
            });
            if (tabs && 0 < tabs.length) {
              var columns = tabs[0].content;
              var portlets = [];
              if ($.isArray(columns)) {
                columns.forEach( function(column) {
                  portlets = portlets.concat(column.content);
                });
              }
              result.layout = portlets;
            }
          } else if ($.isArray(data.layout)) { // layoutDoc
            result.layout = data.layout;
          }

          return result;
        };

        var getApp = function(fname) {
            return $http.get(SERVICE_LOC.base + 'portlet/' +fname + '.json',
              {cache: true})
              .then(
                function(result) {
                    return result;
                },
                function(reason) {
                    miscService.redirectUser(reason.status, 'getApp call');
                    if (reason.status === 403) {
                      reason.deniedTemplate =
                        $sce.trustAsHtml(accessDeniedTemplate);
                    }
                    return reason;
                }
            );
        };

        var getNewStuffFeed = function() {
          return $http.get(SERVICE_LOC.newstuffInfo, {cache: true})
              .then(function(result) {
                  return result.data.stuff;
                },
                function(reason) {
                  miscService.redirectUser(reason.status,
                    'new stuff json feed call');
                }
              );
        };

        var getWidgetJson = function(portlet) {
          return $http.get(portlet.widgetURL, {cache: true})
              .then(function(result) {
                  var data = result.data;
                  if (data) {
                    if (data.result) {
                      portlet.widgetData = data.result;
                    }
                    if (data.content) {
                      portlet.widgetContent = data.content;
                    }
                    $log.log(portlet.fname +
                      '\'s widget data came back with data');
                  }
                  return data;
                },
                function(reason) {
                    miscService.redirectUser(reason.status,
                      'widget json for ' + portlet.fname + ' failed.');
                }
              );
        };

        var getExclusiveMarkup = function(portlet) {
          return $http.get(SERVICE_LOC.context +
              '/p/' + portlet.fname + '/exclusive/render.uP', {cache: true})
              .then(function(result) {
                  var data = result.data;
                  if (data) {
                    portlet.exclusiveContent = $sce.trustAsHtml(data);
                    $log.log(portlet.fname +
                      '\'s exclusive data came back with data');
                  } else {
                    portlet.exclusiveContent =
                        '
' +
                        'This service is unavailable right now. ' +
                        'Please check back later.
';
                  }

                  return data;
                },
                function(reason) {
                  if (reason.status===403) {
                    portlet.exclusiveContent =
                      $sce.trustAsHtml(accessDeniedTemplate);
                  } else {
                    miscService.redirectUser(reason.status,
                      'exclusive markup for ' + portlet.fname + ' failed.');
                  }
                }
              );
        };

        var getGuestMode = function() {
          return mainService.isGuest();
        };

          var getRSSJsonified = function(feedURL) {
            // This is a hack.
            // It would be maybe healthier to enhance RSS widget to
            // support
            // 1. configure explicitly with URL that generates the JSON
            // 2. configure with pithy key to feed ( campus_news )
            // 3. configure explicitly with RSS URL and automatically
            //    run that through an RSS to JSON converter.
            // Whereas this hack repurposes existing configuration for (3)
            // to do (1).
          return $http.get(feedURL, {cache: true});
        };

        return {
            getLayout: getLayout,
            getUncachedLayout: getUncachedLayout,
            formatLayoutForCache: formatLayoutForCache,
            getApp: getApp,
            moveStuff: moveStuff,
            getNewStuffFeed: getNewStuffFeed,
            addToHome: addToHome,
            addToLayoutByFname: addToLayoutByFname,
            removeFromHome: removeFromHome,
            getWidgetJson: getWidgetJson,
            getExclusiveMarkup: getExclusiveMarkup,
            getGuestMode: getGuestMode,
            getRSSJsonified: getRSSJsonified,
        };
    }]);
});
<commit_msg>Remove headers from new layout requests<commit_after>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
'use strict';

define(['angular', 'jquery'], function(angular, $) {
  var accessDeniedTemplate=
    '
Sorry, you\'re not authorized to access this.

' +
    '
' +
    '
' +
    '
If you\'re here by accident, head back to your My-UW ' +
    'homepage.
' +
    '
For help with authorization, contact the ' +
    'DoIT Help Desk.
';

  return angular.module('my-app.layout.services', [])
    .factory('layoutService',
      ['$sce', '$http', '$log', 'miscService',
      'mainService', '$sessionStorage', '$q', 'SERVICE_LOC', 'APP_FLAGS',
      function($sce, $http, $log, miscService,
        mainService, $sessionStorage, $q, SERVICE_LOC, APP_FLAGS) {

        /************************
        * NEW LAYOUT
        * To use new service layout set useNewLayout flag in override.js to true,
        * and useOldLayout to false
        ************************/

        if (APP_FLAGS.useNewLayout) {
          console.log("using new layout");

          var getLayout = function() {
            return checkLayoutCache().then(function(data) {
              var successFn;
              var errorFn;
              var defer;

              // first, check the local storage...
              if (data) {
                defer = $q.defer();
                defer.resolve(data);
                return defer.promise;
              }

              successFn = function(result) {
                var data = formatLayoutForCache(result.data);
                storeLayoutInCache(data);
                return data;
              };

              errorFn = function(reason) {
                miscService.redirectUser(reason.status, 'layout call');
              };
            return $http.get(
                SERVICE_LOC.newLayout)
                  .then(successFn, errorFn);
            });
          };

          var addToHome = function addToHomeFunction(portlet) {
            var fname = portlet.fname;
            return getLayout().then(function(data) {
              var newLayout = data.layout.concat(fname);
              return $http({
                method: 'POST',
                url: SERVICE_LOC.newLayout,
                data: {"layout" : newLayout, "new" : false},
                dataType: 'json'
              });
            })
          };

          var removeFromHome = function removeFromHomeFunction(fname) {
            return getLayout().then(function(data) {
              var newLayout = data.layout.filter(function(val){
                return val !== fname;
              });
              return $http({
                  method: 'POST',
                  url: SERVICE_LOC.newLayout,
                  data: {"layout" : newLayout, "new" : false},
                  dataType: 'json'
              });
            })
          };

          var moveStuff = function moveStuffFunction() {
            return getLayout().then(function(data) {
              var newLayout = data.layout;
              console.log("newLayout", newLayout);
                return $http({
                  method: 'POST',
                  url: SERVICE_LOC.newLayout,
                  data: {"layout" : newLayout, "new" : false},
                  dataType: 'json'
              });
            });

          };
        }

        /************************
        ** OLD LAYOUT
        ** To use old service layout set useOldLayout flag in override.js to true,
        ** and useNewLayout to false
        *************************/

        if (APP_FLAGS.useOldLayout) {
          console.log("using old layout");

          var getLayout = function() {
            return checkLayoutCache().then(function(data) {
                var successFn;
                var errorFn;
                var defer;

                // first, check the local storage...
                if (data) {
                    defer = $q.defer();
                    defer.resolve(data);
                    return defer.promise;
                }

                successFn = function(result) {
                    var data = formatLayoutForCache(result.data);
                    storeLayoutInCache(data);
                    return data;
                };

                errorFn = function(reason) {
                    miscService.redirectUser(reason.status, 'layout call');
                };

                // no caching...  request from the server
                return $http.get(
                  SERVICE_LOC.context + SERVICE_LOC.layout, {cache: true} )
                    .then(successFn, errorFn);
            });
          };

          var addToHome = function addToHomeFunction(portlet) {
              var fname = portlet.fname;
              var tabName = SERVICE_LOC.layoutTab;
              return $.ajax({
                  url: SERVICE_LOC.base + 'layout?action=addPortlet&fname=' +
                    fname + '&tabName=' + tabName,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function(request, text) {
                      $log.log('Added ' + portlet.fname + ' successfully');
                      miscService.pushGAEvent(
                        'Layout Modification', 'Add', portlet.name);
                      return true;
                  },
                  error: function(request, text, error) {
                      $log.warn('failed to add app to home.');
                      return false;
                  },
              });
          };

          var removeFromHome = function removeFromHomeFunction(fname) {
              return $.ajax({
                  url: SERVICE_LOC.base +
                    'layout?action=removeByFName&fname=' + fname,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function(request, text) {
                      $log.log('removed ' + fname + ' successfully.');
                      miscService.pushGAEvent(
                        'Layout Modification', 'Remove', fname);
                  },
                  error: function(request, text, error) {
                  },
              });
          };

          var moveStuff = function moveStuffFunction(
                index, length, sourceId, previousNodeId, nextNodeId) {
            var insertNode = function(sourceId, previousNodeId, nextNodeId) {
              var saveOrderURL = SERVICE_LOC.base +
                  'layout?action=movePortletAjax' +
                  '&sourceId=' + sourceId +
                  '&previousNodeId=' + previousNodeId +
                  '&nextNodeId=' + nextNodeId;
              $log.log(saveOrderURL);
              $.ajax({
                  url: saveOrderURL,
                  type: 'POST',
                  data: null,
                  dataType: 'json',
                  async: true,
                  success: function() {
                    $log.log('layout move successful.');
                  },
                  error: function(request, text, error) {
                    $log.error('Error persisting move ' + saveOrderURL);
                  },
              });
            };

            insertNode(sourceId, previousNodeId, nextNodeId);
          };
        }

        var getUncachedLayout = function() {
          console.log("in getUncachedLayout");
          var successFn = function(result) {
              var data = formatLayoutForCache(result.data);
              storeLayoutInCache(data);
              return data;
          };

          var errorFn = function(reason) {
              miscService.redirectUser(reason.status, 'layout call');
          };

          // no caching...  request from the server
          return $http.get(SERVICE_LOC.context + SERVICE_LOC.layout,
            {cache: true} )
              .then(successFn, errorFn);
        };

        var addToLayoutByFname = function addToLayoutByFname(fname) {
          var tabName = SERVICE_LOC.layoutTab;
          return $.ajax({
              url: SERVICE_LOC.base + 'layout?action=addPortlet&fname=' +
                fname + '&tabName=' + tabName,
              type: 'POST',
              data: null,
              dataType: 'json',
              async: true,
              success: function() {
                  $log.log('Added ' + fname + ' successfully');
                  miscService.pushGAEvent(
                    'Layout Modification', 'Add', fname);
                  },
              error: function() {
                  $log.warn('failed to add app to home.');
                  return false;
              },
          });
        };

        var checkLayoutCache = function() {
            var userPromise = mainService.getUser();
            return userPromise.then(function(user) {
                if ($sessionStorage.sessionKey === user.sessionKey &&
                    $sessionStorage.layout) {
                  return $sessionStorage.layout;
                }

                return null;
            });
        };

        var storeLayoutInCache = function(data) {
            var userPromise = mainService.getUser();
            userPromise.then(function(user) {
                $sessionStorage.sessionKey = user.sessionKey;
                $sessionStorage.layout = data;
                return user;
            }).catch(function() {
              $log.warn('Could not getUser');
            });
        };

        var formatLayoutForCache = function(data) {
          var result = {
            'layout': [],
          };
          // layout will map to an array of objects each with an fname field.
          // those fnames represent, in order,
          // the home page content for the user
          if ($.isPlainObject(data.layout) &&
              $.isArray(data.layout.folders)) { // layout.json v1
            var folders = data.layout.folders.filter(function(el) {
              var result = false;
              if (el && SERVICE_LOC.layoutTab === el.title) {
                result = true;
              }
              return result;
            });
            if (folders && 0 < folders.length) {
              result.layout = folders[0].portlets;
            }
          } else if ( data.layout.navigation &&
              $.isPlainObject(data.layout.navigation) &&
              $.isArray(data.layout.navigation.tabs)) { // v4-3
            // var tabs will be tabs matching the layoutTab name
            // expected to be an array with length 1
            var tabs = data.layout.navigation.tabs.filter(function(el) {
              var result = false;
              if (el && SERVICE_LOC.layoutTab === el.name) {
                result = true;
              }
              return result;
            });
            if (tabs && 0 < tabs.length) {
              var columns = tabs[0].content;
              var portlets = [];
              if ($.isArray(columns)) {
                columns.forEach( function(column) {
                  portlets = portlets.concat(column.content);
                });
              }
              result.layout = portlets;
            }
          } else if ($.isArray(data.layout)) { // layoutDoc
            result.layout = data.layout;
          }

          return result;
        };

        var getApp = function(fname) {
            return $http.get(SERVICE_LOC.base + 'portlet/' +fname + '.json',
              {cache: true})
              .then(
                function(result) {
                    return result;
                },
                function(reason) {
                    miscService.redirectUser(reason.status, 'getApp call');
                    if (reason.status === 403) {
                      reason.deniedTemplate =
                        $sce.trustAsHtml(accessDeniedTemplate);
                    }
                    return reason;
                }
            );
        };

        var getNewStuffFeed = function() {
          return $http.get(SERVICE_LOC.newstuffInfo, {cache: true})
              .then(function(result) {
                  return result.data.stuff;
                },
                function(reason) {
                  miscService.redirectUser(reason.status,
                    'new stuff json feed call');
                }
              );
        };

        var getWidgetJson = function(portlet) {
          return $http.get(portlet.widgetURL, {cache: true})
              .then(function(result) {
                  var data = result.data;
                  if (data) {
                    if (data.result) {
                      portlet.widgetData = data.result;
                    }
                    if (data.content) {
                      portlet.widgetContent = data.content;
                    }
                    $log.log(portlet.fname +
                      '\'s widget data came back with data');
                  }
                  return data;
                },
                function(reason) {
                    miscService.redirectUser(reason.status,
                      'widget json for ' + portlet.fname + ' failed.');
                }
              );
        };

        var getExclusiveMarkup = function(portlet) {
          return $http.get(SERVICE_LOC.context +
              '/p/' + portlet.fname + '/exclusive/render.uP', {cache: true})
              .then(function(result) {
                  var data = result.data;
                  if (data) {
                    portlet.exclusiveContent = $sce.trustAsHtml(data);
                    $log.log(portlet.fname +
                      '\'s exclusive data came back with data');
                  } else {
                    portlet.exclusiveContent =
                        '
' +
                        'This service is unavailable right now. ' +
                        'Please check back later.
';
                  }

                  return data;
                },
                function(reason) {
                  if (reason.status===403) {
                    portlet.exclusiveContent =
                      $sce.trustAsHtml(accessDeniedTemplate);
                  } else {
                    miscService.redirectUser(reason.status,
                      'exclusive markup for ' + portlet.fname + ' failed.');
                  }
                }
              );
        };

        var getGuestMode = function() {
          return mainService.isGuest();
        };

          var getRSSJsonified = function(feedURL) {
            // This is a hack.
            // It would be maybe healthier to enhance RSS widget to
            // support
            // 1. configure explicitly with URL that generates the JSON
            // 2. configure with pithy key to feed ( campus_news )
            // 3. configure explicitly with RSS URL and automatically
            //    run that through an RSS to JSON converter.
            // Whereas this hack repurposes existing configuration for (3)
            // to do (1).
          return $http.get(feedURL, {cache: true});
        };

        return {
            getLayout: getLayout,
            getUncachedLayout: getUncachedLayout,
            formatLayoutForCache: formatLayoutForCache,
            getApp: getApp,
            moveStuff: moveStuff,
            getNewStuffFeed: getNewStuffFeed,
            addToHome: addToHome,
            addToLayoutByFname: addToLayoutByFname,
            removeFromHome: removeFromHome,
            getWidgetJson: getWidgetJson,
            getExclusiveMarkup: getExclusiveMarkup,
            getGuestMode: getGuestMode,
            getRSSJsonified: getRSSJsonified,
        };
    }]);
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

var call = require('../lib/index').call;
var path = require('path');
var config;

// try to read package.json config
try {
  config = require(path.resolve('./package.json')).runjs || {};
} catch (e) {
  config = {};
}

// try to load babel-register
try {
  console.log('Requiring babel-register...')
  if (config['babel-register']) {
    require(path.resolve(config['babel-register']));
  } else {
    require(path.resolve('./node_modules/babel-register'));
  }
} catch (e) {
  console.log('Requiring failed. Fallback to pure node.');
  if (config['babel-register']) {
    throw e.stack
  }
}

// process runfile.js
console.log('Processing runfile...')
var runfile = require(path.resolve('./runfile'));
call(runfile, process.argv.slice(2));
<commit_msg>Catch the error for the absence of runfile.js module.<commit_after>#!/usr/bin/env node

var call = require('../lib/index').call;
var path = require('path');
const fs = require('fs');
var config;

// try to read package.json config
try {
  config = require(path.resolve('./package.json')).runjs || {};
} catch (error) {
  config = {};
}

// try to load babel-register
try {
  console.log('Requiring babel-register...')
  if (config['babel-register']) {
    require(path.resolve(config['babel-register']));
  } else {
    require(path.resolve('./node_modules/babel-register'));
  }
} catch (error) {
  console.log('Requiring failed. Fallback to pure node.');
  if (config['babel-register']) {
    throw error.stack
  }
}

try {
  fs.accessSync(path.resolve('./runfile.js'));
} catch (error) {
  console.log(`No runfile.js defined in ${process.cwd()}`);
  process.exit(1);
}

// process runfile.js
console.log('Processing runfile...')
var runfile = require(path.resolve('./runfile'));

call(runfile, process.argv.slice(2));
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////////////////////////
// The Main App file
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Bjørn Bråthen, Concept NTNU
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////////

/* eslint no-sync: 0 */
/* eslint no-console: 0 */

'use strict';

const BrowserWindow = require('electron').BrowserWindow;
const childProcess = require('child_process');
const pjson = require('./package.json');
const app = require('electron').app;
const path = require('path');
const net = require('net');
const os = require('os');
const fs = require('fs');

// Set in package.json
const appName = pjson.name;
const env = process.env;

// -- Some mongo and node variables --------------------------------------------

const domain = 'http://localhost';
const mongoRootUrl = 'mongodb://localhost:';
const dbName = 'meteor';

// -- Browser window setup -----------------------------------------------------

const width = 1200;
const height = 800;
const minWidth = 1000;
const minHeight = 800;

const resizeable = true;
const frame = true;

// -- Set up paths -------------------------------------------------------------

const resourcesDir = path.join(__dirname, '..', 'app.asar.unpacked', 'resources');
const meteorServerPath = path.join(__dirname, 'bundle', 'programs', 'server');
const mongodPath = path.join(resourcesDir, 'mongod');

const platform = os.platform();

let appPath = '';

if (platform === 'darwin') {
  appPath = path.join(env.HOME, 'Library', 'Application Support', appName);
} else if (platform === 'win32') {
  appPath = path.join(env.HOMEPATH, 'AppData', 'Local', appName);
} else if (platform === 'linux') {
  appPath = path.join(env.HOME, '.config', appName);
}

const dataPath = path.join(appPath, 'data');

console.log('Root dir:', __dirname);
console.log('App directory path:', appPath);
console.log('DB path:', dataPath);
console.log('Mongod path:', mongodPath);

// -- Helper functions -----------------------------------------------------------------------------

/**
 * Determine an unoccupied port
 */
function freePort(callback) {
  const server = net.createServer();
  let port = 0;

  server.on('listening', () => {
    port = server.address().port;
    server.close();
  });

  server.on('close', () => {
    callback(null, port);
  });

  server.listen(0, '127.0.0.1');
}

/**
 * Create a dir if it not exists
 */
function createDirSync(p) {
  if (!fs.existsSync(p)) {
    fs.mkdirSync(p);
  }
}

/**
 * Read file if exists
 */
function readFileSync(p) {
  if (fs.existsSync(p)) {
    return fs.readFileSync(path.join(p), 'utf8');
  }
}

/**
 * Start Node Child
 */
function startNode(options, mongoChild, callback) {

  console.log('Starting meteor instance...');

  const nodeArgs = path.join(meteorServerPath, 'boot.js');
  const rootUrl = `${domain}:${options.webPort}/`;
  let opened = false;

  const nodeEnv = {
    ROOT_URL: rootUrl,
    PORT: options.webPort,
    DB_PATH: dataPath,
    MONGO_URL: `${mongoRootUrl}${options.mongoPort}/${dbName}`,
    METEOR_SETTINGS: readFileSync(path.join(__dirname, 'settings.json')),
    NODE_ENV: 'production',
    ELECTRON_RUN_AS_NODE: 1
  };

  const nodeChild = childProcess.fork(nodeArgs,
    [
      path.join(meteorServerPath, 'program.json')
    ], {
      env: nodeEnv,
      silent: true // to be able to listen to stdout and stderr
    }
  );

  // listen for errors
  nodeChild.stderr.setEncoding('utf8');
  nodeChild.stderr.on('data', (nodeData) => {
    console.log('stderr: ', nodeData);
  });

  // Listen on stdout from our meteor instance
  nodeChild.stdout.setEncoding('utf8');
  nodeChild.stdout.on('data', (nodeData) => {

    console.log(nodeData);

    // If meteor tells it's ready
    if (nodeData.indexOf('Meteor app started.') !== -1) {
      if (!opened) {
        opened = true;
      } else {
        return;
      }

      setTimeout(() => callback(rootUrl, nodeChild, mongoChild), 100);
    }
  });
}

/**
 * Starts mongo on specified port and trigger start of meteor instance on finish
 */
function startMongo(options, callback) {

  console.log('Starting mongodb...');

  let started = false;

  const mongodArgs = [
    '--storageEngine',
    'mmapv1',
    '--bind_ip',
    '127.0.0.1',
    '--dbpath',
    dataPath,
    '--port',
    options.mongoPort,
    '--smallfiles',
    '--journal'
  ];

  // Arguments passed to mongod
  if (platform !== 'win32') {
    mongodArgs.push('--unixSocketPrefix');
    mongodArgs.push(dataPath);
  }

  // Start the Mongo process.
  const mongoChild = childProcess.spawn(mongodPath, mongodArgs, {
    env: {
      PURPOSE: appName
    }
  });

  // Listen on mongod errors
  mongoChild.stderr.setEncoding('utf8');
  mongoChild.stderr.on('data', (data) => console.log(data));

  // Listen on mongod stdout
  mongoChild.stdout.setEncoding('utf8');
  mongoChild.stdout.on('data', (data) => {
    const err = data.toLowerCase().indexOf('assertion');

    if (err !== -1) {
      throw new Error(data);
    }

    const mongoRunnning = data.indexOf(`waiting for connections on port ${options.mongoPort}`);

    // If mongo is up and running
    if (mongoRunnning !== -1) {
      if (!started) {
        started = true;
      } else {
        return;
      }
      console.log('Mongo started...');

      // Start node child
      startNode({
        mongoPort: options.mongoPort,
        webPort: options.webPort
      }, mongoChild, callback);
    }
  });
}

/**
 * Trigger the boot process
 */
function start(callback) {
  if (process.env.NODE_ENV === 'development') {
    console.log('Running in Dev mode.');
    return callback('http://localhost:3000');
  }

  process.stdout.write('Starting production server\n');

  // Create paths
  createDirSync(appPath);
  createDirSync(dataPath);

  // Detect unoccupied ports
  freePort((err, webPort) => {
    freePort((error, mongoPort) => {
      if (error) {
        throw error;
      }

      console.log('MongoPort: ', mongoPort);
      console.log('WebPort: ', webPort);

      // Delete the mongod and/or WiredTiger lock file
      fs.unlink(path.join(dataPath, 'mongod.lock'), () => {
        fs.unlink(path.join(dataPath, 'WiredTiger.lock'), () => {
          // Start mongo first
          startMongo({
            mongoPort,
            webPort
          }, callback);
        });
      });
    });
  });

}

// -- Setup the app ------------------------------------------------------------

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is garbage collected.

global.mainWindow = null;

// Emitted when the application is activated while there is no opened windows.
// It usually happens when a user has closed all of application's windows and
// then click on the application's dock icon.
app.on('activate-with-no-open-windows', () => {
  if (global.mainWindow) {
    global.mainWindow.show();
  }

  return false;
});

let mainWindow;

// Emitted when Electron has done all of the initialization.
function createWindow() {

  const splashScreen = new BrowserWindow({
    width: 400,
    height: 300,
    resizable: false,
    movable: false,
    minimizable: false,
    maximizable: false,
    closable: true,
    fullscreenable: false,
    center: true,
    frame: false
  });

  splashScreen.focus();
  splashScreen.loadURL('file://' + app.getAppPath() + '/.splash.html');

  start((url, nodeChild, mongoChild) => {
    console.log('App occupying ', url);

    const cleanup = () => {
      console.log('Cleaning up children.');

      if (nodeChild) {
        console.log('cleaning up node child');
        nodeChild.kill('SIGTERM');
      }

      if (mongoChild) {
        console.log('cleaning up mongo child');
        mongoChild.kill('SIGTERM');
      }

      app.quit();
    };

    // Create the browser window.
    const windowOptions = {
      width,
      height,
      'min-width': minWidth,
      'min-height': minHeight,
      resizeable,
      frame,
      webPreferences: {
        nodeIntegration: false,
        // Meteor overrides the require method, which do not find our electron
        // modules etc. We have to copy the require method. _require()
        // should be used on the client to access node and electron modules.
        preload: require.resolve('./.preload')
      }
    };

    mainWindow = new BrowserWindow(windowOptions);
    mainWindow.focus();
    splashScreen.close();

    mainWindow.loadURL(url);
    global.mainWindow = mainWindow;

    if (process.env.NODE_ENV === 'development') {
      mainWindow.webContents.openDevTools();
    }

    process.on('uncaughtException', cleanup);

    mainWindow.on('closed', () => {
      mainWindow = null;
    });

    mainWindow.once('did-finish-load', (e) => {
      console.log(e);
      console.log('finished loading.');
    });

    mainWindow.once('ready-to-show', (e) => {
      console.log(e);
      console.log('ready to show.');
    });

    app.on('will-quit', () => {
      cleanup();
    });

    app.on('window-all-closed', () => {
      cleanup();
    });

  });
}

app.on('ready', createWindow);

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});
<commit_msg>Fix min width and height on window.<commit_after>////////////////////////////////////////////////////////////////////////////////////////////////////
// The Main App file
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Bjørn Bråthen, Concept NTNU
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////////

/* eslint no-sync: 0 */
/* eslint no-console: 0 */

'use strict';

const BrowserWindow = require('electron').BrowserWindow;
const childProcess = require('child_process');
const pjson = require('./package.json');
const app = require('electron').app;
const path = require('path');
const net = require('net');
const os = require('os');
const fs = require('fs');

// Set in package.json
const appName = pjson.name;
const env = process.env;

// -- Some mongo and node variables --------------------------------------------

const domain = 'http://localhost';
const mongoRootUrl = 'mongodb://localhost:';
const dbName = 'meteor';

// -- Browser window setup -----------------------------------------------------

const width = 1200;
const height = 800;
const minWidth = 1000;
const minHeight = 700;

const resizeable = true;
const frame = true;

// -- Set up paths -------------------------------------------------------------

const resourcesDir = path.join(__dirname, '..', 'app.asar.unpacked', 'resources');
const meteorServerPath = path.join(__dirname, 'bundle', 'programs', 'server');
const mongodPath = path.join(resourcesDir, 'mongod');

const platform = os.platform();

let appPath = '';

if (platform === 'darwin') {
  appPath = path.join(env.HOME, 'Library', 'Application Support', appName);
} else if (platform === 'win32') {
  appPath = path.join(env.HOMEPATH, 'AppData', 'Local', appName);
} else if (platform === 'linux') {
  appPath = path.join(env.HOME, '.config', appName);
}

const dataPath = path.join(appPath, 'data');

console.log('Root dir:', __dirname);
console.log('App directory path:', appPath);
console.log('DB path:', dataPath);
console.log('Mongod path:', mongodPath);

// -- Helper functions -----------------------------------------------------------------------------

/**
 * Determine an unoccupied port
 */
function freePort(callback) {
  const server = net.createServer();
  let port = 0;

  server.on('listening', () => {
    port = server.address().port;
    server.close();
  });

  server.on('close', () => {
    callback(null, port);
  });

  server.listen(0, '127.0.0.1');
}

/**
 * Create a dir if it not exists
 */
function createDirSync(p) {
  if (!fs.existsSync(p)) {
    fs.mkdirSync(p);
  }
}

/**
 * Read file if exists
 */
function readFileSync(p) {
  if (fs.existsSync(p)) {
    return fs.readFileSync(path.join(p), 'utf8');
  }
}

/**
 * Start Node Child
 */
function startNode(options, mongoChild, callback) {

  console.log('Starting meteor instance...');

  const nodeArgs = path.join(meteorServerPath, 'boot.js');
  const rootUrl = `${domain}:${options.webPort}/`;
  let opened = false;

  const nodeEnv = {
    ROOT_URL: rootUrl,
    PORT: options.webPort,
    DB_PATH: dataPath,
    MONGO_URL: `${mongoRootUrl}${options.mongoPort}/${dbName}`,
    METEOR_SETTINGS: readFileSync(path.join(__dirname, 'settings.json')),
    NODE_ENV: 'production',
    ELECTRON_RUN_AS_NODE: 1
  };

  const nodeChild = childProcess.fork(nodeArgs,
    [
      path.join(meteorServerPath, 'program.json')
    ], {
      env: nodeEnv,
      silent: true // to be able to listen to stdout and stderr
    }
  );

  // listen for errors
  nodeChild.stderr.setEncoding('utf8');
  nodeChild.stderr.on('data', (nodeData) => {
    console.log('stderr: ', nodeData);
  });

  // Listen on stdout from our meteor instance
  nodeChild.stdout.setEncoding('utf8');
  nodeChild.stdout.on('data', (nodeData) => {

    console.log(nodeData);

    // If meteor tells it's ready
    if (nodeData.indexOf('Meteor app started.') !== -1) {
      if (!opened) {
        opened = true;
      } else {
        return;
      }

      setTimeout(() => callback(rootUrl, nodeChild, mongoChild), 100);
    }
  });
}

/**
 * Starts mongo on specified port and trigger start of meteor instance on finish
 */
function startMongo(options, callback) {

  console.log('Starting mongodb...');

  let started = false;

  const mongodArgs = [
    '--storageEngine',
    'mmapv1',
    '--bind_ip',
    '127.0.0.1',
    '--dbpath',
    dataPath,
    '--port',
    options.mongoPort,
    '--smallfiles',
    '--journal'
  ];

  // Arguments passed to mongod
  if (platform !== 'win32') {
    mongodArgs.push('--unixSocketPrefix');
    mongodArgs.push(dataPath);
  }

  // Start the Mongo process.
  const mongoChild = childProcess.spawn(mongodPath, mongodArgs, {
    env: {
      PURPOSE: appName
    }
  });

  // Listen on mongod errors
  mongoChild.stderr.setEncoding('utf8');
  mongoChild.stderr.on('data', (data) => console.log(data));

  // Listen on mongod stdout
  mongoChild.stdout.setEncoding('utf8');
  mongoChild.stdout.on('data', (data) => {
    const err = data.toLowerCase().indexOf('assertion');

    if (err !== -1) {
      throw new Error(data);
    }

    const mongoRunnning = data.indexOf(`waiting for connections on port ${options.mongoPort}`);

    // If mongo is up and running
    if (mongoRunnning !== -1) {
      if (!started) {
        started = true;
      } else {
        return;
      }
      console.log('Mongo started...');

      // Start node child
      startNode({
        mongoPort: options.mongoPort,
        webPort: options.webPort
      }, mongoChild, callback);
    }
  });
}

/**
 * Trigger the boot process
 */
function start(callback) {
  if (process.env.NODE_ENV === 'development') {
    console.log('Running in Dev mode.');
    return callback('http://localhost:3000');
  }

  process.stdout.write('Starting production server\n');

  // Create paths
  createDirSync(appPath);
  createDirSync(dataPath);

  // Detect unoccupied ports
  freePort((err, webPort) => {
    freePort((error, mongoPort) => {
      if (error) {
        throw error;
      }

      console.log('MongoPort: ', mongoPort);
      console.log('WebPort: ', webPort);

      // Delete the mongod and/or WiredTiger lock file
      fs.unlink(path.join(dataPath, 'mongod.lock'), () => {
        fs.unlink(path.join(dataPath, 'WiredTiger.lock'), () => {
          // Start mongo first
          startMongo({
            mongoPort,
            webPort
          }, callback);
        });
      });
    });
  });

}

// -- Setup the app ------------------------------------------------------------

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is garbage collected.

global.mainWindow = null;

// Emitted when the application is activated while there is no opened windows.
// It usually happens when a user has closed all of application's windows and
// then click on the application's dock icon.
app.on('activate-with-no-open-windows', () => {
  if (global.mainWindow) {
    global.mainWindow.show();
  }

  return false;
});

let mainWindow;

// Emitted when Electron has done all of the initialization.
function createWindow() {

  const splashScreen = new BrowserWindow({
    width: 400,
    height: 300,
    resizable: false,
    movable: false,
    minimizable: false,
    maximizable: false,
    closable: true,
    fullscreenable: false,
    center: true,
    frame: false
  });

  splashScreen.focus();
  splashScreen.loadURL('file://' + app.getAppPath() + '/.splash.html');

  start((url, nodeChild, mongoChild) => {
    console.log('App occupying ', url);

    const cleanup = () => {
      console.log('Cleaning up children.');

      if (nodeChild) {
        console.log('cleaning up node child');
        nodeChild.kill('SIGTERM');
      }

      if (mongoChild) {
        console.log('cleaning up mongo child');
        mongoChild.kill('SIGTERM');
      }

      app.quit();
    };

    // Create the browser window.
    const windowOptions = {
      width,
      height,
      minWidth,
      minHeight,
      resizeable,
      frame,
      webPreferences: {
        nodeIntegration: false,
        // Meteor overrides the require method, which do not find our electron
        // modules etc. We have to copy the require method. _require()
        // should be used on the client to access node and electron modules.
        preload: require.resolve('./.preload')
      }
    };

    mainWindow = new BrowserWindow(windowOptions);
    mainWindow.focus();
    splashScreen.close();

    mainWindow.loadURL(url);
    global.mainWindow = mainWindow;

    if (process.env.NODE_ENV === 'development') {
      mainWindow.webContents.openDevTools();
    }

    process.on('uncaughtException', cleanup);

    mainWindow.on('closed', () => {
      mainWindow = null;
    });

    mainWindow.once('did-finish-load', (e) => {
      console.log(e);
      console.log('finished loading.');
    });

    mainWindow.once('ready-to-show', (e) => {
      console.log(e);
      console.log('ready to show.');
    });

    app.on('will-quit', () => {
      cleanup();
    });

    app.on('window-all-closed', () => {
      cleanup();
    });

  });
}

app.on('ready', createWindow);

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});
<|endoftext|>


<commit_before>// VRPlanetChase - WebVR Game
// For more info see website [http://vrplanetchase.com]
// Author: Amber Roy [http://github.com/amberroy]
//
// Credits:
//
// Theme music:
// Interstellar by Lloyd Boland
// (used with permission of composer)
// * Interstellar [https://soundcloud.com/lloydboland/interstellar-unfinished]
//
// Sound Effects from FreeSound.org [http://www.freesound.org]
// * sci-fi-victory [people/LittleRobotSoundFactory/sounds/270528]
// * sci-fi-crash [people/korgchops/sounds/170635/]
// * sci-fi-warp [people/LittleRobotSoundFactory/sounds/270524]
//
// Textures:
// * RockPerforated [http://www.cgtextures.com/texview.php?id=38675&PHPSESSID=oldd4h4s24tovt8avisojo2vq5]
// * RedRock [http://fc09.deviantart.net/fs45/i/2009/111/6/6/Red_Rock_Texture_by_Dachande99.jpg]
//
// License: MIT License [http://opensource.org/licenses/MIT]
// Copyright (c) 2015 Amber Roy

VRPlanetChase =	function ( params ) {

	this.mouseDownIntervalID = -1;
	this.redPlanet;
	this.isRedPlanetFound = false;
	this.asteroidsArray;

	this.asteroidMaterial;
	this.redPlanetMaterial;
	this.redPlaentFoundMaterial;
	this.asteroidCollisionMaterial;

	this.cockpit;
	this.capsuleMesh;
	this.flyControls;

	this.soundVictory;
	this.soundWarp;
	this.soundCrash;
	this.musicTheme;

	// Constants

	this.asteroidRadius = 50;

	this.colors = {
		BLUE: 0x0000ff,
		RED: 0xff0000,
		GRAY: 0x808080,
		GOLD: 0xFFD700,
	};

	this.capsuleMaterial = new THREE.MeshBasicMaterial(
		//{ wireframe: true, side: THREE.DoubleSide }
		{ side: THREE.DoubleSide,
		  map: THREE.ImageUtils.loadTexture( "./assets/images/spaceship-texture.png" ),
		  transparent: true,
		  opacity: 0.5,
		}
	);
	this.capsuleMaterialCrash = new THREE.MeshBasicMaterial(
		{ side: THREE.DoubleSide,
		  map: THREE.ImageUtils.loadTexture( "./assets/images/spaceship-texture.png" ),
		  transparent: true,
		  opacity: 0.8,
		}
	);
	this.capsuleMaterialVictory = new THREE.MeshBasicMaterial(
		{ wireframe: true, side: THREE.DoubleSide, color: this.colors.BLUE }
	);

};

VRPlanetChase.prototype.init = function() {

	var audioDir = "./assets/sounds/";
	this.soundWarp = GameManager.loadAudio(audioDir + 'sci-fi-warp');
	this.soundVictory = GameManager.loadAudio(audioDir + 'sci-fi-victory');
	this.soundCrash = GameManager.loadAudio(audioDir + 'sci-fi-crash');
	this.musicTheme = GameManager.loadAudio(audioDir + 'Interstellar');

	this._createCockpit();
	this._createFlyControls();

	// Need light source with phong material, otherwise spheres look black.
	var pointerOne = new THREE.PointLight(0xffffff);
	pointerOne.position.set(-100,-90,130);
	GameManager.scene.add(pointerOne);

	this._createStars();
	this._createGameObjects();

	this.musicTheme.autoplay = true;
	this.musicTheme.loop = true;
};

VRPlanetChase.prototype.update = function() {

	var delta = this.clock.getDelta();
	this.flyControls.update( delta );

	this.redPlanet.rotation.y += 0.001;
	/*
	for (var i=0; i < this.asteroidsArray.length; i++ ) {
		var asteroid = this.asteroidsArray[i];
		asteroid.rotation.y += 10;
		console.log("asteroid rotation", asteroid.rotation);
	}
	*/
	/*
	if ( this.isRedPlanetFound ) {
		this.capsuleMesh.rotation.y += 0.01;
	} else {
		this.capsuleMesh.rotation.y = 0;
	}
	*/

} // no-op

VRPlanetChase.prototype._createCockpit = function() {

    this.cockpit = new THREE.Object3D(); // grouping object
    this.cockpit.name = "cockpit";

    var top = 2.0;
    var bottom = 2.5;
    var height = 5.0;
    var radiusSeg = 12;
    var heightSeg = 50;
    var isOpenEnded = true;

    this.capsuleMesh = new THREE.Mesh(
    	new THREE.CylinderGeometry( top, bottom, height, radiusSeg, heightSeg, isOpenEnded ),
		//new THREE.MeshBasicMaterial( { wireframe: true, side: THREE.DoubleSide } )
		this.capsuleMaterial
	);
    this.capsuleMesh.rotation.x =  -1 * Math.PI / 2;
	this.cockpit.add( this.capsuleMesh );

	var backWallMesh = new THREE.Mesh(
    	new THREE.CircleGeometry( bottom, heightSeg ),
		this.capsuleMaterial
	);
	backWallMesh.position.z = height / 2;
	this.cockpit.add( backWallMesh );

	GameManager.scene.add( this.cockpit );

};

VRPlanetChase.prototype._createFlyControls = function() {

	var params = {
		checkCollision: this.checkCollision.bind( this ),
		collisionCallback: this.collisionCallback.bind( this ),
	};

	// Fly controls: [WASD] move, [R|F] up | down,
	// [Q|E] roll, [up|down] pitch, [left|right] yaw
	this.flyControls = new THREE.FlyControls( this.cockpit, document.body, params );
	this.flyControls.movementSpeed = 100;
	this.flyControls.rollSpeed = Math.PI / 24;
	this.flyControls.autoForward = false;
	this.flyControls.dragToLook = true;

	this.cockpit.add( GameManager.player );

	// Clock used to get delta when updating flycontrols.
	this.clock = new THREE.Clock();

};

VRPlanetChase.prototype._createGameObjects = function() {

	this.isRedPlanetFound = false;

	console.log("Creating new asteroid field");

	// Create the game world objects and randomize their position.

	var NUM_ASTEROIDS = 100;

	// Use sphere with shiny phong material, requries a light source.
	// SphereGeometry params: radius, widthSegments, heightSegments
	// Phong params: color, specular(color), shininess
	//var geometry = new THREE.SphereGeometry( 50, 16, 16);
	var asteroidGeo = new THREE.SphereGeometry( this.asteroidRadius, 16, 50);

	this.asteroidMaterial = new THREE.MeshPhongMaterial(
		{ map: THREE.ImageUtils.loadTexture( "./assets/images/RockPerforated.jpg" ) }
	);
	this.redPlanetMaterial = new THREE.MeshPhongMaterial(
		{ map: THREE.ImageUtils.loadTexture( "./assets/images/RedRock.jpg" ) }
	);
	this.redPlaentFoundMaterial = new THREE.MeshPhongMaterial({ color: this.colors.BLUE });
	this.asteroidCollisionMaterial = new THREE.MeshPhongMaterial({ color: this.colors.GOLD });

	this.asteroidsArray = [];								// Used for collision detection.

	// Create the asteroids.
	for (var i = 0; i < NUM_ASTEROIDS; i ++) {

		var asteroid = new THREE.Mesh( asteroidGeo, this.asteroidMaterial );
		this._setRandomPosition(asteroid);
		asteroid.matrixAutoUpdate = false; // Remove this if asteroids rotate.

		this.asteroidsArray.push(asteroid);
	}

	// Create the planet.
	var planetGeo = new THREE.SphereGeometry( this.asteroidRadius * 2, 16, 50 );
	this.redPlanet = new THREE.Mesh( planetGeo, this.redPlanetMaterial );
	this._setRandomPosition( this.redPlanet );

	for (var i=0; i < this.asteroidsArray.length; i++) {
		GameManager.scene.add( this.asteroidsArray[i] );
	}
	GameManager.scene.add(this.redPlanet);

};

VRPlanetChase.prototype._createStars = function() {
	// based on http://threejs.org/examples/misc_controls_fly.html

	var r = this.asteroidRadius; 	// for scaling star to match scene

	var i, starsGeometry = [ new THREE.Geometry(), new THREE.Geometry() ];

	for ( i = 0; i < 250; i ++ ) {

		var vertex = new THREE.Vector3();
		vertex.x = Math.random() * 2 - 1;
		vertex.y = Math.random() * 2 - 1;
		vertex.z = Math.random() * 2 - 1;
		vertex.multiplyScalar( r );

		starsGeometry[ 0 ].vertices.push( vertex );

	}

	for ( i = 0; i < 1500; i ++ ) {

		var vertex = new THREE.Vector3();
		vertex.x = Math.random() * 2 - 1;
		vertex.y = Math.random() * 2 - 1;
		vertex.z = Math.random() * 2 - 1;
		vertex.multiplyScalar( r );

		starsGeometry[ 1 ].vertices.push( vertex );

	}

	var stars;
	var starsMaterials = [
		new THREE.PointCloudMaterial( { color: 0x555555, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x555555, size: 1, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x333333, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x3a3a3a, size: 1, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x1a1a1a, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x1a1a1a, size: 1, sizeAttenuation: false } )
	];

	for ( i = 10; i < 30; i ++ ) {

		stars = new THREE.PointCloud( starsGeometry[ i % 2 ], starsMaterials[ i % 6 ] );

		stars.rotation.x = Math.random() * 6;
		stars.rotation.y = Math.random() * 6;
		stars.rotation.z = Math.random() * 6;

		s = i * 10;
		stars.scale.set( s, s, s );

		stars.matrixAutoUpdate = false;
		stars.updateMatrix();

		GameManager.scene.add( stars );

	}
};

VRPlanetChase.prototype._setRandomPosition = function(mesh) {
		mesh.position.x = Math.random() * 2000 - 1000;
		mesh.position.y = Math.random() * 2000 - 1000;
		mesh.position.z = Math.random() * 2000 - 1000;
		mesh.rotation.x = Math.random() * 2 * Math.PI;
		mesh.rotation.y = Math.random() * 2 * Math.PI;
		mesh.rotation.z = Math.random() * 2 * Math.PI;
		mesh.updateMatrix();
};

VRPlanetChase.prototype.checkCollision = function(cameraPosition) {
	// Simple collision detection algorithm.

	var collisionInfo = {
		collisionObject: null,
		isRedPlanet: false
	};

	// Check for collision between camera and each asteroid.
	var asteroidBuffer = 5;
	for (var i = 0; i < this.asteroidsArray.length; i++) {
		var sphere = this.asteroidsArray[i];
		var distance = cameraPosition.distanceTo(sphere.position);
		if (distance < sphere.geometry.boundingSphere.radius + asteroidBuffer) {
			collisionInfo.collisionObject = sphere;
			console.log("Collision with sphere", i, "radius", sphere.geometry.radius);
			console.log("camera position", cameraPosition);
			console.log("sphere position", sphere.position);

			break;
		}
	}

	// For red planet, detect collision when in the buffer zone, before camera
	// collides, so player can see the planet color change.
	var distance = cameraPosition.distanceTo(this.redPlanet.position);
	var redPlanetBuffer = this.redPlanet.geometry.boundingSphere.radius * 1;
	if (distance < this.redPlanet.geometry.boundingSphere.radius + redPlanetBuffer) {
		collisionInfo.collisionObject = this.redPlanet;
		collisionInfo.isRedPlanet = true;
	}

	// if (isCollision) { //
	if ( collisionInfo.collisionObject ) { //
		console.log("Collision detected", collisionInfo.collisionObject);
	}

	// If collision, return collisionInfo object, else return null.
	return collisionInfo.collisionObject ? collisionInfo : null;
};

VRPlanetChase.prototype.collisionCallback = function( collisionInfo ) {

	// Collision Effect

	if ( collisionInfo.isRedPlanet ) {

		if ( this.isRedPlanetFound ) {
			// We are in the process of resetting the game.
			return ;
		}

		this.isRedPlanetFound = true;

		/* TODO
		this.capsuleMesh.material = this.capsuleMaterialVictory;
		setTimeout(function() {
			this.capsuleMesh.material = this.capsuleMaterial;
		}.bind( this ), 3000)
		*/

		this.soundVictory.play();

		// Reset the game. Create new set of asteroids to navigate.
		setTimeout(function() {

			this.soundWarp.play();
			GameManager.scene.remove(this.asteroidsArray);
			GameManager.scene.remove(this.redPlanet);

			// Start player back at center
			this.player.position.copy( GameManager.scene.position );

			this._createGameObjects();
			this.isRedPlanetFound = false;

		}.bind( this ), 3000);	 // Wait a few seconds before restarting.

	} else {

		/* TODO
		var capsuleMeshClone = this.capsuleMesh.clone();
		capsuleMeshClone.material = this.capsuleMaterialCrash; // XXX
		GameManager.scene.add( capsuleMeshClone );

		//this.capsuleMesh.material = this.capsuleMaterialCrash; // XXX
		setTimeout(function() {
			//this.capsuleMesh.material = this.capsuleMaterial; // XXX
			GameManager.scene.remove( capsuleMeshClone );
		}.bind( this ), 400)
		*/

		this.soundCrash.play();

	}

};

VRPlanetChase.prototype.moveForward = function(moveDistance) {

	var movedCamera = GameManager.camera.clone();
	movedCamera.translateZ(moveDistance);

	// Don't let the camera get too far from center of scene.
	var sceneCenterPosition = GameManager.scene.position;
	var distance = movedCamera.position.distanceTo( GameManager.scene.position );
	if (distance >= 1500) {
		console.log("Movement stopped, too far from center of scene", distance);
		return;
	}

	if (!this.checkCollision(movedCamera.position)) {
		GameManager.camera.translateZ(moveDistance);
	}
};

<commit_msg>Added crash and victory effects to capsule<commit_after>// VRPlanetChase - WebVR Game
// For more info see website [http://vrplanetchase.com]
// Author: Amber Roy [http://github.com/amberroy]
//
// Credits:
//
// Theme music:
// Interstellar by Lloyd Boland
// (used with permission of composer)
// * Interstellar [https://soundcloud.com/lloydboland/interstellar-unfinished]
//
// Sound Effects from FreeSound.org [http://www.freesound.org]
// * sci-fi-victory [people/LittleRobotSoundFactory/sounds/270528]
// * sci-fi-crash [people/korgchops/sounds/170635/]
// * sci-fi-warp [people/LittleRobotSoundFactory/sounds/270524]
//
// Textures:
// * RockPerforated [http://www.cgtextures.com/texview.php?id=38675&PHPSESSID=oldd4h4s24tovt8avisojo2vq5]
// * RedRock [http://fc09.deviantart.net/fs45/i/2009/111/6/6/Red_Rock_Texture_by_Dachande99.jpg]
//
// License: MIT License [http://opensource.org/licenses/MIT]
// Copyright (c) 2015 Amber Roy

VRPlanetChase =	function ( params ) {

	this.mouseDownIntervalID = -1;
	this.redPlanet;
	this.isRedPlanetFound = false;
	this.asteroidsArray;

	this.asteroidMaterial;
	this.redPlanetMaterial;
	this.redPlaentFoundMaterial;
	this.asteroidCollisionMaterial;

	this.cockpit;
	this.capsuleMesh;
	this.flyControls;

	this.soundVictory;
	this.soundWarp;
	this.soundCrash;
	this.musicTheme;

	// Constants

	this.asteroidRadius = 50;

	this.colors = {
		BLUE: 0x0000ff,
		RED: 0xff0000,
		GRAY: 0x808080,
		GOLD: 0xFFD700,
	};

	this.capsuleMaterial = new THREE.MeshBasicMaterial(
		//{ wireframe: true, side: THREE.DoubleSide }
		{ side: THREE.DoubleSide,
		  map: THREE.ImageUtils.loadTexture( "./assets/images/spaceship-texture.png" ),
		  transparent: true,
		  opacity: 0.5,
		}
	);
	this.capsuleMaterialCrash = new THREE.MeshBasicMaterial(
		{ side: THREE.DoubleSide,
		  map: THREE.ImageUtils.loadTexture( "./assets/images/spaceship-texture.png" ),
		  transparent: true,
		  color: this.colors.RED,
		  opacity: 0.8,
		}
	);
	this.capsuleMaterialVictory = new THREE.MeshBasicMaterial(
		{ side: THREE.DoubleSide,
		  map: THREE.ImageUtils.loadTexture( "./assets/images/spaceship-texture.png" ),
		  transparent: true,
		  color: this.colors.GOLD,
		  opacity: 0.8,
		}
	);

};

VRPlanetChase.prototype.init = function() {

	var audioDir = "./assets/sounds/";
	this.soundWarp = GameManager.loadAudio(audioDir + 'sci-fi-warp');
	this.soundVictory = GameManager.loadAudio(audioDir + 'sci-fi-victory');
	this.soundCrash = GameManager.loadAudio(audioDir + 'sci-fi-crash');
	this.musicTheme = GameManager.loadAudio(audioDir + 'Interstellar');

	this._createCockpit();
	this._createFlyControls();

	// Need light source with phong material, otherwise spheres look black.
	var pointerOne = new THREE.PointLight(0xffffff);
	pointerOne.position.set(-100,-90,130);
	GameManager.scene.add(pointerOne);

	this._createStars();
	this._createGameObjects();

	this.musicTheme.autoplay = true;
	this.musicTheme.loop = true;
};

VRPlanetChase.prototype.update = function() {

	var delta = this.clock.getDelta();
	this.flyControls.update( delta );

	this.redPlanet.rotation.y += 0.001;

} // no-op

VRPlanetChase.prototype._createCockpit = function() {

    this.cockpit = new THREE.Object3D(); // grouping object
    this.cockpit.name = "cockpit";

    var top = 2.0;
    var bottom = 2.5;
    var height = 5.0;
    var radiusSeg = 12;
    var heightSeg = 50;
    var isOpenEnded = true;

    this.capsuleMesh = new THREE.Mesh(
    	new THREE.CylinderGeometry( top, bottom, height, radiusSeg, heightSeg, isOpenEnded ),
		//new THREE.MeshBasicMaterial( { wireframe: true, side: THREE.DoubleSide } )
		this.capsuleMaterial
	);
    this.capsuleMesh.rotation.x =  -1 * Math.PI / 2;
	this.cockpit.add( this.capsuleMesh );

	var backWallMesh = new THREE.Mesh(
    	new THREE.CircleGeometry( bottom, heightSeg ),
		this.capsuleMaterial
	);
	backWallMesh.position.z = height / 2;
	this.cockpit.add( backWallMesh );

	GameManager.scene.add( this.cockpit );

};

VRPlanetChase.prototype._createFlyControls = function() {

	var params = {
		checkCollision: this.checkCollision.bind( this ),
		collisionCallback: this.collisionCallback.bind( this ),
	};

	// Fly controls: [WASD] move, [R|F] up | down,
	// [Q|E] roll, [up|down] pitch, [left|right] yaw
	this.flyControls = new THREE.FlyControls( this.cockpit, document.body, params );
	this.flyControls.movementSpeed = 100;
	this.flyControls.rollSpeed = Math.PI / 24;
	this.flyControls.autoForward = false;
	this.flyControls.dragToLook = true;

	this.cockpit.add( GameManager.player );

	// Clock used to get delta when updating flycontrols.
	this.clock = new THREE.Clock();

};

VRPlanetChase.prototype._createGameObjects = function() {

	this.isRedPlanetFound = false;

	console.log("Creating new asteroid field");

	// Create the game world objects and randomize their position.

	var NUM_ASTEROIDS = 100;

	// Use sphere with shiny phong material, requries a light source.
	// SphereGeometry params: radius, widthSegments, heightSegments
	// Phong params: color, specular(color), shininess
	//var geometry = new THREE.SphereGeometry( 50, 16, 16);
	var asteroidGeo = new THREE.SphereGeometry( this.asteroidRadius, 16, 50);

	this.asteroidMaterial = new THREE.MeshPhongMaterial(
		{ map: THREE.ImageUtils.loadTexture( "./assets/images/RockPerforated.jpg" ) }
	);
	this.redPlanetMaterial = new THREE.MeshPhongMaterial(
		{ map: THREE.ImageUtils.loadTexture( "./assets/images/RedRock.jpg" ) }
	);
	this.redPlaentFoundMaterial = new THREE.MeshPhongMaterial({ color: this.colors.BLUE });
	this.asteroidCollisionMaterial = new THREE.MeshPhongMaterial({ color: this.colors.GOLD });

	this.asteroidsArray = [];								// Used for collision detection.

	// Create the asteroids.
	for (var i = 0; i < NUM_ASTEROIDS; i ++) {

		var asteroid = new THREE.Mesh( asteroidGeo, this.asteroidMaterial );
		this._setRandomPosition(asteroid);
		asteroid.matrixAutoUpdate = false; // Remove this if asteroids rotate.

		this.asteroidsArray.push(asteroid);
	}

	// Create the planet.
	var planetGeo = new THREE.SphereGeometry( this.asteroidRadius * 2, 16, 50 );
	this.redPlanet = new THREE.Mesh( planetGeo, this.redPlanetMaterial );
	this._setRandomPosition( this.redPlanet );

	for (var i=0; i < this.asteroidsArray.length; i++) {
		GameManager.scene.add( this.asteroidsArray[i] );
	}
	GameManager.scene.add(this.redPlanet);

};

VRPlanetChase.prototype._createStars = function() {
	// based on http://threejs.org/examples/misc_controls_fly.html

	var r = this.asteroidRadius; 	// for scaling star to match scene

	var i, starsGeometry = [ new THREE.Geometry(), new THREE.Geometry() ];

	for ( i = 0; i < 250; i ++ ) {

		var vertex = new THREE.Vector3();
		vertex.x = Math.random() * 2 - 1;
		vertex.y = Math.random() * 2 - 1;
		vertex.z = Math.random() * 2 - 1;
		vertex.multiplyScalar( r );

		starsGeometry[ 0 ].vertices.push( vertex );

	}

	for ( i = 0; i < 1500; i ++ ) {

		var vertex = new THREE.Vector3();
		vertex.x = Math.random() * 2 - 1;
		vertex.y = Math.random() * 2 - 1;
		vertex.z = Math.random() * 2 - 1;
		vertex.multiplyScalar( r );

		starsGeometry[ 1 ].vertices.push( vertex );

	}

	var stars;
	var starsMaterials = [
		new THREE.PointCloudMaterial( { color: 0x555555, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x555555, size: 1, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x333333, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x3a3a3a, size: 1, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x1a1a1a, size: 2, sizeAttenuation: false } ),
		new THREE.PointCloudMaterial( { color: 0x1a1a1a, size: 1, sizeAttenuation: false } )
	];

	for ( i = 10; i < 30; i ++ ) {

		stars = new THREE.PointCloud( starsGeometry[ i % 2 ], starsMaterials[ i % 6 ] );

		stars.rotation.x = Math.random() * 6;
		stars.rotation.y = Math.random() * 6;
		stars.rotation.z = Math.random() * 6;

		s = i * 10;
		stars.scale.set( s, s, s );

		stars.matrixAutoUpdate = false;
		stars.updateMatrix();

		GameManager.scene.add( stars );

	}
};

VRPlanetChase.prototype._setRandomPosition = function(mesh) {
		mesh.position.x = Math.random() * 2000 - 1000;
		mesh.position.y = Math.random() * 2000 - 1000;
		mesh.position.z = Math.random() * 2000 - 1000;
		mesh.rotation.x = Math.random() * 2 * Math.PI;
		mesh.rotation.y = Math.random() * 2 * Math.PI;
		mesh.rotation.z = Math.random() * 2 * Math.PI;
		mesh.updateMatrix();
};

VRPlanetChase.prototype.checkCollision = function(cameraPosition) {
	// Simple collision detection algorithm.

	var collisionInfo = {
		collisionObject: null,
		isRedPlanet: false
	};

	// Check for collision between camera and each asteroid.
	var asteroidBuffer = 5;
	for (var i = 0; i < this.asteroidsArray.length; i++) {
		var sphere = this.asteroidsArray[i];
		var distance = cameraPosition.distanceTo(sphere.position);
		if (distance < sphere.geometry.boundingSphere.radius + asteroidBuffer) {
			collisionInfo.collisionObject = sphere;
			console.log("Collision with sphere", i, "radius", sphere.geometry.radius);
			console.log("camera position", cameraPosition);
			console.log("sphere position", sphere.position);

			break;
		}
	}

	// For red planet, detect collision when in the buffer zone, before camera
	// collides, so player can see the planet color change.
	var distance = cameraPosition.distanceTo(this.redPlanet.position);
	var redPlanetBuffer = this.redPlanet.geometry.boundingSphere.radius * 1;
	if (distance < this.redPlanet.geometry.boundingSphere.radius + redPlanetBuffer) {
		collisionInfo.collisionObject = this.redPlanet;
		collisionInfo.isRedPlanet = true;
	}

	// if (isCollision) { //
	if ( collisionInfo.collisionObject ) { //
		console.log("Collision detected", collisionInfo.collisionObject);
	}

	// If collision, return collisionInfo object, else return null.
	return collisionInfo.collisionObject ? collisionInfo : null;
};

VRPlanetChase.prototype.collisionCallback = function( collisionInfo ) {

	// Collision Effect

	if ( collisionInfo.isRedPlanet ) {

		if ( this.isRedPlanetFound ) {
			// We are in the process of resetting the game.
			return ;
		}

		this.isRedPlanetFound = true;

		this.capsuleMesh.material = this.capsuleMaterialVictory;
		setTimeout(function() {
			this.capsuleMesh.material = this.capsuleMaterial;
		}.bind( this ), 3000)

		this.soundVictory.play();

		// Reset the game. Create new set of asteroids to navigate.
		setTimeout(function() {

			this.soundWarp.play();
			GameManager.scene.remove(this.asteroidsArray);
			GameManager.scene.remove(this.redPlanet);

			// Start player back at center
			this.player.position.copy( GameManager.scene.position );

			this._createGameObjects();
			this.isRedPlanetFound = false;

		}.bind( this ), 3000);	 // Wait a few seconds before restarting.

	} else {

		this.capsuleMesh.material = this.capsuleMaterialCrash;
		setTimeout(function() {
			this.capsuleMesh.material = this.capsuleMaterial;
			GameManager.scene.remove( capsuleMeshClone );
		}.bind( this ), 400)

		this.soundCrash.play();

	}

};

VRPlanetChase.prototype.moveForward = function(moveDistance) {

	var movedCamera = GameManager.camera.clone();
	movedCamera.translateZ(moveDistance);

	// Don't let the camera get too far from center of scene.
	var sceneCenterPosition = GameManager.scene.position;
	var distance = movedCamera.position.distanceTo( GameManager.scene.position );
	if (distance >= 1500) {
		console.log("Movement stopped, too far from center of scene", distance);
		return;
	}

	if (!this.checkCollision(movedCamera.position)) {
		GameManager.camera.translateZ(moveDistance);
	}
};

<|endoftext|>