<commit_before>/*
 * Afrimesh: easy management for B.A.T.M.A.N. wireless mesh networks
 * Copyright (C) 2008-2009 Meraka Institute of the CSIR
 * All rights reserved.
 *
 * This software is licensed as free software under the terms of the
 * New BSD License. See /LICENSE for more information.
 */

var Map = undefined;
(function() {

  /** Includes ------------------------------------------------------------ */
  load("javascript/afrimesh.maps.js");
  OpenLayers.ImgPath = "images/";

  /** Map ----------------------------------------------------------------- */
  function _Map(id, longitude, latitude, extent, zoom, update_frequency) {

    this.update_frequency = update_frequency;
    var the_map = create_map();

    function create_map() {
      var options = {
        projection        : epsg_900913,
        displayProjection : epsg_4326,
        units             : "m",
        numZoomLevels     : 20,
        restrictedExtent  : new OpenLayers.Bounds(),
        theme             : "style/map.default.css"
      };
      options.restrictedExtent.extend(LonLat(longitude - extent, latitude - extent));
      options.restrictedExtent.extend(LonLat(longitude + extent, latitude + extent));
      var map = new OpenLayers.Map(id, options);
      //var osma = new OpenLayers.Layer.OSM.Osmarender("Osmarender");
      var mapnik = new OpenLayers.Layer.OSM.Mapnik("Street Map");
      var relief = undefined;
      console.debug("map server: " + afrimesh.settings.map.server);
      if (afrimesh.settings.map.server == "openstreetmaps.org") {
        relief = new OpenLayers.Layer.OSM.CycleMap("Relief Map");
      } else {
        relief = new OpenLayers.Layer.OSM.LocalMap("Relief Map", "http://" + afrimesh.settings.map.server + "/tiles/");
      }
      if (afrimesh.settings.map.aerial) {
        var satellite = new OpenLayers.Layer.Yahoo("Aerial Map", { // TODO - http://labs.metacarta.com/osm/over-yahoo/
            type              : YAHOO_MAP_SAT,
            sphericalMercator : true
          });
        map.addLayers([ relief, /*osma,*/ mapnik, satellite ]);
      } else {
        map.addLayers([ relief, /*osma,*/ mapnik ]);
      }
      map.addControl(new OpenLayers.Control.Attribution());
      map.addControl(new OpenLayers.Control.MousePosition());
      map.addControl(new OpenLayers.Control.LayerSwitcher());
      map.addControl(new OpenLayers.Control.ScaleLine());
      map.setCenter(LonLat(longitude, latitude), zoom);
      if (!map.getCenter()) { map.zoomToMaxExtent(); }
      map.addLayer(new OpenLayers.Layer.Vector("Mesh Links"));
      map.addLayer(new OpenLayers.Layer.Vector("Mesh Routers"));
      map.routes = map.getLayersByName("Mesh Links")[0];
      map.routers  = map.getLayersByName("Mesh Routers")[0];

      var dragger = new OpenLayers.Control.DragFeature(map.routers);
      dragger.onComplete = on_position;
      map.addControl(dragger);
      dragger.activate();
      /**var click_selector = new OpenLayers.Control.SelectFeature(map.routers);
      click_selector.multiple = false;
      click_selector.toggle = true;
      click_selector.onSelect = on_select_router;
      click_selector.onUnselect = on_unselect_router;
      map.addControl(click_selector);
      click_selector.activate();*/
      var router_hover_selector = new OpenLayers.Control.SelectFeature(map.routers,
                                                                { multiple : false,
                                                                  hover    : false });
      router_hover_selector.onSelect = on_select_router;
      router_hover_selector.onUnselect = on_unselect_router;
      map.addControl(router_hover_selector);
      router_hover_selector.activate();

      var route_hover_selector = new OpenLayers.Control.SelectFeature(map.routes,
                                                                { multiple : false,
                                                                  hover    : true });
      route_hover_selector.onSelect = on_select_route;
      route_hover_selector.onUnselect = on_unselect_route;
      map.addControl(route_hover_selector);
      route_hover_selector.activate();

      return map;
    };

    /**
     * Return the map feature representing the given router, creating it and
     * adding it to the map if it doesn't exist yet.
     */
    this.routers = the_map.routers;
    this.router = function(router) {
      var feature = the_map.routers.getFeatureById(router.address);
      if (feature) {
        return feature;
      }
      return add_router(router);
    };
    function add_router(router) {
      var feature = new OpenLayers.Feature.Vector();
      feature.style = { fillColor: "blue",
                        fillOpacity: 0.0,
                        strokeOpacity: 1.0,
                        strokeColor: "black",
                        strokeWidth: 1.0,
                        pointRadius: 10.0 };
      feature.id = router.address;
      feature.router = router;
      the_map.routers.addFeatures([feature]);
      afrimesh.villagebus.uci.get.async(function (config) {
          feature.geometry = new Point(config.afrimesh.location.longitude, config.afrimesh.location.latitude);
          the_map.routers.redraw();
        }, router.address, "afrimesh.location");
      return feature;
    };

    /**
     * Return the map feature representing the given route, creating it and
     * adding it to the map if it doesn't exist yet.
     */
    this.routes = the_map.routes;
    this.route = function(route) {
      if (route.gateway) { return { }; } // skip gateways for now
      var feature = the_map.routes.getFeatureById(route.router + "->" + route.neighbour);
      if (feature) {
        return feature;
      }
      return add_route(route);
    };
    function add_route(route) {
      var feature_origin      = the_map.routers.getFeatureById(route.router);
      var feature_destination = the_map.routers.getFeatureById(route.neighbour);
      if (!feature_origin      || !feature_origin.geometry ||
          !feature_destination || !feature_destination.geometry) {
        //console.debug("Still waiting for location information for route: " + (route.router + "->" + route.neighbour));
        return {};
      }
      var feature = new OpenLayers.Feature.Vector();
      feature.style = { strokeOpacity: 0.0,
                        strokeColor: "black",
                        strokeWidth: 10,
                        strokeDashstyle: "solid",
                        strokeLinecap: "round",
                        pointRadius: 0 };
      feature.id = route.router + "->" + route.neighbour;
      feature.route = route;
      feature.geometry = new OpenLayers.Geometry.LineString([ feature_origin.geometry, feature_destination.geometry ]);
      the_map.routes.addFeatures([feature]);
      //console.debug("Added route for route: " + (route.router + "->" + route.neighbour));
      return feature;
    };

    /**
     * Take a B.A.T.M.A.N. link quality value and convert it to a HTML color string
     */
    var lq_to_color = function(lq) {
      if (lq == "HNA") {
        return "black";
      }
      lq = lq + 0.0;
      if (lq > 1.06) {
        return "red";
      } else if (lq > 1.04) {
        return "orange";
      } else if (lq > 1.02) {
        return "green";
      }
      return "lightblue";
    }
    this.lq_to_color = lq_to_color;

This font is 14pt, the line height is 20pt, it's color is orange, and the font family will be 'Garamond'. If the user's computer doesn't have 'Garamond', it will use 'Georgia'. Failing that it will use the default 'serif' font on the user's computer (this is often 'Times' or 'Times Roman' - just leave it as 'serif'). You can also specify bold text and italics if you wish!

    /* event handling ----------------------------------------------------- */

    function on_select_router(feature) {
      afrimesh.network.accounting(feature.router);
      the_map.selected = feature;
      var html = "
";
      html += "
" + "" + feature.router.address + "" + "  ";
      html += "" + (feature.router.macaddr ? feature.router.macaddr : "unknown mac")  + "

";
      var now = new Date();
      var last_seen = now - feature.last_seen;
      if (last_seen <= (update_frequency * 2.0)) { // UDE - this is a bit clumsy
        html += "
node is healthy

";
      } else {
        html += "
node is missing
";
        html += "
last checked in " + Math.floor(last_seen / 1000) + " seconds ago
";
      }
      if (feature.router.recBytes) {
	      html += "
 In/Out:   ";
		html += "" + feature.router.recBytes;
      } else {
	      //html += "
 Bytes transmitted: No Bytes transmitted

" ;
      }
      if (feature.router.tranBytes) {
	      html += "/" + feature.router.tranBytes + "

" ;
      } else {
	      //html += "
 Bytes recieved: No Bytes recieved

" ;
      }
      html += "
";
      html+= "Neighbours";
      html+= "
";
      var tog = 1;
      feature.router.routes.map(function (route) {
          if (route.neighbour) {
              var clor = lq_to_color(route.label);
            if (tog == 1) {
              html += "
";
              html += route.neighbour + " " + "(" + route.label + ")"
              html += "&nbsp" + "	";
              tog = 0;
            } else {
              html += "";
              html += route.neighbour + " " +"("+ route.label + ")";
              html += "&nbsp" +"
";
              tog =1;
            }
          }
        });

      html += "
";
      html+= "";
      html += "
";
    //var myObj = new getObj('MyText');

      var popup = new OpenLayers.Popup.AnchoredBubble("id" + feature.router.address,
                                                      feature.geometry.getBounds().getCenterLonLat(),
                                                      null, html, null, false,
                                                      function(event){on_unselect_router(the_map.selected);} );
      popup.setBackgroundColor("black");
      popup.setOpacity(0.9);
      popup.autoSize = false;
      feature.popup = popup;
      the_map.addPopup(popup);

      $("#ip").bind("click", function(event) {
          evil_display_overlay("http://10.216.144.1/");
          //evil_display_overlay("http://" + feature.router.address +"/");
        });
    };

    function on_unselect_router(feature) {

      the_map.selected = null;
      if (feature.popup) {
        the_map.removePopup(feature.popup);
        feature.popup.destroy();
        feature.popup = null;
      }
    };

    function on_select_route(feature) {
      console.debug("selected: " + feature);
    }

    function on_unselect_route(feature) {
      console.debug("unselected: " + feature);
    }

    function on_position(feature) {
      // update router location config
      var location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y).transform(epsg_900913, epsg_4326);
      afrimesh.villagebus.uci.set.async(function (response) {
          console.debug("Updated router location for:" + feature.router.address);
        }, feature.router.address,
        [ { config: "afrimesh", section: "location", option: "longitude", value: location.lon },
          { config: "afrimesh", section: "location", option: "latitude",  value: location.lat } ]);

      // update route geometry
      feature.router.routes.map(function(route) {
          if (route.gateway) { return; } // skip gateways for now
          var feature_destination = the_map.routers.getFeatureById(route.neighbour);
          var feature_route       = the_map.routes.getFeatureById(route.router + "->" + route.neighbour);
          if (!feature_destination || !feature_route) {
            return;
          }
          // just a tad irritating to have to remove and re-add features when changing geometry!
          the_map.routes.removeFeatures([feature_route]);
          feature_route.geometry = new OpenLayers.Geometry.LineString([ feature.geometry, feature_destination.geometry ]);
          the_map.routes.addFeatures([feature_route]);
          the_map.routes.redraw();
          console.debug("Updated route geometry for: " + (route.router + "->" + route.neighbour));
        });
    };

  };
  Map = _Map;

})();

<commit_msg>Removed a little typo.<commit_after>/*
 * Afrimesh: easy management for B.A.T.M.A.N. wireless mesh networks
 * Copyright (C) 2008-2009 Meraka Institute of the CSIR
 * All rights reserved.
 *
 * This software is licensed as free software under the terms of the
 * New BSD License. See /LICENSE for more information.
 */

var Map = undefined;
(function() {

  /** Includes ------------------------------------------------------------ */
  load("javascript/afrimesh.maps.js");
  OpenLayers.ImgPath = "images/";

  /** Map ----------------------------------------------------------------- */
  function _Map(id, longitude, latitude, extent, zoom, update_frequency) {

    this.update_frequency = update_frequency;
    var the_map = create_map();

    function create_map() {
      var options = {
        projection        : epsg_900913,
        displayProjection : epsg_4326,
        units             : "m",
        numZoomLevels     : 20,
        restrictedExtent  : new OpenLayers.Bounds(),
        theme             : "style/map.default.css"
      };
      options.restrictedExtent.extend(LonLat(longitude - extent, latitude - extent));
      options.restrictedExtent.extend(LonLat(longitude + extent, latitude + extent));
      var map = new OpenLayers.Map(id, options);
      //var osma = new OpenLayers.Layer.OSM.Osmarender("Osmarender");
      var mapnik = new OpenLayers.Layer.OSM.Mapnik("Street Map");
      var relief = undefined;
      console.debug("map server: " + afrimesh.settings.map.server);
      if (afrimesh.settings.map.server == "openstreetmaps.org") {
        relief = new OpenLayers.Layer.OSM.CycleMap("Relief Map");
      } else {
        relief = new OpenLayers.Layer.OSM.LocalMap("Relief Map", "http://" + afrimesh.settings.map.server + "/tiles/");
      }
      if (afrimesh.settings.map.aerial) {
        var satellite = new OpenLayers.Layer.Yahoo("Aerial Map", { // TODO - http://labs.metacarta.com/osm/over-yahoo/
            type              : YAHOO_MAP_SAT,
            sphericalMercator : true
          });
        map.addLayers([ relief, /*osma,*/ mapnik, satellite ]);
      } else {
        map.addLayers([ relief, /*osma,*/ mapnik ]);
      }
      map.addControl(new OpenLayers.Control.Attribution());
      map.addControl(new OpenLayers.Control.MousePosition());
      map.addControl(new OpenLayers.Control.LayerSwitcher());
      map.addControl(new OpenLayers.Control.ScaleLine());
      map.setCenter(LonLat(longitude, latitude), zoom);
      if (!map.getCenter()) { map.zoomToMaxExtent(); }
      map.addLayer(new OpenLayers.Layer.Vector("Mesh Links"));
      map.addLayer(new OpenLayers.Layer.Vector("Mesh Routers"));
      map.routes = map.getLayersByName("Mesh Links")[0];
      map.routers  = map.getLayersByName("Mesh Routers")[0];

      var dragger = new OpenLayers.Control.DragFeature(map.routers);
      dragger.onComplete = on_position;
      map.addControl(dragger);
      dragger.activate();
      /**var click_selector = new OpenLayers.Control.SelectFeature(map.routers);
      click_selector.multiple = false;
      click_selector.toggle = true;
      click_selector.onSelect = on_select_router;
      click_selector.onUnselect = on_unselect_router;
      map.addControl(click_selector);
      click_selector.activate();*/
      var router_hover_selector = new OpenLayers.Control.SelectFeature(map.routers,
                                                                { multiple : false,
                                                                  hover    : false });
      router_hover_selector.onSelect = on_select_router;
      router_hover_selector.onUnselect = on_unselect_router;
      map.addControl(router_hover_selector);
      router_hover_selector.activate();

      var route_hover_selector = new OpenLayers.Control.SelectFeature(map.routes,
                                                                { multiple : false,
                                                                  hover    : true });
      route_hover_selector.onSelect = on_select_route;
      route_hover_selector.onUnselect = on_unselect_route;
      map.addControl(route_hover_selector);
      route_hover_selector.activate();

      return map;
    };

    /**
     * Return the map feature representing the given router, creating it and
     * adding it to the map if it doesn't exist yet.
     */
    this.routers = the_map.routers;
    this.router = function(router) {
      var feature = the_map.routers.getFeatureById(router.address);
      if (feature) {
        return feature;
      }
      return add_router(router);
    };
    function add_router(router) {
      var feature = new OpenLayers.Feature.Vector();
      feature.style = { fillColor: "blue",
                        fillOpacity: 0.0,
                        strokeOpacity: 1.0,
                        strokeColor: "black",
                        strokeWidth: 1.0,
                        pointRadius: 10.0 };
      feature.id = router.address;
      feature.router = router;
      the_map.routers.addFeatures([feature]);
      afrimesh.villagebus.uci.get.async(function (config) {
          feature.geometry = new Point(config.afrimesh.location.longitude, config.afrimesh.location.latitude);
          the_map.routers.redraw();
        }, router.address, "afrimesh.location");
      return feature;
    };

    /**
     * Return the map feature representing the given route, creating it and
     * adding it to the map if it doesn't exist yet.
     */
    this.routes = the_map.routes;
    this.route = function(route) {
      if (route.gateway) { return { }; } // skip gateways for now
      var feature = the_map.routes.getFeatureById(route.router + "->" + route.neighbour);
      if (feature) {
        return feature;
      }
      return add_route(route);
    };
    function add_route(route) {
      var feature_origin      = the_map.routers.getFeatureById(route.router);
      var feature_destination = the_map.routers.getFeatureById(route.neighbour);
      if (!feature_origin      || !feature_origin.geometry ||
          !feature_destination || !feature_destination.geometry) {
        //console.debug("Still waiting for location information for route: " + (route.router + "->" + route.neighbour));
        return {};
      }
      var feature = new OpenLayers.Feature.Vector();
      feature.style = { strokeOpacity: 0.0,
                        strokeColor: "black",
                        strokeWidth: 10,
                        strokeDashstyle: "solid",
                        strokeLinecap: "round",
                        pointRadius: 0 };
      feature.id = route.router + "->" + route.neighbour;
      feature.route = route;
      feature.geometry = new OpenLayers.Geometry.LineString([ feature_origin.geometry, feature_destination.geometry ]);
      the_map.routes.addFeatures([feature]);
      //console.debug("Added route for route: " + (route.router + "->" + route.neighbour));
      return feature;
    };

    /**
     * Take a B.A.T.M.A.N. link quality value and convert it to a HTML color string
     */
    var lq_to_color = function(lq) {
      if (lq == "HNA") {
        return "black";
      }
      lq = lq + 0.0;
      if (lq > 1.06) {
        return "red";
      } else if (lq > 1.04) {
        return "orange";
      } else if (lq > 1.02) {
        return "green";
      }
      return "lightblue";
    }
    this.lq_to_color = lq_to_color;

    /* event handling ----------------------------------------------------- */

    function on_select_router(feature) {
      afrimesh.network.accounting(feature.router);
      the_map.selected = feature;
      var html = "
";
      html += "
" + "" + feature.router.address + "" + "  ";
      html += "" + (feature.router.macaddr ? feature.router.macaddr : "unknown mac")  + "

";
      var now = new Date();
      var last_seen = now - feature.last_seen;
      if (last_seen <= (update_frequency * 2.0)) { // UDE - this is a bit clumsy
        html += "
node is healthy

";
      } else {
        html += "
node is missing
";
        html += "
last checked in " + Math.floor(last_seen / 1000) + " seconds ago
";
      }
      if (feature.router.recBytes) {
	      html += "
 In/Out:   ";
		html += "" + feature.router.recBytes;
      } else {
	      //html += "
 Bytes transmitted: No Bytes transmitted

" ;
      }
      if (feature.router.tranBytes) {
	      html += "/" + feature.router.tranBytes + "

" ;
      } else {
	      //html += "
 Bytes recieved: No Bytes recieved

" ;
      }
      html += "
";
      html+= "Neighbours";
      html+= "
";
      var tog = 1;
      feature.router.routes.map(function (route) {
          if (route.neighbour) {
              var clor = lq_to_color(route.label);
            if (tog == 1) {
              html += "
";
              html += route.neighbour + " " + "(" + route.label + ")"
              html += "&nbsp" + "	";
              tog = 0;
            } else {
              html += "";
              html += route.neighbour + " " +"("+ route.label + ")";
              html += "&nbsp" +"
";
              tog =1;
            }
          }
        });

      html += "
";
      html+= "";
      html += "
";
    //var myObj = new getObj('MyText');

      var popup = new OpenLayers.Popup.AnchoredBubble("id" + feature.router.address,
                                                      feature.geometry.getBounds().getCenterLonLat(),
                                                      null, html, null, false,
                                                      function(event){on_unselect_router(the_map.selected);} );
      popup.setBackgroundColor("black");
      popup.setOpacity(0.9);
      popup.autoSize = false;
      feature.popup = popup;
      the_map.addPopup(popup);

      $("#ip").bind("click", function(event) {
          evil_display_overlay("http://10.216.144.1/");
          //evil_display_overlay("http://" + feature.router.address +"/");
        });
    };

    function on_unselect_router(feature) {

      the_map.selected = null;
      if (feature.popup) {
        the_map.removePopup(feature.popup);
        feature.popup.destroy();
        feature.popup = null;
      }
    };

    function on_select_route(feature) {
      console.debug("selected: " + feature);
    }

    function on_unselect_route(feature) {
      console.debug("unselected: " + feature);
    }

    function on_position(feature) {
      // update router location config
      var location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y).transform(epsg_900913, epsg_4326);
      afrimesh.villagebus.uci.set.async(function (response) {
          console.debug("Updated router location for:" + feature.router.address);
        }, feature.router.address,
        [ { config: "afrimesh", section: "location", option: "longitude", value: location.lon },
          { config: "afrimesh", section: "location", option: "latitude",  value: location.lat } ]);

      // update route geometry
      feature.router.routes.map(function(route) {
          if (route.gateway) { return; } // skip gateways for now
          var feature_destination = the_map.routers.getFeatureById(route.neighbour);
          var feature_route       = the_map.routes.getFeatureById(route.router + "->" + route.neighbour);
          if (!feature_destination || !feature_route) {
            return;
          }
          // just a tad irritating to have to remove and re-add features when changing geometry!
          the_map.routes.removeFeatures([feature_route]);
          feature_route.geometry = new OpenLayers.Geometry.LineString([ feature.geometry, feature_destination.geometry ]);
          the_map.routes.addFeatures([feature_route]);
          the_map.routes.redraw();
          console.debug("Updated route geometry for: " + (route.router + "->" + route.neighbour));
        });
    };

  };
  Map = _Map;

})();

<|endoftext|>


<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * 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.
 */
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */

'use strict';

var EXPORTED_SYMBOLS = ['PdfjsContentUtils'];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');

let PdfjsContentUtils = {
  _mm: null,

  /*
   * Public API
   */

  get isRemote() {
    return (Services.appinfo.processType ===
            Services.appinfo.PROCESS_TYPE_CONTENT);
  },

  init: function () {
    // child *process* mm, or when loaded into the parent for in-content
    // support the psuedo child process mm 'child PPMM'.
    if (!this._mm) {
      this._mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
        getService(Ci.nsISyncMessageSender);
      this._mm.addMessageListener('PDFJS:Child:refreshSettings', this);
      Services.obs.addObserver(this, 'quit-application', false);
    }
  },

  uninit: function () {
    if (this._mm) {
      this._mm.removeMessageListener('PDFJS:Child:refreshSettings', this);
      Services.obs.removeObserver(this, 'quit-application');
    }
    this._mm = null;
  },

  /*
   * prefs utilities - the child does not have write access to prefs.
   * note, the pref names here are cross-checked against a list of
   * approved pdfjs prefs in chrome utils.
   */

  clearUserPref: function (aPrefName) {
    this._mm.sendSyncMessage('PDFJS:Parent:clearUserPref', {
      name: aPrefName
    });
  },

  setIntPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setIntPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setBoolPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setBoolPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setCharPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setCharPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setStringPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setStringPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  /*
   * Forwards default app query to the parent where we check various
   * handler app settings only available in the parent process.
   */
  isDefaultHandlerApp: function () {
    return this._mm.sendSyncMessage('PDFJS:Parent:isDefaultHandlerApp')[0];
  },

  /*
   * Request the display of a notification warning in the associated window
   * when the renderer isn't sure a pdf displayed correctly.
   */
  displayWarning: function (aWindow, aMessage, aCallback, aLabel, accessKey) {
    // the child's dom frame mm associated with the window.
    let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDocShell)
                       .QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIContentFrameMessageManager);
    winmm.sendAsyncMessage('PDFJS:Parent:displayWarning', {
      message: aMessage,
      label: aLabel,
      accessKey: accessKey
    }, {
      callback: aCallback
    });
  },

  /*
   * Events
   */

  observe: function(aSubject, aTopic, aData) {
    if (aTopic === 'quit-application') {
      this.uninit();
    }
  },

  receiveMessage: function (aMsg) {
    switch (aMsg.name) {
      case 'PDFJS:Child:refreshSettings':
        // Only react to this if we are remote.
        if (Services.appinfo.processType ===
            Services.appinfo.PROCESS_TYPE_CONTENT) {
          let jsm = 'resource://pdf.js/PdfJs.jsm';
          let pdfjs = Components.utils.import(jsm, {}).PdfJs;
          pdfjs.updateRegistration();
        }
        break;
    }
  },

  /*
   * CPOWs
   */

  getChromeWindow: function (aWindow) {
    let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell)
                        .sameTypeRootTreeItem
                        .QueryInterface(Ci.nsIDocShell)
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIContentFrameMessageManager);
    // Sync calls don't support cpow wrapping of returned results, so we
    // send over a small container for the object we want.
    let suitcase = {
      _window: null,
      setChromeWindow: function (aObj) {
        this._window = aObj;
      }
    };
    if (!winmm.sendSyncMessage('PDFJS:Parent:getChromeWindow', {},
                               { suitcase: suitcase })[0]) {
      Cu.reportError('A request for a CPOW wrapped chrome window ' +
                     'failed for unknown reasons.');
      return null;
    }
    return suitcase._window;
  },

  getFindBar: function (aWindow) {
    let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell)
                        .sameTypeRootTreeItem
                        .QueryInterface(Ci.nsIDocShell)
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIContentFrameMessageManager);
    let suitcase = {
      _findbar: null,
      setFindBar: function (aObj) {
        this._findbar = aObj;
      }
    };
    if (!winmm.sendSyncMessage('PDFJS:Parent:getFindBar', {},
                               { suitcase: suitcase })[0]) {
      Cu.reportError('A request for a CPOW wrapped findbar ' +
                     'failed for unknown reasons.');
      return null;
    }
    return suitcase._findbar;
  }
};
<commit_msg>Remove obsolete CPOW code from PdfjsContentUtils.jsm (PR 5749 followup)<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * 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.
 */
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */

'use strict';

var EXPORTED_SYMBOLS = ['PdfjsContentUtils'];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');

let PdfjsContentUtils = {
  _mm: null,

  /*
   * Public API
   */

  get isRemote() {
    return (Services.appinfo.processType ===
            Services.appinfo.PROCESS_TYPE_CONTENT);
  },

  init: function () {
    // child *process* mm, or when loaded into the parent for in-content
    // support the psuedo child process mm 'child PPMM'.
    if (!this._mm) {
      this._mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
        getService(Ci.nsISyncMessageSender);
      this._mm.addMessageListener('PDFJS:Child:refreshSettings', this);
      Services.obs.addObserver(this, 'quit-application', false);
    }
  },

  uninit: function () {
    if (this._mm) {
      this._mm.removeMessageListener('PDFJS:Child:refreshSettings', this);
      Services.obs.removeObserver(this, 'quit-application');
    }
    this._mm = null;
  },

  /*
   * prefs utilities - the child does not have write access to prefs.
   * note, the pref names here are cross-checked against a list of
   * approved pdfjs prefs in chrome utils.
   */

  clearUserPref: function (aPrefName) {
    this._mm.sendSyncMessage('PDFJS:Parent:clearUserPref', {
      name: aPrefName
    });
  },

  setIntPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setIntPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setBoolPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setBoolPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setCharPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setCharPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  setStringPref: function (aPrefName, aPrefValue) {
    this._mm.sendSyncMessage('PDFJS:Parent:setStringPref', {
      name: aPrefName,
      value: aPrefValue
    });
  },

  /*
   * Forwards default app query to the parent where we check various
   * handler app settings only available in the parent process.
   */
  isDefaultHandlerApp: function () {
    return this._mm.sendSyncMessage('PDFJS:Parent:isDefaultHandlerApp')[0];
  },

  /*
   * Request the display of a notification warning in the associated window
   * when the renderer isn't sure a pdf displayed correctly.
   */
  displayWarning: function (aWindow, aMessage, aCallback, aLabel, accessKey) {
    // the child's dom frame mm associated with the window.
    let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDocShell)
                       .QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIContentFrameMessageManager);
    winmm.sendAsyncMessage('PDFJS:Parent:displayWarning', {
      message: aMessage,
      label: aLabel,
      accessKey: accessKey
    }, {
      callback: aCallback
    });
  },

  /*
   * Events
   */

  observe: function(aSubject, aTopic, aData) {
    if (aTopic === 'quit-application') {
      this.uninit();
    }
  },

  receiveMessage: function (aMsg) {
    switch (aMsg.name) {
      case 'PDFJS:Child:refreshSettings':
        // Only react to this if we are remote.
        if (Services.appinfo.processType ===
            Services.appinfo.PROCESS_TYPE_CONTENT) {
          let jsm = 'resource://pdf.js/PdfJs.jsm';
          let pdfjs = Components.utils.import(jsm, {}).PdfJs;
          pdfjs.updateRegistration();
        }
        break;
    }
  }
};
<|endoftext|>


<commit_before>export { DEvolution_VersusSubmitter as VersusSubmitter };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import { VersusId } from "../../util/DEvolution_VersusId.js";

/**
 *
 *
 *
 * @member {string} measurement_id
 *   The measurement id of stream of property of Google Analytics v4.
 *
 * @member {string} api_secret
 *   The measurement api secret of stream of property of Google Analytics v4.
 *
 * @member {string} client_id
 *   The client id when sending measurement protocol.
 */
class DEvolution_VersusSubmitter extends Recyclable.Root {

  /**
   * Used as default DEvolution.VersusSubmitter provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "DEvolution.VersusSubmitter.Pool",
    DEvolution_VersusSubmitter, DEvolution_VersusSubmitter.setAsConstructor );

  /** */
  constructor( measurement_id, api_secret, client_id ) {
    super();
    DEvolution_VersusSubmitter.setAsConstructor_self.call( this,
      measurement_id, api_secret, client_id );
  }

  /** @override */
  static setAsConstructor( measurement_id, api_secret, client_id ) {
    super.setAsConstructor();
    DEvolution_VersusSubmitter.setAsConstructor_self.call( this,
      measurement_id, api_secret, client_id );
    return this;
  }

  /** @override */
  static setAsConstructor_self( measurement_id, api_secret, client_id ) {
    this.measurement_id = measurement_id;
    this.api_secret = api_secret;
    this.client_id = client_id;
  }

  /** @override */
  disposeResources() {
    this.client_id = undefined;
    this.api_secret = undefined;
    this.measurement_id = undefined;
    super.disposeResources();
  }

  /**
   *
   * @param {string} versusIdString
   *   The versus id string. (e.g. EntityNo_ParentGenerationNo_OffspringGenerationNo).
   *
   * @param {number} nNegativeZeroPositive
   *   The lose/draw/win value of the versus. (-1 or 0 or +1)
   *     - -1 (if parent lose offspring)
   *     -  0 (if parent draw offspring)
   *     - +1 (if parent win offspring)
   */
  send( versusIdString, nNegativeZeroPositive ) {

    let url = `${DEvolution_VersusSubmitter.urlBase}?measurement_id=${
      this.measurement_id}&api_secret=${this.api_secret}`;

    // Every versus result viewed as purchasing an item.
    //   - itemName is versus id
    //   - quantity is -1 or 0 or +1 representing versus result.
    //
    // Q1: Why send item_name (rather than item_id)?
    // A1: For report viewing convenience. Because in Google Analytics Report UI,
    //     the default e-commerce report uses itemName (not itemId).
    //
    // Q2: Why send quantity (rather than price)?
    // A2: According to experiment, The Google Analytics Data report's itemRevenue
    //     only works if ( quantity, price, currency ) all provided (and some
    //     floating-point accumulation error might be introduced). However, report's
    //     itemsPurchased only needs ( quantity ) and no floating-point accumulation
    //     error (because it is an integer).
    //
    let itemVersusResult = {
      item_name: versusIdString,
      quantity: nNegativeZeroPositive,
    };

    let eventPurchase = {
      name: "purchase",
      params: { items: [ itemVersusResult ] }
    };

    let postBody = {
      client_id: this.client_id, // (e.g. "XXXXXXXXXX.YYYYYYYYYY")
      events: [ eventPurchase  ]
    };

    let postBodyString = JSON.stringify( postBody );
    let options = {
      method: "POST",
      body: postBodyString
    };

    fetch( url, options );
  }

}

DEvolution_VersusSubmitter.urlBase = "https://www.google-analytics.com/mp/collect";
<commit_msg>non_personalized_ads: true<commit_after>export { DEvolution_VersusSubmitter as VersusSubmitter };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import { VersusId } from "../../util/DEvolution_VersusId.js";

/**
 *
 *
 *
 * @member {string} measurement_id
 *   The measurement id of stream of property of Google Analytics v4.
 *
 * @member {string} api_secret
 *   The measurement api secret of stream of property of Google Analytics v4.
 *
 * @member {string} client_id
 *   The client id when sending measurement protocol.
 */
class DEvolution_VersusSubmitter extends Recyclable.Root {

  /**
   * Used as default DEvolution.VersusSubmitter provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "DEvolution.VersusSubmitter.Pool",
    DEvolution_VersusSubmitter, DEvolution_VersusSubmitter.setAsConstructor );

  /** */
  constructor( measurement_id, api_secret, client_id ) {
    super();
    DEvolution_VersusSubmitter.setAsConstructor_self.call( this,
      measurement_id, api_secret, client_id );
  }

  /** @override */
  static setAsConstructor( measurement_id, api_secret, client_id ) {
    super.setAsConstructor();
    DEvolution_VersusSubmitter.setAsConstructor_self.call( this,
      measurement_id, api_secret, client_id );
    return this;
  }

  /** @override */
  static setAsConstructor_self( measurement_id, api_secret, client_id ) {
    this.measurement_id = measurement_id;
    this.api_secret = api_secret;
    this.client_id = client_id;
  }

  /** @override */
  disposeResources() {
    this.client_id = undefined;
    this.api_secret = undefined;
    this.measurement_id = undefined;
    super.disposeResources();
  }

  /**
   *
   * @param {string} versusIdString
   *   The versus id string. (e.g. EntityNo_ParentGenerationNo_OffspringGenerationNo).
   *
   * @param {number} nNegativeZeroPositive
   *   The lose/draw/win value of the versus. (-1 or 0 or +1)
   *     - -1 (if parent lose offspring)
   *     -  0 (if parent draw offspring)
   *     - +1 (if parent win offspring)
   */
  send( versusIdString, nNegativeZeroPositive ) {

    let url = `${DEvolution_VersusSubmitter.urlBase}?measurement_id=${
      this.measurement_id}&api_secret=${this.api_secret}`;

    // Every versus result viewed as purchasing an item.
    //   - itemName is versus id
    //   - quantity is -1 or 0 or +1 representing versus result.
    //
    // Q1: Why send item_name (rather than item_id)?
    // A1: For report viewing convenience. Because in Google Analytics Report UI,
    //     the default e-commerce report uses itemName (not itemId).
    //
    // Q2: Why send quantity (rather than price)?
    // A2: According to experiment, The Google Analytics Data report's itemRevenue
    //     only works if ( quantity, price, currency ) all provided (and some
    //     floating-point accumulation error might be introduced). However, report's
    //     itemsPurchased only needs ( quantity ) and no floating-point accumulation
    //     error (because it is an integer).
    //
    let itemVersusResult = {
      item_name: versusIdString,
      quantity: nNegativeZeroPositive,
    };

    let eventPurchase = {
      name: "purchase",
      params: { items: [ itemVersusResult ] }
    };

    let postBody = {
      client_id: this.client_id, // (e.g. "XXXXXXXXXX.YYYYYYYYYY")
      non_personalized_ads: true, // Because this information is not personalized.
      events: [ eventPurchase  ]
    };

    let postBodyString = JSON.stringify( postBody );
    let options = {
      method: "POST",
      body: postBodyString
    };

    fetch( url, options );
  }

}

DEvolution_VersusSubmitter.urlBase = "https://www.google-analytics.com/mp/collect";
<|endoftext|>


<commit_before>// Convert an element into a 3D laptop, moving its contents into the screen.

import { sneakyHashChange } from '../helpers';
import { Navigation } from '.';

window.sassLengthVariable = 30;
window.sassWidthVariable = (window.sassLengthVariable / 3) * 2;
window.sassHeightVariable = (window.sassLengthVariable / 50);

export class Laptop {
  static get defaultLidAngle() { return 100; }

  constructor(elem, index) {
    this.elem = elem;
    this.index = index;
    this.hash = this.elem.getAttribute('data-laptop3d-hash');

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = Laptop.defaultLidAngle;

    this.elem.classList.add('laptop3d');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Set transition time
    this.transitionTime = this.baseTransitionTime = 0.3;

    // Lift up a bit on hover
    this.wrapper.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
    this.wrapper.addEventListener('mouseleave', () => { this.translateZ = 0; });

    // Center self or close navigation on click
    this.wrapper.addEventListener('click', () => {
      if (this.carousel) {
        if (this.index !== this.carousel.position) this.centerSelf();
        else if (this.carousel.navigation) this.carousel.navigation.close();
      }
    });

    this._applyTransform();
  }

  centerSelf() {
    return new Promise((resolve, reject) => {
      // Requires a carousel to be attached
      if (this.carousel) {
        // Resolve instantly if nothing is changing
        if (this.index === this.carousel.position) resolve();
        // Otherwise change and resolve when CSS animation will have finished
        else {
          this.carousel.position = this.index;
          setTimeout(resolve, this.transitionTime * 1000);
        }
      // If there isn't a carousel, reject
      } else {
        reject('No carousel connected');
      }
    });
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-${window.sassWidthVariable * 2}vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation

  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }
  // Promise versions
  _setRotatePromise(axis, val) {
    return new Promise((resolve) => {
      // Resolve instantly if nothing is changing
      if (this[`_rotate${axis}`] === val) resolve();
      // Otherwise change and resolve when CSS animation will have finished
      else {
        this._setRotate(axis, val);
        setTimeout(resolve, this.transitionTime * 1000);
      }
    });
  }
  setRotateX(val) { return this._setRotatePromise('X', val); }
  setRotateY(val) { return this._setRotatePromise('Y', val); }
  setRotateZ(val) { return this._setRotatePromise('Z', val); }

  // Lid

  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }
  setLidAngle(val) { // promise version
    return new Promise((resolve) => {
      // Resolve instantly if nothing is changing
      if (this.lidAngle === val) resolve();
      // Otherwise change and resolve when CSS animation will have finished
      else {
        this.lidAngle = val;
        setTimeout(resolve, this.transitionTime * 1000);
      }
    });
  }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.lid.style.transition = `transform ${secs}s`;
  }
}

export class LaptopCarousel {
  static get rotLimit() { return 75; }

  constructor(container, laptops, navigation) {
    this.container = container;
    this.laptops = laptops;
    this.navigation = navigation; // passing a Navigation instance is optional
    this.offsetAngle = 30; // Laptops are 30 degrees from eachother
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });

    if (this.navigation) this._position = this.getLaptopWithHash(Navigation.hash).index;
    else this._position = 0;
    // Trigger immediate layout of laptops
    this.position = this._position;

    this.shouldPushState = false;
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  // Force a number to be inside (-rotLimit, rotLimit)
  static boundRotation(rot) {
    const sign = Math.sign(rot);
    return sign * Math.min(Math.abs(rot), LaptopCarousel.rotLimit);
  }

  // Each 1 position value represents centering the next laptop. Position x will result in the
  // the laptop with index x being centered
  get position() { return this._position; }
  set position(pos) {
    (async () => {
      // Wait for safe to animate if this is part of a Navigation
      if (this.navigation) {
        await this.navigation.safeToAnimate; // Wait for it to be safe to animate
        this.navigation.animationStarted(); // Register that an animation is in progress
      }

      // Cancel hover effect
      this.laptops.forEach((laptop) => { laptop.translateZ = 0; });

      // Close laptops
      const lidsClosed = this.laptops.map(laptop => laptop.setLidAngle(0));
      await Promise.all(lidsClosed); // Wait for all to close

      // Update internal position value
      const delta = Math.abs(this._position - pos);
      this._position = pos;

      // Navigation things
      sneakyHashChange(this.laptopsByIndex[pos].hash, this.shouldPushState); // change URL hash
      Navigation.navBarUpdate(); // Change top bar appearance
      // Reset shouldPushState (should only push once until explicitly set to push again)
      if (this.shouldPushState) this.shouldPushState = false;

      // Rotate laptops
      const rotations = this.laptops.map((laptop) => {
        const baseRot = laptop.index * -this.offsetAngle; // laptop rotation when position is 0
        const finalRot = baseRot + (this.position * this.offsetAngle); // Adjust for position
        laptop.transitionTime = (1 + ((delta - 1) * 0.5)) * this.baseTransitionTime;
        return laptop.setRotateZ(LaptopCarousel.boundRotation(finalRot)); // Set rotation
      });
      await Promise.all(rotations); // Wait for all to rotate
      this.transitionTime = this.baseTransitionTime;

      // Open the selected laptop
      if (this.position in this.laptopsByIndex) {
        await this.laptopsByIndex[this.position].setLidAngle(100);
      }

      this.navigation.animationFinished();
    })();
  }

  left() {
    if (this.position > this.minIndex) this.position -= 1;
  }
  right() {
    if (this.position < this.maxIndex) this.position += 1;
  }

  set transitionTime(secs) {
    this.laptops.forEach((l) => { l.transitionTime = secs; });
  }

  get transitionTime() {
    const answer = this.laptops[0].transitionTime;
    // Warn if not every laptop has the same transitionTime
    if (!this.laptops.every(laptop => laptop.transitionTime === answer)) console.warn('LaptopCarousel.transitionTime called but transitionTime of laptops is inconsistent');
    return answer;
  }

  get baseTransitionTime() {
    const answer = this.laptops[0].baseTransitionTime;
    // Warn if not every laptop has the same baseTransitionTime
    if (!this.laptops.every(laptop => laptop.baseTransitionTime === answer)) console.warn('LaptopCarousel.baseTransitionTime called but baseTransitionTime of laptops is inconsistent');
    return answer;
  }

  addLaptop(laptop) {
    // Prevent index overlap
    if (this.indices.includes(laptop.index)) throw new Error(`A laptop with index ${laptop.index} is already present`);
    // Add to laptops array and re-sort
    this.laptops.push(laptop);
    this.laptops.sort((a, b) => a.index - b.index);
    // Record in laptopsByIndex object
    this.laptopsByIndex[laptop.index] = laptop;
  }

  removeLaptop(laptop) {
    // Remove from laptopsByIndex
    this.laptopsByIndex[laptop.index] = undefined;
    // Remove from laptops array. Array will still be sorted after removal
    if (this.laptops.indexOf(laptop) !== -1) this.laptops.splice(this.laptops.indexOf(laptop), 1);
  }

  getLaptopWithHash(hash) {
    return this.laptops.filter(n => n.hash === hash)[0];
  }
}
<commit_msg>Fix resolve timing of centerSelf<commit_after>// Convert an element into a 3D laptop, moving its contents into the screen.

import { sneakyHashChange } from '../helpers';
import { Navigation } from '.';

window.sassLengthVariable = 30;
window.sassWidthVariable = (window.sassLengthVariable / 3) * 2;
window.sassHeightVariable = (window.sassLengthVariable / 50);

export class Laptop {
  static get defaultLidAngle() { return 100; }

  constructor(elem, index) {
    this.elem = elem;
    this.index = index;
    this.hash = this.elem.getAttribute('data-laptop3d-hash');

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = Laptop.defaultLidAngle;

    this.elem.classList.add('laptop3d');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Set transition time
    this.transitionTime = this.baseTransitionTime = 0.3;

    // Lift up a bit on hover
    this.wrapper.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
    this.wrapper.addEventListener('mouseleave', () => { this.translateZ = 0; });

    // Center self or close navigation on click
    this.wrapper.addEventListener('click', () => {
      if (this.carousel) {
        if (this.index !== this.carousel.position) this.centerSelf();
        else if (this.carousel.navigation) this.carousel.navigation.close();
      }
    });

    this._applyTransform();
  }

  centerSelf() {
    return new Promise((resolve, reject) => {
      // Requires a carousel to be attached
      if (this.carousel) {
        // Resolve instantly if nothing is changing
        if (this.index === this.carousel.position) resolve();
        // Otherwise change and resolve when CSS animation will have finished
        else {
          this.carousel.position = this.index;
          setTimeout(resolve, this.carousel.getTimeToPos(this.index));
        }
      // If there isn't a carousel, reject
      } else {
        reject('No carousel connected');
      }
    });
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-${window.sassWidthVariable * 2}vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation

  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }
  // Promise versions
  _setRotatePromise(axis, val) {
    return new Promise((resolve) => {
      // Resolve instantly if nothing is changing
      if (this[`_rotate${axis}`] === val) resolve();
      // Otherwise change and resolve when CSS animation will have finished
      else {
        this._setRotate(axis, val);
        setTimeout(resolve, this.transitionTime * 1000);
      }
    });
  }
  setRotateX(val) { return this._setRotatePromise('X', val); }
  setRotateY(val) { return this._setRotatePromise('Y', val); }
  setRotateZ(val) { return this._setRotatePromise('Z', val); }

  // Lid

  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }
  setLidAngle(val) { // promise version
    return new Promise((resolve) => {
      // Resolve instantly if nothing is changing
      if (this.lidAngle === val) resolve();
      // Otherwise change and resolve when CSS animation will have finished
      else {
        this.lidAngle = val;
        setTimeout(resolve, this.transitionTime * 1000);
      }
    });
  }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.lid.style.transition = `transform ${secs}s`;
  }
}

export class LaptopCarousel {
  static get rotLimit() { return 75; }

  constructor(container, laptops, navigation) {
    this.container = container;
    this.laptops = laptops;
    this.navigation = navigation; // passing a Navigation instance is optional
    this.offsetAngle = 30; // Laptops are 30 degrees from eachother
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });

    if (this.navigation) this._position = this.getLaptopWithHash(Navigation.hash).index;
    else this._position = 0;
    // Trigger immediate layout of laptops
    this.position = this._position;

    this.shouldPushState = false;
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  // Force a number to be inside (-rotLimit, rotLimit)
  static boundRotation(rot) {
    const sign = Math.sign(rot);
    return sign * Math.min(Math.abs(rot), LaptopCarousel.rotLimit);
  }

  // Each 1 position value represents centering the next laptop. Position x will result in the
  // the laptop with index x being centered
  get position() { return this._position; }
  set position(pos) {
    (async () => {
      // Wait for safe to animate if this is part of a Navigation
      if (this.navigation) {
        await this.navigation.safeToAnimate; // Wait for it to be safe to animate
        this.navigation.animationStarted(); // Register that an animation is in progress
      }

      // Cancel hover effect
      this.laptops.forEach((laptop) => { laptop.translateZ = 0; });

      // Close laptops
      const lidsClosed = this.laptops.map(laptop => laptop.setLidAngle(0));
      await Promise.all(lidsClosed); // Wait for all to close

      // Update internal position value
      const delta = Math.abs(this._position - pos);
      this._position = pos;

      // Navigation things
      sneakyHashChange(this.laptopsByIndex[pos].hash, this.shouldPushState); // change URL hash
      Navigation.navBarUpdate(); // Change top bar appearance
      // Reset shouldPushState (should only push once until explicitly set to push again)
      if (this.shouldPushState) this.shouldPushState = false;

      // Rotate laptops
      const rotations = this.laptops.map((laptop) => {
        const baseRot = laptop.index * -this.offsetAngle; // laptop rotation when position is 0
        const finalRot = baseRot + (this.position * this.offsetAngle); // Adjust for position
        laptop.transitionTime = (1 + ((delta - 1) * 0.5)) * this.baseTransitionTime;
        return laptop.setRotateZ(LaptopCarousel.boundRotation(finalRot)); // Set rotation
      });
      await Promise.all(rotations); // Wait for all to rotate
      this.transitionTime = this.baseTransitionTime;

      // Open the selected laptop
      if (this.position in this.laptopsByIndex) {
        await this.laptopsByIndex[this.position].setLidAngle(100);
      }

      this.navigation.animationFinished();
    })();
  }

  /** Return the number of milliseconds it would take to transition to a given position */
  getTimeToPos(pos) {
    let total = 0;
    const delta = Math.abs(this._position - pos);
    total += this.transitionTime; // Close laptops
    total += (1 + ((delta - 1) * 0.5)) * this.baseTransitionTime; // Rotate laptops
    total += this.baseTransitionTime; // Open selected laptop
    return total * 1000;
  }

  left() {
    if (this.position > this.minIndex) this.position -= 1;
  }
  right() {
    if (this.position < this.maxIndex) this.position += 1;
  }

  set transitionTime(secs) {
    this.laptops.forEach((l) => { l.transitionTime = secs; });
  }

  get transitionTime() {
    const answer = this.laptops[0].transitionTime;
    // Warn if not every laptop has the same transitionTime
    if (!this.laptops.every(laptop => laptop.transitionTime === answer)) console.warn('LaptopCarousel.transitionTime called but transitionTime of laptops is inconsistent');
    return answer;
  }

  get baseTransitionTime() {
    const answer = this.laptops[0].baseTransitionTime;
    // Warn if not every laptop has the same baseTransitionTime
    if (!this.laptops.every(laptop => laptop.baseTransitionTime === answer)) console.warn('LaptopCarousel.baseTransitionTime called but baseTransitionTime of laptops is inconsistent');
    return answer;
  }

  addLaptop(laptop) {
    // Prevent index overlap
    if (this.indices.includes(laptop.index)) throw new Error(`A laptop with index ${laptop.index} is already present`);
    // Add to laptops array and re-sort
    this.laptops.push(laptop);
    this.laptops.sort((a, b) => a.index - b.index);
    // Record in laptopsByIndex object
    this.laptopsByIndex[laptop.index] = laptop;
  }

  removeLaptop(laptop) {
    // Remove from laptopsByIndex
    this.laptopsByIndex[laptop.index] = undefined;
    // Remove from laptops array. Array will still be sorted after removal
    if (this.laptops.indexOf(laptop) !== -1) this.laptops.splice(this.laptops.indexOf(laptop), 1);
  }

  getLaptopWithHash(hash) {
    return this.laptops.filter(n => n.hash === hash)[0];
  }
}
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

'use strict';

const address = require('network-address'),
	url = require('url'),
	route = require('koa-route'),
	service = require('kronos-service'),
	ServiceConsumerMixin = require('kronos-service').ServiceConsumerMixin;

class ServiceConsul extends service.Service {

	static get name() {
		return 'consul';
	}

	get type() {
		return ServiceConsul.name;
	}

	get autostart() {
		return true;
	}

	constructor(config, owner) {
		super(config, owner);

		// id of our node in the consul cluster
		Object.defineProperty(this, 'id', {
			value: address()
		});

		Object.defineProperty(this, 'checkPath', {
			value: config.checkPath || '/check'
		});

		Object.defineProperty(this, 'checkInterval', {
			value: config.checkInterval || '10s'
		});
	}

	_configure(config) {
		const options = {
			promisify(fn) {
				return new Promise((resolve, reject) => {
					try {
						return fn((err, data, res) => {
							if (err) {
								err.res = res;
								return reject(err);
							}
							return resolve([data, res]);
						});
					} catch (err) {
						return reject(err);
					}
				});
			}
		};

		['host', 'port', 'secure', 'ca'].forEach(name => {
			if (config[name] !== undefined) {
				options[name] = config[name];
			}
		});

		this.consul = require('consul')(options);
	}

	get serviceDefinition() {
		return {
			name: 'kronos',
			id: this.id,
			port: this.listener.port,
			address: this.listener.hostname,
			tags: this.tags,
			check: {
				id: this.listener.url + this.checkPath,
				http: this.listener.url + this.checkPath,
				interval: this.checkInterval,
				timeout: '1s'
			}
		};
	}

	/**
	 * Register the service in consul
	 * @return {Promise} that fullfills on succesfull startup
	 */
	_start() {
		return super._start().then(() => {
			this.tags = Object.keys(this.owner.steps);

			// wait until health-check and koa services are present
			return ServiceConsumerMixin.defineServiceConsumerProperties(this, {
				listener: {
					name: 'koa-admin',
					type: 'koa'
				},
				hcs: {
					name: 'health-check',
					type: 'health-check'
				}
			}, this.owner, true).then(() =>
				this.listener.start().then(() =>
					this.consul.agent.service.register(this.serviceDefinition).then(f => {
						this.consul.status.leader().then(leader => this.info(level =>
							`Consul raft leader is ${Object.keys(leader).join(',')}`));
						this.consul.status.peers().then(peers => this.info(level =>
							`Consul raft peers are ${peers.map(p => p.body)}`));
						this.kronosNodes().then(nodes => this.info(level =>
							`Kronos nodes are ${nodes[0].map( n => n.ServiceID)}`));

						/*
												this.kronosNodes().then(nodes => this.info(level =>
													`Kronos nodes are ${nodes.map(n => JSON.stringify(n.body))}`)).catch(console.log);
						*/

						this._stepRegisteredListener = step => {
							this.tags = Object.keys(this.owner.steps);
							this.update(5000);
						};

						this.owner.addListener('stepRegistered', this._stepRegisteredListener);

						this.listener.koa.use(route.get(this.checkPath, ctx =>
							this.hcs.endpoints.state.receive({}).then(r => {
								this.info({
									'health': r
								});
								this.status = r ? 200 : 300;
								ctx.body = r ? 'OK' : 'ERROR';
							})
						));

						return Promise.resolve();
					})
				)
			);
		});
	}

	/**
	 * deregister the service from consul
	 * @return {Promise} that fullfills when the deregitering has finished
	 */
	_stop() {
		return this.consul.agent.service.deregister(this.serviceDefinition.id).then(f => {
			this.owner.removeListener('stepRegistered', this._stepRegisteredListener);
			return Promise.resolve();
		});
	}

	/**
	 * Update service definition in consul
	 * @param {Number} delay time to wait before doing the unregister/register action
	 */
	update(delay) {
		const reregister = () =>
			this.consul.agent.service.deregister(this.serviceDefinition.id)
			.then(() => this.consul.agent.service.register(this.serviceDefinition));

		if (this._updateTimer) {
			clearTimeout(this._updateTimer);
		}

		if (delay) {
			this._updateTimer = setTimeout(reregister, delay);
		} else {
			return reregister();
		}
	}

	kronosNodes() {
		return this.consul.catalog.service.nodes({
			service: this.serviceDefinition.name
		});
	}

	registerService(name, options) {
		this.info({
			message: 'registerService',
			name: name,
			options: options
		});

		const u = url.parse(options.url);

		return this.consul.kv.set({
			key: `services/${name}/${this.id}/url`,
			value: options.url
		});

		/*
				const serviceDefinition = {
					name: name,
					id: u.href,
					address: u.hostname,
					port: parseInt(u.port, 10),
					tags: options.tags
				};

				return consul.agent.service.register(serviceDefinition).then(f => {
					//this.info(`registered: ${JSON.stringify(f)}`);
					return Promise.resolve();
				});
				*/
	}

	unregisterService(name) {
		this.info({
			message: 'unregisterService',
			name: name
		});

		return this.consul.kv.del({
			key: `services/${name}/${this.id}`,
			recurse: true
		});

		//return consul.agent.service.deregister(name);
	}

	* serviceURLs(name) {
		let si = [];

		let firstPromise = this.consul.kv.get({
				key: `services/${name}`,
				recurse: true
			})
			.then(data => {
				si = data[0].map(d => d.Value);
				firstPromise = undefined;
				return si.length === 0 ? Promise.reject() : Promise.resolve(si[0]);
			});

		while (firstPromise) {
			yield firstPromise;
			//console.log(`size: ${si.length} ${firstPromise}`);
		}

		if (si.length) {
			for (let i = 1;; i++) {
				if (i >= si.length) {
					i = 0;
				}
				//console.log(`yield: ${i} ${si.length}`);
				yield Promise.resolve(si[i]);
			}
		}
		return undefined;
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(ServiceConsul).then(sf =>
		manager.declareService({
			'type': sf.name,
			'name': 'registry'
		}));
<commit_msg>feat: nodes endpoint<commit_after>/* jslint node: true, esnext: true */

'use strict';

const address = require('network-address'),
	url = require('url'),
	route = require('koa-route'),
	endpoint = require('kronos-endpoint'),
	service = require('kronos-service'),
	ServiceConsumerMixin = require('kronos-service').ServiceConsumerMixin;

class ServiceConsul extends service.Service {

	static get name() {
		return 'consul';
	}

	get type() {
		return ServiceConsul.name;
	}

	get autostart() {
		return true;
	}

	constructor(config, owner) {
		super(config, owner);

		// id of our node in the consul cluster
		Object.defineProperty(this, 'id', {
			value: config.id || address()
		});

		Object.defineProperty(this, 'checkPath', {
			value: config.checkPath || '/check'
		});

		Object.defineProperty(this, 'checkInterval', {
			value: config.checkInterval || '10s'
		});

		this.addEndpoint(new endpoint.ReceiveEndpoint('nodes', this)).receive = request => this.kronosNodes();
	}

	_configure(config) {
		const options = {
			promisify(fn) {
				return new Promise((resolve, reject) => {
					try {
						return fn((err, data, res) => {
							if (err) {
								err.res = res;
								return reject(err);
							}
							return resolve([data, res]);
						});
					} catch (err) {
						return reject(err);
					}
				});
			}
		};

		['host', 'port', 'secure', 'ca'].forEach(name => {
			if (config[name] !== undefined) {
				options[name] = config[name];
			}
		});

		this.consul = require('consul')(options);
	}

	get serviceDefinition() {
		return {
			name: 'kronos',
			id: this.id,
			port: this.listener.port,
			address: this.listener.hostname,
			tags: this.tags,
			check: {
				id: this.listener.url + this.checkPath,
				http: this.listener.url + this.checkPath,
				interval: this.checkInterval,
				timeout: '1s'
			}
		};
	}

	/**
	 * Register the service in consul
	 * @return {Promise} that fullfills on succesfull startup
	 */
	_start() {
		return super._start().then(() => {
			this.tags = Object.keys(this.owner.steps);

			// wait until health-check and koa services are present
			return ServiceConsumerMixin.defineServiceConsumerProperties(this, {
				listener: {
					name: 'koa-admin',
					type: 'koa'
				},
				hcs: {
					name: 'health-check',
					type: 'health-check'
				}
			}, this.owner, true).then(() =>
				this.listener.start().then(() =>
					this.consul.agent.service.register(this.serviceDefinition).then(f => {
						this.consul.status.leader().then(leader => this.info(level =>
							`Consul raft leader is ${Object.keys(leader).join(',')}`));
						this.consul.status.peers().then(peers => this.info(level =>
							`Consul raft peers are ${peers.map(p => p.body)}`));
						this.kronosNodes().then(nodes => this.info(level =>
							`Kronos nodes are ${nodes[0].map( n => n.ServiceID)}`));

						/*
												this.kronosNodes().then(nodes => this.info(level =>
													`Kronos nodes are ${nodes.map(n => JSON.stringify(n.body))}`)).catch(console.log);
						*/

						this._stepRegisteredListener = step => {
							this.tags = Object.keys(this.owner.steps);
							this.update(5000);
						};

						this.owner.addListener('stepRegistered', this._stepRegisteredListener);

						this.listener.koa.use(route.get(this.checkPath, ctx =>
							this.hcs.endpoints.state.receive({}).then(r => {
								this.info({
									'health': r
								});
								this.status = r ? 200 : 300;
								ctx.body = r ? 'OK' : 'ERROR';
							})
						));

						return Promise.resolve();
					})
				)
			);
		});
	}

	/**
	 * deregister the service from consul
	 * @return {Promise} that fullfills when the deregitering has finished
	 */
	_stop() {
		return this.consul.agent.service.deregister(this.serviceDefinition.id).then(f => {
			this.owner.removeListener('stepRegistered', this._stepRegisteredListener);
			return Promise.resolve();
		});
	}

	/**
	 * Update service definition in consul
	 * @param {Number} delay time to wait before doing the unregister/register action
	 */
	update(delay) {
		const reregister = () =>
			this.consul.agent.service.deregister(this.serviceDefinition.id)
			.then(() => this.consul.agent.service.register(this.serviceDefinition));

		if (this._updateTimer) {
			clearTimeout(this._updateTimer);
		}

		if (delay) {
			this._updateTimer = setTimeout(reregister, delay);
		} else {
			return reregister();
		}
	}

	kronosNodes() {
		return this.consul.catalog.service.nodes({
			service: this.serviceDefinition.name
		});
	}

	registerService(name, options) {
		this.info({
			message: 'registerService',
			name: name,
			options: options
		});

		const u = url.parse(options.url);

		return this.consul.kv.set({
			key: `services/${name}/${this.id}/url`,
			value: options.url
		});

		/*
				const serviceDefinition = {
					name: name,
					id: u.href,
					address: u.hostname,
					port: parseInt(u.port, 10),
					tags: options.tags
				};

				return consul.agent.service.register(serviceDefinition).then(f => {
					//this.info(`registered: ${JSON.stringify(f)}`);
					return Promise.resolve();
				});
				*/
	}

	unregisterService(name) {
		this.info({
			message: 'unregisterService',
			name: name
		});

		return this.consul.kv.del({
			key: `services/${name}/${this.id}`,
			recurse: true
		});

		//return consul.agent.service.deregister(name);
	}

	* serviceURLs(name) {
		let si = [];

		let firstPromise = this.consul.kv.get({
				key: `services/${name}`,
				recurse: true
			})
			.then(data => {
				si = data[0].map(d => d.Value);
				firstPromise = undefined;
				return si.length === 0 ? Promise.reject() : Promise.resolve(si[0]);
			});

		while (firstPromise) {
			yield firstPromise;
			//console.log(`size: ${si.length} ${firstPromise}`);
		}

		if (si.length) {
			for (let i = 1;; i++) {
				if (i >= si.length) {
					i = 0;
				}
				//console.log(`yield: ${i} ${si.length}`);
				yield Promise.resolve(si[i]);
			}
		}
		return undefined;
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(ServiceConsul).then(sf =>
		manager.declareService({
			'type': sf.name,
			'name': 'registry'
		}));
<|endoftext|>


<commit_before>var defaultTime;
var selectedTime;
const date = {"sun": 1, "mon": 2, "tue": 3, "wed": 4, "thu": 5, "fri": 6, "sat": 7};
const week = {1: "sun", 2: "mon", 3: "tue", 4: "wed", 5: "thu", 6: "fri", 7: "sat"};
var startTimeClicked = false;
var timeArr = [];
var timePeriod = {};
var finalPeriod;

$('.time').on('touchstart click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('touchmove click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('touchend click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('tap click', function(e) {
    e.preventDefault(); //stops 'ghost clicks' (double clicking)
    defaultTime = $(this).children().eq(0).attr('id');

    selectedTime = id_convert_to_Num(defaultTime);

    timeArr.push(selectedTime);

    $('.selectionBox').show();

    mark_check_box(defaultTime);
});

$('#startTime').on('tap click', function() {
    startTimeClicked = true;
    if (timeArr.length === 1) {
        if ($(this).attr('id') in timePeriod) {
            alert('Start time already selected');
            $('.selectionBox').hide();
        } else {
            timePeriod[$(this).attr('id')] = selectedTime;
        }
    }

    mark_check_box(num_convert_to_id(selectedTime));
    timeArr = [];
    $('.selectionBox').hide();
});

$('#endTime').on('tap click', function(e) {
    e.preventDefault(); //stops 'ghost clicks' (double clicking)

    if (timeArr.length === 1) {
        if ($(this).attr('id') in timePeriod) {
            alert('Start time already selected');
            $('.selectionBox').hide();
        }

        if (!('endTime' in timePeriod) && !('startTime' in timePeriod)) {
            alert('Select start time first');
            $('.selectionBox').hide();
        }

        if (selectedTime < timePeriod['startTime']) {
            alert('End time < Start Time, please select again');
            $('.selectionBox').hide();
        }
        else {
            timePeriod[$(this).attr('id')] = selectedTime;
            finalPeriod = timePeriod;
            timePeriod = {};
        }
    }

    timeArr = [];

    $('.selectionBox').hide();
    let stime = finalPeriod['startTime'];
    let etime = finalPeriod['endTime'];
    a = num_convert_to_id(stime);
    b = num_convert_to_id(etime);

    for (let i = stime; i <= etime; i += 50) {
        if ( i%10000 === 2400 ) {
            i = ( parseInt(i/10000) + 1) *10000;
        }
        mark_check_box(num_convert_to_id(i));
    }
});

$('#cancel').on('tap click', function(e) {
    e.preventDefault(); //stops 'ghost clicks' (double clicking))

    remove_mark_box(num_convert_to_id(timeArr[0]));
    timeArr = [];
    $('.selectionBox').hide();
});

//Function to Mark box is selected
function mark_check_box(id) {
    return $(".time").find('#' + id).prop('checked', true);
}

function remove_mark_box(id) {
    return $(".time").find('#' + id).prop('checked', false);
}

//Convert string Id to Num
function id_convert_to_Num(id) {
    let dayInWeek = id.slice(0, 3);
    let dateNum = date[dayInWeek];
    let dayTime = id.slice(3, -2);

    if (dayTime.length > 2) {
        dayTime = dayTime.slice(0, -2) + 50; // 730 => 750, 1130 => 1150
        id = id.slice(0, 3) + dayTime + id.slice(-2);
    }

    switch (dayTime.length) {
        case 1:
            dayTime = '0' + dayTime + '00';
            break;
        case 2:
            dayTime = dayTime + '00';
            break;
        case 3:
            dayTime = '0' + dayTime;
            break;
        default:
            dayTime = dayTime;
    }

    //Handle corner case
    if(dayTime.slice(0, 2) === "12")
    {
        if(id.slice(-2) == "am")
        {
            dayTime = dayTime.replace("12","00");
        }
    }
    else if(id.slice(-2) == "pm")
    {
        dayTime = (parseInt(dayTime) + 1200).toString();
    }

    let numTime = parseInt(dateNum + dayTime);

    return numTime;
}

//Convert num Id to original Id
function num_convert_to_id(num) {
    let strNum = num.toString();
    let strDay = week[strNum.slice(0, 1)]; //eg: sun, mon...
    let dayTimeStr = strNum.slice(1, 5);

    //handle corner case
    if (strNum % 10000 === 0 ) {
        return strDay + '12am';

    }
    if (strNum % 10000 === 50) {
        return strDay + '1230am';
    }

    var clock = parseInt(dayTimeStr.slice(0,2));
    var is_pm = false;

    if(clock === 12)
    {
        is_pm = true;
    }
    else if(clock > 12)
    {
        is_pm = true;
        clock = clock - 12;
    }

    if(dayTimeStr.slice(2,4) == "50")
    {
        clock = clock * 100 + 30;
    }

    if (is_pm)
    {
        return strDay + clock + "pm";
    }

    return strDay + clock + "am";
}

<commit_msg>Final commit<commit_after>var defaultTime;
var selectedTime;
const date = {"sun": 1, "mon": 2, "tue": 3, "wed": 4, "thu": 5, "fri": 6, "sat": 7};
const week = {1: "sun", 2: "mon", 3: "tue", 4: "wed", 5: "thu", 6: "fri", 7: "sat"};
var startTimeClicked = false;
var timeArr = [];
var timePeriod = {};
var finalPeriod;

$('.time').on('touchstart click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('touchmove click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('touchend click', function(e) {
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)
});

$('.time').on('tap click', function(e) {
    e.preventDefault();
    e.stopPropagation();
    //$(this).off('click');
    defaultTime = $(this).children().eq(0).attr('id');

    selectedTime = id_convert_to_Num(defaultTime);

    timeArr.push(selectedTime);

    $('.selectionBox').show();

    mark_check_box(defaultTime);
});

$('#startTime').on('tap click', function(e) {
    e.preventDefault();
    e.stopPropagation();
    //$(this).off('click');
    startTimeClicked = true;
    if (timeArr.length === 1) {
        if ($(this).attr('id') in timePeriod) {
            alert('Start time already selected');
            $('.selectionBox').hide();
        } else {
            timePeriod[$(this).attr('id')] = selectedTime;
        }
    }

    mark_check_box(num_convert_to_id(selectedTime));
    timeArr = [];
    $('.selectionBox').hide();
});

$('#endTime').on('tap click', function(e) {
    e.preventDefault();
    e.stopPropagation();
    //$(this).off('click');
    //e.preventDefault(); //stops 'ghost clicks' (double clicking)

    if (timeArr.length === 1) {
        if ($(this).attr('id') in timePeriod) {
            alert('Start time already selected');
            $('.selectionBox').hide();
        }

        if (!('endTime' in timePeriod) && !('startTime' in timePeriod)) {
            alert('Select start time first');
            $('.selectionBox').hide();
        }

        if (selectedTime < timePeriod['startTime']) {
            alert('End time < Start Time, please select again');
            $('.selectionBox').hide();
        }
        else {
            timePeriod[$(this).attr('id')] = selectedTime;
            finalPeriod = timePeriod;
            timePeriod = {};
        }
    }

    timeArr = [];

    $('.selectionBox').hide();
    let stime = finalPeriod['startTime'];
    let etime = finalPeriod['endTime'];
    a = num_convert_to_id(stime);
    b = num_convert_to_id(etime);

    for (let i = stime; i <= etime; i += 50) {
        if ( i%10000 === 2400 ) {
            i = ( parseInt(i/10000) + 1) *10000;
        }
        mark_check_box(num_convert_to_id(i));
    }
});

$('#cancel').on('tap click', function(e) {
    e.preventDefault(); //stops 'ghost clicks' (double clicking))
    //e.preventDefault();
    e.stopPropagation();
    //$(this).off('click');
    remove_mark_box(num_convert_to_id(timeArr[0]));
    timeArr = [];
    $('.selectionBox').hide();
});

//Function to Mark box is selected
function mark_check_box(id) {
    return $(".time").find('#' + id).prop('checked', true);
}

function remove_mark_box(id) {
    return $(".time").find('#' + id).prop('checked', false);
}

//Convert string Id to Num
function id_convert_to_Num(id) {
    let dayInWeek = id.slice(0, 3);
    let dateNum = date[dayInWeek];
    let dayTime = id.slice(3, -2);

    if (dayTime.length > 2) {
        dayTime = dayTime.slice(0, -2) + 50; // 730 => 750, 1130 => 1150
        id = id.slice(0, 3) + dayTime + id.slice(-2);
    }

    switch (dayTime.length) {
        case 1:
            dayTime = '0' + dayTime + '00';
            break;
        case 2:
            dayTime = dayTime + '00';
            break;
        case 3:
            dayTime = '0' + dayTime;
            break;
        default:
            dayTime = dayTime;
    }

    //Handle corner case
    if(dayTime.slice(0, 2) === "12")
    {
        if(id.slice(-2) == "am")
        {
            dayTime = dayTime.replace("12","00");
        }
    }
    else if(id.slice(-2) == "pm")
    {
        dayTime = (parseInt(dayTime) + 1200).toString();
    }

    let numTime = parseInt(dateNum + dayTime);

    return numTime;
}

//Convert num Id to original Id
function num_convert_to_id(num) {
    let strNum = num.toString();
    let strDay = week[strNum.slice(0, 1)]; //eg: sun, mon...
    let dayTimeStr = strNum.slice(1, 5);

    //handle corner case
    if (strNum % 10000 === 0 ) {
        return strDay + '12am';

    }
    if (strNum % 10000 === 50) {
        return strDay + '1230am';
    }

    var clock = parseInt(dayTimeStr.slice(0,2));
    var is_pm = false;

    if(clock === 12)
    {
        is_pm = true;
    }
    else if(clock > 12)
    {
        is_pm = true;
        clock = clock - 12;
    }

    if(dayTimeStr.slice(2,4) == "50")
    {
        clock = clock * 100 + 30;
    }

    if (is_pm)
    {
        return strDay + clock + "pm";
    }

    return strDay + clock + "am";
}

<|endoftext|>