<commit_before>define({
  root: ({
    map: {
      error: "Unable to create map"
    },
    onlineStatus: {
      offline: "You are currently working offline. Form submissions will be saved locally until a connection to the server can be made.",
      reconnecting: "Reconnecting…",
      pending: "${total} pending edit(s) will be submitted when a network connection is re-established."
    },
    configure: {
      mapdlg: {
        items: {
          organizationLabel: "My Organization",
          onlineLabel: "ArcGIS Online",
          contentLabel: "My Content",
          favoritesLabel: "My Favorites"
        },
        title: "Select Web Map",
        searchTitle: "Search",
        ok: "Ok",
        cancel: "Cancel",
        placeholder: "Enter search term"
      },
      groupdlg: {
        items: {
          organizationLabel: "My Organization",
          onlineLabel: "ArcGIS Online",
          contentLabel: "My Content",
          favoritesLabel: "My Favorites"
        },
        title: "Select Group",
        searchTitle: "Search",
        ok: "Ok",
        cancel: "Cancel",
        placeholder: "Enter search term"
      },
      sharedlg: {
        items: {},
        mailtoLinkDescription: "Here is a link to a GeoForm"
      }
    },
    user: {
      mgrs: "MGRS",
      usng: "USNG",
      utm: "UTM",
      utm_northing: "Northing",
      utm_easting: "Easting",
      utm_zone_number: "Zone Number",
      selectLayerTabText: "${formSection} Select Form",
      geoFormGeneralTabText: "${formSection} Enter Information",
      locationInformationText: "${formSection} Select Location",
      submitInformationText: "${formSection} Complete Form",
      submitInstructions: "Add this information to the map.",
      myLocationText: "Current Location",
      locationDescriptionForMoreThanOneOption: "Specify the location for this entry by clicking/tapping the map or by using one of the following options.",
      locationDescriptionForOneOption: "Specify the location for this entry by clicking/tapping the map or by using the following option.",
      locationDescriptionForNoOption: "Specify the location for this entry by clicking/tapping the map.",
      addressText: "Search",
      geographic: "Lat/Lon",
      locationTabText: "Location",
      locationPopupTitle: "Location",
      submitButtonText: "Submit Entry",
      submitButtonTextLoading: "Submitting…",
      formValidationMessageAlertText: "The following fields are required:",
      selectLocation: "Please select a location for your submission.",
      emptylatitudeAlertMessage: "Please enter a ${openLink}latitude${closeLink} coordinate.",
      emptylongitudeAlertMessage: "Please enter a ${openLink}longitude${closeLink} coordinate.",
      shareUserTitleMessage: "Thank you for your contribution!",
      entrySubmitted: "Your entry has been submitted to the map.",
      shareThisForm: "Share This Form",
      shareUserTextMessage: "Tell others to contribute using the following options.",
      addAttachmentFailedMessage: "Unable to add attachment to layer",
      addFeatureFailedMessage: "Unable to add feature to layer",
      noLayerConfiguredMessage: "An error occurred loading or finding an editable feature layer. In order to display the form and start collecting submissions, add an editable Feature Layer to the Webmap.",
      placeholderLatitude: "Latitude (Y)",
      placeholderLongitude: "Longitude (X)",
      latitude: "Latitude",
      longitude: "Longitude",
      findMyLocation: "Locate Me",
      finding: "Locating…",
      backToTop: "Back to top",
      addressSearchText: "Your submission will appear here. You can drag the pin to correct the location.",
      shareModalFormText: "Form Link",
      close: "Close",
      locationNotFound: "Location could not be found.",
      setLocation: "Set Location",
      find: "Find address or place",
      attachment: "Attachment",
      toggleDropdown: "Toggle Dropdown",
      invalidString: "Please enter valid value.",
      invalidSmallNumber: "Please enter valid ${openStrong}integer${closeStrong} value between -32768 and 32767.",
      invalidNumber: "Please enter valid ${openStrong}integer${closeStrong} value between -2147483648 and 2147483647.",
      invalidFloat: "Please enter valid ${openStrong}floating point${closeStrong} value.",
      invalidDouble: "Please enter valid ${openStrong}double${closeStrong} value.",
      invalidLatLong: "Please enter valid latitude and longitude coordinates.",
      invalidUTM: "Please enter valid UTM coordinates.",
      invalidUSNG: "Please enter valid USNG coordinates.",
      invalidMGRS: "Please enter valid MGRS coordinates.",
      geoformTitleText: "GeoForm",
      domainDefaultText: "Select…",
      applyEditsFailedMessage: "Sorry your entry cannot be submitted. Please try again.",
      requiredFields: "There are some errors. Please correct them below.",
      requiredField: "(required)",
      error: "Error",
      textRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum value ${minValue} and Maximum value ${maxValue}",
      dateRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum Date ${minValue} and Maximum Date ${maxValue}",
      remainingCharactersHintMessage: "${value} characters remaining",
      mapFullScreen: "Full Screen",
      mapRestore: "Restore",
      filterSelectEmptyText: "Select",
      invalidLayerMessage: "Form layer does not exist. Please configure the application and set the layer.",
      selectedLayerText: "All",
      fileUploadStatus: "File Upload Status",
      uploadingBadge: " Uploading…",
      successBadge: " Uploaded",
      retryBadge: "Retry",
      errorBadge: "Error uploading   ",
      fileTooLargeError: "File too large to attach",
      exceededFileCountError: "Exceeded maximum no. of attachments allowed",
      selectFileTitle: "Select a file"

        btnViewSubmissions: "View Submissions"
    },
    builder: {
      invalidUser: "Sorry, you don't have permission to view this item",
      invalidWebmapSelectionAlert: "The selected webmap does not contain a valid layer to use. Please add an editable FeatureLayer into your webmap to continue.",
      invalidWebmapSelectionAlert2: "For More Information please refer to ${openLink}What is Feature Service?${closeLink}",
      selectFieldsText: "Select Form Fields",
      selectThemeText: "Select Form Theme",
      webmapText: "Webmap",
      layerText: "Layer",
      detailsText: "Details",
      fieldsText: "Fields",
      styleText: "Style",
      optionText: "Options",
      previewText: "Preview",
      publishText: "Publish",
      optionsApplicationText: "Options",
      titleText: "Builder",
      descriptionText: "GeoForm is a configurable template for form-based data editing of a ${link1}Feature Service${closeLink}. This application allows users to enter data through a form instead of a map’s pop-up while leveraging the power of the ${link2}Web Map${closeLink} and editable Feature Services. Use the following steps to customize and deploy your GeoForm.",
      btnPreviousText: "Previous",
      btnNextText: "Next",
      webmapTabTitleText: "Select a Webmap",
      viewWebmap: "View webmap",
      webmapDetailsText: "The selected webmap is ${webMapTitleLink}${webMapTitle}${closeLink}. To select a different webmap please click on 'Choose Webmap' button",
      btnSelectWebmapText: "Choose Webmap",
      btnSelectWebmapTextLoading: "Loading…",
      layerTabTitleText: "Select Editable Layer",
      selectLayerLabelText: "Layer",
      selectLayerDefaultOptionText: "Select Layer",
      defaultBasemap: "Basemap Toggle",
      secondaryBasemap: "Default Basemap",
      detailsTabTitleText: "Form Details",
      detailTitleLabelText: "Title",
      detailLogoLabelText: "Logo Image",
      descriptionLabelText: "Form Instructions & Details",
      fieldDescriptionLabelText: "Help Text (optional)",
      fieldTabFieldHeaderText: "Field",
      fieldTabLabelHeaderText: "Label",
      fieldTabDisplayTypeHeaderText: "Display As",
      fieldTabOrderColumnText: "Order",
      fieldTabVisibleColumnText: "Enabled",
      displayFieldText: "Display Field",
      selectMenuOption: "Select Menu",
      selectRadioOption: "Radio Button",
      selectTextOption: "Text",
      selectDateOption: "Date Picker",
      selectRangeOption: "Touch-Spinner",
      selectCheckboxOption: "Checkbox",
      selectMailOption: "Email",
      selectUrlOption: "URL",
      selectTextAreaOption: "Text Area",
      previewApplicationText: "Preview Application",
      saveApplicationText: "Save Application",
      saveText: "Save",
      toggleNavigationText: "Toggle navigation",
      formPlaceholderText: "My Form",
      shareBuilderInProgressTitleMessage: "Publishing GeoForm",
      shareBuilderProgressBarMessage: "Please Wait…",
      shareBuilderTitleMessage: "Success! Item saved",
      shareBuilderTextMessage: "You can start collecting information by sharing with others",
      shareModalFormText: "Form Link",
      shareBuilderSuccess: "Your GeoForm has been updated & published!",
      geoformTitleText: "Geo Form",
      layerTabText: "This is the layer that the GeoForm will be built from. The layer must be a feature service that is enabled for editing with sharing permissions appropriate for your audience.",
      detailsTabText: "Use the Form Detail boxes below to customize the Title, add a custom logo, and provide a short description for your GeoForm audience. In the description you can add links to other resources, contact information, and even point your audience to a web mapping application featuring all of the data collected with the GeoForm.",
      fieldsTabText: "Here you can select which fields will be visible to your GeoForm audience, edit the Labels they will see, and add a short Description to help with data entry.",
      styleTabText: "Style your GeoForm using the themes below based on your preference.",
      publishTabText: "If you are finished customizing your GeoForm, save the application and begin sharing with your audience. You can always return to this builder and continue customizing it based on feedback.",
      headerSizeLabel: "Header Size",
      smallHeader: "Use Small Header",
      bigHeader: "Use Large Header",
      pushpinText: "Push pin",
      doneButtonText: "Save and Exit",
      fieldTabPlaceHolderHeaderText: "Hint (optional)",
      enableAttachmentLabelText: "${openStrong}Enable Attachments${closeStrong}",
      enableAttachmentLabelHint: "You can enable/disable the attachments here",
      attachmentIsRequiredLabelText: "${openStrong}Attachment Required${closeStrong}",
      attachmentIsRequiredLabelHint: "If necessary, users can be required to enter an attachment.",
      attachmentLabelText: "Attachment Button Label",
      attachmentLabelHint: "This text will appear next to the Attachment Button. You can use this space to describe what you would like your audience to attach (photo, video, document, etc.), the file format you are asking for (.jpeg, .png, .docx, .pdf, etc.), and any additional instructions",
      attachmentDescription: "Attachment Description",
      attachmentHint: "If necessary, you can provide additional attachment instructions here.",
      jumbotronDescription: "Use large or small heading for your form. A large header may help define the purpose of your application but it takes up more room on your screen",
      shareGeoformText: "Share Geoform",
      shareDescription: "The sharing panel makes it easy for your audience to share the GeoForm with other collaborators once they have made a submission - this can be disabled at any time.",
      defaultMapExtent: "Default Map Extent",
      defaultMapExtentDescription: "The map will reset to the default extent in your web map after submission - this can be disabled at any time.",
      pushpinOptionsDescription: "Choose from a variety of colors for the map pushpin, it should be different from the map symbology to help the user put their submission on the map",
      selectLocationText: "Select Location By",
      myLocationText: "My Location",
      searchText: "Search",
      coordinatesText: "Latitude & Longitude Coordinates",
      usng: "USNG Coordinates",
      mgrs: "MGRS Coordinates",
      utm: "UTM Coordinates",
      selectLocationSDescription: "Allow users to select a location using these methods.",
      dragTooltipText: "Drag the field where you want it to appear",
      showHideLayerText: "Show Layer",
      showHideLayerHelpText: "You can configure the GeoForm to Show/Hide Layer.This option only applies to a single layer setup.",
      labelHelpMessage: "Label",
      placeHolderHintMessage: "Hint Text",
      placeHolderHelpMessage: "Help Text",
      selectTextOptionValue: "Filter Select",
      disableLogo: "Disable Logo",
      disableLogoDescription: "You can configure the GeoForm to Show/Hide the Logo in the form header",
      locateOnLoadText: "Locate On Load",
      locateOnLoadDescription: "You can configure the GeoForm to use the current location on page load",
      selectLayerFieldTabText: "Select Layer",
      allLayerSelectOptionText: "All",
      disableViewer: "Disable Viewer",
      disableViewerDescription: "You can configure the GeoForm to disable/enable Viewer",
      displayFieldHintText: "Selected display field will be shown in viewerMode as title field"
    },
    viewer: {
      geocoderCancelText: "Cancel",
      viewReportsTabText: "Submissions",
      viewLegendTabText: "Legend",
      viewAboutusTabText: "About",
      viewMapTabText: "Map",
      sortHeaderText: "Sort By:",
      btnSubmitReportText: "Submit a Report",
      geocoderPlaceholderText: "Zip Code, city, etc.",
      noSearchResult: "No result found",
      recordsTabTooltip: "View Submissions",
      legendTabTooltip: "Legend",
      aboutUsTabTooltip: "AboutUs",
      mapTabTooltip: "Map",
      appLoadingFailedMessage: "ViewerMode is Unavailable",
      btnDescendingText: "Desc",
      btnAscendingText: "Asc",
      geometryUnavailableErrorMessage: "Unable to find the geometry of the feature",
      infoPopupOffErrorMessage: "InfoPopup is off",
      btnLoadMoreText: "Load More",
      unavailableTitleText: "Untitled",
      unavailableConfigMessage: "Unable to load config"
    }
  }),
  "ar": 1,
  "cs": 1,
  "da": 1,
  "de": 1,
  "es": 1,
  "et": 1,
  "fi": 1,
  "fr": 1,
  "he": 1,
  "it": 1,
  "ja": 1,
  "ko": 1,
  "lt": 1,
  "lv": 1,
  "nl": 1,
  "nb": 1,
  "pl": 1,
  "pt-br": 1,
  "pt-pt": 1,
  "ro": 1,
  "ru": 1,
  "sv": 1,
  "th": 1,
  "tr": 1,
  "vi": 1,
  "zh-cn": 1
});<commit_msg>NLS fix<commit_after>define({
  root: ({
    map: {
      error: "Unable to create map"
    },
    onlineStatus: {
      offline: "You are currently working offline. Form submissions will be saved locally until a connection to the server can be made.",
      reconnecting: "Reconnecting…",
      pending: "${total} pending edit(s) will be submitted when a network connection is re-established."
    },
    configure: {
      mapdlg: {
        items: {
          organizationLabel: "My Organization",
          onlineLabel: "ArcGIS Online",
          contentLabel: "My Content",
          favoritesLabel: "My Favorites"
        },
        title: "Select Web Map",
        searchTitle: "Search",
        ok: "Ok",
        cancel: "Cancel",
        placeholder: "Enter search term"
      },
      groupdlg: {
        items: {
          organizationLabel: "My Organization",
          onlineLabel: "ArcGIS Online",
          contentLabel: "My Content",
          favoritesLabel: "My Favorites"
        },
        title: "Select Group",
        searchTitle: "Search",
        ok: "Ok",
        cancel: "Cancel",
        placeholder: "Enter search term"
      },
      sharedlg: {
        items: {},
        mailtoLinkDescription: "Here is a link to a GeoForm"
      }
    },
    user: {
      mgrs: "MGRS",
      usng: "USNG",
      utm: "UTM",
      utm_northing: "Northing",
      utm_easting: "Easting",
      utm_zone_number: "Zone Number",
      selectLayerTabText: "${formSection} Select Form",
      geoFormGeneralTabText: "${formSection} Enter Information",
      locationInformationText: "${formSection} Select Location",
      submitInformationText: "${formSection} Complete Form",
      submitInstructions: "Add this information to the map.",
      myLocationText: "Current Location",
      locationDescriptionForMoreThanOneOption: "Specify the location for this entry by clicking/tapping the map or by using one of the following options.",
      locationDescriptionForOneOption: "Specify the location for this entry by clicking/tapping the map or by using the following option.",
      locationDescriptionForNoOption: "Specify the location for this entry by clicking/tapping the map.",
      addressText: "Search",
      geographic: "Lat/Lon",
      locationTabText: "Location",
      locationPopupTitle: "Location",
      submitButtonText: "Submit Entry",
      submitButtonTextLoading: "Submitting…",
      formValidationMessageAlertText: "The following fields are required:",
      selectLocation: "Please select a location for your submission.",
      emptylatitudeAlertMessage: "Please enter a ${openLink}latitude${closeLink} coordinate.",
      emptylongitudeAlertMessage: "Please enter a ${openLink}longitude${closeLink} coordinate.",
      shareUserTitleMessage: "Thank you for your contribution!",
      entrySubmitted: "Your entry has been submitted to the map.",
      shareThisForm: "Share This Form",
      shareUserTextMessage: "Tell others to contribute using the following options.",
      addAttachmentFailedMessage: "Unable to add attachment to layer",
      addFeatureFailedMessage: "Unable to add feature to layer",
      noLayerConfiguredMessage: "An error occurred loading or finding an editable feature layer. In order to display the form and start collecting submissions, add an editable Feature Layer to the Webmap.",
      placeholderLatitude: "Latitude (Y)",
      placeholderLongitude: "Longitude (X)",
      latitude: "Latitude",
      longitude: "Longitude",
      findMyLocation: "Locate Me",
      finding: "Locating…",
      backToTop: "Back to top",
      addressSearchText: "Your submission will appear here. You can drag the pin to correct the location.",
      shareModalFormText: "Form Link",
      close: "Close",
      locationNotFound: "Location could not be found.",
      setLocation: "Set Location",
      find: "Find address or place",
      attachment: "Attachment",
      toggleDropdown: "Toggle Dropdown",
      invalidString: "Please enter valid value.",
      invalidSmallNumber: "Please enter valid ${openStrong}integer${closeStrong} value between -32768 and 32767.",
      invalidNumber: "Please enter valid ${openStrong}integer${closeStrong} value between -2147483648 and 2147483647.",
      invalidFloat: "Please enter valid ${openStrong}floating point${closeStrong} value.",
      invalidDouble: "Please enter valid ${openStrong}double${closeStrong} value.",
      invalidLatLong: "Please enter valid latitude and longitude coordinates.",
      invalidUTM: "Please enter valid UTM coordinates.",
      invalidUSNG: "Please enter valid USNG coordinates.",
      invalidMGRS: "Please enter valid MGRS coordinates.",
      geoformTitleText: "GeoForm",
      domainDefaultText: "Select…",
      applyEditsFailedMessage: "Sorry your entry cannot be submitted. Please try again.",
      requiredFields: "There are some errors. Please correct them below.",
      requiredField: "(required)",
      error: "Error",
      textRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum value ${minValue} and Maximum value ${maxValue}",
      dateRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum Date ${minValue} and Maximum Date ${maxValue}",
      remainingCharactersHintMessage: "${value} characters remaining",
      mapFullScreen: "Full Screen",
      mapRestore: "Restore",
      filterSelectEmptyText: "Select",
      invalidLayerMessage: "Form layer does not exist. Please configure the application and set the layer.",
      selectedLayerText: "All",
      fileUploadStatus: "File Upload Status",
      uploadingBadge: " Uploading…",
      successBadge: " Uploaded",
      retryBadge: "Retry",
      errorBadge: "Error uploading   ",
      fileTooLargeError: "File too large to attach",
      exceededFileCountError: "Exceeded maximum no. of attachments allowed",
      selectFileTitle: "Select a file",
      btnViewSubmissions: "View Submissions"
    },
    builder: {
      invalidUser: "Sorry, you don't have permission to view this item",
      invalidWebmapSelectionAlert: "The selected webmap does not contain a valid layer to use. Please add an editable FeatureLayer into your webmap to continue.",
      invalidWebmapSelectionAlert2: "For More Information please refer to ${openLink}What is Feature Service?${closeLink}",
      selectFieldsText: "Select Form Fields",
      selectThemeText: "Select Form Theme",
      webmapText: "Webmap",
      layerText: "Layer",
      detailsText: "Details",
      fieldsText: "Fields",
      styleText: "Style",
      optionText: "Options",
      previewText: "Preview",
      publishText: "Publish",
      optionsApplicationText: "Options",
      titleText: "Builder",
      descriptionText: "GeoForm is a configurable template for form-based data editing of a ${link1}Feature Service${closeLink}. This application allows users to enter data through a form instead of a map’s pop-up while leveraging the power of the ${link2}Web Map${closeLink} and editable Feature Services. Use the following steps to customize and deploy your GeoForm.",
      btnPreviousText: "Previous",
      btnNextText: "Next",
      webmapTabTitleText: "Select a Webmap",
      viewWebmap: "View webmap",
      webmapDetailsText: "The selected webmap is ${webMapTitleLink}${webMapTitle}${closeLink}. To select a different webmap please click on 'Choose Webmap' button",
      btnSelectWebmapText: "Choose Webmap",
      btnSelectWebmapTextLoading: "Loading…",
      layerTabTitleText: "Select Editable Layer",
      selectLayerLabelText: "Layer",
      selectLayerDefaultOptionText: "Select Layer",
      defaultBasemap: "Basemap Toggle",
      secondaryBasemap: "Default Basemap",
      detailsTabTitleText: "Form Details",
      detailTitleLabelText: "Title",
      detailLogoLabelText: "Logo Image",
      descriptionLabelText: "Form Instructions & Details",
      fieldDescriptionLabelText: "Help Text (optional)",
      fieldTabFieldHeaderText: "Field",
      fieldTabLabelHeaderText: "Label",
      fieldTabDisplayTypeHeaderText: "Display As",
      fieldTabOrderColumnText: "Order",
      fieldTabVisibleColumnText: "Enabled",
      displayFieldText: "Display Field",
      selectMenuOption: "Select Menu",
      selectRadioOption: "Radio Button",
      selectTextOption: "Text",
      selectDateOption: "Date Picker",
      selectRangeOption: "Touch-Spinner",
      selectCheckboxOption: "Checkbox",
      selectMailOption: "Email",
      selectUrlOption: "URL",
      selectTextAreaOption: "Text Area",
      previewApplicationText: "Preview Application",
      saveApplicationText: "Save Application",
      saveText: "Save",
      toggleNavigationText: "Toggle navigation",
      formPlaceholderText: "My Form",
      shareBuilderInProgressTitleMessage: "Publishing GeoForm",
      shareBuilderProgressBarMessage: "Please Wait…",
      shareBuilderTitleMessage: "Success! Item saved",
      shareBuilderTextMessage: "You can start collecting information by sharing with others",
      shareModalFormText: "Form Link",
      shareBuilderSuccess: "Your GeoForm has been updated & published!",
      geoformTitleText: "Geo Form",
      layerTabText: "This is the layer that the GeoForm will be built from. The layer must be a feature service that is enabled for editing with sharing permissions appropriate for your audience.",
      detailsTabText: "Use the Form Detail boxes below to customize the Title, add a custom logo, and provide a short description for your GeoForm audience. In the description you can add links to other resources, contact information, and even point your audience to a web mapping application featuring all of the data collected with the GeoForm.",
      fieldsTabText: "Here you can select which fields will be visible to your GeoForm audience, edit the Labels they will see, and add a short Description to help with data entry.",
      styleTabText: "Style your GeoForm using the themes below based on your preference.",
      publishTabText: "If you are finished customizing your GeoForm, save the application and begin sharing with your audience. You can always return to this builder and continue customizing it based on feedback.",
      headerSizeLabel: "Header Size",
      smallHeader: "Use Small Header",
      bigHeader: "Use Large Header",
      pushpinText: "Push pin",
      doneButtonText: "Save and Exit",
      fieldTabPlaceHolderHeaderText: "Hint (optional)",
      enableAttachmentLabelText: "${openStrong}Enable Attachments${closeStrong}",
      enableAttachmentLabelHint: "You can enable/disable the attachments here",
      attachmentIsRequiredLabelText: "${openStrong}Attachment Required${closeStrong}",
      attachmentIsRequiredLabelHint: "If necessary, users can be required to enter an attachment.",
      attachmentLabelText: "Attachment Button Label",
      attachmentLabelHint: "This text will appear next to the Attachment Button. You can use this space to describe what you would like your audience to attach (photo, video, document, etc.), the file format you are asking for (.jpeg, .png, .docx, .pdf, etc.), and any additional instructions",
      attachmentDescription: "Attachment Description",
      attachmentHint: "If necessary, you can provide additional attachment instructions here.",
      jumbotronDescription: "Use large or small heading for your form. A large header may help define the purpose of your application but it takes up more room on your screen",
      shareGeoformText: "Share Geoform",
      shareDescription: "The sharing panel makes it easy for your audience to share the GeoForm with other collaborators once they have made a submission - this can be disabled at any time.",
      defaultMapExtent: "Default Map Extent",
      defaultMapExtentDescription: "The map will reset to the default extent in your web map after submission - this can be disabled at any time.",
      pushpinOptionsDescription: "Choose from a variety of colors for the map pushpin, it should be different from the map symbology to help the user put their submission on the map",
      selectLocationText: "Select Location By",
      myLocationText: "My Location",
      searchText: "Search",
      coordinatesText: "Latitude & Longitude Coordinates",
      usng: "USNG Coordinates",
      mgrs: "MGRS Coordinates",
      utm: "UTM Coordinates",
      selectLocationSDescription: "Allow users to select a location using these methods.",
      dragTooltipText: "Drag the field where you want it to appear",
      showHideLayerText: "Show Layer",
      showHideLayerHelpText: "You can configure the GeoForm to Show/Hide Layer.This option only applies to a single layer setup.",
      labelHelpMessage: "Label",
      placeHolderHintMessage: "Hint Text",
      placeHolderHelpMessage: "Help Text",
      selectTextOptionValue: "Filter Select",
      disableLogo: "Disable Logo",
      disableLogoDescription: "You can configure the GeoForm to Show/Hide the Logo in the form header",
      locateOnLoadText: "Locate On Load",
      locateOnLoadDescription: "You can configure the GeoForm to use the current location on page load",
      selectLayerFieldTabText: "Select Layer",
      allLayerSelectOptionText: "All",
      disableViewer: "Disable Viewer",
      disableViewerDescription: "You can configure the GeoForm to disable/enable Viewer",
      displayFieldHintText: "Selected display field will be shown in viewerMode as title field"
    },
    viewer: {
      geocoderCancelText: "Cancel",
      viewReportsTabText: "Submissions",
      viewLegendTabText: "Legend",
      viewAboutusTabText: "About",
      viewMapTabText: "Map",
      sortHeaderText: "Sort By:",
      btnSubmitReportText: "Submit a Report",
      geocoderPlaceholderText: "Zip Code, city, etc.",
      noSearchResult: "No result found",
      recordsTabTooltip: "View Submissions",
      legendTabTooltip: "Legend",
      aboutUsTabTooltip: "AboutUs",
      mapTabTooltip: "Map",
      appLoadingFailedMessage: "ViewerMode is Unavailable",
      btnDescendingText: "Desc",
      btnAscendingText: "Asc",
      geometryUnavailableErrorMessage: "Unable to find the geometry of the feature",
      infoPopupOffErrorMessage: "InfoPopup is off",
      btnLoadMoreText: "Load More",
      unavailableTitleText: "Untitled",
      unavailableConfigMessage: "Unable to load config"
    }
  }),
  "ar": 1,
  "cs": 1,
  "da": 1,
  "de": 1,
  "es": 1,
  "et": 1,
  "fi": 1,
  "fr": 1,
  "he": 1,
  "it": 1,
  "ja": 1,
  "ko": 1,
  "lt": 1,
  "lv": 1,
  "nl": 1,
  "nb": 1,
  "pl": 1,
  "pt-br": 1,
  "pt-pt": 1,
  "ro": 1,
  "ru": 1,
  "sv": 1,
  "th": 1,
  "tr": 1,
  "vi": 1,
  "zh-cn": 1
});<|endoftext|>


<commit_before>/*global define */
/*
 | Copyright 2014 Esri
 |
 | 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.
 */
define({
    root: ({
        map: {
            error: "Unable to create map",
            zoomInTooltip: "Zoom in",  // Command button to zoom in to the map
            zoomOutTooltip: "Zoom out",  // Command button to zoom out of the map
            geolocationTooltip: "Current location"  // Command button to navigate to the current geographical position
        },
        main: {
            noGroup: "No group configured", // Shown when no group is configured in the configuration file
            submitReportButtonText: "Submit a report", //Submit report  text for buttons on map and list
            gotoListViewTooltip: "List view", // Go to List view tooltip text
            noFeatureGeomtery: "Feature cannot be displayed" // Error message when geomtery is not available
        },
        signin: {
            guestSigninText: "Proceed as Guest", // Shown in the 'Sign in' page below the icon for accessing application as an anonymous user
            signInOrText: "Or", // Or text on sign in screen
            signinOptionsText: "Sign in with:", // Shown in the 'Sign in' page above the icons for social media sign in
            noGroupNameText: "Please sign in", // Shown when the group title is not available or the group is private
            guestLoginTooltip: "Sign in as a guest", // Command button to access the application as an anonymous user
            facebookLoginTooltip: "Sign in with Facebook", // Command button to access the application via Facebook login
            twitterLoginTooltip: "Sign in with Twitter", // Command button to access the application via Twitter login
            googlePlusLoginTooltip: "Sign in with Google+", // Command button to access the application via Google+ login
            agolLoginTooltip: "Sign in with ArcGIS" // Command button to access the application via AGOL login
        },
        webMapList: {
            owner: "Owner", // Shown in the 'Map information' section indicating the owner of the webmap
            created: "Date dreated", // Shown in the 'Map information' section indicating the date when the webmap was created
            modified: "Date modified", // Shown in the 'Map information' section indicating the date when the webmap was modified
            description: "Description", // Shown in the 'Map information' section describing the webmap
            snippet: "Summary", // Shown in the 'Map information' section providing the summary of the webmap
            licenseInfo: "Access and use constraints", // Shown in the map information section indicating the webmap license information
            accessInformation: "Credits", // Shown in the 'Map information' section indicating account credits
            tags: "Tags", // Shown in the 'Map information' section indicating tags of the webmap
            numViews: "Number of views", // Shown in the 'Map information' section indicating number of times the webmap has been viewed
            avgRating: "Rating", // Shown in the 'Map information' section indicating webmap rating
            noWebMapInGroup: "Configured group is invalid or no items have been shared with this group yet.", // Shown when the configured group is invalid/private or no items have been shared with the group
            infoBtnToolTip: "Map information" // Command button to view the 'Map information'
        },
        issueWall: {
            noResultsFound: "No reports available in the current area", // Shown in the issue wall when no issues are present in the current map extent
            gotoWebmapListTooltip: "Go to main list", // Tooltip for back icon in list header
            gotoMapViewTooltip: "Map view" // Tooltip for map-it icon in list header
        },
        appHeader: {
            myReport: "My Reports", // Command button shown in mobile menu list
            signIn: "Sign In", // Command button shown in mobile menu list and in appheader
            signOut: "Sign Out", // Command button shown in mobile menu list
            help: "Help", // Command button shown in mobile menu list
            signInTooltip: "Sign in", // Tooltip to 'Sign in' option
            signOutTooltip: "Sign out", // Tooltip  to 'Sign out' option
            myReportTooltip: "View reports submitted by me", // Tooltip  to 'My Reports' option
            helpTooltip: "Help" // Tooltip  to 'Help' option
        },
        geoform: {
            enterInformation: "Details", // Shown as the first section of the geoform, where the user can enter details of the issue
            selectAttachments: "Attachments", // Appears above 'Select file' button indicating option to attach files
            selectFileText: "Browse", // Command button to open a dialog box to select file(s) to be attached
            enterLocation: "Location", // Shown as the second section of the geoform, where the user can select a location on the map
            reportItButton: "Report It", // Command button to submit the geoform to report an issue
            cancelButton: "Cancel", //Command button to close the geoform
            requiredField: "(required)", // Shown next to the field in which the data is mandatory
            selectDefaultText: "Select…", // Shown in the dropdown field indicating to select an option
            invalidInputValue: "Please enter valid value.", // Shown when user clicks/taps the required field but does not enter the data and comes out of the required field
            noFieldsConfiguredMessage: "Layer fields are not configured to capture data", // Shown when all the fields of the selected layer are disabled
            invalidSmallNumber: "Please enter an integer", // Shown when the entered value is beyond the specified range (valid ${openStrong}integer${closeStrong} value between -32768 and 32767.)
            invalidNumber: "Please enter an integer", // Shown when the entered value is beyond the specified range (valid ${openStrong}integer${closeStrong} value between -2147483648 and 2147483647.)
            invalidFloat: "Please enter a number", // Shown when the entered value is beyond the specified range (valid ${openStrong}floating point${closeStrong} value between -3.4E38 and 1.2E38 )
            invalidDouble: "Please enter a number", // Shown when the entered value is beyond the specified range (valid ${openStrong}double${closeStrong} value between -2.2E308 and 1.8E308)
            requiredFields: "Please provide values for all required fields", // Shown when user submits the geoform without entering data in the mandatory field(s)
            selectLocation: "Please select the location for your report", // Shown when user submits the geoform without selecting location on the map
            numericRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum value ${minValue} and Maximum value ${maxValue}", // Shown as a pop over above the fields with numeric values, indicating the minimum and maximum range
            dateRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum Date ${minValue} and Maximum Date ${maxValue}", // Shown as a pop over above the fields with date values, indicating the minimum and maximum date range
            errorsInApplyEdits: "Issue could not be reported", // Shown when there is an error in any of the services while submitting the geoform
            attachmentSelectedMsg: "attachment(s) selected", // Shown besides the select file button indicating the number of files attached
            attachmentUploadStatus: "${failed} of ${total} attachment(s) failed to upload", // Shown when there is error while uploading the attachment, while submitting the geoform
            geoLocationError: "Current location not available",  // Shown when the browser returns an error instead of the current geographical position
            geoLocationOutOfExtent: "Current location is out of basemap extent",  // Shown when the current geographical position is out of the basemap extent
            submitButtonTooltip: "Report It", // Command button to open the geoform
            cancelButtonTooltip: "Cancel", //tooltip for cancel button
            geoformBackButtonTooltip: "Go to the report list" //tooltip for Geoform back button

        },
        locator: {
            addressText: "Address:", // Shown as a title for a group of addresses returned on performing unified search
            usngText: "USNG", // Shown as a title for a group of USNG values returned on performing unified search
            mgrsText: "MGRS", // Shown as a title for a group of MGRS values returned on performing unified search
            latLongText: "Latitude/Longitude", // Shown as a title for a group of latitude longitude values returned on performing unified search
            invalidSearch: "No results found", // Shown in the address container when no results are returned on performing unified search
            locatorPlaceholder: "Enter an address to search", // Shown in the address container textbox as a placeholder
            locationOutOfExtent: "Located address is out of basemap extent", // Shown as an alert when the selected address in the search result is out of basemap extent
            searchButtonTooltip: "Search", // Tooltip for search button
            clearButtonTooltip: "Clear search value" // Tooltip for Geocoder clear button
        },
        myIssues: {
            title: "My Reports", // Shown as a title in 'My issues' panel
            myIssuesTooltip: "My Reports", // Command button to access issues reported by the logged in user
            noResultsFound: "No reports found" // Shown when no issues are reported by the logged in user
        },
        itemDetails: {  // Detailed information about an item and a list of its comments
            likeButtonLabel: "Like", // Command button shown in details panel
            likeButtonTooltip: "Vote for this report",  // Tooltip for command button shown in details panel
            commentButtonLabel: "Comment", // Command button shown in details panel
            commentButtonTooltip: "Comment on this report", // Tooltip for command button shown in details panel
            galleryButtonLabel: "Gallery", // Command button shown in details panel
            galleryButtonTooltip: "See attached documents", // Tooltip for command button shown in details panel
            mapButtonLabel: "View on Map", // Command button shown in details panel
            mapButtonTooltip: "View the location of this report", // Tooltip for command button shown in details panel
            commentsListHeading: "Comments", // List heading for Comments section in details panel
            unableToUpdateVoteField: "Your vote cannot be added at this time.", // Error message for feature unable to update
            gotoIssueListTooltip: "Go to the report list" // Tooltip for back icon in Issue list header
        },
        itemList: {  // List of feature layer items shown in my-issues and issue-wall
            likesForThisItemTooltip: "Votes for this report "//Shown on hovering of the like icon in my-issues and issue-wall
        },
        comment: {
            commentsFormText: "Comment",
            commentsFormSubmitButton: "Submit Comment",
            commentsFormCancelButton: "Cancel",
            errorInSubmittingComment: "Comment could not be submitted.", // Shown when user is unable to add comments
            emptyCommentMessage: "Please enter a comment.", // Shown when user submits a comment without any text/character
            placeHolderText: "Type a comment", // Shown as a placeholder in comments textbox
            noCommentsAvailableText: "No comments available", // Shown when no comments are available for the selected issue
            remainingTextCount: "${0} character(s) remain", // Shown below the comments textbox indicating the number of characters that can be added
            showNoText: "No" // Shown when comments character limit is exceeded
        },
        gallery: {
            galleryHeaderText: "Gallery",
            noAttachmentsAvailableText: "No attachments found" // Shown when no comments are available for the selected issue
        }
    }),
    "ar": 1,
    "cs": 1,
    "da": 1,
    "de": 1,
    "el": 1,
    "en": 1,
    "es": 1,
    "et": 1,
    "fi": 1,
    "fr": 1,
    "he": 1,
    "it": 1,
    "ja": 1,
    "ko": 1,
    "lt": 1,
    "lv": 1,
    "nb": 1,
    "nl": 1,
    "pl": 1,
    "pt-br": 1,
    "pt-pt": 1,
    "ro": 1,
    "ru": 1,
    "sv": 1,
    "th": 1,
    "tr": 1,
    "vi": 1,
    "zh-cn": 1,
    "zh-hk": 1,
    "zh-tw": 1
});
<commit_msg>moved space to after string<commit_after>/*global define */
/*
 | Copyright 2014 Esri
 |
 | 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.
 */
define({
    root: ({
        map: {
            error: "Unable to create map",
            zoomInTooltip: "Zoom in",  // Command button to zoom in to the map
            zoomOutTooltip: "Zoom out",  // Command button to zoom out of the map
            geolocationTooltip: "Current location"  // Command button to navigate to the current geographical position
        },
        main: {
            noGroup: "No group configured", // Shown when no group is configured in the configuration file
            submitReportButtonText: "Submit a report", //Submit report  text for buttons on map and list
            gotoListViewTooltip: "List view", // Go to List view tooltip text
            noFeatureGeomtery: "Feature cannot be displayed" // Error message when geomtery is not available
        },
        signin: {
            guestSigninText: "Proceed as Guest", // Shown in the 'Sign in' page below the icon for accessing application as an anonymous user
            signInOrText: "Or", // Or text on sign in screen
            signinOptionsText: "Sign in with:", // Shown in the 'Sign in' page above the icons for social media sign in
            noGroupNameText: "Please sign in", // Shown when the group title is not available or the group is private
            guestLoginTooltip: "Sign in as a guest", // Command button to access the application as an anonymous user
            facebookLoginTooltip: "Sign in with Facebook", // Command button to access the application via Facebook login
            twitterLoginTooltip: "Sign in with Twitter", // Command button to access the application via Twitter login
            googlePlusLoginTooltip: "Sign in with Google+", // Command button to access the application via Google+ login
            agolLoginTooltip: "Sign in with ArcGIS" // Command button to access the application via AGOL login
        },
        webMapList: {
            owner: "Owner", // Shown in the 'Map information' section indicating the owner of the webmap
            created: "Date dreated", // Shown in the 'Map information' section indicating the date when the webmap was created
            modified: "Date modified", // Shown in the 'Map information' section indicating the date when the webmap was modified
            description: "Description", // Shown in the 'Map information' section describing the webmap
            snippet: "Summary", // Shown in the 'Map information' section providing the summary of the webmap
            licenseInfo: "Access and use constraints", // Shown in the map information section indicating the webmap license information
            accessInformation: "Credits", // Shown in the 'Map information' section indicating account credits
            tags: "Tags", // Shown in the 'Map information' section indicating tags of the webmap
            numViews: "Number of views", // Shown in the 'Map information' section indicating number of times the webmap has been viewed
            avgRating: "Rating", // Shown in the 'Map information' section indicating webmap rating
            noWebMapInGroup: "Configured group is invalid or no items have been shared with this group yet.", // Shown when the configured group is invalid/private or no items have been shared with the group
            infoBtnToolTip: "Map information" // Command button to view the 'Map information'
        },
        issueWall: {
            noResultsFound: "No reports available in the current area", // Shown in the issue wall when no issues are present in the current map extent
            gotoWebmapListTooltip: "Go to main list", // Tooltip for back icon in list header
            gotoMapViewTooltip: "Map view" // Tooltip for map-it icon in list header
        },
        appHeader: {
            myReport: "My Reports", // Command button shown in mobile menu list
            signIn: "Sign In", // Command button shown in mobile menu list and in appheader
            signOut: "Sign Out", // Command button shown in mobile menu list
            help: "Help", // Command button shown in mobile menu list
            signInTooltip: "Sign in", // Tooltip to 'Sign in' option
            signOutTooltip: "Sign out", // Tooltip  to 'Sign out' option
            myReportTooltip: "View reports submitted by me", // Tooltip  to 'My Reports' option
            helpTooltip: "Help" // Tooltip  to 'Help' option
        },
        geoform: {
            enterInformation: "Details", // Shown as the first section of the geoform, where the user can enter details of the issue
            selectAttachments: "Attachments", // Appears above 'Select file' button indicating option to attach files
            selectFileText: "Browse", // Command button to open a dialog box to select file(s) to be attached
            enterLocation: "Location", // Shown as the second section of the geoform, where the user can select a location on the map
            reportItButton: "Report It", // Command button to submit the geoform to report an issue
            cancelButton: "Cancel", //Command button to close the geoform
            requiredField: "(required)", // Shown next to the field in which the data is mandatory
            selectDefaultText: "Select…", // Shown in the dropdown field indicating to select an option
            invalidInputValue: "Please enter valid value.", // Shown when user clicks/taps the required field but does not enter the data and comes out of the required field
            noFieldsConfiguredMessage: "Layer fields are not configured to capture data", // Shown when all the fields of the selected layer are disabled
            invalidSmallNumber: "Please enter an integer", // Shown when the entered value is beyond the specified range (valid ${openStrong}integer${closeStrong} value between -32768 and 32767.)
            invalidNumber: "Please enter an integer", // Shown when the entered value is beyond the specified range (valid ${openStrong}integer${closeStrong} value between -2147483648 and 2147483647.)
            invalidFloat: "Please enter a number", // Shown when the entered value is beyond the specified range (valid ${openStrong}floating point${closeStrong} value between -3.4E38 and 1.2E38 )
            invalidDouble: "Please enter a number", // Shown when the entered value is beyond the specified range (valid ${openStrong}double${closeStrong} value between -2.2E308 and 1.8E308)
            requiredFields: "Please provide values for all required fields", // Shown when user submits the geoform without entering data in the mandatory field(s)
            selectLocation: "Please select the location for your report", // Shown when user submits the geoform without selecting location on the map
            numericRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum value ${minValue} and Maximum value ${maxValue}", // Shown as a pop over above the fields with numeric values, indicating the minimum and maximum range
            dateRangeHintMessage: "${openStrong}Hint:${closeStrong} Minimum Date ${minValue} and Maximum Date ${maxValue}", // Shown as a pop over above the fields with date values, indicating the minimum and maximum date range
            errorsInApplyEdits: "Issue could not be reported", // Shown when there is an error in any of the services while submitting the geoform
            attachmentSelectedMsg: "attachment(s) selected", // Shown besides the select file button indicating the number of files attached
            attachmentUploadStatus: "${failed} of ${total} attachment(s) failed to upload", // Shown when there is error while uploading the attachment, while submitting the geoform
            geoLocationError: "Current location not available",  // Shown when the browser returns an error instead of the current geographical position
            geoLocationOutOfExtent: "Current location is out of basemap extent",  // Shown when the current geographical position is out of the basemap extent
            submitButtonTooltip: "Report It", // Command button to open the geoform
            cancelButtonTooltip: "Cancel", //tooltip for cancel button
            geoformBackButtonTooltip: "Go to the report list" //tooltip for Geoform back button

        },
        locator: {
            addressText: "Address:", // Shown as a title for a group of addresses returned on performing unified search
            usngText: "USNG", // Shown as a title for a group of USNG values returned on performing unified search
            mgrsText: "MGRS", // Shown as a title for a group of MGRS values returned on performing unified search
            latLongText: "Latitude/Longitude", // Shown as a title for a group of latitude longitude values returned on performing unified search
            invalidSearch: "No results found", // Shown in the address container when no results are returned on performing unified search
            locatorPlaceholder: "Enter an address to search", // Shown in the address container textbox as a placeholder
            locationOutOfExtent: "Located address is out of basemap extent", // Shown as an alert when the selected address in the search result is out of basemap extent
            searchButtonTooltip: "Search", // Tooltip for search button
            clearButtonTooltip: "Clear search value" // Tooltip for Geocoder clear button
        },
        myIssues: {
            title: "My Reports", // Shown as a title in 'My issues' panel
            myIssuesTooltip: "My Reports", // Command button to access issues reported by the logged in user
            noResultsFound: "No reports found" // Shown when no issues are reported by the logged in user
        },
        itemDetails: {  // Detailed information about an item and a list of its comments
            likeButtonLabel: "Like", // Command button shown in details panel
            likeButtonTooltip: "Vote for this report",  // Tooltip for command button shown in details panel
            commentButtonLabel: "Comment", // Command button shown in details panel
            commentButtonTooltip: "Comment on this report", // Tooltip for command button shown in details panel
            galleryButtonLabel: "Gallery", // Command button shown in details panel
            galleryButtonTooltip: "See attached documents", // Tooltip for command button shown in details panel
            mapButtonLabel: "View on Map", // Command button shown in details panel
            mapButtonTooltip: "View the location of this report", // Tooltip for command button shown in details panel
            commentsListHeading: "Comments", // List heading for Comments section in details panel
            unableToUpdateVoteField: "Your vote cannot be added at this time.", // Error message for feature unable to update
            gotoIssueListTooltip: "Go to the report list" // Tooltip for back icon in Issue list header
        },
        itemList: {  // List of feature layer items shown in my-issues and issue-wall
            likesForThisItemTooltip: "Votes for this report" //Shown on hovering of the like icon in my-issues and issue-wall
        },
        comment: {
            commentsFormText: "Comment",
            commentsFormSubmitButton: "Submit Comment",
            commentsFormCancelButton: "Cancel",
            errorInSubmittingComment: "Comment could not be submitted.", // Shown when user is unable to add comments
            emptyCommentMessage: "Please enter a comment.", // Shown when user submits a comment without any text/character
            placeHolderText: "Type a comment", // Shown as a placeholder in comments textbox
            noCommentsAvailableText: "No comments available", // Shown when no comments are available for the selected issue
            remainingTextCount: "${0} character(s) remain", // Shown below the comments textbox indicating the number of characters that can be added
            showNoText: "No" // Shown when comments character limit is exceeded
        },
        gallery: {
            galleryHeaderText: "Gallery",
            noAttachmentsAvailableText: "No attachments found" // Shown when no comments are available for the selected issue
        }
    }),
    "ar": 1,
    "cs": 1,
    "da": 1,
    "de": 1,
    "el": 1,
    "en": 1,
    "es": 1,
    "et": 1,
    "fi": 1,
    "fr": 1,
    "he": 1,
    "it": 1,
    "ja": 1,
    "ko": 1,
    "lt": 1,
    "lv": 1,
    "nb": 1,
    "nl": 1,
    "pl": 1,
    "pt-br": 1,
    "pt-pt": 1,
    "ro": 1,
    "ru": 1,
    "sv": 1,
    "th": 1,
    "tr": 1,
    "vi": 1,
    "zh-cn": 1,
    "zh-hk": 1,
    "zh-tw": 1
});
<|endoftext|>


<commit_before>// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

/* global Signal:false */
/* global Backbone: false */

/* global drawAttention: false */
/* global i18n: false */
/* global storage: false */
/* global Whisper: false */
/* global _: false */

// eslint-disable-next-line func-names
(function () {
  window.Whisper = window.Whisper || {};

  // The keys and values don't match here. This is because the values correspond to old
  //   setting names. In the future, we may wish to migrate these to match.
  const SettingNames = {
    NO_NAME_OR_MESSAGE: 'count',
    NAME_ONLY: 'name',
    NAME_AND_MESSAGE: 'message',
  };

  // Electron, at least on Windows and macOS, only shows one notification at a time (see
  //   issues [#15364][0] and [#21646][1], among others). Because of that, we have a
  //   single slot for notifications, and once a notification is dismissed, all of
  //   Signal's notifications are dismissed.
  // [0]: https://github.com/electron/electron/issues/15364
  // [1]: https://github.com/electron/electron/issues/21646
  Whisper.Notifications = {
    ...Backbone.Events,

    isEnabled: false,

    // This is either a standard `Notification` or null.
    lastNotification: null,

    // This is either null or an object of this shape:
    //
    //     {
    //       conversationId: string;
    //       messageId: string;
    //       senderTitle: string;
    //       message: string;
    //       notificationIconUrl: string | void;
    //       isExpiringMessage: boolean;
    //       reaction: {
    //         emoji: string;
    //         fromId: string;
    //       };
    //     }
    notificationData: null,

    add(notificationData) {
      this.notificationData = notificationData;
      this.update();
    },

    // Remove the last notification if both conditions hold:
    //
    // 1. Either `conversationId` or `messageId` matches (if present)
    // 2. `emoji`, `targetAuthorUuid`, `targetTimestamp` matches (if present)
    removeBy({
      conversationId,
      messageId,
      emoji,
      targetAuthorUuid,
      targetTimestamp,
    }) {
      if (!this.notificationData) {
        return;
      }

      let shouldClear = false;
      if (
        conversationId &&
        this.notificationData.conversationId === conversationId
      ) {
        shouldClear = true;
      }
      if (messageId && this.notificationData.messageId === messageId) {
        shouldClear = true;
      }

      if (!shouldClear) {
        return;
      }

      const { reaction } = this.notificationData;
      if (
        reaction &&
        emoji &&
        targetAuthorUuid &&
        targetTimestamp &&
        (reaction.emoji !== emoji ||
          reaction.targetAuthorUuid !== targetAuthorUuid ||
          reaction.targetTimestamp !== targetTimestamp)
      ) {
        return;
      }

      this.clear();
      this.update();
    },

    fastUpdate() {
      if (this.lastNotification) {
        this.lastNotification.close();
        this.lastNotification = null;
      }

      const { isEnabled } = this;
      const isAppFocused = window.isActive();
      const isAudioNotificationEnabled =
        storage.get('audio-notification') || false;
      const userSetting = this.getUserSetting();

      const status = Signal.Notifications.getStatus({
        isAppFocused,
        isAudioNotificationEnabled,
        isEnabled,
        hasNotifications: Boolean(this.notificationData),
        userSetting,
      });

      if (status.type !== 'ok') {
        window.log.info(
          `Not updating notifications; notification status is ${status.type}. ${
            status.shouldClearNotifications ? 'Also clearing notifications' : ''
          }`
        );

        if (status.shouldClearNotifications) {
          this.notificationData = null;
        }

        return;
      }
      window.log.info('Showing a notification');

      let notificationTitle;
      let notificationMessage;
      let notificationIconUrl;

      const {
        conversationId,
        messageId,
        senderTitle,
        message,
        isExpiringMessage,
        reaction,
      } = this.notificationData;

      if (
        userSetting === SettingNames.NAME_ONLY ||
        userSetting === SettingNames.NAME_AND_MESSAGE
      ) {
        notificationTitle = senderTitle;
        ({ notificationIconUrl } = this.notificationData);

        const shouldHideExpiringMessageBody =
          isExpiringMessage && (Signal.OS.isMacOS() || Signal.OS.isWindows());
        if (shouldHideExpiringMessageBody) {
          notificationMessage = i18n('newMessage');
        } else if (userSetting === SettingNames.NAME_ONLY) {
          if (reaction) {
            notificationMessage = i18n('notificationReaction', {
              sender: senderTitle,
              emoji: reaction.emoji,
            });
          } else {
            notificationMessage = i18n('newMessage');
          }
        } else if (reaction) {
          notificationMessage = i18n('notificationReactionMessage', {
            sender: senderTitle,
            emoji: reaction.emoji,
            message,
          });
        } else {
          notificationMessage = message;
        }
      } else {
        if (userSetting !== SettingNames.NO_NAME_OR_MESSAGE) {
          window.log.error(
            `Error: Unknown user notification setting: '${userSetting}'`
          );
        }
        notificationTitle = 'Signal';
        notificationMessage = i18n('newMessage');
      }

      const shouldDrawAttention = storage.get(
        'notification-draw-attention',
        true
      );
      if (shouldDrawAttention) {
        drawAttention();
      }

      this.lastNotification = window.Signal.Services.notify({
        title: notificationTitle,
        icon: notificationIconUrl,
        message: notificationMessage,
        silent: !status.shouldPlayNotificationSound,
        onNotificationClick: () => {
          this.trigger('click', conversationId, messageId);
        },
      });
    },

    getUserSetting() {
      return (
        storage.get('notification-setting') || SettingNames.NAME_AND_MESSAGE
      );
    },
    clear() {
      window.log.info('Removing notification');
      this.notificationData = null;
      this.update();
    },
    // We don't usually call this, but when the process is shutting down, we should at
    //   least try to remove the notification immediately instead of waiting for the
    //   normal debounce.
    fastClear() {
      this.notificationData = null;
      this.fastUpdate();
    },
    enable() {
      const needUpdate = !this.isEnabled;
      this.isEnabled = true;
      if (needUpdate) {
        this.update();
      }
    },
    disable() {
      this.isEnabled = false;
    },
  };

  // Testing indicated that trying to create/destroy notifications too quickly
  //   resulted in notifications that stuck around forever, requiring the user
  //   to manually close them. This introduces a minimum amount of time between calls,
  //   and batches up the quick successive update() calls we get from an incoming
  //   read sync, which might have a number of messages referenced inside of it.
  Whisper.Notifications.update = _.debounce(
    Whisper.Notifications.fastUpdate.bind(Whisper.Notifications),
    1000
  );
})();
<commit_msg>Draw attention even if notifications are disabled<commit_after>// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

/* global Signal:false */
/* global Backbone: false */

/* global drawAttention: false */
/* global i18n: false */
/* global storage: false */
/* global Whisper: false */
/* global _: false */

// eslint-disable-next-line func-names
(function () {
  window.Whisper = window.Whisper || {};

  // The keys and values don't match here. This is because the values correspond to old
  //   setting names. In the future, we may wish to migrate these to match.
  const SettingNames = {
    NO_NAME_OR_MESSAGE: 'count',
    NAME_ONLY: 'name',
    NAME_AND_MESSAGE: 'message',
  };

  // Electron, at least on Windows and macOS, only shows one notification at a time (see
  //   issues [#15364][0] and [#21646][1], among others). Because of that, we have a
  //   single slot for notifications, and once a notification is dismissed, all of
  //   Signal's notifications are dismissed.
  // [0]: https://github.com/electron/electron/issues/15364
  // [1]: https://github.com/electron/electron/issues/21646
  Whisper.Notifications = {
    ...Backbone.Events,

    isEnabled: false,

    // This is either a standard `Notification` or null.
    lastNotification: null,

    // This is either null or an object of this shape:
    //
    //     {
    //       conversationId: string;
    //       messageId: string;
    //       senderTitle: string;
    //       message: string;
    //       notificationIconUrl: string | void;
    //       isExpiringMessage: boolean;
    //       reaction: {
    //         emoji: string;
    //         fromId: string;
    //       };
    //     }
    notificationData: null,

    add(notificationData) {
      this.notificationData = notificationData;
      this.update();
    },

    // Remove the last notification if both conditions hold:
    //
    // 1. Either `conversationId` or `messageId` matches (if present)
    // 2. `emoji`, `targetAuthorUuid`, `targetTimestamp` matches (if present)
    removeBy({
      conversationId,
      messageId,
      emoji,
      targetAuthorUuid,
      targetTimestamp,
    }) {
      if (!this.notificationData) {
        return;
      }

      let shouldClear = false;
      if (
        conversationId &&
        this.notificationData.conversationId === conversationId
      ) {
        shouldClear = true;
      }
      if (messageId && this.notificationData.messageId === messageId) {
        shouldClear = true;
      }

      if (!shouldClear) {
        return;
      }

      const { reaction } = this.notificationData;
      if (
        reaction &&
        emoji &&
        targetAuthorUuid &&
        targetTimestamp &&
        (reaction.emoji !== emoji ||
          reaction.targetAuthorUuid !== targetAuthorUuid ||
          reaction.targetTimestamp !== targetTimestamp)
      ) {
        return;
      }

      this.clear();
      this.update();
    },

    fastUpdate() {
      if (this.lastNotification) {
        this.lastNotification.close();
        this.lastNotification = null;
      }

      const { isEnabled } = this;
      const isAppFocused = window.isActive();
      const isAudioNotificationEnabled =
        storage.get('audio-notification') || false;
      const userSetting = this.getUserSetting();

      const status = Signal.Notifications.getStatus({
        isAppFocused,
        isAudioNotificationEnabled,
        isEnabled,
        hasNotifications: Boolean(this.notificationData),
        userSetting,
      });

      const shouldDrawAttention = storage.get(
        'notification-draw-attention',
        true
      );
      if (shouldDrawAttention) {
        drawAttention();
      }

      if (status.type !== 'ok') {
        window.log.info(
          `Not updating notifications; notification status is ${status.type}. ${
            status.shouldClearNotifications ? 'Also clearing notifications' : ''
          }`
        );

        if (status.shouldClearNotifications) {
          this.notificationData = null;
        }

        return;
      }
      window.log.info('Showing a notification');

      let notificationTitle;
      let notificationMessage;
      let notificationIconUrl;

      const {
        conversationId,
        messageId,
        senderTitle,
        message,
        isExpiringMessage,
        reaction,
      } = this.notificationData;

      if (
        userSetting === SettingNames.NAME_ONLY ||
        userSetting === SettingNames.NAME_AND_MESSAGE
      ) {
        notificationTitle = senderTitle;
        ({ notificationIconUrl } = this.notificationData);

        const shouldHideExpiringMessageBody =
          isExpiringMessage && (Signal.OS.isMacOS() || Signal.OS.isWindows());
        if (shouldHideExpiringMessageBody) {
          notificationMessage = i18n('newMessage');
        } else if (userSetting === SettingNames.NAME_ONLY) {
          if (reaction) {
            notificationMessage = i18n('notificationReaction', {
              sender: senderTitle,
              emoji: reaction.emoji,
            });
          } else {
            notificationMessage = i18n('newMessage');
          }
        } else if (reaction) {
          notificationMessage = i18n('notificationReactionMessage', {
            sender: senderTitle,
            emoji: reaction.emoji,
            message,
          });
        } else {
          notificationMessage = message;
        }
      } else {
        if (userSetting !== SettingNames.NO_NAME_OR_MESSAGE) {
          window.log.error(
            `Error: Unknown user notification setting: '${userSetting}'`
          );
        }
        notificationTitle = 'Signal';
        notificationMessage = i18n('newMessage');
      }

      this.lastNotification = window.Signal.Services.notify({
        title: notificationTitle,
        icon: notificationIconUrl,
        message: notificationMessage,
        silent: !status.shouldPlayNotificationSound,
        onNotificationClick: () => {
          this.trigger('click', conversationId, messageId);
        },
      });
    },

    getUserSetting() {
      return (
        storage.get('notification-setting') || SettingNames.NAME_AND_MESSAGE
      );
    },
    clear() {
      window.log.info('Removing notification');
      this.notificationData = null;
      this.update();
    },
    // We don't usually call this, but when the process is shutting down, we should at
    //   least try to remove the notification immediately instead of waiting for the
    //   normal debounce.
    fastClear() {
      this.notificationData = null;
      this.fastUpdate();
    },
    enable() {
      const needUpdate = !this.isEnabled;
      this.isEnabled = true;
      if (needUpdate) {
        this.update();
      }
    },
    disable() {
      this.isEnabled = false;
    },
  };

  // Testing indicated that trying to create/destroy notifications too quickly
  //   resulted in notifications that stuck around forever, requiring the user
  //   to manually close them. This introduces a minimum amount of time between calls,
  //   and batches up the quick successive update() calls we get from an incoming
  //   read sync, which might have a number of messages referenced inside of it.
  Whisper.Notifications.update = _.debounce(
    Whisper.Notifications.fastUpdate.bind(Whisper.Notifications),
    1000
  );
})();
<|endoftext|>


<commit_before>var removeIconColumnStyle = {
  fontSize: '1.3em',
  height: '120px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
},
progressBarStyle = {
  height: '15px',
  width: '230px',
  backgroundColor: '#444',
  border: '2px solid #eee',
  display: 'inline-block',
};

var MyFilesRow = React.createClass({
  onRemoveClicked: function() {
     var alertText = 'Are you sure you\'d like to remove "' + this.props.title + '?" This will ' +
                     (this.completed ? ' stop the download and ' : '') +
                     'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = this.props.ratioLoaded * 230;
      curProgressBarStyle.borderRightWidth = 230 - (this.props.ratioLoaded * 230) + 2;
    }
    return (

{this.props.title}

          { ' ' }
          {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

          <Link icon="icon-close" title="Remove file" onClick={() => { this.onRemoveClicked() } } />

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    } else {
      if (this.state.filesInfo.length == 0) {
        var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
      } else {
        var content = [];
        for (let {completed, written_bytes, total_bytes, lbry_uri, stopped, metadata} of this.state.filesInfo) {
          let {name, thumbnail} = metadata;
          content.push(<MyFilesRow lbryUri={lbry_uri} title={name} completed={completed} stopped={stopped}
                                   ratioLoaded={written_bytes / total_bytes} imgUrl={thumbnail}/>);
        }
      }
      return (

My files

        {content}

          <Link href="/" label="<< Return" />

      );
    }
  }
});<commit_msg>Make stream name display more robust (inc. fall back to URI)<commit_after>var removeIconColumnStyle = {
  fontSize: '1.3em',
  height: '120px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
},
progressBarStyle = {
  height: '15px',
  width: '230px',
  backgroundColor: '#444',
  border: '2px solid #eee',
  display: 'inline-block',
};

var MyFilesRow = React.createClass({
  onRemoveClicked: function() {
     var alertText = 'Are you sure you\'d like to remove "' + this.props.title + '?" This will ' +
                     (this.completed ? ' stop the download and ' : '') +
                     'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = this.props.ratioLoaded * 230;
      curProgressBarStyle.borderRightWidth = 230 - (this.props.ratioLoaded * 230) + 2;
    }
    return (

{this.props.title}

          { ' ' }
          {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

          <Link icon="icon-close" title="Remove file" onClick={() => { this.onRemoveClicked() } } />

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    } else {
      if (this.state.filesInfo.length == 0) {
        var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
      } else {
        var content = [];
        for (let {completed, written_bytes, total_bytes, lbry_uri, stopped, metadata} of this.state.filesInfo) {
          let {name, stream_name, thumbnail} = metadata;
          var title = (name || stream_name || ('lbry://' + lbry_uri));
          var ratioLoaded = written_bytes / total_bytes;
          content.push(<MyFilesRow lbryUri={lbry_uri} title={title} completed={completed} stopped={stopped}
                                   ratioLoaded={ratioLoaded} imgUrl={thumbnail}/>);
        }
      }
      return (

My files

        {content}

          <Link href="/" label="<< Return" />

      );
    }
  }
});<|endoftext|>


<commit_before>// User menu toggle
$("#dropdown-menu a").on("click", function(event) {
    $(this).parent().toggleClass("open");
});
$("body").on("click", function(event) {
    if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
        $("#dropdown-menu").removeClass("open");
    }
});

var piholeVersion = $("#piholeVersion").html();
var webVersion = $("#webVersion").html();

// Credit for following function: https://gist.github.com/alexey-bass/1115557
function versionCompare(left, right) {
    if (typeof left + typeof right != 'stringstring')
        return false;

    var a = left.split('.')
        ,   b = right.split('.')
        ,   i = 0, len = Math.max(a.length, b.length);

    for (; i < len; i++) {
        if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
            return 1;
        } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
            return -1;
        }
    }

    return 0;
}

// Update check
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
    if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#alPiholeUpdate").show();
        if(!$("#dropdown-menu").hasClass("open")) {
            $("#dropdown-menu").addClass("open");
        }
    }
});
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
    if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#alWebUpdate").show();
        if(!$("#dropdown-menu").hasClass("open")) {
            $("#dropdown-menu").addClass("open");
        }
    }
});<commit_msg>Add prompt for users to update Pi-hole<commit_after>// User menu toggle
$("#dropdown-menu a").on("click", function(event) {
    $(this).parent().toggleClass("open");
});
$("body").on("click", function(event) {
    if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
        $("#dropdown-menu").removeClass("open");
    }
});

var piholeVersion = $("#piholeVersion").html();
var webVersion = $("#webVersion").html();

// Credit for following function: https://gist.github.com/alexey-bass/1115557
function versionCompare(left, right) {
    if (typeof left + typeof right != 'stringstring')
        return false;

    var a = left.split('.')
        ,   b = right.split('.')
        ,   i = 0, len = Math.max(a.length, b.length);

    for (; i < len; i++) {
        if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
            return 1;
        } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
            return -1;
        }
    }

    return 0;
}

// Update check
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
    if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#alPiholeUpdate").show();
        if(!$("#dropdown-menu").hasClass("open")) {
            $("#dropdown-menu").addClass("open");
        }
    }
});
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
    if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#alWebUpdate").show();
        if(!$("#dropdown-menu").hasClass("open")) {
            $("#dropdown-menu").addClass("open");
        }
    }
});

/*
 * Make sure that Pi-hole is updated to at least v2.6.4, since that is needed to use the sudo
 * features of the interface
 */
if(versionCompare(piholeVersion, "v2.6.4") < 0)
    alert("Pi-hole needs to be updated to at least v2.6.4 before you can use features such as whitelisting/blacklisting from this web interface!")
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 */

var d3 = require('../lib/').d3;
var _ = require('../lib/')._;

var format = require('../data/util/format');
var log = require('../lib/').bows('Basal');

module.exports = function(pool, opts) {
  opts = opts || {};

  var defaults = {};

  function rowHeightFn(numSchedules) {
    return function() {
      return pool.height() / numSchedules;
    };
  }

  opts = _.defaults(opts, defaults);

  var mainGroup = pool.parent();

  function basaltab(selection) {
    opts.xScale = pool.xScale().copy();

    selection.each(function(currentData) {
      var data = _.groupBy(currentData, 'schedule');
      var numSchedules = Object.keys(data).length;
      opts.rowHeight = rowHeightFn(numSchedules)();
      var index = 0;
      var schedules = Object.keys(data);
      // remove 'Standard' from array if present and put it at the beginning instead
      var standardIndex = _.findIndex(schedules, basaltab.isStandard);
      if (standardIndex !== -1) {
        schedules.splice(standardIndex, 1);
        schedules.sort();
        schedules.unshift('Standard');
      }
      else {
        schedules.sort();
      }
      for (var i = 0; i < schedules.length; ++i) {
        var key = schedules[i];
        // must check that schedule actually exists
        // schedule names come through for empty schedules
        if (data[key] != null) {
          var tabsGroup = selection.selectAll('#' + pool.id() + '_' + key.replace(' ', '_')).data([data[key]]);
          tabsGroup.enter().append('g').attr('id', pool.id() + '_' + key.replace(' ', '_'))
            .attr('transform', selection.attr('transform'));
          var tabs = tabsGroup.selectAll('g.d3-cell-group.d3-' + key.replace(' ','-').toLowerCase())
            .data(data[key], basaltab.id);

          var cellGroups = tabs.enter().append('g')
            .attr({
              'class': 'd3-cell-group ' + key.replace(' ','-').toLowerCase(),
              id: function(d) { return 'd3-cell-group_' + d.id; }
            });

          cellGroups.append('rect')
            .attr({
              x: basaltab.xPosition,
              y: index * opts.rowHeight,
              width: basaltab.width,
              height: opts.rowHeight,
              'class': basaltab.matchClass,
              id: function(d) { return 'd3-cell-rect_' + d.id; }
            })
            .classed('d3-cell-rect', true);

          cellGroups.append('text')
            .attr({
              x: function(d) {
                return basaltab.xPosition(d) + (basaltab.width(d) / 2);
              },
              y: (index * opts.rowHeight) + (opts.rowHeight/2),
              'class': basaltab.matchClass,
              id: function(d) { return 'd3-cell-label_' + d.id; }
            })
            .classed('d3-cell-label', true)
            .text(function(d) {
              if (String(d.value).indexOf('.') === -1) {
                return d.value.toFixed(1);
              }
              else return d.value;
            })
            .each(function(d) {
              if (this.getBBox().width > basaltab.width(d)) {
                d3.select(this).attr('display', 'none');
              }
            });

          tabs.exit().remove();
          index++;
        }
      }
    });
  }

  basaltab.matchClass = function(d) {
    if (d.actualized) {
      return 'd3-matched';
    }
    else {
      return 'd3-unmatched';
    }
  };

  basaltab.xPosition = function(d) {
    return opts.xScale(Date.parse(d.normalTime));
  };

  basaltab.width = function(d) {
    var s = Date.parse(d.normalTime), e = Date.parse(d.normalEnd);
    return opts.xScale(e) - opts.xScale(s);
  };

  basaltab.isStandard = function(el) {
    if (el === 'Standard') {
      return true;
    }
    return false;
  };

  return basaltab;
};<commit_msg>early return when pool is hidden to prevent SVG rendering errors<commit_after>/*
 * == BSD2 LICENSE ==
 */

var d3 = require('../lib/').d3;
var _ = require('../lib/')._;

var format = require('../data/util/format');
var log = require('../lib/').bows('Basal');

module.exports = function(pool, opts) {
  opts = opts || {};

  var defaults = {};

  function rowHeightFn(numSchedules) {
    return function() {
      return pool.height() / numSchedules;
    };
  }

  opts = _.defaults(opts, defaults);

  var mainGroup = pool.parent();

  function basaltab(selection) {
    opts.xScale = pool.xScale().copy();

    if (pool.hidden()) {
      return;
    }

    selection.each(function(currentData) {
      var data = _.groupBy(currentData, 'schedule');
      var numSchedules = Object.keys(data).length;
      opts.rowHeight = rowHeightFn(numSchedules)();
      var index = 0;
      var schedules = Object.keys(data);
      // remove 'Standard' from array if present and put it at the beginning instead
      var standardIndex = _.findIndex(schedules, basaltab.isStandard);
      if (standardIndex !== -1) {
        schedules.splice(standardIndex, 1);
        schedules.sort();
        schedules.unshift('Standard');
      }
      else {
        schedules.sort();
      }
      for (var i = 0; i < schedules.length; ++i) {
        var key = schedules[i];
        // must check that schedule actually exists
        // schedule names come through for empty schedules
        if (data[key] != null) {
          var tabsGroup = selection.selectAll('#' + pool.id() + '_' + key.replace(' ', '_')).data([data[key]]);
          tabsGroup.enter().append('g').attr('id', pool.id() + '_' + key.replace(' ', '_'))
            .attr('transform', selection.attr('transform'));
          var tabs = tabsGroup.selectAll('g.d3-cell-group.d3-' + key.replace(' ','-').toLowerCase())
            .data(data[key], basaltab.id);

          var cellGroups = tabs.enter().append('g')
            .attr({
              'class': 'd3-cell-group ' + key.replace(' ','-').toLowerCase(),
              id: function(d) { return 'd3-cell-group_' + d.id; }
            });

          cellGroups.append('rect')
            .attr({
              x: basaltab.xPosition,
              y: index * opts.rowHeight,
              width: basaltab.width,
              height: opts.rowHeight,
              'class': basaltab.matchClass,
              id: function(d) { return 'd3-cell-rect_' + d.id; }
            })
            .classed('d3-cell-rect', true);

          cellGroups.append('text')
            .attr({
              x: function(d) {
                return basaltab.xPosition(d) + (basaltab.width(d) / 2);
              },
              y: (index * opts.rowHeight) + (opts.rowHeight/2),
              'class': basaltab.matchClass,
              id: function(d) { return 'd3-cell-label_' + d.id; }
            })
            .classed('d3-cell-label', true)
            .text(function(d) {
              if (String(d.value).indexOf('.') === -1) {
                return d.value.toFixed(1);
              }
              else return d.value;
            })
            .each(function(d) {
              if (this.getBBox().width > basaltab.width(d)) {
                d3.select(this).attr('display', 'none');
              }
            });

          tabs.exit().remove();
          index++;
        }
      }
    });
  }

  basaltab.matchClass = function(d) {
    if (d.actualized) {
      return 'd3-matched';
    }
    else {
      return 'd3-unmatched';
    }
  };

  basaltab.xPosition = function(d) {
    return opts.xScale(Date.parse(d.normalTime));
  };

  basaltab.width = function(d) {
    var s = Date.parse(d.normalTime), e = Date.parse(d.normalEnd);
    return opts.xScale(e) - opts.xScale(s);
  };

  basaltab.isStandard = function(el) {
    if (el === 'Standard') {
      return true;
    }
    return false;
  };

  return basaltab;
};<|endoftext|>


<commit_before>game.TitleScreen = me.ScreenObject.extend({
    /**
     *  action to perform on state change
     */
    onResetEvent: function() {
        me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

        me.game.world.addChild(new (me.Renderable.extend({
            init: function() {
                this._super(me.Renderable, 'init', [270, 240, 300, 50]);
                this.font = new me.Font("arial", 46, "white");
                me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
            },
            draw: function(renderer) {
                this.font.draw(renderer.getContext(), "start a new game", this.pos.x, this.pos.y);

            },
            update: function(dt) {
                return true;
            },
            newGame: function() {
                me.input.releasePointerEvent('pointerdown', this);
                me.input.realsePointerEvent('pointerdown', game.data.option2);
                me.state.change(me.state.NEW);
            }
        })));

        me.game.world.addChild(new (me.Renderable.extend({
            init: function() {
                this._super(me.Renderable, 'init', [380, 340, 250, 50]);
                this.font = new me.Font("arial", 46, "white");
                me.input.registerPointerEvent('pointerdown', this, this.newGame())
            },
            draw: function(renderer) {
                this.font.draw(renderer.getContext(), "continue", this.pos.x, this.pos.y);

            },
            update: function(dt) {
                return true;
            },
            newGame: function() {
                me.input.releasePointerEvent('pointerdown', game.data.option1);
                me.input.releasePointerEvent('pointerdown', this);
                me.state.change(me.state.LOAD);
            }
        })));

   },
    /**
     *  action to perform when leaving this screen (state change)
     */
    onDestroyEvent: function() {
    }
});
<commit_msg>final<commit_after>game.TitleScreen = me.ScreenObject.extend({
    /**
     *  action to perform on state change
     */
    onResetEvent: function() {
        me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

        me.game.world.addChild(new (me.Renderable.extend({
            init: function() {
                this._super(me.Renderable, 'init', [270, 240, 300, 50]);
                this.font = new me.Font("arial", 46, "white");
                me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
            },
            draw: function(renderer) {
                this.font.draw(renderer.getContext(), "start a new game", this.pos.x, this.pos.y);

            },
            update: function(dt) {
                return true;
            },
            newGame: function() {
                me.input.releasePointerEvent('pointerdown', this);
                me.input.realsePointerEvent('pointerdown', game.data.option2);
                me.state.change(me.state.NEW);
            }
        })));

        me.game.world.addChild(new (me.Renderable.extend({
            init: function() {
                this._super(me.Renderable, 'init', [380, 340, 250, 50]);
                this.font = new me.Font("arial", 46, "white");
                me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
            },
            draw: function(renderer) {
                this.font.draw(renderer.getContext(), "continue", this.pos.x, this.pos.y);

            },
            update: function(dt) {
                return true;
            },
            newGame: function() {
                me.input.releasePointerEvent('pointerdown', game.data.option1);
                me.input.releasePointerEvent('pointerdown', this);
                me.state.change(me.state.LOAD);
            }
        })));

   },
    /**
     *  action to perform when leaving this screen (state change)
     */
    onDestroyEvent: function() {
    }
});
<|endoftext|>


<commit_before>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {

	me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10);
	me.input.bindKey(me.input.KEY.ENTER, "start");

	me.game.world.addChild(new(me.Renderable.extend({

		init: function() {
			this._super(me.Renderable, 'init', 510, 30, me.game.viewport.height]);
			this.font = new me.Font("Arial", 46, "white");
		},

		draw: function(renderer) {
			this.font.draw(renderer.getContext(), "Awsomenauts", 450, 140);
			this.font.draw(renderer.getContext(), "Press Enter", 250, 530);
		},

	})));

	this.handler = me.event.subscribe(me.event.KEYDOWN, function(action, keyCode, edge) {
		if (action === "start") {

		}
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
		 // TODO
	}
});
<commit_msg>27 Making the Title Screen Functional: -Made title screen Appear -doesn't take the whole screen -Start button (enter) wont work<commit_after>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {

	me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10);
	me.input.bindKey(me.input.KEY.ENTER, "start");

	me.game.world.addChild(new (me.Renderable.extend({

		init: function() {
			this._super(me.Renderable, 'init', [510, 30,  me.game.viewport.width, me.game.viewport.height]);
			this.font = new me.Font("Arial", 46, "white");
		},

		draw: function(renderer) {
			this.font.draw(renderer.getContext(), "Awsomenauts", 450, 130);
			this.font.draw(renderer.getContext(), "Press Enter", 250, 530);
		},

	})));

	this.handler = me.event.subscribe(me.event.KEYDOWN, function(action, keyCode, edge) {
		if (action === "start") {
			me.state.change(me.state.PLAY);
		}
		});
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
		 me.input.unbindKey(me.input.KEY.ENTER);
		 me.event.unsubcribe(this.handler);
	}
});
<|endoftext|>


<commit_before>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		//x and y placement we want the screen to start with our top left corner and screen
		//call our image
		//-10 is our z layer, it puts the title screen way in the back
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO
		//binding the key
		//a key to make us go to our play screen
		me.input.bindKey(me.input.KEY.ENTER, "start");
		//add some text
		me.game.world.addChild(new (me.Renderable.extend({
			//initialize function
			init: function(){
				//make a call to our super class
				//passing a renderable and basic info
				this._super(me.Renderable, 'init', [510, 30, me.game.viewport.width, me.game.viewport.height]);
				//initialization of text
				this.font = new me.Font("Arial", 46, "white");

			},
			//draw whats on the screen
			//passing whatever our renderer is as its parameter
			draw: function(renderer){
				//coordinates of where we draw
				this.font.draw(renderer.getContext(), "Awesomenauts!", 450, 130);
				//the button to start
				this.font.draw(renderer.getContext(), "Press ENTER to play!", 250, 530);
			}
		})));
		//an event handler
		//we need event handler to listen for someone pressing the enter button
		this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge){
			if(action === "start"){
				me.state.change(me.state.PLAY);
			}
		});
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
		//unbinding a key before we start
		//not make us start our game over if button is pushed again
		me.input.unbindKey(me.input.KEY.ENTER); // TODO
		//telling our game to not listen to a button
		//unsubscribing from the handler
		me.event.unsubscribe(this.handler);
	}
});
<commit_msg>coded for video 39<commit_after>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		//x and y placement we want the screen to start with our top left corner and screen
		//call our image
		//-10 is our z layer, it puts the title screen way in the back
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

		//add some text
		me.game.world.addChild(new (me.Renderable.extend({
			//initialize function
			init: function(){
				//make a call to our super class
				//passing a renderable and basic info
				this._super(me.Renderable, 'init', [270, 240, 300, 50]);
				//initialization of text
				this.font = new me.Font("Arial", 46, "white");
				me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
			},
			//draw whats on the screen
			//passing whatever our renderer is as its parameter
			draw: function(renderer){
				//coordinates of where we draw
				this.font.draw(renderer.getContext(), "START A NEW GAME", this.pos.x, this.pos.y);
			},
			update: function(dt){
				return true;
			},
			newGame: function(){
				me.input.releasePointerEvent('pointerdown', this);
				me.save.remove('exp');
				me.save.remove('exp1');
				me.save.remove('exp2');
				me.save.remove('exp3');
				me.save.remove('exp4');
				me.state.change(me.state.PLAY);
			}
		})));
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {

	}
});
<|endoftext|>