<commit_before>/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig 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:
 *
 * 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.
 */

var uportal = uportal || {};

(function($, _) {
   /**
    * Finds the appropriate property configuration for the current institution
    */
   var findPropertyConfig = function() {
      if (up.analytics.model == null) {
         return null;
      }

      if (_.isArray(up.analytics.model.institutions)) {
         var propertyConfig = _.find(up.analytics.model.hosts, function(propertyConfig) {
            if (propertyConfig.name == up.analytics.host) {
               return propertyConfig;
            }
         });

         if (propertyConfig != null) {
            return propertyConfig;
         }
      }

      return up.analytics.model.defaultConfig;
   };

   /**
    * Create the tracker with the propertyId and configuration from the
    * specified propertyConfig
    */
   var createTracker = function(propertyConfig) {
      var createSettings = {};
      _.each(propertyConfig.config || [], function(setting) {
         // Name isn't supported, we assume the default tracker is used in other
         // places
         if (setting.name != "name") {
            createSettings[setting.name] = setting.value;
         }
      });
      ga('create', propertyConfig.propertyId, createSettings); // Create the
   };

   /**
    * Set the dimensions that apply to the current user
    */
   var setDimensions = function(propertyConfig) {
      var dimensions = {};
      _.each(propertyConfig.dimensionGroups || [], function(setting) {
         dimensions['dimension' + setting.name] = setting.value;
      });

      ga('set', dimensions);
   };

   /**
    * Build the page URI for a tab
    */
   var getTabUri = function(fragmentName, tabName) {
      if (up.analytics.pageData.tab != null) {
         fragmentName = fragmentName || up.analytics.pageData.tab.fragmentName;
         tabName = tabName || up.analytics.pageData.tab.tabName
      }

      var uri = '/';

      if (fragmentName != null) {
         uri += 'tab/' + fragmentName;

         if (tabName != null) {
            uri += '/' + tabName;
         }
      }

      return uri
   };

   /**
    * Set variables specific to the current page
    */
   var setPageVariables = function(fragmentName, tabName) {
      if (up.analytics.pageData.tab != null) {
         fragmentName = fragmentName || up.analytics.pageData.tab.fragmentName;
         tabName = tabName || up.analytics.pageData.tab.tabName
      }

      var title;
      if (tabName != null) {
         title = 'Tab: ' + tabName;
      }
      else if (up.analytics.pageData.urlState == null) {
         title = "Portal Home"
      }
      else {
         title = "No Tab"
      }

      ga('set', {
         'page' : getTabUri(fragmentName, tabName),
         'title' : title
      });
   };

   /**
    * Safe way to resolve the portlet's fname from the windowId, falls back to
    * just using the portlet's windowId as the value if no fname is found in the
    * portletData
    */
   var getPortletFname = function(windowId) {
      var portletData = up.analytics.portletData[windowId];
      if (portletDate == null) {
         return windowId;
      }

      return portletData.fname;
   };

   /**
    * Safe way to resolve the portlet's title from the windowId, falls back to
    * just using getPortletFname(windowId) if the title can't be found
    */
   var getRenderedPortletTitle = function(windowId) {
      var portletWindowWrapper = $("div.up-portlet-windowId-content-wrapper." + windowId);
      if (portletWindowWrapper == null) {
         return getPortletFname(windowId);
      }

      var portletWrapper = portletWindowWrapper.parents("div.up-portlet-wrapper-inner");
      if (portletWrapper == null) {
         return getPortletFname(windowId);
      }

      var portletTitle = portletWrapper.find("div.up-portlet-titlebar h2 a");
      if (portletTitle == null) {
         return getPortletFname(windowId);
      }

      return portletTitle.text().trim();
   };

   /**
    * Build the portlet URI for the specified portlet
    */
   var getPortletUri = function(fname) {
      return '/portlet/' + fname;
   };

   /**
    * Set variables specific to the specified portlet
    */
   var setPortletVariables = function(windowId, portletData) {
      var portletTitle = getRenderedPortletTitle(windowId);

      if (portletData == null) {
         portletData = up.analytics.portletData[windowId];
      }

      ga('set', {
         'page' : getPortletUri(portletData.fname),
         'title' : 'Portlet: ' + portletTitle
      });
   };

   /**
    * Finds a child element based on the selector and then return the first
    * class element that is not equal to excludedClasses or contained in the
    * excludedClasses array
    */
   var getInfoClass = function(selectorFunction, excludedClasses) {
      // Convert excludedClasses to an array for simpler code below
      if (!_.isArray(excludedClasses)) {
         excludedClasses = [excludedClasses];
      }

      var classAttr = selectorFunction().attr("class");
      if (classAttr == null) {
         return null;
      }

      var classes = classAttr.split(/\s+/);
      return _.find(classes, function(cls) {
         if (!_.contains(excludedClasses, cls)) {
            return cls;
         }
      });
   };

   /**
    * Determine the fname of the portle the clicked flyout was rendered for
    */
   var getFlyoutFname = function(clickedLink) {
      return getInfoClass(function() {
         return clickedLink.parents("div.up-portlet-fname-subnav-wrapper")
      }, "up-portlet-fname-subnav-wrapper");
   };

   /**
    * Determine the fname of the portle the clicked flyout was rendered for
    */
   var getExternaLinkWindowId = function(clickedLink) {
      return getInfoClass(function() {
         return clickedLink.parents("div.up-portlet-windowId-content-wrapper")
      }, "up-portlet-windowId-content-wrapper");
   };

   /**
    * Handler for sending an analytics event when a link is clicked and then
    * dealing with opening a new window or emulating the click
    */
   var handleLinkClickEvent = function(event, clickedLink, eventOpts) {
      // Click will open in a new window if it is the middle button or the
      // meta or control keys are held
      var newWindow = event.button == 1 || event.metaKey || event.ctrlKey || clickedLink.attr("target") != null;

      var clickFunction;
      if (newWindow) {
         clickFunction = function() {
         };
      } else {
         clickFunction = function() {
            document.location = clickedLink.attr("href");
         };
      }

      // Send the event
      setPageVariables();
      ga('send', $.extend({
         'hitType' : 'event',
         'hitCallback' : clickFunction
      }, eventOpts));

      // If not opening a new window prevent the event and set the fallback
      // to make sure the page navigates even if the hitCallback
      // is never called
      if (!newWindow) {
         // Fallback in case hitCallback takes too long to get called, don't
         // want clicks to hang
         setTimeout(clickFunction, 200);

         event.preventDefault();
      }
   };

   /**
    * Add click handlers to all of the flyout menus to fire flyout events when
    * they are used
    */
   var addFlyoutHandlers = function() {
      $("ul.fl-tabs li.portal-navigation a.portal-subnav-link").click(function(event) {
         var clickedLink = $(this);

         // Find the target portlet's title
         var portletFlyoutTitle = clickedLink.find("span.portal-subnav-label").text();

         // Find the target portlet's fname
         var fname = getFlyoutFname(clickedLink);

         // Setup the page level state
         setPageVariables();

         // Send the event and deal with the click
         handleLinkClickEvent(event, clickedLink, {
            'eventCategory' : 'Flyout Link',
            'eventAction' : getPortletUri(fname),
            'eventLabel' : portletFlyoutTitle
         });
      });
   };

   /**
    * Inspects all clicks on links, any of the clicks that result in existing to
    * a different host are tracked as Outbound Link events
    */
   var addExternalLinkHandlers = function() {
      $('a').click(function(event) {
         var clickedLink = $(this);

         var linkHost = clickedLink.prop("hostname");
         if (linkHost != "" && linkHost != document.domain) {
            var windowId = getExternaLinkWindowId(clickedLink);
            if (windowId != null) {
               setPortletVariables(windowId);
            } else {
               setPageVariables();
            }

            // Send the event and deal with the click
            handleLinkClickEvent(event, clickedLink, {
               'eventCategory' : 'Outbound Link',
               'eventAction' : clickedLink.prop("href"),
               'eventLabel' : clickedLink.text()
            });
         }
      });
   };

   var addMobileListTabHandlers = function() {
      $('ul.up-portal-nav li.up-tab').click(function(event) {
         var clickedTab = $(this);

         //Ignore clicks on already open tabs
         if (clickedTab.hasClass("up-tab-open")) {
            return;
         }

         var fragmentName = getInfoClass(function() {
               return clickedTab.find("div.up-tab-owner");
            }, "up-tab-owner");

         var tabName = clickedTab.find("span.up-tab-name").text().trim();

         setPageVariables(fragmentName, tabName);
         ga('send', 'pageview');
      });
   };

   $(document).ready(function() {
      // Fail safe, if the analytics library isn't loaded make sure the function
      // exists
      window['ga'] = window['ga'] || function() {
      };

      var propertyConfig = findPropertyConfig();

      // No property config means nothing to do
      if (propertyConfig == null) {
         return;
      }

      // Create the tracker
      createTracker(propertyConfig);

      // Set Dimensions
      setDimensions(propertyConfig);

      // Page Event
      setPageVariables();
      // Don't bother sending the view in MAX WindowState
      if (up.analytics.pageData.urlState != "MAX") {
         ga('send', 'pageview');
      }
      ga('send', {
        'hitType': 'timing',
        'timingCategory': 'tab',
        'timingVar': getTabUri(),
        'timingValue': (up.analytics.pageData.executionTimeNano / 1000000)
      });

      // Portlet Events
      _.each(up.analytics.portletData, function(portletData, windowId) {
         // TODO configure portlet analytics include/exclude list
         if (portletData.fname == "google-analytics-config") {
            return;
         }

         setPortletVariables(windowId, portletData);
         ga('send', 'pageview');
         ga('send', {
           'hitType': 'timing',
           'timingCategory': 'portlet',
           'timingVar': getPortletUri(portletData.fname),
           'timingValue':(portletData.executionTimeNano / 1000000)
         });
      });

      // Add handlers to deal with click events on flyouts
      addFlyoutHandlers();

      // Add handlers to deal with click events on external links
      addExternalLinkHandlers();

      // Add handlers to deal with "tab" clicks on the mobile accordian view
      addMobileListTabHandlers();
   });
})(jQuery, _);
<commit_msg>UP-3784<commit_after>/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig 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:
 *
 * 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.
 */

var uportal = uportal || {};

(function($, _) {
   /**
    * Finds the appropriate property configuration for the current institution
    */
   var findPropertyConfig = function() {
      if (up.analytics.model == null) {
         return null;
      }

      if (_.isArray(up.analytics.model.hosts)) {
         var propertyConfig = _.find(up.analytics.model.hosts, function(propertyConfig) {
            if (propertyConfig.name == up.analytics.host) {
               return propertyConfig;
            }
         });

         if (propertyConfig != null) {
            return propertyConfig;
         }
      }

      return up.analytics.model.defaultConfig;
   };

   /**
    * Create the tracker with the propertyId and configuration from the
    * specified propertyConfig
    */
   var createTracker = function(propertyConfig) {
      var createSettings = {};
      _.each(propertyConfig.config || [], function(setting) {
         // Name isn't supported, we assume the default tracker is used in other
         // places
         if (setting.name != "name") {
            createSettings[setting.name] = setting.value;
         }
      });
      ga('create', propertyConfig.propertyId, createSettings); // Create the
   };

   /**
    * Set the dimensions that apply to the current user
    */
   var setDimensions = function(propertyConfig) {
      var dimensions = {};
      _.each(propertyConfig.dimensionGroups || [], function(setting) {
         dimensions['dimension' + setting.name] = setting.value;
      });

      ga('set', dimensions);
   };

   /**
    * Build the page URI for a tab
    */
   var getTabUri = function(fragmentName, tabName) {
      if (up.analytics.pageData.tab != null) {
         fragmentName = fragmentName || up.analytics.pageData.tab.fragmentName;
         tabName = tabName || up.analytics.pageData.tab.tabName
      }

      var uri = '/';

      if (fragmentName != null) {
         uri += 'tab/' + fragmentName;

         if (tabName != null) {
            uri += '/' + tabName;
         }
      }

      return uri
   };

   /**
    * Set variables specific to the current page
    */
   var setPageVariables = function(fragmentName, tabName) {
      if (up.analytics.pageData.tab != null) {
         fragmentName = fragmentName || up.analytics.pageData.tab.fragmentName;
         tabName = tabName || up.analytics.pageData.tab.tabName
      }

      var title;
      if (tabName != null) {
         title = 'Tab: ' + tabName;
      }
      else if (up.analytics.pageData.urlState == null) {
         title = "Portal Home"
      }
      else {
         title = "No Tab"
      }

      ga('set', {
         'page' : getTabUri(fragmentName, tabName),
         'title' : title
      });
   };

   /**
    * Safe way to resolve the portlet's fname from the windowId, falls back to
    * just using the portlet's windowId as the value if no fname is found in the
    * portletData
    */
   var getPortletFname = function(windowId) {
      var portletData = up.analytics.portletData[windowId];
      if (portletDate == null) {
         return windowId;
      }

      return portletData.fname;
   };

   /**
    * Safe way to resolve the portlet's title from the windowId, falls back to
    * just using getPortletFname(windowId) if the title can't be found
    */
   var getRenderedPortletTitle = function(windowId) {
      var portletWindowWrapper = $("div.up-portlet-windowId-content-wrapper." + windowId);
      if (portletWindowWrapper == null) {
         return getPortletFname(windowId);
      }

      var portletWrapper = portletWindowWrapper.parents("div.up-portlet-wrapper-inner");
      if (portletWrapper == null) {
         return getPortletFname(windowId);
      }

      var portletTitle = portletWrapper.find("div.up-portlet-titlebar h2 a");
      if (portletTitle == null) {
         return getPortletFname(windowId);
      }

      return portletTitle.text().trim();
   };

   /**
    * Build the portlet URI for the specified portlet
    */
   var getPortletUri = function(fname) {
      return '/portlet/' + fname;
   };

   /**
    * Set variables specific to the specified portlet
    */
   var setPortletVariables = function(windowId, portletData) {
      var portletTitle = getRenderedPortletTitle(windowId);

      if (portletData == null) {
         portletData = up.analytics.portletData[windowId];
      }

      ga('set', {
         'page' : getPortletUri(portletData.fname),
         'title' : 'Portlet: ' + portletTitle
      });
   };

   /**
    * Finds a child element based on the selector and then return the first
    * class element that is not equal to excludedClasses or contained in the
    * excludedClasses array
    */
   var getInfoClass = function(selectorFunction, excludedClasses) {
      // Convert excludedClasses to an array for simpler code below
      if (!_.isArray(excludedClasses)) {
         excludedClasses = [excludedClasses];
      }

      var classAttr = selectorFunction().attr("class");
      if (classAttr == null) {
         return null;
      }

      var classes = classAttr.split(/\s+/);
      return _.find(classes, function(cls) {
         if (!_.contains(excludedClasses, cls)) {
            return cls;
         }
      });
   };

   /**
    * Determine the fname of the portle the clicked flyout was rendered for
    */
   var getFlyoutFname = function(clickedLink) {
      return getInfoClass(function() {
         return clickedLink.parents("div.up-portlet-fname-subnav-wrapper")
      }, "up-portlet-fname-subnav-wrapper");
   };

   /**
    * Determine the fname of the portle the clicked flyout was rendered for
    */
   var getExternaLinkWindowId = function(clickedLink) {
      return getInfoClass(function() {
         return clickedLink.parents("div.up-portlet-windowId-content-wrapper")
      }, "up-portlet-windowId-content-wrapper");
   };

   /**
    * Handler for sending an analytics event when a link is clicked and then
    * dealing with opening a new window or emulating the click
    */
   var handleLinkClickEvent = function(event, clickedLink, eventOpts) {
      // Click will open in a new window if it is the middle button or the
      // meta or control keys are held
      var newWindow = event.button == 1 || event.metaKey || event.ctrlKey || clickedLink.attr("target") != null;

      var clickFunction;
      if (newWindow) {
         clickFunction = function() {
         };
      } else {
         clickFunction = function() {
            document.location = clickedLink.attr("href");
         };
      }

      // Send the event
      setPageVariables();
      ga('send', $.extend({
         'hitType' : 'event',
         'hitCallback' : clickFunction
      }, eventOpts));

      // If not opening a new window prevent the event and set the fallback
      // to make sure the page navigates even if the hitCallback
      // is never called
      if (!newWindow) {
         // Fallback in case hitCallback takes too long to get called, don't
         // want clicks to hang
         setTimeout(clickFunction, 200);

         event.preventDefault();
      }
   };

   /**
    * Add click handlers to all of the flyout menus to fire flyout events when
    * they are used
    */
   var addFlyoutHandlers = function() {
      $("ul.fl-tabs li.portal-navigation a.portal-subnav-link").click(function(event) {
         var clickedLink = $(this);

         // Find the target portlet's title
         var portletFlyoutTitle = clickedLink.find("span.portal-subnav-label").text();

         // Find the target portlet's fname
         var fname = getFlyoutFname(clickedLink);

         // Setup the page level state
         setPageVariables();

         // Send the event and deal with the click
         handleLinkClickEvent(event, clickedLink, {
            'eventCategory' : 'Flyout Link',
            'eventAction' : getPortletUri(fname),
            'eventLabel' : portletFlyoutTitle
         });
      });
   };

   /**
    * Inspects all clicks on links, any of the clicks that result in existing to
    * a different host are tracked as Outbound Link events
    */
   var addExternalLinkHandlers = function() {
      $('a').click(function(event) {
         var clickedLink = $(this);

         var linkHost = clickedLink.prop("hostname");
         if (linkHost != "" && linkHost != document.domain) {
            var windowId = getExternaLinkWindowId(clickedLink);
            if (windowId != null) {
               setPortletVariables(windowId);
            } else {
               setPageVariables();
            }

            // Send the event and deal with the click
            handleLinkClickEvent(event, clickedLink, {
               'eventCategory' : 'Outbound Link',
               'eventAction' : clickedLink.prop("href"),
               'eventLabel' : clickedLink.text()
            });
         }
      });
   };

   var addMobileListTabHandlers = function() {
      $('ul.up-portal-nav li.up-tab').click(function(event) {
         var clickedTab = $(this);

         //Ignore clicks on already open tabs
         if (clickedTab.hasClass("up-tab-open")) {
            return;
         }

         var fragmentName = getInfoClass(function() {
               return clickedTab.find("div.up-tab-owner");
            }, "up-tab-owner");

         var tabName = clickedTab.find("span.up-tab-name").text().trim();

         setPageVariables(fragmentName, tabName);
         ga('send', 'pageview');
      });
   };

   $(document).ready(function() {
      // Fail safe, if the analytics library isn't loaded make sure the function
      // exists
      window['ga'] = window['ga'] || function() {
      };

      var propertyConfig = findPropertyConfig();

      // No property config means nothing to do
      if (propertyConfig == null) {
         return;
      }

      // Create the tracker
      createTracker(propertyConfig);

      // Set Dimensions
      setDimensions(propertyConfig);

      // Page Event
      setPageVariables();
      // Don't bother sending the view in MAX WindowState
      if (up.analytics.pageData.urlState != "MAX") {
         ga('send', 'pageview');
      }
      ga('send', {
        'hitType': 'timing',
        'timingCategory': 'tab',
        'timingVar': getTabUri(),
        'timingValue': (up.analytics.pageData.executionTimeNano / 1000000)
      });

      // Portlet Events
      _.each(up.analytics.portletData, function(portletData, windowId) {
         // TODO configure portlet analytics include/exclude list
         if (portletData.fname == "google-analytics-config") {
            return;
         }

         setPortletVariables(windowId, portletData);
         ga('send', 'pageview');
         ga('send', {
           'hitType': 'timing',
           'timingCategory': 'portlet',
           'timingVar': getPortletUri(portletData.fname),
           'timingValue':(portletData.executionTimeNano / 1000000)
         });
      });

      // Add handlers to deal with click events on flyouts
      addFlyoutHandlers();

      // Add handlers to deal with click events on external links
      addExternalLinkHandlers();

      // Add handlers to deal with "tab" clicks on the mobile accordian view
      addMobileListTabHandlers();
   });
})(jQuery, _);
<|endoftext|>


<commit_before>import {QueryCtrl} from 'app/plugins/sdk';
import _ from 'lodash';
import * as utils from './utils';
import * as metricFunctions from './metricFunctions';
import * as migrations from './migrations';

import './add-metric-function.directive';
import './metric-function-editor.directive';

import './css/query-editor.css!';

export class ZabbixQueryController extends QueryCtrl {

  // ZabbixQueryCtrl constructor
  constructor($scope, $injector, $sce, $q, templateSrv) {

    // Call superclass constructor
    super($scope, $injector);

    this.zabbix = this.datasource.zabbixAPI;
    this.cache = this.datasource.zabbixCache;
    this.$q = $q;

    this.editorModes = {
      0: 'num',
      1: 'itservice',
      2: 'text'
    };

    // Map functions for bs-typeahead
    this.getGroupNames = _.partial(getMetricNames, this, 'groupList');
    this.getHostNames = _.partial(getMetricNames, this, 'hostList');
    this.getApplicationNames = _.partial(getMetricNames, this, 'appList');
    this.getItemNames = _.partial(getMetricNames, this, 'itemList');

    this.init = function() {

      this.templateSrv = templateSrv;
      var target = this.target;

      // Migrate old targets
      target = migrations.migrate(target);

      var scopeDefaults = {
        metric: {},
        oldTarget: _.cloneDeep(this.target)
      };
      _.defaults(this, scopeDefaults);

      // Load default values
      var targetDefaults = {
        mode: 0,
        group: { filter: "" },
        host: { filter: "" },
        application: { filter: "" },
        item: { filter: "" },
        functions: [],
        refId: "A"
      };
      _.defaults(target, targetDefaults);

      // Create function instances from saved JSON
      target.functions = _.map(target.functions, function(func) {
        return metricFunctions.createFuncInstance(func.def, func.params);
      });

      if (target.mode === 0 ||
          target.mode === 2) {

        this.downsampleFunctionList = [
          {name: "avg", value: "avg"},
          {name: "min", value: "min"},
          {name: "max", value: "max"}
        ];

        this.initFilters();
      }
      else if (target.mode === 1) {
        this.slaPropertyList = [
          {name: "Status", property: "status"},
          {name: "SLA", property: "sla"},
          {name: "OK time", property: "okTime"},
          {name: "Problem time", property: "problemTime"},
          {name: "Down time", property: "downtimeTime"}
        ];
        this.itserviceList = [{name: "test"}];
        this.updateITServiceList();
      }
    };

    this.init();
  }

  initFilters() {
    var self = this;
    var itemtype = self.editorModes[self.target.mode];
    return this.$q.when(this.suggestGroups())
      .then(() => {return self.suggestHosts();})
      .then(() => {return self.suggestApps();})
      .then(() => {return self.suggestItems(itemtype);});
  }

  suggestGroups() {
    var self = this;
    return this.cache.getGroups().then(groups => {
      self.metric.groupList = groups;
      return groups;
    });
  }

  suggestHosts() {
    var self = this;
    var groupFilter = this.templateSrv.replace(this.target.group.filter);
    return this.datasource.queryProcessor
      .filterGroups(self.metric.groupList, groupFilter)
      .then(groups => {
        var groupids = _.map(groups, 'groupid');
        return self.zabbix
          .getHosts(groupids)
          .then(hosts => {
            self.metric.hostList = hosts;
            return hosts;
          });
      });
  }

  suggestApps() {
    var self = this;
    var hostFilter = this.templateSrv.replace(this.target.host.filter);
    return this.datasource.queryProcessor
      .filterHosts(self.metric.hostList, hostFilter)
      .then(hosts => {
        var hostids = _.map(hosts, 'hostid');
        return self.zabbix
          .getApps(hostids)
          .then(apps => {
            return self.metric.appList = apps;
          });
      });
  }

  suggestItems(itemtype='num') {
    var self = this;
    var appFilter = this.templateSrv.replace(this.target.application.filter);
    if (appFilter) {
      // Filter by applications
      return this.datasource.queryProcessor
        .filterApps(self.metric.appList, appFilter)
        .then(apps => {
          var appids = _.map(apps, 'applicationid');
          return self.zabbix
            .getItems(undefined, appids, itemtype)
            .then(items => {
              if (!self.target.showDisabledItems) {
                items = _.filter(items, {'status': '0'});
              }
              self.metric.itemList = items;
              return items;
            });
        });
    } else {
      // Return all items belonged to selected hosts
      var hostids = _.map(self.metric.hostList, 'hostid');
      return self.zabbix
        .getItems(hostids, undefined, itemtype)
        .then(items => {
          if (!self.target.showDisabledItems) {
            items = _.filter(items, {'status': '0'});
          }
          self.metric.itemList = items;
          return items;
        });
    }
  }

  onTargetPartChange(targetPart) {
    /*var regexStyle = {'color': '#CCA300'};
    targetPart.isRegex = utils.isRegex(targetPart.filter);
    targetPart.style = targetPart.isRegex ? regexStyle : {};*/
  }

  isRegex(str) {
    return utils.isRegex(str);
  }

  isVariable(str) {
    var variablePattern = /^\$\w+/;
    if (variablePattern.test(str)) {
      var variables = _.map(this.templateSrv.variables, variable => {
        return '$' + variable.name;
      });
      return _.contains(variables, str);
    } else {
      return false;
    }
  }

  onTargetBlur() {
    var newTarget = _.cloneDeep(this.target);
    if (!_.isEqual(this.oldTarget, this.target)) {
      this.oldTarget = newTarget;
      this.initFilters();
      this.parseTarget();
      this.panelCtrl.refresh();
    }
  }

  parseTarget() {
    // Parse target
  }

  // Validate target and set validation info
  validateTarget() {
    // validate
  }

  targetChanged() {
    this.panelCtrl.refresh();
  }

  addFunction(funcDef) {
    var newFunc = metricFunctions.createFuncInstance(funcDef);
    newFunc.added = true;
    this.target.functions.push(newFunc);

    this.moveAliasFuncLast();

    if (newFunc.params.length && newFunc.added ||
        newFunc.def.params.length === 0) {
      this.targetChanged();
    }
  }

  removeFunction(func) {
    this.target.functions = _.without(this.target.functions, func);
    this.targetChanged();
  }

  moveAliasFuncLast() {
    var aliasFunc = _.find(this.target.functions, function(func) {
      return func.def.name === 'alias' ||
        func.def.name === 'aliasByNode' ||
        func.def.name === 'aliasByMetric';
    });

    if (aliasFunc) {
      this.target.functions = _.without(this.target.functions, aliasFunc);
      this.target.functions.push(aliasFunc);
    }
  }

  /**
   * Switch query editor to specified mode.
   * Modes:
   *  0 - items
   *  1 - IT services
   *  2 - Text metrics
   */
  switchEditorMode(mode) {
    this.target.mode = mode;
    this.init();
  }

  /////////////////
  // IT Services //
  /////////////////

  /**
   * Update list of IT services
   */
  updateITServiceList() {
    var self = this;
    this.datasource.zabbixAPI.getITService().then(function (iteservices) {
      self.itserviceList = [];
      self.itserviceList = self.itserviceList.concat(iteservices);
    });
  }

  /**
   * Call when IT service is selected.
   */
  selectITService() {
    if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {
      this.oldTarget = angular.copy(this.target);
      this.panelCtrl.refresh();
    }
  }

}

// Set templateUrl as static property
ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';

// Get list of metric names for bs-typeahead directive
function getMetricNames(scope, metricList) {
  return _.uniq(_.map(scope.metric[metricList], 'name'));
}
<commit_msg>Update metric suggestion when template variable was changed.<commit_after>import {QueryCtrl} from 'app/plugins/sdk';
import _ from 'lodash';
import * as utils from './utils';
import * as metricFunctions from './metricFunctions';
import * as migrations from './migrations';

import './add-metric-function.directive';
import './metric-function-editor.directive';

import './css/query-editor.css!';

export class ZabbixQueryController extends QueryCtrl {

  // ZabbixQueryCtrl constructor
  constructor($scope, $injector, $rootScope, $sce, $q, templateSrv) {

    // Call superclass constructor
    super($scope, $injector);

    this.zabbix = this.datasource.zabbixAPI;
    this.cache = this.datasource.zabbixCache;
    this.$q = $q;

    // Use custom format for template variables
    this.replaceTemplateVars = this.datasource.replaceTemplateVars;
    this.templateSrv = templateSrv;

    this.editorModes = {
      0: 'num',
      1: 'itservice',
      2: 'text'
    };

    // Map functions for bs-typeahead
    this.getGroupNames = _.partial(getMetricNames, this, 'groupList');
    this.getHostNames = _.partial(getMetricNames, this, 'hostList');
    this.getApplicationNames = _.partial(getMetricNames, this, 'appList');
    this.getItemNames = _.partial(getMetricNames, this, 'itemList');

    // Update metric suggestion when template variable was changed
    $rootScope.$on('template-variable-value-updated', () => this.onVariableChange());

    this.init = function() {
      var target = this.target;

      // Migrate old targets
      target = migrations.migrate(target);

      var scopeDefaults = {
        metric: {},
        oldTarget: _.cloneDeep(this.target)
      };
      _.defaults(this, scopeDefaults);

      // Load default values
      var targetDefaults = {
        mode: 0,
        group: { filter: "" },
        host: { filter: "" },
        application: { filter: "" },
        item: { filter: "" },
        functions: [],
        refId: "A"
      };
      _.defaults(target, targetDefaults);

      // Create function instances from saved JSON
      target.functions = _.map(target.functions, function(func) {
        return metricFunctions.createFuncInstance(func.def, func.params);
      });

      if (target.mode === 0 ||
          target.mode === 2) {

        this.downsampleFunctionList = [
          {name: "avg", value: "avg"},
          {name: "min", value: "min"},
          {name: "max", value: "max"}
        ];

        this.initFilters();
      }
      else if (target.mode === 1) {
        this.slaPropertyList = [
          {name: "Status", property: "status"},
          {name: "SLA", property: "sla"},
          {name: "OK time", property: "okTime"},
          {name: "Problem time", property: "problemTime"},
          {name: "Down time", property: "downtimeTime"}
        ];
        this.itserviceList = [{name: "test"}];
        this.updateITServiceList();
      }
    };

    this.init();
  }

  initFilters() {
    var self = this;
    var itemtype = self.editorModes[self.target.mode];
    return this.$q.when(this.suggestGroups())
      .then(() => {return self.suggestHosts();})
      .then(() => {return self.suggestApps();})
      .then(() => {return self.suggestItems(itemtype);});
  }

  suggestGroups() {
    var self = this;
    return this.cache.getGroups().then(groups => {
      self.metric.groupList = groups;
      return groups;
    });
  }

  suggestHosts() {
    var self = this;
    var groupFilter = this.replaceTemplateVars(this.target.group.filter);
    console.log(groupFilter);
    return this.datasource.queryProcessor
      .filterGroups(self.metric.groupList, groupFilter)
      .then(groups => {
        var groupids = _.map(groups, 'groupid');
        return self.zabbix
          .getHosts(groupids)
          .then(hosts => {
            self.metric.hostList = hosts;
            return hosts;
          });
      });
  }

  suggestApps() {
    var self = this;
    var hostFilter = this.replaceTemplateVars(this.target.host.filter);
    return this.datasource.queryProcessor
      .filterHosts(self.metric.hostList, hostFilter)
      .then(hosts => {
        var hostids = _.map(hosts, 'hostid');
        return self.zabbix
          .getApps(hostids)
          .then(apps => {
            return self.metric.appList = apps;
          });
      });
  }

  suggestItems(itemtype='num') {
    var self = this;
    var appFilter = this.replaceTemplateVars(this.target.application.filter);
    if (appFilter) {
      // Filter by applications
      return this.datasource.queryProcessor
        .filterApps(self.metric.appList, appFilter)
        .then(apps => {
          var appids = _.map(apps, 'applicationid');
          return self.zabbix
            .getItems(undefined, appids, itemtype)
            .then(items => {
              if (!self.target.showDisabledItems) {
                items = _.filter(items, {'status': '0'});
              }
              self.metric.itemList = items;
              return items;
            });
        });
    } else {
      // Return all items belonged to selected hosts
      var hostids = _.map(self.metric.hostList, 'hostid');
      return self.zabbix
        .getItems(hostids, undefined, itemtype)
        .then(items => {
          if (!self.target.showDisabledItems) {
            items = _.filter(items, {'status': '0'});
          }
          self.metric.itemList = items;
          return items;
        });
    }
  }

  onTargetPartChange(targetPart) {
    /*var regexStyle = {'color': '#CCA300'};
    targetPart.isRegex = utils.isRegex(targetPart.filter);
    targetPart.style = targetPart.isRegex ? regexStyle : {};*/
  }

  isRegex(str) {
    return utils.isRegex(str);
  }

  isVariable(str) {
    var variablePattern = /^\$\w+/;
    if (variablePattern.test(str)) {
      var variables = _.map(this.templateSrv.variables, variable => {
        return '$' + variable.name;
      });
      return _.contains(variables, str);
    } else {
      return false;
    }
  }

  onTargetBlur() {
    var newTarget = _.cloneDeep(this.target);
    if (!_.isEqual(this.oldTarget, this.target)) {
      this.oldTarget = newTarget;
      this.targetChanged();
    }
  }

  onVariableChange() {
    if (this.isContainsVariables()) {
      this.targetChanged();
    }
  }

  /**
   * Check query for template variables
   */
  isContainsVariables() {
    var self = this;
    return _.some(self.templateSrv.variables, variable => {
      return _.some(['group', 'host', 'application', 'item'], field => {
        return self.templateSrv.containsVariable(self.target[field].filter, variable.name);
      });
    });
  }

  parseTarget() {
    // Parse target
  }

  // Validate target and set validation info
  validateTarget() {
    // validate
  }

  targetChanged() {
    this.initFilters();
    this.parseTarget();
    this.panelCtrl.refresh();
  }

  addFunction(funcDef) {
    var newFunc = metricFunctions.createFuncInstance(funcDef);
    newFunc.added = true;
    this.target.functions.push(newFunc);

    this.moveAliasFuncLast();

    if (newFunc.params.length && newFunc.added ||
        newFunc.def.params.length === 0) {
      this.targetChanged();
    }
  }

  removeFunction(func) {
    this.target.functions = _.without(this.target.functions, func);
    this.targetChanged();
  }

  moveAliasFuncLast() {
    var aliasFunc = _.find(this.target.functions, function(func) {
      return func.def.name === 'alias' ||
        func.def.name === 'aliasByNode' ||
        func.def.name === 'aliasByMetric';
    });

    if (aliasFunc) {
      this.target.functions = _.without(this.target.functions, aliasFunc);
      this.target.functions.push(aliasFunc);
    }
  }

  /**
   * Switch query editor to specified mode.
   * Modes:
   *  0 - items
   *  1 - IT services
   *  2 - Text metrics
   */
  switchEditorMode(mode) {
    this.target.mode = mode;
    this.init();
  }

  /////////////////
  // IT Services //
  /////////////////

  /**
   * Update list of IT services
   */
  updateITServiceList() {
    var self = this;
    this.datasource.zabbixAPI.getITService().then(function (iteservices) {
      self.itserviceList = [];
      self.itserviceList = self.itserviceList.concat(iteservices);
    });
  }

  /**
   * Call when IT service is selected.
   */
  selectITService() {
    if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {
      this.oldTarget = angular.copy(this.target);
      this.panelCtrl.refresh();
    }
  }

}

// Set templateUrl as static property
ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';

// Get list of metric names for bs-typeahead directive
function getMetricNames(scope, metricList) {
  return _.uniq(_.map(scope.metric[metricList], 'name'));
}
<|endoftext|>


<commit_before>define([
	'lodash',
	'app/config',
	'app/components/events',
	'app/components/component',
	'./keyboard'
], function(
	_,
	Config,
	EVENTS,
	Component,
	KeyboardInputComponent
) {

	/**
	 * Defines the keyboard shortcuts.
	 * @type {object}
	 * @const
	 */
	var SHORTS = Config.get('keyboardShortcuts');

	/**
	 * Defines whether keyboard shortcuts are enabled/disabled by default.
	 * @type {boolean}
	 */
	var KEYBOARD_SHORTCUTS_ENABLED = Config.get('general.keyboardShortcutsEnabled');

	/**
	 * This Shortcuts component is responsible for handling the
	 * shortcut logic.
	 *
	 * It is primarily concerned with the action to take when a
	 * shortcut is triggered. It depends on a sub-component
	 * to take keypresses and turn them into actions.
	 *
	 * @constructor
	 */
	var KeyboardShortcutsComponent = function(settings) {
		this.settings = settings || {};

		if(this.settings.hasOwnProperty('keySignature')) {
			this.keySignature = this.settings.keySignature;
		} else {
			throw new Error("missing key signature");
		}

		this.enabled = KEYBOARD_SHORTCUTS_ENABLED;
		if(this.settings.hasOwnProperty('enabled')) {
			this.enabled = this.settings.enabled;
		}

		this.noteAnchor = 48;
		if(SHORTS.hasOwnProperty('noteAnchor')) {
			this.noteAnchor = SHORTS.noteAnchor;
		}

		this.setComponent('input', new KeyboardInputComponent({
			keyMap: SHORTS.keyMap,
			keyCode: SHORTS.keyCode
		}));
	};

	KeyboardShortcutsComponent.prototype = new Component();

	_.extend(KeyboardShortcutsComponent.prototype, {
		/**
		 * Initializes the component.
		 *
		 * @return undefined
		 */
		initComponent: function() {
			this.messages = [
				'depressSustain',
				'retakeSustain',
				'releaseSustain',
				'rotateKeyFlatward',
				'rotateKeySharpward',
				'setKeyToNone',
				'toggleMetronome',
				'toggleMode',
				'clearNotes',
				'bankChord',
				'toggleNote'
			];

			this.toggleMode = this.execIf([this.isKeyDown], this.toggleMode);
			this.toggleNote = this.execIf([this.isEnabled], this.toggleNote);

			_.each(this.messages, function(msg) {
				var fn = this[msg];
				if(msg !== 'toggleNote' && msg !== 'toggleMode') {
					this[msg] = this.execIf([this.isEnabled, this.isKeyDown], fn);
				}
			}, this);

			_.bindAll(this, this.messages);
			_.bindAll(this, ['handleToggle']);

			this.initListeners();
		},
		/**
		 * Helper function to execute a function if every predicate
		 * returns true, otherwise cancels the action on the first
		 * one that returns false.
		 *
		 * @return {Function} a function that tests each predicate before
		 * calling the given function.
		 */
		execIf: function(predicates, fn) {
			return function() {
				var result, i, len;
				for(i = 0, len = predicates.length; i < len; i++) {
					result = predicates[i].apply(this, arguments);
					if(!result) {
						return;
					}
				}
				fn.apply(this, arguments);
			};
		},
		/**
		 * Initializes listeners on the input component.
		 *
		 * @return undefined
		 */
		initListeners: function() {
			var input = this.getComponent('input');
			_.each(this.messages, function(msg) {
				input.bind(msg, this[msg]);
			}, this);

			this.subscribe(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.handleToggle);
		},
		/**
		 * Removes listeners on the input component.
		 *
		 * @return undefined;
		 */
		removeListeners: function() {
			var input = this.getComponent('input');
			_.each(this.messages, function(msg) {
				input.unbind(msg, this[msg]);
			}, this);

			this.unsubscribe(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.handleToggle);
		},
		/**
		 * Enables shortcuts.
		 *
		 * @return undefined
		 */
		enable: function() {
			this.enabled = true;
		},
		/**
		 * Disables shortcuts.
		 *
		 * @return undefined
		 */
		disable: function() {
			this.enabled = false;
		},
		/**
		 * Checks if shortcuts are enabled.
		 *
		 * @return {boolean} True if enabled, false otherwise.
		 */
		isEnabled: function() {
			return this.enabled ? true : false;
		},
		/**
		 * Checks if the key is up/down.
		 *
		 * @return {boolean} True if the key is down, otherwise false.
		 */
		isKeyDown: function(state) {
			return state ? true : false;
		},
		/**
		 * Toggles the shortcut mode to enable/disable shortcuts.
		 *
		 * @return undefined
		 */
		toggleMode: function(state) {
			this.enabled = !this.enabled;
			this.broadcast(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.enabled);
		},
		/**
		 * Handles a toggle event.
		 *
		 * @return undefined
		 */
		handleToggle: function(enabled) {
			this[enabled?'enable':'disable']();
		},
		/**
		 * Flattens the key.
		 *
		 * @return undefined
		 */
		rotateKeyFlatward: function(state) {
			this.keySignature.rotateFlatward();
		},
		/**
		 * Sharpens the key.
		 *
		 * @return undefined
		 */
		rotateKeySharpward: function(state) {
			this.keySignature.rotateSharpward();
		},
		/**
		 * Sets the key to none.
		 *
		 * @return undefined
		 */
		setKeyToNone: function(state) {
			this.keySignature.changeKey('jC_', true);
		},
		/**
		 * Depresses the sustain pedal.
		 *
		 * @return undefined
		 */
		depressSustain: function(state) {
			this.broadcast(EVENTS.BROADCAST.PEDAL, 'sustain', 'on');
		},
		/**
		 * Releases the sustain pedal.
		 *
		 * @return undefined
		 */
		releaseSustain: function(state) {
			this.broadcast(EVENTS.BROADCAST.PEDAL, 'sustain', 'off');
		},
		/**
		 * Retakes the sustain pedal.
		 *
		 * @return undefined
		 */
		retakeSustain: function(state) {
			if(!state) {
				return;
			}
			this.retakeTimeoutID = this.retakeTimeoutID || null;
			if(this.retakeTimeoutID !== null) {
				window.clearTimeout(this.retakeTimeoutID);
			}

			this.releaseSustain();
			window.setTimeout(_.bind(function() {
				this.depressSustain();
				this.retakeTimeoutID = null;
			}, this), 100);
		},
		/**
		 * Clears all the notes.
		 *
		 * @return undefined
		 */
		clearNotes: function(state) {
			this.broadcast(EVENTS.BROADCAST.CLEAR_NOTES);
		},
		/**
		 * Banks a chord.
		 *
		 * @return undefined
		 */
		bankChord: function(state) {
			this.broadcast(EVENTS.BROADCAST.BANK_NOTES);
		},
		/**
		 * Toggles the metronome (play and stop).
		 *
		 * @return undefined
		 */
		toggleMetronome: function(state) {
			this.broadcast(EVENTS.BROADCAST.TOGGLE_METRONOME);
		},
		/**
		 * Broadcasts a note ON/OFF event.
		 *
		 * @param {string} state
		 * @param {number} noteOffset
		 * @return undefined
		 */
		toggleNote: function(state, noteOffset) {
			var on_or_off = state ? 'on' : 'off';
			var note_value = this.calculateNote(noteOffset);
			this.broadcast(EVENTS.BROADCAST.NOTE, on_or_off, note_value);
		},
		/**
		 * Calculates the MIDI note number given a relative offset.
		 *
		 * @param {number} noteOffset
		 * @return {number} The midi note number.
		 */
		calculateNote: function(noteOffset) {
			return this.noteAnchor + noteOffset;
		}
	});

	return KeyboardShortcutsComponent;
});
<commit_msg>Fixed retake sustain pedal<commit_after>define([
	'lodash',
	'app/config',
	'app/components/events',
	'app/components/component',
	'./keyboard'
], function(
	_,
	Config,
	EVENTS,
	Component,
	KeyboardInputComponent
) {

	/**
	 * Defines the keyboard shortcuts.
	 * @type {object}
	 * @const
	 */
	var SHORTS = Config.get('keyboardShortcuts');

	/**
	 * Defines whether keyboard shortcuts are enabled/disabled by default.
	 * @type {boolean}
	 */
	var KEYBOARD_SHORTCUTS_ENABLED = Config.get('general.keyboardShortcutsEnabled');

	/**
	 * This Shortcuts component is responsible for handling the
	 * shortcut logic.
	 *
	 * It is primarily concerned with the action to take when a
	 * shortcut is triggered. It depends on a sub-component
	 * to take keypresses and turn them into actions.
	 *
	 * @constructor
	 */
	var KeyboardShortcutsComponent = function(settings) {
		this.settings = settings || {};

		if(this.settings.hasOwnProperty('keySignature')) {
			this.keySignature = this.settings.keySignature;
		} else {
			throw new Error("missing key signature");
		}

		this.enabled = KEYBOARD_SHORTCUTS_ENABLED;
		if(this.settings.hasOwnProperty('enabled')) {
			this.enabled = this.settings.enabled;
		}

		this.noteAnchor = 48;
		if(SHORTS.hasOwnProperty('noteAnchor')) {
			this.noteAnchor = SHORTS.noteAnchor;
		}

		this.setComponent('input', new KeyboardInputComponent({
			keyMap: SHORTS.keyMap,
			keyCode: SHORTS.keyCode
		}));
	};

	KeyboardShortcutsComponent.prototype = new Component();

	_.extend(KeyboardShortcutsComponent.prototype, {
		/**
		 * Initializes the component.
		 *
		 * @return undefined
		 */
		initComponent: function() {
			this.messages = [
				'depressSustain',
				'retakeSustain',
				'releaseSustain',
				'rotateKeyFlatward',
				'rotateKeySharpward',
				'setKeyToNone',
				'toggleMetronome',
				'toggleMode',
				'clearNotes',
				'bankChord',
				'toggleNote'
			];

			this.toggleMode = this.execIf([this.isKeyDown], this.toggleMode);
			this.toggleNote = this.execIf([this.isEnabled], this.toggleNote);

			_.each(this.messages, function(msg) {
				var fn = this[msg];
				if(msg !== 'toggleNote' && msg !== 'toggleMode') {
					this["_"+msg] = fn;
					this[msg] = this.execIf([this.isEnabled, this.isKeyDown], fn);
				}
			}, this);

			_.bindAll(this, this.messages);
			_.bindAll(this, ['handleToggle']);

			this.initListeners();
		},
		/**
		 * Helper function to execute a function if every predicate
		 * returns true, otherwise cancels the action on the first
		 * one that returns false.
		 *
		 * @return {Function} a function that tests each predicate before
		 * calling the given function.
		 */
		execIf: function(predicates, fn) {
			return function() {
				var result, i, len;
				for(i = 0, len = predicates.length; i < len; i++) {
					result = predicates[i].apply(this, arguments);
					if(!result) {
						return;
					}
				}
				fn.apply(this, arguments);
			};
		},
		/**
		 * Initializes listeners on the input component.
		 *
		 * @return undefined
		 */
		initListeners: function() {
			var input = this.getComponent('input');
			_.each(this.messages, function(msg) {
				input.bind(msg, this[msg]);
			}, this);

			this.subscribe(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.handleToggle);
		},
		/**
		 * Removes listeners on the input component.
		 *
		 * @return undefined;
		 */
		removeListeners: function() {
			var input = this.getComponent('input');
			_.each(this.messages, function(msg) {
				input.unbind(msg, this[msg]);
			}, this);

			this.unsubscribe(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.handleToggle);
		},
		/**
		 * Enables shortcuts.
		 *
		 * @return undefined
		 */
		enable: function() {
			this.enabled = true;
		},
		/**
		 * Disables shortcuts.
		 *
		 * @return undefined
		 */
		disable: function() {
			this.enabled = false;
		},
		/**
		 * Checks if shortcuts are enabled.
		 *
		 * @return {boolean} True if enabled, false otherwise.
		 */
		isEnabled: function() {
			return this.enabled ? true : false;
		},
		/**
		 * Checks if the key is up/down.
		 *
		 * @return {boolean} True if the key is down, otherwise false.
		 */
		isKeyDown: function(state) {
			return state ? true : false;
		},
		/**
		 * Toggles the shortcut mode to enable/disable shortcuts.
		 *
		 * @return undefined
		 */
		toggleMode: function(state) {
			this.enabled = !this.enabled;
			this.broadcast(EVENTS.BROADCAST.TOGGLE_SHORTCUTS, this.enabled);
		},
		/**
		 * Handles a toggle event.
		 *
		 * @return undefined
		 */
		handleToggle: function(enabled) {
			this[enabled?'enable':'disable']();
		},
		/**
		 * Flattens the key.
		 *
		 * @return undefined
		 */
		rotateKeyFlatward: function(state) {
			this.keySignature.rotateFlatward();
		},
		/**
		 * Sharpens the key.
		 *
		 * @return undefined
		 */
		rotateKeySharpward: function(state) {
			this.keySignature.rotateSharpward();
		},
		/**
		 * Sets the key to none.
		 *
		 * @return undefined
		 */
		setKeyToNone: function(state) {
			this.keySignature.changeKey('jC_', true);
		},
		/**
		 * Depresses the sustain pedal.
		 *
		 * @return undefined
		 */
		depressSustain: function(state) {
			this.broadcast(EVENTS.BROADCAST.PEDAL, 'sustain', 'on');
		},
		/**
		 * Releases the sustain pedal.
		 *
		 * @return undefined
		 */
		releaseSustain: function(state) {
			this.broadcast(EVENTS.BROADCAST.PEDAL, 'sustain', 'off');
		},
		/**
		 * Retakes the sustain pedal.
		 *
		 * @return undefined
		 */
		retakeSustain: function(state) {
			if(!state) {
				return;
			}

			var onTimeoutDepressSustain = _.bind(function() {
				this._depressSustain();
				this.retakeTimeoutID = null;
			},this);

			this.retakeTimeoutID = this.retakeTimeoutID || null;
			if(this.retakeTimeoutID !== null) {
				window.clearTimeout(this.retakeTimeoutID);
			}

			this._releaseSustain();
			this.retakeTimeoutID = window.setTimeout(onTimeoutDepressSustain, 100);
		},
		/**
		 * Clears all the notes.
		 *
		 * @return undefined
		 */
		clearNotes: function(state) {
			this.broadcast(EVENTS.BROADCAST.CLEAR_NOTES);
		},
		/**
		 * Banks a chord.
		 *
		 * @return undefined
		 */
		bankChord: function(state) {
			this.broadcast(EVENTS.BROADCAST.BANK_NOTES);
		},
		/**
		 * Toggles the metronome (play and stop).
		 *
		 * @return undefined
		 */
		toggleMetronome: function(state) {
			this.broadcast(EVENTS.BROADCAST.TOGGLE_METRONOME);
		},
		/**
		 * Broadcasts a note ON/OFF event.
		 *
		 * @param {string} state
		 * @param {number} noteOffset
		 * @return undefined
		 */
		toggleNote: function(state, noteOffset) {
			var on_or_off = state ? 'on' : 'off';
			var note_value = this.calculateNote(noteOffset);
			this.broadcast(EVENTS.BROADCAST.NOTE, on_or_off, note_value);
		},
		/**
		 * Calculates the MIDI note number given a relative offset.
		 *
		 * @param {number} noteOffset
		 * @return {number} The midi note number.
		 */
		calculateNote: function(noteOffset) {
			return this.noteAnchor + noteOffset;
		}
	});

	return KeyboardShortcutsComponent;
});
<|endoftext|>


<commit_before>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 *
 * path: ui/suggestion/create.js
 * author: berg
 * version: 1.0.0
 * date: 2010-06-01
 */

///import baidu.dom.g;

///import baidu.ui.suggestion;
///import baidu.ui.suggestion.Suggestion;

///import baidu.ui.suggestion.Suggestion$data;
///import baidu.ui.suggestion.Suggestion$input;
///import baidu.ui.suggestion.Suggestion$fixWidth;

/**
 * 创建suggetion对象
 * @function
 * @param   {string|HTMLElement}     target             要加suggestion的目标input
 * @param   {Object}                 [options]          选项
 * @config  {Function}               onshow             当显示时触发。
 * @config  {Function}               onhide             当隐藏时触发，input或者整个window失去焦点，或者confirm以后会自动隐藏。
 * @config  {Function}               onconfirm          当确认条目时触发，回车后，或者在条目上按鼠标会触发确认操作。参数是event对象，其中有data属性，包括item和index值。item为当前确认的条目，index是条目索引。。
 * @config  {Function}               onbeforepick       使用方向键选中某一行，鼠标点击前触发。
 * @config  {Function}               onpick             使用方向键选中某一行，鼠标点击时触发。参数是event对象，其中有data属性，包括item和index值。item为当前确认的条目，index是条目索引。
 * @config  {Function}               onhighlight        当高亮时触发，使用方向键移过某一行，使用鼠标滑过某一行时会触发高亮。参数是event对象，其中有data属性，包括item和index值。item为当前确认的条目，index是条目索引。
 * @config  {Function}               view               重新定位时，会调用这个方法来获取新的位置，传入的参数中会包括top、 left、width三个值。
 * @config  {Function}               getData            在需要获取数据的时候会调用此函数来获取数据，传入的参数word是用户在input中输入的数据。
 * @config  {String}                 prependHTML        写在下拉框列表前面的html
 * @config  {String}                 appendHTML         写在下拉框列表后面的html
 *
 * @return {baidu.ui.suggetion.Suggestion} suggestion对象
 */

baidu.ui.suggestion.create = function(target, options){
    var s = new baidu.ui.suggestion.Suggestion(options);
    s.render(target);
    return s;
};
<commit_msg>删除Suggestion/create.js<commit_after><|endoftext|>


<commit_before>import * as containers from "./container-view-builder";
import url from "url";
import { fetch } from "@lynx-json/jsua";

export function createDataUri(link) {
  var contentType = link.type;
  var encoding = link.encoding || "utf-8";

  if (!contentType) throw new Error("A link with a 'data' property must have a valid 'type' property.");
  if (encoding !== "utf-8" && encoding !== "base64") throw new Error("The 'encoding' property value for a link must be 'utf-8' or 'base64'.");

  var dataUri = "data:" + contentType;

  if (encoding === "base64") {
    dataUri += ";base64,";
  } else {
    dataUri += ",";
  }

  var isJSON = /\/json|\+json/;

  if (encoding === "utf-8" && isJSON.test(contentType)) {
    dataUri += JSON.stringify(link.data);
  } else {
    dataUri += link.data;
  }

  return dataUri;
}

export function linkViewBuilder(node) {
  var view = document.createElement("a");

  if (node.value.data) {
    node.value.href = exports.createDataUri(node.value);
  }

  if (node.base) {
    view.href = url.resolve(node.base, node.value.href);
  } else {
    view.href = node.value.href;
  }

  view.type = node.value.type;

  var followTimeout = tryGetFollowTimeout(node);

  if (followTimeout) {
    view.addEventListener("jsua-attach", function () {
      setTimeout(function () {
        view.click();
      }, followTimeout);
    });
  }

  view.addEventListener("click", function (evt) {
    evt.preventDefault();
    evt.stopPropagation();
    fetch(view.href, { origin: view });
  });

  return containers.buildChildViews(node)
    .then(function (childViews) {
      childViews.forEach(childView => view.appendChild(childView));

      if (view.children.length === 0) {
        view.textContent = view.href;
      }

      return view;
    });
}

function tryGetFollowTimeout(node) {
  var follow = +node.value.follow;
  if (isNaN(follow)) follow = +node.spec.follow;
  if (isNaN(follow)) return;
  return follow < 10 ? 10 : follow;
}
<commit_msg>Add 'automatic' To Options<commit_after>import * as containers from "./container-view-builder";
import url from "url";
import { fetch } from "@lynx-json/jsua";

export function createDataUri(link) {
  var contentType = link.type;
  var encoding = link.encoding || "utf-8";

  if (!contentType) throw new Error("A link with a 'data' property must have a valid 'type' property.");
  if (encoding !== "utf-8" && encoding !== "base64") throw new Error("The 'encoding' property value for a link must be 'utf-8' or 'base64'.");

  var dataUri = "data:" + contentType;

  if (encoding === "base64") {
    dataUri += ";base64,";
  } else {
    dataUri += ",";
  }

  var isJSON = /\/json|\+json/;

  if (encoding === "utf-8" && isJSON.test(contentType)) {
    dataUri += JSON.stringify(link.data);
  } else {
    dataUri += link.data;
  }

  return dataUri;
}

export function linkViewBuilder(node) {
  var view = document.createElement("a");

  if (node.value.data) {
    node.value.href = exports.createDataUri(node.value);
  }

  if (node.base) {
    view.href = url.resolve(node.base, node.value.href);
  } else {
    view.href = node.value.href;
  }

  view.type = node.value.type;

  var followTimeout = tryGetFollowTimeout(node);

  if (followTimeout) {
    view.addEventListener("jsua-attach", function () {
      setTimeout(function () {
        fetch(view.href, { origin: view, automatic: true });
      }, followTimeout);
    });
  }

  view.addEventListener("click", function (evt) {
    evt.preventDefault();
    evt.stopPropagation();
    fetch(view.href, { origin: view });
  });

  return containers.buildChildViews(node)
    .then(function (childViews) {
      childViews.forEach(childView => view.appendChild(childView));

      if (view.children.length === 0) {
        view.textContent = view.href;
      }

      return view;
    });
}

function tryGetFollowTimeout(node) {
  var follow = +node.value.follow;
  if (isNaN(follow)) follow = +node.spec.follow;
  if (isNaN(follow)) return;
  return follow < 10 ? 10 : follow;
}
<|endoftext|>


<commit_before>import IDGenerator from './id-generator';

function createCommitResult(attrs = {}) {
  return {
    commit: {
      status: {
        contexts: [ {state: 'PASSED'} ]
      }
    }
  };
}

export function createStatusContextResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('context'),
    context: 'context',
    description: 'description',
    state: 'SUCCESS',
    creatorLogin: 'me',
    creatorAvatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=1',
    ...idGen.embed(),
    ...attrs,
  }

  if (!o.targetUrl) {
    o.targetUrl = `https://ci.provider.com/builds/${o.id}`
  }

  return {
    id: o.id,
    context: o.context,
    description: o.description,
    state: o.state,
    targetUrl: o.targetUrl,
    creator: {
      avatarUrl: o.creatorAvatarUrl,
      login: o.creatorLogin,
    }
  }
}

export function createPullRequestResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('pullrequest'),
    number: 0,
    repositoryID: idGen.generate('repository'),
    summaryState: null,
    states: null,
    headRefName: 'master',
    includeEdges: false,
    ...attrs,
  };

  if (o.summaryState && !o.states) {
    o.states = [{state: o.summaryState, ...idGen.embed()}];
  }

  if (o.states) {
    o.states = o.states.map(state => {
      return typeof state === 'string'
        ? {state: state, ...idGen.embed()}
        : state
    });
  }

  const commit = {
    id: idGen.generate('commit'),
  };

  if (o.states === null) {
    commit.status = null;
  } else {
    commit.status = {
      state: o.summaryState,
      contexts: o.states.map(createStatusContextResult),
    };
  }

  const commits = o.includeEdges
    ? {edges: [{node: {id: idGen.generate('node'), commit}}]}
    : {nodes: [{commit, id: idGen.generate('node')}]};

  return {
    __typename: 'PullRequest',
    id: o.id,
    number: o.number,
    title: `Pull Request ${o.number}`,
    url: `https://github.com/owner/repo/pulls/${o.number}`,
    author: {
      __typename: 'User',
      login: 'me',
      avatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=4',
      id: 'user0'
    },
    createdAt: '2018-06-12T14:50:08Z',
    headRefName: o.headRefName,

    repository: {
      id: o.repositoryID,
    },

    commits,
  }
}

export function createPullRequestDetailResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('pullrequest'),
    number: 0,
    title: 'title',
    state: 'OPEN',
    authorLogin: 'me',
    authorAvatarURL: 'https://avatars3.githubusercontent.com/u/000?v=4',
    headRefName: 'headref',
    headRepositoryLogin: 'headlogin',
    baseRepositoryLogin: 'baseLogin',
    ...attrs,
  };

  const commit = {
    id: idGen.generate('commit'),
    status: null,
  };

  return {
    __typename: 'PullRequest',
    id: o.id,
    title: o.title,
    number: o.number,
    state: o.state,
    bodyHTML: '
body
',
    author: {
      __typename: 'User',
      id: idGen.generate('user'),
      login: o.authorLogin,
      avatarUrl: o.authorAvatarURL,
      url: `https://github.com/${o.authorLogin}`,
    },
    url: `https://github.com/owner/repo/pull/${o.number}`,
    reactionGroups: [],
    commits: {
      edges: [{
        node: {commit, id: 'node0'}
      }],
    },
    timeline: {
      pageInfo: {
        endCursor: 'end',
        hasNextPage: false,
      },
      edges: [],
    },
    headRefName: o.headRefName,
    headRepositoryOwner: {
      __typename: 'User',
      id: idGen.generate('user'),
      login: o.headRepositoryLogin,
    },
    repository: {
      owner: {
        __typename: 'User',
        id: idGen.generate('user'),
        login: o.baseRepositoryLogin,
      },
      id: idGen.generate('repository'),
    }
  };
}
<commit_msg>Factory to create a sequence of pull request results<commit_after>import IDGenerator from './id-generator';

function createCommitResult(attrs = {}) {
  return {
    commit: {
      status: {
        contexts: [ {state: 'PASSED'} ]
      }
    }
  };
}

export function createStatusContextResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('context'),
    context: 'context',
    description: 'description',
    state: 'SUCCESS',
    creatorLogin: 'me',
    creatorAvatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=1',
    ...idGen.embed(),
    ...attrs,
  }

  if (!o.targetUrl) {
    o.targetUrl = `https://ci.provider.com/builds/${o.id}`
  }

  return {
    id: o.id,
    context: o.context,
    description: o.description,
    state: o.state,
    targetUrl: o.targetUrl,
    creator: {
      avatarUrl: o.creatorAvatarUrl,
      login: o.creatorLogin,
    }
  }
}

export function createPullRequestResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('pullrequest'),
    number: 0,
    repositoryID: idGen.generate('repository'),
    summaryState: null,
    states: null,
    headRefName: 'master',
    includeEdges: false,
    ...attrs,
  };

  if (o.summaryState && !o.states) {
    o.states = [{state: o.summaryState, ...idGen.embed()}];
  }

  if (o.states) {
    o.states = o.states.map(state => {
      return typeof state === 'string'
        ? {state: state, ...idGen.embed()}
        : state
    });
  }

  const commit = {
    id: idGen.generate('commit'),
  };

  if (o.states === null) {
    commit.status = null;
  } else {
    commit.status = {
      state: o.summaryState,
      contexts: o.states.map(createStatusContextResult),
    };
  }

  const commits = o.includeEdges
    ? {edges: [{node: {id: idGen.generate('node'), commit}}]}
    : {nodes: [{commit, id: idGen.generate('node')}]};

  return {
    __typename: 'PullRequest',
    id: o.id,
    number: o.number,
    title: `Pull Request ${o.number}`,
    url: `https://github.com/owner/repo/pulls/${o.number}`,
    author: {
      __typename: 'User',
      login: 'me',
      avatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=4',
      id: 'user0'
    },
    createdAt: '2018-06-12T14:50:08Z',
    headRefName: o.headRefName,

    repository: {
      id: o.repositoryID,
    },

    commits,
  }
}

export function createPullRequestsResult(...attrs) {
  const idGen = IDGenerator.fromOpts({});
  const embed = idGen.embed();

  return attrs.map(attr => {
    return createPullRequestResult({...attr, ...embed});
  });
}

export function createPullRequestDetailResult(attrs = {}) {
  const idGen = IDGenerator.fromOpts(attrs);

  const o = {
    id: idGen.generate('pullrequest'),
    number: 0,
    title: 'title',
    state: 'OPEN',
    authorLogin: 'me',
    authorAvatarURL: 'https://avatars3.githubusercontent.com/u/000?v=4',
    headRefName: 'headref',
    headRepositoryLogin: 'headlogin',
    baseRepositoryLogin: 'baseLogin',
    ...attrs,
  };

  const commit = {
    id: idGen.generate('commit'),
    status: null,
  };

  return {
    __typename: 'PullRequest',
    id: o.id,
    title: o.title,
    number: o.number,
    state: o.state,
    bodyHTML: '
body
',
    author: {
      __typename: 'User',
      id: idGen.generate('user'),
      login: o.authorLogin,
      avatarUrl: o.authorAvatarURL,
      url: `https://github.com/${o.authorLogin}`,
    },
    url: `https://github.com/owner/repo/pull/${o.number}`,
    reactionGroups: [],
    commits: {
      edges: [{
        node: {commit, id: 'node0'}
      }],
    },
    timeline: {
      pageInfo: {
        endCursor: 'end',
        hasNextPage: false,
      },
      edges: [],
    },
    headRefName: o.headRefName,
    headRepositoryOwner: {
      __typename: 'User',
      id: idGen.generate('user'),
      login: o.headRepositoryLogin,
    },
    repository: {
      owner: {
        __typename: 'User',
        id: idGen.generate('user'),
        login: o.baseRepositoryLogin,
      },
      id: idGen.generate('repository'),
    }
  };
}
<|endoftext|>


<commit_before>// Alphanumeric and hyphenated housenumbers

var tape = require('tape');
var Carmen = require('..');
var index = require('../lib/index');
var context = require('../lib/context');
var mem = require('../lib/api-mem');
var queue = require('queue-async');
var addFeature = require('../lib/util/addfeature');

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index alphanum address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _cluster: {
                    '9b': { type: "Point", coordinates: [0,0] },
                    '10c': { type: "Point", coordinates: [0,0] },
                    '7': { type: "Point", coordinates: [0,0] }
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test address index for alphanumerics', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _cluster: {
                    '9': { type: "Point", coordinates: [0,0] },
                    '10': { type: "Point", coordinates: [0,0] },
                    '7': { type: "Point", coordinates: [0,0] }
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test address query with alphanumeric', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _rangetype:'tiger',
                _lfromhn: '0',
                _ltohn: '100',
                _geometry: {
                    type:'LineString',
                    coordinates:[[0,0],[0,100]]
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test alphanumeric address query with address range', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.equals(res.features[0].address, '9b', 'address number is 9b');
            t.end();
        });
    });

    tape('test alphanumeric address query with invalid address number', function(t) {
        c.geocode('9bc fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.ok(res.features[0].place_name, 'fake street', 'found fake street feature');
            t.ok((res.features[0].relevance < 0.6), 'appropriate relevance');
            t.ok((res.features[0].address === undefined), 'address number is not defined');
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'beach street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _rangetype:'tiger',
                _lfromhn: '23-100',
                _ltohn: '23-500',
                _geometry: {
                    type:'LineString',
                    coordinates:[[0,0],[0,100]]
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test hyphenated address query with address range', function(t) {
        c.geocode('23-414 beach street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '23-414 beach street', 'found 23-414 beach street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

tape('index.teardown', function(assert) {
    index.teardown();
    context.getTile.cache.reset();
    assert.end();
});

<commit_msg>UK postcode / address range test<commit_after>// Alphanumeric and hyphenated housenumbers

var tape = require('tape');
var Carmen = require('..');
var index = require('../lib/index');
var context = require('../lib/context');
var mem = require('../lib/api-mem');
var queue = require('queue-async');
var addFeature = require('../lib/util/addfeature');

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index alphanum address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _cluster: {
                    '9b': { type: "Point", coordinates: [0,0] },
                    '10c': { type: "Point", coordinates: [0,0] },
                    '7': { type: "Point", coordinates: [0,0] }
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test address index for alphanumerics', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _cluster: {
                    '9': { type: "Point", coordinates: [0,0] },
                    '10': { type: "Point", coordinates: [0,0] },
                    '7': { type: "Point", coordinates: [0,0] }
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test address query with alphanumeric', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'fake street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _rangetype:'tiger',
                _lfromhn: '0',
                _ltohn: '100',
                _geometry: {
                    type:'LineString',
                    coordinates:[[0,0],[0,100]]
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test alphanumeric address query with address range', function(t) {
        c.geocode('9b fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '9b fake street', 'found 9b fake street');
            t.equals(res.features[0].relevance, 0.99);
            t.equals(res.features[0].address, '9b', 'address number is 9b');
            t.end();
        });
    });

    tape('test alphanumeric address query with invalid address number', function(t) {
        c.geocode('9bc fake street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.ok(res.features[0].place_name, 'fake street', 'found fake street feature');
            t.ok((res.features[0].relevance < 0.6), 'appropriate relevance');
            t.ok((res.features[0].address === undefined), 'address number is not defined');
            t.end();
        });
    });
})();

(function() {
    var conf = {
        postcode: new mem({maxzoom: 6 }, function() {}),
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index fake UK address range', function(t) {
            var address = {
                _id: 1,
                _text:'B77',
                _zxy:['6/32/32'],
                _center:[0,0],
                _rangetype:'tiger',
                _lfromhn: '0',
                _ltohn: '100',
                _geometry: {
                    type:'LineString',
                    coordinates:[[0,0],[0,100]]
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('index fake UK postcode', function(t) {
            var postcode = {
                _id: 2,
                _text:'B77 1AB',
                _zxy:['6/32/32'],
                _center:[0,0],
                _geometry: {
                    type: 'Polygon',
                    coordinates: [
                        [-1, -1],
                        [101, -1],
                        [101, 101],
                        [-1, 101],
                        [-1, -1]
                    ]
                }
            };
            addFeature(conf.postcode, postcode, t.end);
    });
    tape('test UK postcode not getting confused w/ address range', function(t) {
        c.geocode('B77 1AB', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, 'B77 1AB', 'found feature \'B77 1AB\'');
            t.equals(res.features[0].relevance, 0.99);
            t.equals(res.features[0].id.split('.')[0], 'postcode', 'feature is from layer postcode');
            t.end();
        });
    });
})();

(function() {
    var conf = {
        address: new mem({maxzoom: 6, geocoder_address: 1}, function() {})
    };
    var c = new Carmen(conf);
    tape('index address', function(t) {
            var address = {
                _id:1,
                _text:'beach street',
                _zxy:['6/32/32'],
                _center:[0,0],
                _rangetype:'tiger',
                _lfromhn: '23-100',
                _ltohn: '23-500',
                _geometry: {
                    type:'LineString',
                    coordinates:[[0,0],[0,100]]
                }
            };
            addFeature(conf.address, address, t.end);
    });
    tape('test hyphenated address query with address range', function(t) {
        c.geocode('23-414 beach street', { limit_verify: 1 }, function (err, res) {
            t.ifError(err);
            t.equals(res.features[0].place_name, '23-414 beach street', 'found 23-414 beach street');
            t.equals(res.features[0].relevance, 0.99);
            t.end();
        });
    });
})();

tape('index.teardown', function(assert) {
    index.teardown();
    context.getTile.cache.reset();
    assert.end();
});

<|endoftext|>