text:
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Overrided metadata worker's path.
 * @type {string}
 */
ContentMetadataProvider.WORKER_SCRIPT = '/js/metadata_worker.js';

/**
 * Gallery for viewing and editing image files.
 *
 * @param {!VolumeManagerWrapper} volumeManager
 * @constructor
 * @struct
 */
function Gallery(volumeManager) {
  /**
   * @type {{appWindow: chrome.app.window.AppWindow, onClose: function(),
   *     onMaximize: function(), onMinimize: function(),
   *     onAppRegionChanged: function(), readonlyDirName: string,
   *     displayStringFunction: function(), loadTimeData: Object,
   *     curDirEntry: Entry, searchResults: *}}
   * @private
   *
   * TODO(yawano): curDirEntry and searchResults seem not to be used.
   *     Investigate them and remove them if possible.
   */
  this.context_ = {
    appWindow: chrome.app.window.current(),
    onClose: function() { window.close(); },
    onMaximize: function() {
      var appWindow = chrome.app.window.current();
      if (appWindow.isMaximized())
        appWindow.restore();
      else
        appWindow.maximize();
    },
    onMinimize: function() { chrome.app.window.current().minimize(); },
    onAppRegionChanged: function() {},
    readonlyDirName: '',
    displayStringFunction: function() { return ''; },
    loadTimeData: {},
    curDirEntry: null,
    searchResults: null
  };
  this.container_ = queryRequiredElement(document, '.gallery');
  this.document_ = document;
  this.volumeManager_ = volumeManager;
  /**
   * @private {!MetadataModel}
   * @const
   */
  this.metadataModel_ = MetadataModel.create(volumeManager);
  /**
   * @private {!ThumbnailModel}
   * @const
   */
  this.thumbnailModel_ = new ThumbnailModel(this.metadataModel_);
  this.selectedEntry_ = null;
  this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this);
  this.initialized_ = false;

  this.dataModel_ = new GalleryDataModel(this.metadataModel_);
  var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo(
      VolumeManagerCommon.VolumeType.DOWNLOADS);
  downloadVolumeInfo.resolveDisplayRoot().then(function(entry) {
    this.dataModel_.fallbackSaveDirectory = entry;
  }.bind(this)).catch(function(error) {
    console.error(
        'Failed to obtain the fallback directory: ' + (error.stack || error));
  });
  this.selectionModel_ = new cr.ui.ListSelectionModel();

  /**
   * @type {(SlideMode|MosaicMode)}
   * @private
   */
  this.currentMode_ = null;

  /**
   * @type {boolean}
   * @private
   */
  this.changingMode_ = false;

  // -----------------------------------------------------------------
  // Initializes the UI.

  // Initialize the dialog label.
  cr.ui.dialogs.BaseDialog.OK_LABEL = str('GALLERY_OK_LABEL');
  cr.ui.dialogs.BaseDialog.CANCEL_LABEL = str('GALLERY_CANCEL_LABEL');

  var content = queryRequiredElement(document, '#content');
  content.addEventListener('click', this.onContentClick_.bind(this));

  this.header_ = queryRequiredElement(document, '#header');
  this.toolbar_ = queryRequiredElement(document, '#toolbar');

  var preventDefault = function(event) { event.preventDefault(); };

  var minimizeButton = util.createChild(this.header_,
                                        'minimize-button tool dimmable',
                                        'button');
  minimizeButton.tabIndex = -1;
  minimizeButton.addEventListener('click', this.onMinimize_.bind(this));
  minimizeButton.addEventListener('mousedown', preventDefault);

  var maximizeButton = util.createChild(this.header_,
                                        'maximize-button tool dimmable',
                                        'button');
  maximizeButton.tabIndex = -1;
  maximizeButton.addEventListener('click', this.onMaximize_.bind(this));
  maximizeButton.addEventListener('mousedown', preventDefault);

  var closeButton = util.createChild(this.header_,
                                     'close-button tool dimmable',
                                     'button');
  closeButton.tabIndex = -1;
  closeButton.addEventListener('click', this.onClose_.bind(this));
  closeButton.addEventListener('mousedown', preventDefault);

  this.filenameSpacer_ = queryRequiredElement(this.toolbar_,
      '.filename-spacer');
  this.filenameEdit_ = util.createChild(this.filenameSpacer_,
                                        'namebox', 'input');

  this.filenameEdit_.setAttribute('type', 'text');
  this.filenameEdit_.addEventListener('blur',
      this.onFilenameEditBlur_.bind(this));

  this.filenameEdit_.addEventListener('focus',
      this.onFilenameFocus_.bind(this));

  this.filenameEdit_.addEventListener('keydown',
      this.onFilenameEditKeydown_.bind(this));

  var middleSpacer = queryRequiredElement(this.toolbar_, '.middle-spacer');
  var buttonSpacer = queryRequiredElement(this.toolbar_, '.button-spacer');

  this.prompt_ = new ImageEditor.Prompt(this.container_, strf);

  this.errorBanner_ = new ErrorBanner(this.container_);

  this.modeButton_ = queryRequiredElement(this.toolbar_, 'button.mode');
  this.modeButton_.addEventListener('click',
      this.toggleMode_.bind(this, undefined));

  this.mosaicMode_ = new MosaicMode(content,
                                    this.errorBanner_,
                                    this.dataModel_,
                                    this.selectionModel_,
                                    this.volumeManager_,
                                    this.toggleMode_.bind(this, undefined));

  this.slideMode_ = new SlideMode(this.container_,
                                  content,
                                  this.toolbar_,
                                  this.prompt_,
                                  this.errorBanner_,
                                  this.dataModel_,
                                  this.selectionModel_,
                                  this.metadataModel_,
                                  this.thumbnailModel_,
                                  this.context_,
                                  this.volumeManager_,
                                  this.toggleMode_.bind(this),
                                  str);

  this.slideMode_.addEventListener('image-displayed', function() {
    cr.dispatchSimpleEvent(this, 'image-displayed');
  }.bind(this));

  this.deleteButton_ = this.initToolbarButton_('delete', 'GALLERY_DELETE');
  this.deleteButton_.addEventListener('click', this.delete_.bind(this));

  this.shareButton_ = this.initToolbarButton_('share', 'GALLERY_SHARE');
  this.shareButton_.addEventListener(
      'click', this.onShareButtonClick_.bind(this));

  this.dataModel_.addEventListener('splice', this.onSplice_.bind(this));
  this.dataModel_.addEventListener('content', this.onContentChange_.bind(this));

  this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
  this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this));

  this.shareDialog_ = new ShareDialog(this.container_);

  // -----------------------------------------------------------------
  // Initialize listeners.

  this.keyDownBound_ = this.onKeyDown_.bind(this);
  this.document_.body.addEventListener('keydown', this.keyDownBound_);

  this.inactivityWatcher_ = new MouseInactivityWatcher(
      this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this));

  // TODO(hirono): Add observer to handle thumbnail update.
  this.volumeManager_.addEventListener(
      'externally-unmounted', this.onExternallyUnmountedBound_);
  // The 'pagehide' event is called when the app window is closed.
  window.addEventListener('pagehide', this.onPageHide_.bind(this));
}

/**
 * Gallery extends cr.EventTarget.
 */
Gallery.prototype.__proto__ = cr.EventTarget.prototype;

/**
 * Tools fade-out timeout in milliseconds.
 * @const
 * @type {number}
 */
Gallery.FADE_TIMEOUT = 2000;

/**
 * First time tools fade-out timeout in milliseconds.
 * @const
 * @type {number}
 */
Gallery.FIRST_FADE_TIMEOUT = 1000;

/**
 * Time until mosaic is initialized in the background. Used to make gallery
 * in the slide mode load faster. In milliseconds.
 * @const
 * @type {number}
 */
Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000;

/**
 * Types of metadata Gallery uses (to query the metadata cache).
 * @const
 * @type {!Array<string>}
 */
Gallery.PREFETCH_PROPERTY_NAMES =
    ['imageWidth', 'imageHeight', 'size', 'present'];

/**
 * Closes gallery when a volume containing the selected item is unmounted.
 * @param {!Event} event The unmount event.
 * @private
 */
Gallery.prototype.onExternallyUnmounted_ = function(event) {
  if (!this.selectedEntry_)
    return;

  if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) ===
      event.volumeInfo) {
    window.close();
  }
};

/**
 * Unloads the Gallery.
 * @private
 */
Gallery.prototype.onPageHide_ = function() {
  this.volumeManager_.removeEventListener(
      'externally-unmounted', this.onExternallyUnmountedBound_);
  this.volumeManager_.dispose();
};

/**
 * Initializes a toolbar button.
 *
 * @param {string} className Class to add.
 * @param {string} title Button title.
 * @return {!HTMLElement} Newly created button.
 * @private
 */
Gallery.prototype.initToolbarButton_ = function(className, title) {
  var button = queryRequiredElement(this.toolbar_, 'button.' + className);
  button.title = str(title);
  return button;
};

/**
 * Loads the content.
 *
 * @param {!Array<!Entry>} selectedEntries Array of selected entries.
 */
Gallery.prototype.load = function(selectedEntries) {
  GalleryUtil.createEntrySet(selectedEntries).then(function(allEntries) {
    this.loadInternal_(allEntries, selectedEntries);
  }.bind(this));
};

/**
 * Loads the content.
 *
 * @param {!Array<!FileEntry>} entries Array of entries.
 * @param {!Array<!FileEntry>} selectedEntries Array of selected entries.
 * @private
 */
Gallery.prototype.loadInternal_ = function(entries, selectedEntries) {
  // Add the entries to data model.
  var items = [];
  for (var i = 0; i < entries.length; i++) {
    var locationInfo = this.volumeManager_.getLocationInfo(entries[i]);
    if (!locationInfo)  // Skip the item, since gone.
      return;
    items.push(new Gallery.Item(
        entries[i],
        locationInfo,
        null,
        null,
        true));
  }
  this.dataModel_.splice(0, this.dataModel_.length);
  this.updateThumbnails_();  // Remove the caches.

  GalleryDataModel.prototype.splice.apply(
      this.dataModel_, [0, 0].concat(items));

  // Apply the selection.
  var selectedSet = {};
  for (var i = 0; i < selectedEntries.length; i++) {
    selectedSet[selectedEntries[i].toURL()] = true;
  }
  for (var i = 0; i < items.length; i++) {
    if (!selectedSet[items[i].getEntry().toURL()])
      continue;
    this.selectionModel_.setIndexSelected(i, true);
  }
  this.onSelection_();

  // Obtains max chank size.
  var maxChunkSize = 20;
  var volumeInfo = this.volumeManager_.getVolumeInfo(entries[0]);
  if (volumeInfo) {
    if (GalleryUtil.isOnMTPVolume(entries[0], this.volumeManager_))
      maxChunkSize = 1;

    if (volumeInfo.isReadOnly ||
        GalleryUtil.isOnMTPVolume(entries[0], this.volumeManager_)) {
      this.context_.readonlyDirName = volumeInfo.label;
    }
  }

  // If items are empty, stop initialization.
  if (items.length === 0) {
    this.dataModel_.splice(0, this.dataModel_.length);
    return;
  }

  // Load entries.
  // Use the self variable capture-by-closure because it is faster than bind.
  var self = this;
  var thumbnailModel = new ThumbnailModel(this.metadataModel_);
  var loadChunk = function(firstChunk) {
    // Extract chunk.
    var chunk = items.splice(0, maxChunkSize);
    if (!chunk.length)
      return;
    var entries = chunk.map(function(chunkItem) {
      return chunkItem.getEntry();
    });
    var metadataPromise = self.metadataModel_.get(
        entries, Gallery.PREFETCH_PROPERTY_NAMES);
    var thumbnailPromise = thumbnailModel.get(entries);
    return Promise.all([metadataPromise, thumbnailPromise]).then(
        function(metadataLists) {
      // Add items to the model.
      chunk.forEach(function(chunkItem, index) {
        chunkItem.setMetadataItem(metadataLists[0][index]);
        chunkItem.setThumbnailMetadataItem(metadataLists[1][index]);

        if (!firstChunk || self.initialized_) {
          var event = new Event('content');
          event.item = chunkItem;
          event.oldEntry = chunkItem.getEntry();
          event.thumbnailChanged = true;
          self.dataModel_.dispatchEvent(event);
        }
      });

      // Init modes after the first chunk is loaded.
      if (firstChunk && !self.initialized_) {
        // Determine the initial mode.
        var shouldShowMosaic = selectedEntries.length > 1 ||
            (self.context_.pageState &&
             self.context_.pageState.gallery === 'mosaic');
        self.setCurrentMode_(
            shouldShowMosaic ? self.mosaicMode_ : self.slideMode_);

        // Init mosaic mode.
        var mosaic = self.mosaicMode_.getMosaic();
        mosaic.init();

        // Do the initialization for each mode.
        if (shouldShowMosaic) {
          mosaic.show();
          self.inactivityWatcher_.check();  // Show the toolbar.
          cr.dispatchSimpleEvent(self, 'loaded');
        } else {
          self.slideMode_.enter(
              null,
              function() {
                // Flash the toolbar briefly to show it is there.
                self.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT);
              },
              function() {
                cr.dispatchSimpleEvent(self, 'loaded');
              });
        }
        self.initialized_ = true;
      }

      // Continue to load chunks.
      return loadChunk(/* firstChunk */ false);
    });
  };
  loadChunk(/* firstChunk */ true).catch(function(error) {
    console.error(error.stack || error);
  });
};

/**
 * Handles user's 'Close' action.
 * @private
 */
Gallery.prototype.onClose_ = function() {
  this.executeWhenReady(this.context_.onClose);
};

/**
 * Handles user's 'Maximize' action (Escape or a click on the X icon).
 * @private
 */
Gallery.prototype.onMaximize_ = function() {
  this.executeWhenReady(this.context_.onMaximize);
};

/**
 * Handles user's 'Maximize' action (Escape or a click on the X icon).
 * @private
 */
Gallery.prototype.onMinimize_ = function() {
  this.executeWhenReady(this.context_.onMinimize);
};

/**
 * Executes a function when the editor is done with the modifications.
 * @param {function()} callback Function to execute.
 */
Gallery.prototype.executeWhenReady = function(callback) {
  this.currentMode_.executeWhenReady(callback);
};

/**
 * @return {!Object} File manager private API.
 */
Gallery.getFileManagerPrivate = function() {
  return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate;
};

/**
 * @return {boolean} True if some tool is currently active.
 */
Gallery.prototype.hasActiveTool = function() {
  return (this.currentMode_ && this.currentMode_.hasActiveTool()) ||
      this.isRenaming_();
};

/**
* External user action event handler.
* @private
*/
Gallery.prototype.onUserAction_ = function() {
  // Show the toolbar and hide it after the default timeout.
  this.inactivityWatcher_.kick();
};

/**
 * Sets the current mode, update the UI.
 * @param {!(SlideMode|MosaicMode)} mode Current mode.
 * @private
 */
Gallery.prototype.setCurrentMode_ = function(mode) {
  if (mode !== this.slideMode_ && mode !== this.mosaicMode_)
    console.error('Invalid Gallery mode');

  this.currentMode_ = mode;
  this.container_.setAttribute('mode', this.currentMode_.getName());
  this.updateSelectionAndState_();
  this.updateButtons_();
};

/**
 * Mode toggle event handler.
 * @param {function()=} opt_callback Callback.
 * @param {Event=} opt_event Event that caused this call.
 * @private
 */
Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) {
  if (!this.modeButton_)
    return;

  if (this.changingMode_) // Do not re-enter while changing the mode.
    return;

  if (opt_event)
    this.onUserAction_();

  this.changingMode_ = true;

  var onModeChanged = function() {
    this.changingMode_ = false;
    if (opt_callback) opt_callback();
  }.bind(this);

  var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);

  var mosaic = this.mosaicMode_.getMosaic();
  var tileRect = mosaic.getTileRect(tileIndex);

  if (this.currentMode_ === this.slideMode_) {
    this.setCurrentMode_(this.mosaicMode_);
    mosaic.transform(
        tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
    this.slideMode_.leave(
        tileRect,
        function() {
          // Animate back to normal position.
          mosaic.transform(null, null);
          mosaic.show();
          onModeChanged();
        }.bind(this));
  } else {
    this.setCurrentMode_(this.slideMode_);
    this.slideMode_.enter(
        tileRect,
        function() {
          // Animate to zoomed position.
          mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
          mosaic.hide();
        }.bind(this),
        onModeChanged);
  }
};

/**
 * Deletes the selected items.
 * @private
 */
Gallery.prototype.delete_ = function() {
  this.onUserAction_();

  // Clone the sorted selected indexes array.
  var indexesToRemove = this.selectionModel_.selectedIndexes.slice();
  if (!indexesToRemove.length)
    return;

  /* TODO(dgozman): Implement Undo delete, Remove the confirmation dialog. */

  var itemsToRemove = this.getSelectedItems();
  var plural = itemsToRemove.length > 1;
  var param = plural ? itemsToRemove.length : itemsToRemove[0].getFileName();

  function deleteNext() {
    if (!itemsToRemove.length)
      return;  // All deleted.

    var entry = itemsToRemove.pop().getEntry();
    entry.remove(deleteNext, function() {
      console.error('Error deleting: ' + entry.name);
      deleteNext();
    });
  }

  // Prevent the Gallery from handling Esc and Enter.
  this.document_.body.removeEventListener('keydown', this.keyDownBound_);
  var restoreListener = function() {
    this.document_.body.addEventListener('keydown', this.keyDownBound_);
  }.bind(this);

  var confirm = new cr.ui.dialogs.ConfirmDialog(this.container_);
  confirm.setOkLabel(str('DELETE_BUTTON_LABEL'));
  confirm.show(strf(plural ?
      'GALLERY_CONFIRM_DELETE_SOME' : 'GALLERY_CONFIRM_DELETE_ONE', param),
      function() {
        restoreListener();
        this.selectionModel_.unselectAll();
        this.selectionModel_.leadIndex = -1;
        // Remove items from the data model, starting from the highest index.
        while (indexesToRemove.length)
          this.dataModel_.splice(indexesToRemove.pop(), 1);
        // Delete actual files.
        deleteNext();
      }.bind(this),
      function() {
        // Restore the listener after a timeout so that ESC is processed.
        setTimeout(restoreListener, 0);
      },
      null);
};

/**
 * @return {!Array<Gallery.Item>} Current selection.
 */
Gallery.prototype.getSelectedItems = function() {
  return this.selectionModel_.selectedIndexes.map(
      this.dataModel_.item.bind(this.dataModel_));
};

/**
 * @return {!Array<Entry>} Array of currently selected entries.
 */
Gallery.prototype.getSelectedEntries = function() {
  return this.selectionModel_.selectedIndexes.map(function(index) {
    return this.dataModel_.item(index).getEntry();
  }.bind(this));
};

/**
 * @return {?Gallery.Item} Current single selection.
 */
Gallery.prototype.getSingleSelectedItem = function() {
  var items = this.getSelectedItems();
  if (items.length > 1) {
    console.error('Unexpected multiple selection');
    return null;
  }
  return items[0];
};

/**
  * Selection change event handler.
  * @private
  */
Gallery.prototype.onSelection_ = function() {
  this.updateSelectionAndState_();
};

/**
  * Data model splice event handler.
  * @private
  */
Gallery.prototype.onSplice_ = function() {
  this.selectionModel_.adjustLength(this.dataModel_.length);
  this.selectionModel_.selectedIndexes =
      this.selectionModel_.selectedIndexes.filter(function(index) {
    return 0 <= index && index < this.dataModel_.length;
  }.bind(this));
};

/**
 * Content change event handler.
 * @param {!Event} event Event.
 * @private
*/
Gallery.prototype.onContentChange_ = function(event) {
  this.updateSelectionAndState_();
};

/**
 * Keydown handler.
 *
 * @param {!Event} event Event.
 * @private
 */
Gallery.prototype.onKeyDown_ = function(event) {
  var keyString = util.getKeyModifiers(event) + event.keyIdentifier;

  // Handle debug shortcut keys.
  switch (keyString) {
    case 'Ctrl-Shift-U+0049': // Ctrl+Shift+I
      chrome.fileManagerPrivate.openInspector('normal');
      break;
    case 'Ctrl-Shift-U+004A': // Ctrl+Shift+J
      chrome.fileManagerPrivate.openInspector('console');
      break;
    case 'Ctrl-Shift-U+0043': // Ctrl+Shift+C
      chrome.fileManagerPrivate.openInspector('element');
      break;
    case 'Ctrl-Shift-U+0042': // Ctrl+Shift+B
      chrome.fileManagerPrivate.openInspector('background');
      break;
  }

  // Do not capture keys when share dialog is shown.
  if (this.shareDialog_.isShowing())
    return;

  // Handle mode specific shortcut keys.
  if (this.currentMode_.onKeyDown(event))
    return;

  // Handle application wide shortcut keys.
  switch (keyString) {
    case 'U+0008': // Backspace.
      // The default handler would call history.back and close the Gallery.
      event.preventDefault();
      break;

    case 'U+004D':  // 'm' switches between Slide and Mosaic mode.
      this.toggleMode_(undefined, event);
      break;

    case 'U+0056':  // 'v'
    case 'MediaPlayPause':
      this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event);
      break;

    case 'U+007F':  // Delete
    case 'Shift-U+0033':  // Shift+'3' (Delete key might be missing).
    case 'U+0044':  // 'd'
      this.delete_();
      break;

    case 'U+001B':  // Escape
      window.close();
      break;
  }
};

// Name box and rename support.

/**
 * Updates the UI related to the selected item and the persistent state.
 *
 * @private
 */
Gallery.prototype.updateSelectionAndState_ = function() {
  var numSelectedItems = this.selectionModel_.selectedIndexes.length;
  var selectedEntryURL = null;

  // If it's selecting something, update the variable values.
  if (numSelectedItems) {
    // Delete button is available when all images are NOT readOnly.
    this.deleteButton_.disabled = !this.selectionModel_.selectedIndexes
        .every(function(i) {
          return !this.dataModel_.item(i).getLocationInfo().isReadOnly;
        }, this);

    // Obtains selected item.
    var selectedItem =
        this.dataModel_.item(this.selectionModel_.selectedIndex);
    this.selectedEntry_ = selectedItem.getEntry();
    selectedEntryURL = this.selectedEntry_.toURL();

    // Update cache.
    selectedItem.touch();
    this.dataModel_.evictCache();

    // Update the title and the display name.
    if (numSelectedItems === 1) {
      document.title = this.selectedEntry_.name;
      this.filenameEdit_.disabled = selectedItem.getLocationInfo().isReadOnly;
      this.filenameEdit_.value =
          ImageUtil.getDisplayNameFromName(this.selectedEntry_.name);
      this.shareButton_.hidden = !selectedItem.getLocationInfo().isDriveBased;
    } else {
      if (this.context_.curDirEntry) {
        // If the Gallery was opened on search results the search query will not
        // be recorded in the app state and the relaunch will just open the
        // gallery in the curDirEntry directory.
        document.title = this.context_.curDirEntry.name;
      } else {
        document.title = '';
      }
      this.filenameEdit_.disabled = true;
      this.filenameEdit_.value =
          strf('GALLERY_ITEMS_SELECTED', numSelectedItems);
      this.shareButton_.hidden = true;
    }
  } else {
    document.title = '';
    this.filenameEdit_.disabled = true;
    this.deleteButton_.disabled = true;
    this.filenameEdit_.value = '';
    this.shareButton_.hidden = true;
  }

  util.updateAppState(
      null,  // Keep the current directory.
      selectedEntryURL,  // Update the selection.
      {gallery: (this.currentMode_ === this.mosaicMode_ ? 'mosaic' : 'slide')});
};

/**
 * Click event handler on filename edit box
 * @private
 */
Gallery.prototype.onFilenameFocus_ = function() {
  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true);
  this.filenameEdit_.originalValue = this.filenameEdit_.value;
  setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0);
  this.onUserAction_();
};

/**
 * Blur event handler on filename edit box.
 *
 * @param {!Event} event Blur event.
 * @private
 */
Gallery.prototype.onFilenameEditBlur_ = function(event) {
  var item = this.getSingleSelectedItem();
  if (item) {
    var oldEntry = item.getEntry();

    item.rename(this.filenameEdit_.value).then(function() {
      var event = new Event('content');
      event.item = item;
      event.oldEntry = oldEntry;
      event.thumbnailChanged = false;
      this.dataModel_.dispatchEvent(event);
    }.bind(this), function(error) {
      if (error === 'NOT_CHANGED')
        return Promise.resolve();
      this.filenameEdit_.value =
          ImageUtil.getDisplayNameFromName(item.getEntry().name);
      this.filenameEdit_.focus();
      if (typeof error === 'string')
        this.prompt_.showStringAt('center', error, 5000);
      else
        return Promise.reject(error);
    }.bind(this)).catch(function(error) {
      console.error(error.stack || error);
    });
  }

  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false);
  this.onUserAction_();
};

/**
 * Keydown event handler on filename edit box
 * @param {!Event} event A keyboard event.
 * @private
 */
Gallery.prototype.onFilenameEditKeydown_ = function(event) {
  event = assertInstanceof(event, KeyboardEvent);
  switch (event.keyCode) {
    case 27:  // Escape
      this.filenameEdit_.value = this.filenameEdit_.originalValue;
      this.filenameEdit_.blur();
      break;

    case 13:  // Enter
      this.filenameEdit_.blur();
      break;
  }
  event.stopPropagation();
};

/**
 * @return {boolean} True if file renaming is currently in progress.
 * @private
 */
Gallery.prototype.isRenaming_ = function() {
  return this.filenameSpacer_.hasAttribute('renaming');
};

/**
 * Content area click handler.
 * @private
 */
Gallery.prototype.onContentClick_ = function() {
  this.filenameEdit_.blur();
};

/**
 * Share button handler.
 * @private
 */
Gallery.prototype.onShareButtonClick_ = function() {
  var item = this.getSingleSelectedItem();
  if (!item)
    return;
  this.shareDialog_.showEntry(item.getEntry(), function() {});
};

/**
 * Updates thumbnails.
 * @private
 */
Gallery.prototype.updateThumbnails_ = function() {
  if (this.currentMode_ === this.slideMode_)
    this.slideMode_.updateThumbnails();

  if (this.mosaicMode_) {
    var mosaic = this.mosaicMode_.getMosaic();
    if (mosaic.isInitialized())
      mosaic.reload();
  }
};

/**
 * Updates buttons.
 * @private
 */
Gallery.prototype.updateButtons_ = function() {
  if (this.modeButton_) {
    var oppositeMode =
        this.currentMode_ === this.slideMode_ ? this.mosaicMode_ :
                                                this.slideMode_;
    this.modeButton_.title = str(oppositeMode.getTitle());
  }
};

/**
 * Enters the debug mode.
 */
Gallery.prototype.debugMe = function() {
  this.mosaicMode_.debugMe();
};

/**
 * Singleton gallery.
 * @type {Gallery}
 */
var gallery = null;

/**
 * (Re-)loads entries.
 */
function reload() {
  initializePromise.then(function() {
    util.URLsToEntries(window.appState.urls, function(entries) {
      gallery.load(entries);
    });
  });
}

/**
 * Promise to initialize the load time data.
 * @type {!Promise}
 */
var loadTimeDataPromise = new Promise(function(fulfill, reject) {
  chrome.fileManagerPrivate.getStrings(function(strings) {
    window.loadTimeData.data = strings;
    i18nTemplate.process(document, loadTimeData);
    fulfill(true);
  });
});

/**
 * Promise to initialize volume manager.
 * @type {!Promise}
 */
var volumeManagerPromise = new Promise(function(fulfill, reject) {
  var volumeManager = new VolumeManagerWrapper(
      VolumeManagerWrapper.NonNativeVolumeStatus.ENABLED);
  volumeManager.ensureInitialized(fulfill.bind(null, volumeManager));
});

/**
 * Promise to initialize both the volume manager and the load time data.
 * @type {!Promise}
 */
var initializePromise =
    Promise.all([loadTimeDataPromise, volumeManagerPromise]).
    then(function(args) {
      var volumeManager = args[1];
      gallery = new Gallery(volumeManager);
    });

// Loads entries.
initializePromise.then(reload);

/**
 * Enteres the debug mode.
 */
window.debugMe = function() {
  initializePromise.then(function() {
    gallery.debugMe();
  });
};


text:
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST.Extensions;

namespace CppSharp.AST
{
    public static class FunctionExtensions
    {
        public static IEnumerable<Parameter> GatherInternalParams(this Function function,
            bool isItaniumLikeAbi, bool universalDelegate = false)
        {
            var @params = new List<Parameter>();

            var method = function as Method;
            var isInstanceMethod = method != null && !method.IsStatic;

            var pointer = new QualifiedType(new PointerType(new QualifiedType(new BuiltinType(PrimitiveType.Void))));

            if (isInstanceMethod && !isItaniumLikeAbi)
            {
                @params.Add(new Parameter
                    {
                        QualifiedType = pointer,
                        Name = "instance"
                    });
            }

            if (!function.HasIndirectReturnTypeParameter &&
                isInstanceMethod && isItaniumLikeAbi)
            {
                @params.Add(new Parameter
                    {
                        QualifiedType = pointer,
                        Name = "instance"
                    });
            }

            var i = 0;
            foreach (var param in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter))
            {
                @params.Add(new Parameter
                    {
                        QualifiedType = universalDelegate && param.Kind == ParameterKind.IndirectReturnType ?
                            pointer : param.QualifiedType,
                        Kind = param.Kind,
                        Usage = param.Usage,
                        Name = universalDelegate ? "arg" + ++i : param.Name
                    });

                if (param.Kind == ParameterKind.IndirectReturnType &&
                    isInstanceMethod && isItaniumLikeAbi)
                {
                    @params.Add(new Parameter
                        {
                            QualifiedType = pointer,
                            Name = "instance"
                        });
                }
            }

            if (method != null && method.IsConstructor)
            {
                var @class = (Class) method.Namespace;
                if (!isItaniumLikeAbi && @class.Layout.HasVirtualBases)
                {
                    @params.Add(new Parameter
                        {
                            QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.Int)),
                            Name = "__forBases"
                        });
                }
            }

            return @params;
        }

        public static bool CanOverride(this Method @override, Method method)
        {
            return (method.OriginalName == @override.OriginalName &&
                method.OriginalReturnType.ResolvesTo(@override.OriginalReturnType) &&
                method.Parameters.SequenceEqual(@override.Parameters, ParameterTypeComparer.Instance)) ||
                (@override.IsDestructor && method.IsDestructor && method.IsVirtual);
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.bbn.bue.common.temporal;

import com.bbn.bue.common.symbols.Symbol;
import com.bbn.bue.common.symbols.SymbolUtils;

import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

import org.joda.time.Interval;
import org.joda.time.Period;
import org.joda.time.format.ISODateTimeFormat;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Represents a time value according to "TIDES Instruction Manual for the Annotation of Temporal
 * Expressions", Lisa Ferro, 2001. Please refer to that document for details.
 *
 * Beware: full validity checking is not done, so it is possible to construct invalid Timex
 * expressions.
 *
 * Equality is determined strictly by field equality and not by any comparison of the time periods
 * denoted.
 *
 * This currently only supports durations of the form \dE, \dC, \DL, or ISO 8601 periods. Durations
 * which mix and match these (which should be incredibly rare) will act as if they have no duration.
 * See TIMEX2 specification section 3.2.4.1.
 *
 * @author Ryan Gabbard, Feb. 2014
 */
public final class Timex2Time {

  private static final Logger log = LoggerFactory.getLogger(Timex2Time.class);

  public static final ImmutableSet<Symbol> nonISOMarkers = SymbolUtils.setFrom("WE", "MO", "MI",
      "AF", "EV", "NI", "PM", "DT", "FA", "WI", "SP", "SU", "FY", "Q1", "Q2", "Q3", "Q4", "QX",
      "H1", "H2", "HX", "BC", "KA", "MA", "GA");
  private static final Pattern nonISOMarkersPattern = Pattern.compile("("
      + Joiner.on("|").join(nonISOMarkers) + ")");

  public enum Modifier {
    BEFORE, AFTER, ON_OR_BEFORE, ON_OR_AFTER,
    LESS_THAN, MORE_THAN, EQUAL_OR_LESS, EQUAL_OR_MORE,
    START, MID, END, APPROX;
  }

  public enum AnchorDirection {
    STARTING, ENDING, WITHIN, BEFORE, AFTER, AS_OF;
  }

  private static final Symbol PRESENT_REF = Symbol.from("PRESENT_REF");
  private static final Symbol PAST_REF = Symbol.from("PAST_REF");
  private static final Symbol FUTURE_REF = Symbol.from("FUTURE_REF");

  // keeping for backward compatibility
  public static final Symbol BEFORE = Symbol.from(AnchorDirection.BEFORE.name());
  public static final Symbol AFTER = Symbol.from(AnchorDirection.AFTER.name());
  public static final Symbol AS_OF = Symbol.from(AnchorDirection.AS_OF.name());

  private final Symbol val;
  private final Modifier mod;
  private final boolean set;
  private final Symbol granularity;
  private final Symbol periodicity;
  private final Symbol anchorVal;
  private final AnchorDirection anchorDir;
  private final boolean nonSpecific;

  // Joda-time interpetation
  // This is a derived field (derived from val if val denotes a period)
  private final Period duration;

  public boolean isNonSpecific() {
    return nonSpecific;
  }

  public Optional<Symbol> value() {
    return Optional.fromNullable(val);
  }

  public Optional<Modifier> modifier() {
    return Optional.fromNullable(mod);
  }

  public boolean isSet() {
    return set;
  }

  public Optional<Symbol> granularity() {
    return Optional.fromNullable(granularity);
  }

  public Optional<Symbol> periodicity() {
    return Optional.fromNullable(periodicity);
  }

  public Optional<Symbol> anchorValue() {
    return Optional.fromNullable(anchorVal);
  }

  public Optional<AnchorDirection> anchorDirection() {
    return Optional.fromNullable(anchorDir);
  }

  public boolean isReferenceToPresent() {
    return val == PRESENT_REF;
  }

  public boolean isReferenceToPast() {
    return val == PAST_REF;
  }

  public boolean isReferenceToFuture() {
    return val == FUTURE_REF;
  }

  public boolean isDuration() {
    return duration != null;
  }

  public Optional<Period> duration() {
    return Optional.fromNullable(duration);
  }

  public Optional<Interval> anchorAsInterval() {
    if (anchorVal != null) {
      return parseValueAsInterval(anchorVal.toString());
    }
    return Optional.absent();
  }

  public Optional<Interval> valueAsInterval() {
    if (val != null) {
      return parseValueAsInterval(val.toString());
    }
    return Optional.absent();
  }

  /**
   * @deprecated Use {@link #builder()} and {@link Builder#withVal(Symbol)} instead
   */
  @Deprecated
  public static Timex2Time from(final String value) {
    return new Timex2Time(Symbol.from(value), null, false, null, null, null, null, false);
  }

  /**
   * @deprecated Use {@link #builder()} and {@link Builder#withGranularity(Symbol)} and {@link
   * Builder#withPeriodicity(Symbol)}
   */
  @Deprecated
  public static Timex2Time createSet(final String frequency, final String granularity) {
    return new Timex2Time(null, null, true, Symbol.from(frequency), Symbol.from(granularity), null,
        null, false);
  }

  public static Timex2Time createEmpty() {
    return new Timex2Time(null, null, false, null, null, null, null, false);
  }

  public static Timex2Time present() {
    return new Timex2Time(PRESENT_REF, null, false, null, null, null, null, false);
  }

  public static Timex2Time past() {
    return new Timex2Time(PAST_REF, null, false, null, null, null, null, false);
  }

  public static Timex2Time future() {
    return new Timex2Time(FUTURE_REF, null, false, null, null, null, null, false);
  }

  /**
   * Returns a copy of this Timex which is the same except with the anchor attributes set as
   * specified.
   *
   * @deprecated Use {@link #copyBuilder()} and {@link Builder#withAnchorValue(Symbol)} and {@link
   * Builder#withAnchorDirection(Symbol)} instead
   */
  @Deprecated
  public Timex2Time anchoredCopy(final Symbol anchorVal, final Symbol anchorDir) {
    checkNotNull(anchorDir);
    AnchorDirection anchorDirEnum = AnchorDirection.valueOf(anchorDir.asString());
    return new Timex2Time(val, mod, set, granularity, periodicity, checkNotNull(anchorVal),
        anchorDirEnum, nonSpecific);
  }

  /**
   * Returns a copy of this Timex which is the same except with the anchor attributes set as
   * specified.
   *
   * @deprecated Use {@link #copyBuilder()} and {@link Builder#withAnchorValue(Symbol)} and {@link
   * Builder#withAnchorDirection(Symbol)} instead
   */
  @Deprecated
  public Timex2Time anchoredCopy(final String anchorVal, final Symbol anchorDir) {
    return anchoredCopy(Symbol.from(checkNotNull(anchorVal)), checkNotNull(anchorDir));
  }

  /**
   * Returns a copy of this Timex which is the same except with the specified modifier
   *
   * @deprecated Use {@link #copyBuilder()} and {@link Builder#withModifier(Modifier)} instead
   */
  @Deprecated
  public Timex2Time modifiedCopy(final Modifier modifier) {
    return new Timex2Time(val, modifier, set, granularity, periodicity, anchorVal, anchorDir,
        nonSpecific);
  }

  public Builder copyBuilder() {
    Builder builder = new Builder();
    if (this.set) {
      builder.withIsSet(true);
    }
    if (this.periodicity().isPresent()) {
      builder.withPeriodicity(this.periodicity);
    }
    if (this.granularity().isPresent()) {
      builder.withGranularity(this.granularity);
    }
    if (this.isNonSpecific()) {
      builder.setNonSpecific(true);
    }
    if (this.anchorValue().isPresent()) {
      builder.withAnchorValue(this.anchorVal);
    }
    if (this.anchorDirection().isPresent()) {
      builder.withAnchorDirectionFromEnum(this.anchorDir);
    }
    if (this.value().isPresent()) {
      builder.withVal(this.val);
    }
    return builder;
  }

  // Timex stores boolean values as YES or empty
  private static final Symbol YES = Symbol.from("YES");

  private static boolean parseYES(final Symbol s) throws Timex2Exception {
    if (s == YES) {
      return true;
    }
    throw new Timex2Exception(String.format("Invalid boolean flag %s. Must be YES or absent.", s));
  }

  private static final ImmutableMap<Pattern, Integer> periodPatternsToYearMultipliers =
      ImmutableMap.<Pattern, Integer>builder().put(
          // Decades-2001 specification
          Pattern.compile("(\\d+)E"), 10).put(
          // Centuries-2001 specification
          Pattern.compile("(\\d+)C"), 100).put(
          // Millenia-2001 specification
          Pattern.compile("(\\d+)L"), 1000).put(
          // Decades-2005 specification
          Pattern.compile("(\\d+)DE"), 10).put(
          // Centuries-2005 specification
          Pattern.compile("(\\d+)CE"), 100).put(
          // Millenia-2005 specification
          Pattern.compile("(\\d+)ML"), 1000).build();

  private static final PeriodFormatter ISO8601_PERIOD_PARSER = ISOPeriodFormat.standard();

  /**
   * This method makes a "best effort" to make a {@link Period} out of a TIMEX2 period string.

   * TIMEX2 periods are superset of ISO 8601 periods. For example, TIMEX2 periods can have strings
   * like SU (for summer), FY (for fiscal year) or X for unspecified numbers (like PXM for
   * unspecified no. of months). This method will return Optional.absent() for any such non-ISO8601
   * Period values.

   * The only special consideration is with decade,century or millenium markers (E,C,L in Timex2001;
   * CE,DE,ML in Timex2005). These will be multiplied by appropriate multipliers to get the right
   * period. For details refer to sections 4.2 and 4.3 of Timex2005 specification.
   *
   * @param periodSym period-value as Symbol
   * @return Optional {@link Period} object (see the description for when Optional.absent will be
   * returned).
   * @throws Timex2Exception if periodSym is not a valid period string (e.g. it doesn't start with
   *                         P)
   * @author rgabbard
   */
  private Optional<Period> parseDuration(final Symbol periodSym) throws Timex2Exception {
    checkNotNull(periodSym);

    final String period = periodSym.toString();
    if (!period.startsWith("P")) {
      return Optional.absent();
    }

    for (final Map.Entry<Pattern, Integer> timexExtension : periodPatternsToYearMultipliers
        .entrySet()) {
      final Matcher m = timexExtension.getKey().matcher(period);
      try {
        if (m.lookingAt()) {
          return Optional
              .of(Period.years(timexExtension.getValue() * Integer.parseInt(m.group(1))));
        }
      } catch (final NumberFormatException nfe) {
        log.warn("Failed to parse duration {}, skipping. Due to {}", period, nfe);
        return Optional.absent();
      }
    }

    try {
      return Optional.of(ISO8601_PERIOD_PARSER.parsePeriod(period));
    } catch (final IllegalArgumentException iae) {
      return Optional.absent();
    }
  }

  private static final Joiner dashJoiner = Joiner.on("-");

  @Override
  public String toString() {
    final List<String> parts = Lists.newArrayList();

    if (val != null) {
      parts.add(val.toString());
    }

    if (mod != null) {
      parts.add(mod.toString());
    }

    if (set) {
      parts.add("SET");
    }

    if (granularity != null) {
      parts.add(granularity.toString());
    }

    if (periodicity != null) {
      parts.add(periodicity.toString());
    }

    if (anchorVal != null) {
      parts.add(anchorVal.toString());
    }

    if (anchorDir != null) {
      parts.add(anchorDir.toString());
    }

    if (nonSpecific) {
      parts.add("NONSPECIFIC");
    }

    return dashJoiner.join(parts);
  }

  private Timex2Time(final Symbol val, final Modifier mod, final boolean set,
      final Symbol granularity, final Symbol periodicity, final Symbol anchorVal,
      final AnchorDirection anchorDir, final boolean nonSpecific) {
    this.val = val;
    this.mod = mod;
    if (mod != null) {
      checkNotNull(val, "Value cannot be null if mod is %s", mod);
    }
    this.set = set;
    this.granularity = granularity;
    if (granularity != null) {
      // granularity always appears in conjunction with set
      checkArgument(set);
    }
    this.periodicity = periodicity;
    if (periodicity != null) {
      // periodicity always appears in conjunction with set
      checkArgument(set);
    }
    this.anchorVal = anchorVal;
    this.anchorDir = anchorDir;
    this.nonSpecific = nonSpecific;

    if (val != null) {
      this.duration = parseDuration(val).orNull();
    } else {
      this.duration = null;
    }
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(val, mod, set, granularity, periodicity, anchorVal, anchorDir,
        nonSpecific);
  }

  @Override
  public boolean equals(final Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    final Timex2Time other = (Timex2Time) obj;
    return equal(val, other.val) && equal(mod, other.mod) && equal(set, other.set)
        && equal(granularity, other.granularity) && equal(periodicity, other.periodicity)
        && equal(anchorVal, other.anchorVal) && equal(anchorDir, other.anchorDir)
        && equal(nonSpecific, other.nonSpecific);
  }

  /**
   * This method makes a "best effort" to make an {@link Interval} out of a TIMEX2 value string.

   * TIMEX2 value (or date-time) strings are superset of ISO 8601 periods. For example, TIMEX2
   * values can have seasons (like SU for summer, FA for fall, etc) or periods of day (like MO for
   * morning, NI for night), or unspecified values like 1999-09-XX (See section 4.3 of the
   * specification). For such values that make the intervals fuzzy, we will try to find the interval
   * upto which the timex value is specific. For example, 1999-09-08TNI will return the interval for
   * 1999-09-08, and 1999-FA or 1999-WXX will return the interval for 1999. However, we reserve the
   * right to make specific inferences from non-ISO markers in future implementations (e.g. FA could
   * mean the period from third week of September to third week of December).
 TIMEX2 values with
   * omissions, like VAL="199" (meaning the decade of 1990s) or VAL="20" (meaning the 21st century)
   * will be converted to approriate interval values (10 years or 100 years respectively, for this
   * example).
 If no interval can be discerned from the value at all, for example, XXXX-09
   * (September of unspecified year) or XX63 (63rd year of unspecified year), Optional.absent() will
   * be returned.
   *
   * @param valSym timex-value as Symbol
   * @return Optional {@link Interval} object (see the description for when Optional.absent will be
   * returned).
   * @author rgabbard, msrivast
   */
  private Optional<Interval> parseValueAsInterval(Symbol valSym) {
    String val = valSym.asString();

    //first see if time of day is fuzzy (TMO, TNI, TXX etc.), and if so, get rid of that
    String timePart = "";
    if (val.contains("T")) {
      timePart = val.substring(val.indexOf("T") + 1);
      if (timePart.contains("X") || nonISOMarkersPattern.matcher(timePart).find()) {
        timePart = "";
      }
      val = val.substring(0, val.indexOf("T"));
    }
    val = val + (!timePart.equals("") ? "T" + timePart : "");

    //now get rid of unspecified markers (X) or weekend, season, FY etc. markers.
    //Timex2 standard says that it extends ISO 8601 for vals which means basic ISO 8601 format
    //may also be allowed. All the examples that I have seen have always had hyphens tho.
    //Therefore, for simplicity, we will split val on hyphens ~msrivast
    String[] valParts = val.split("-");
    ImmutableList.Builder<String> specificValParts = ImmutableList.builder();
    for (int i = 0; i < valParts.length; i++) {
      String part = valParts[i];
      //if part contains X or is a season, fiscal year, periods of day marker etc. break, since the
      //timex value can be specific only upto here
      if (part.contains("X") || nonISOMarkers.contains(Symbol.from(part))) {
        break;
      }
      specificValParts.add(part);
    }
    val = Joiner.on("-").join(specificValParts.build());

    // it could be a simple date which we can extract
    // directly (very common; needs to come after the above because
    // its regex will match week-based dates, too)
    try {
      return Optional.of(ISODateTimeFormat.yearMonthDay().parseDateTime(val).dayOfMonth()
          .toInterval());
    } catch (final IllegalArgumentException iae) {
      // pass
    }

    // could be YYYY-MM type date
    try {
      return Optional.of(ISODateTimeFormat.yearMonth()
          .parseDateTime(val).monthOfYear().toInterval());
    } catch (final IllegalArgumentException iae) {
      // pass
    }

    // could be a YYYY type date
    try {
      return Optional.of(ISODateTimeFormat.year()
          .parseDateTime(val).year().toInterval());
    } catch (final IllegalArgumentException iae) {
      // pass
    }

    // it could be a 2014-W3-01 style week-based date
    try {
      return Optional.of(ISODateTimeFormat.weekyearWeekDay()
          .parseDateTime(val).dayOfMonth().toInterval());
    } catch (final IllegalArgumentException iae) {
      // it's okay if it's unparseable; just wasn't in this format
    }

    // it would be a 2014-W3 style week-based date
    try {
      return Optional.of(ISODateTimeFormat.weekyearWeek()
          .parseDateTime(val).weekOfWeekyear().toInterval());
    } catch (final IllegalArgumentException iae) {
      // it's okay if it's unparseable; just wasn't in this format
    }

    // this needs to go last or it would short-circuit the week
    // formats
    try {
      return Optional.of(ISODateTimeFormat.dateTimeParser()
          .parseDateTime(val).minuteOfDay().toInterval());
    } catch (final IllegalArgumentException iae) {
      // pass
    }

    // value was not parseable as a joda time Interval--see if the first one, two or three
    // characters of val
    // are digits, which would address the cases like 1,19,199
    String digits = "";
    for (int i = 0; i < 3 && i < val.length() && Character.isDigit(val.charAt(i)); i++) {
      digits += val.substring(i, i + 1);
    }
    if (!digits.equals("")) {
      int period = (int) Math.pow(10, 4 - digits.length());
      int startYear = Integer.parseInt(digits) * period;
      int endYear = startYear + period;
      return Optional.of(Interval.parse(startYear + "/" + endYear));
    }

    log.warn("Value not parseable as interval: {}", val);

    return Optional.absent();
  }

  private Optional<Interval> parseValueAsInterval(String val) {
    return parseValueAsInterval(Symbol.from(val));
  }

  /**
   * @deprecated Use {@link #builder()} and {@link Builder#withVal(Symbol)} instead
   */
  @Deprecated
  public static Builder builderWithValue(Symbol val) {
    return new Builder().withVal(val);
  }

  public static Builder builder() {
    return new Builder();
  }

  public static class Builder {

    private Builder() {
    }

    private Symbol val;
    private Modifier mod = null;
    private boolean isSet = false;
    private Symbol granularity = null;
    private Symbol periodicity = null;
    private Symbol anchorVal = null;
    private AnchorDirection anchorDir = null;
    private boolean nonSpecific = false;

    public Timex2Time build() {
      return new Timex2Time(val, mod, isSet, granularity, periodicity, anchorVal, anchorDir,
          nonSpecific);
    }

    public Builder withVal(Symbol val) {
      this.val = checkNotNull(val);
      return this;
    }

    public Builder withModifier(Modifier mod) {
      this.mod = checkNotNull(mod);
      return this;
    }

    public Builder withModifierFromString(String mod) {
      return withModifier(Modifier.valueOf(checkNotNull(mod)));
    }

    public Builder withIsSetFromTimexBoolean(Symbol timexBoolean) {
      this.isSet = parseYES(timexBoolean);
      return this;
    }

    public Builder withIsSet(boolean isSet) {
      this.isSet = isSet;
      return this;
    }

    public Builder withGranularity(Symbol granularity) {
      this.granularity = checkNotNull(granularity);
      return this;
    }

    public Builder withPeriodicity(Symbol periodicity) {
      this.periodicity = checkNotNull(periodicity);
      return this;
    }

    public Builder withAnchorValue(Symbol anchorValue) {
      this.anchorVal = checkNotNull(anchorValue);
      return this;
    }

    public Builder withAnchorDirection(Symbol anchorDir) {
      checkNotNull(anchorDir);
      this.anchorDir = AnchorDirection.valueOf(anchorDir.asString());
      return this;
    }

    public Builder withAnchorDirectionFromEnum(AnchorDirection anchorDir) {
      this.anchorDir = checkNotNull(anchorDir);
      return this;
    }

    public Builder setNonSpecificFromTimexBoolean(Symbol timexBoolean) {
      this.nonSpecific = parseYES(timexBoolean);
      return this;
    }

    public Builder setNonSpecific(boolean nonSpecific) {
      this.nonSpecific = nonSpecific;
      return this;
    }
  }

}


text:
**python code in order to reproduce GeDR3mock results**

**[py 1](https://github.com/jan-rybizki/Galaxia_wrap/blob/master/notebook/notebook_sweep/%5B1%5Dsweep.py)** Combining all catalog files.

**[py 2](https://github.com/jan-rybizki/Galaxia_wrap/blob/master/notebook/notebook_sweep/%5B2%5Drandom_index.py)** Generating and adding a random index.

**[py 3](https://github.com/jan-rybizki/Galaxia_wrap/blob/master/notebook/notebook_sweep/%5B3%5Dhealpix_count.py)** Adding a running number to the HEALpix source_id

**[py 4](https://github.com/jan-rybizki/Galaxia_wrap/blob/master/notebook/notebook_sweep/%5B4%5Derror_model.py)** Applying the empirical error model and rescaling it to larger Gaia EDR3 time baseline.


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Typography - eKoders Responsive Admin Theme</title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">

    <link rel="stylesheet" href="assets/css/bootstrap.min.css">
    <link rel="stylesheet" href="assets/css/fonts.css">
	<link rel="stylesheet" href="assets/font-awesome/css/font-awesome.min.css">

	<link href="assets/css/plugins/prettify/prettify.css" rel="stylesheet">

	<link rel="stylesheet" type="text/css" href="assets/css/plugins/gritter/jquery.gritter.css" />

	<link id="qstyle" rel="stylesheet" href="assets/css/themes/style.css">

						<button type="button" class="navbar-toggle pull-right" data-toggle="collapse" data-target=".top-collapse">

						</button>

									<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">

									</button>

										 2

													 2 New Messages

																			John Smith: Hi again! I wanted to let you know that the order...

																			 5 minutes ago

																			Roddy Austin: Thanks for the info, if you need anything...

																			 3:39 PM

														Read All Messages

										 3

												 3 New Alerts

																Downloads 16

																Server #8 Rebooted 12 hours ago

																Server #8 Crashed 12 hours ago

													View All Alerts

										 7

												 10 Pending Tasks

																Purchase Order #439 52%

																March Content Update 14%

																Client #42 Data Scrubbing 68%

																PHP Upgrade Server #6 85%

																Malware Scan 66%

													View All Tasks

										 John Smith

													 My Profile

													 My Messages

													 My Tasks

													 Settings

													 Logout

												<form class="" role="search">
													<input type="text" class="form-control" placeholder="Search" />
												</form>

Dashboard

											Components

Elements

Buttons & Icons

Portlet

jQuery UI

FrontEnd New

							<input type="text" class="input-menu" id="input-items" placeholder="Find...">

Navigation

									 Dashboard

									 Components

												 Portlets

												 Elements New

												 Tabs & Accordions

												 Buttons & Icons

												 JQuery UI

												 Nestable Lists

												 Calendar

												 Three Level Menu

														 item 3

															 4rth Level

																	 item1

																	 item2

									 TablesNew

									 Typography

									 Forms

												 Form Elements

												 Form Tools

												 Wizard & Validation

									 Charts

												 Flot Charts

												 Morris Charts

Support

									 eCommerce

											 Products Listing

									 Additional Pages

												 User Profile

												 Inbox

												 Pricing Tables

												 Invoice

												 Timeline

												 Login & Register

												 FAQs

												 Blank Page

									 More Pages

												 Gallery

												 Error 404

												 Error 505

Labels

 My Recent 3

 Background

								Sales Report

								Calculating daily bias... 36%

											Home

Typography

 Tasks

Add new task

Statement

Settings

Typography page-header sub title

											Layout Options

												<input type="checkbox" class="tc" id="fixed-navbar" />
													 Fixed NavBar

												<input type="checkbox" class="tc" id="fixed-sidebar" />
													 Fixed NavBar+SideBar

												<input type="checkbox" class="tc" id="sidebar-toggle" />
													 Sidebar Toggle

												<input type="checkbox" class="tc" id="in-container" />
													 Inside.container

										Color Options

											<input type="checkbox" class="tc" id="side-bar-color" />
											 SideBar (Light)

<button class="btn" style="background-color:#d15050;" onclick="swapStyle('assets/css/themes/style.css')"></button>

<button class="btn" style="background-color:#86618f;" onclick="swapStyle('assets/css/themes/style-1.css')"></button>

<button class="btn" style="background-color:#ba5d32;" onclick="swapStyle('assets/css/themes/style-2.css')"></button>

<button class="btn" style="background-color:#488075;" onclick="swapStyle('assets/css/themes/style-3.css')"></button>

<button class="btn" style="background-color:#4e72c2;" onclick="swapStyle('assets/css/themes/style-4.css')"></button>

Hello eKoders!

This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.

								Large button

New

Heading & Paragraphs

Headings

heading 1

heading 2

heading 3

heading 4

heading 5

heading 6

Paragraphs, Links & Text Utilities

Strong Text Lorem ipsum dolor sit amet, consectetur adipiscing elit. Reguler Link Curabitur bibendum ornare dolor, quis ullamcorper ligula sodales at. Nulla tellus elit, varius non commodo eget, mattis vel eros. In sed ornare nulla.

Nullam quis risus eget urna mollis ornare vel eu leo. Text Underline Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula ut id elit.

Primary Color and Uppercase Text Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Italic text Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec sed odio dui.

Description lists

Description lists

A description list is perfect for defining terms.

Euismod

Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.

Donec id elit non mi porta gravida at eget metus.

Malesuada porta

Etiam porta sem malesuada magna mollis euismod.

Felis euismod semper eget lacinia

Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

 BlockQuote & Address

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer id eleifend nunc. Sed fringilla pellentesque consequat.

												Someone famous in Source Title

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer id eleifend nunc. Sed fringilla pellentesque consequat.

Address

											<address>
												eKoders

795 Folsom Ave, Suite 600,

San Francisco, CA 94107

 (123) 456-7890
											</address>
											<address>
												Sales Team

sales.dpt@example.com
											</address>

Great Content

Bootstrap's default well's work great for widgets! What is a widget anyways...?

Great Content

Bootstrap's default well's work great for widgets! What is a widget anyways...?

List view

Lorem ipsum dolor sit amet

list item small

list item strong tag

Nested List Item

Nested List Item

Nested List Item

Unordered List Item which is a longer item and may break into more lines.

list item bold tag

list item italics tag

Ordered List Item

.text-danger ordered List Item

.text-primary ordered List Item

.text-sucess ordered List Item

.text-info ordered List Item

.text-warning ordered List Item

 Unordered List Item with icon

  Unordered List Item with icon

 List inline item #1

 inline item #2

 inline item #3

 Code view

<p class="muted">Fusce dapibus, tellus ac cursus commodo.</p>
<p class="text-primary">Etiam porta sem malesuada.</p>
<p class="text-sucess">Donec ullamcorper nulla non metus.</p>
<p class="text-info">Aenean eu leo quam.</p>
<p class="text-danger">Duis mollis.</p>

									© 2014 eKoders, All Rights Reserved.

						<button type="button" id="back-to-top" class="btn btn-primary btn-sm back-to-top">

						</button>