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.

#include "chrome/browser/media_galleries/media_scan_manager.h"

#include <stddef.h>

#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/media_galleries/media_galleries_preferences.h"
#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
#include "chrome/browser/media_galleries/media_scan_manager_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/media_galleries.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"

using extensions::ExtensionRegistry;

namespace media_galleries = extensions::api::media_galleries;

namespace {

typedef std::set<std::string /*extension id*/> ScanningExtensionIdSet;

// When multiple scan results have the same parent, sometimes it makes sense
// to combine them into a single scan result at the parent. This constant
// governs when that happens; kContainerDirectoryMinimumPercent percent of the
// directories in the parent directory must be scan results.
const int kContainerDirectoryMinimumPercent = 80;

// How long after a completed media scan can we provide the cached results.
const int kScanResultsExpiryTimeInHours = 24;

struct LocationInfo {
  LocationInfo()
      : pref_id(kInvalidMediaGalleryPrefId),
        type(MediaGalleryPrefInfo::kInvalidType) {}
  LocationInfo(MediaGalleryPrefId pref_id, MediaGalleryPrefInfo::Type type,
               base::FilePath path)
      : pref_id(pref_id), type(type), path(path) {}
  // Highest priority comparison by path, next by type (scan result last),
  // then by pref id (invalid last).
  bool operator<(const LocationInfo& rhs) const {
    if (path.value() == rhs.path.value()) {
      if (type == rhs.type) {
        return pref_id > rhs.pref_id;
      }
      return rhs.type == MediaGalleryPrefInfo::kScanResult;
    }
    return path.value() < rhs.path.value();
  }

  MediaGalleryPrefId pref_id;
  MediaGalleryPrefInfo::Type type;
  base::FilePath path;
  MediaGalleryScanResult file_counts;
};

// Finds new scan results that are shadowed (the same location, or a child) by
// existing locations and moves them from |found_folders| to |child_folders|.
// Also moves new scan results that are shadowed by other new scan results
// to |child_folders|.
void PartitionChildScanResults(
    MediaGalleriesPreferences* preferences,
    MediaFolderFinder::MediaFolderFinderResults* found_folders,
    MediaFolderFinder::MediaFolderFinderResults* child_folders) {
  // Construct a list with everything in it.
  std::vector<LocationInfo> all_locations;
  for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
           found_folders->begin(); it != found_folders->end(); ++it) {
    all_locations.push_back(LocationInfo(kInvalidMediaGalleryPrefId,
                                         MediaGalleryPrefInfo::kScanResult,
                                         it->first));
    all_locations.back().file_counts = it->second;
  }
  const MediaGalleriesPrefInfoMap& known_galleries =
      preferences->known_galleries();
  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
       it != known_galleries.end();
       ++it) {
    all_locations.push_back(LocationInfo(it->second.pref_id, it->second.type,
                                         it->second.AbsolutePath()));
  }
  // Sorting on path should put all paths that are prefixes of other paths
  // next to each other, with the shortest one first.
  std::sort(all_locations.begin(), all_locations.end());

  size_t previous_parent_index = 0;
  for (size_t i = 1; i < all_locations.size(); i++) {
    const LocationInfo& current = all_locations[i];
    const LocationInfo& previous_parent = all_locations[previous_parent_index];
    bool is_child = previous_parent.path.IsParent(current.path);
    if (current.type == MediaGalleryPrefInfo::kScanResult &&
        current.pref_id == kInvalidMediaGalleryPrefId &&
        (is_child || previous_parent.path == current.path)) {
      // Move new scan results that are shadowed.
      (*child_folders)[current.path] = current.file_counts;
      found_folders->erase(current.path);
    } else if (!is_child) {
      previous_parent_index = i;
    }
  }
}

MediaGalleryScanResult SumFilesUnderPath(
    const base::FilePath& path,
    const MediaFolderFinder::MediaFolderFinderResults& candidates) {
  MediaGalleryScanResult results;
  for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
           candidates.begin(); it != candidates.end(); ++it) {
    if (it->first == path || path.IsParent(it->first)) {
      results.audio_count += it->second.audio_count;
      results.image_count += it->second.image_count;
      results.video_count += it->second.video_count;
    }
  }
  return results;
}

void AddScanResultsForProfile(
    MediaGalleriesPreferences* preferences,
    const MediaFolderFinder::MediaFolderFinderResults& found_folders) {
  // First, remove any existing scan results where no app has been granted
  // permission - either it is gone, or is already in the new scan results.
  // This burns some pref ids, but not at an appreciable rate.
  MediaGalleryPrefIdSet to_remove;
  const MediaGalleriesPrefInfoMap& known_galleries =
      preferences->known_galleries();
  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
       it != known_galleries.end();
       ++it) {
    if (it->second.type == MediaGalleryPrefInfo::kScanResult &&
        !preferences->NonAutoGalleryHasPermission(it->first)) {
      to_remove.insert(it->first);
    }
  }
  for (MediaGalleryPrefIdSet::const_iterator it = to_remove.begin();
       it != to_remove.end();
       ++it) {
    preferences->EraseGalleryById(*it);
  }

  MediaFolderFinder::MediaFolderFinderResults child_folders;
  MediaFolderFinder::MediaFolderFinderResults
      unique_found_folders(found_folders);
  PartitionChildScanResults(preferences, &unique_found_folders, &child_folders);

  // Updating prefs while iterating them will invalidate the pointer, so
  // calculate the changes first and then apply them.
  std::map<MediaGalleryPrefId, MediaGalleryScanResult> to_update;
  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
       it != known_galleries.end();
       ++it) {
    const MediaGalleryPrefInfo& gallery = it->second;
    if (!gallery.IsBlackListedType()) {
      MediaGalleryScanResult file_counts =
          SumFilesUnderPath(gallery.AbsolutePath(), child_folders);
      if (gallery.audio_count != file_counts.audio_count ||
          gallery.image_count != file_counts.image_count ||
          gallery.video_count != file_counts.video_count) {
        to_update[it->first] = file_counts;
      }
    }
  }

  for (std::map<MediaGalleryPrefId,
                MediaGalleryScanResult>::const_iterator it = to_update.begin();
       it != to_update.end();
       ++it) {
    const MediaGalleryPrefInfo& gallery =
        preferences->known_galleries().find(it->first)->second;
      preferences->AddGallery(gallery.device_id, gallery.path, gallery.type,
                              gallery.volume_label, gallery.vendor_name,
                              gallery.model_name, gallery.total_size_in_bytes,
                              gallery.last_attach_time,
                              it->second.audio_count,
                              it->second.image_count,
                              it->second.video_count);
  }

  // Add new scan results.
  for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
           unique_found_folders.begin();
       it != unique_found_folders.end();
       ++it) {
    MediaGalleryScanResult file_counts =
        SumFilesUnderPath(it->first, child_folders);
    // The top level scan result is not in |child_folders|. Add it in as well.
    file_counts.audio_count += it->second.audio_count;
    file_counts.image_count += it->second.image_count;
    file_counts.video_count += it->second.video_count;

    MediaGalleryPrefInfo gallery;
    bool existing = preferences->LookUpGalleryByPath(it->first, &gallery);
    DCHECK(!existing);
    preferences->AddGallery(gallery.device_id, gallery.path,
                            MediaGalleryPrefInfo::kScanResult,
                            gallery.volume_label, gallery.vendor_name,
                            gallery.model_name, gallery.total_size_in_bytes,
                            gallery.last_attach_time, file_counts.audio_count,
                            file_counts.image_count, file_counts.video_count);
  }
  UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanGalleriesPopulated",
                             unique_found_folders.size() + to_update.size());
}

int CountScanResultsForExtension(MediaGalleriesPreferences* preferences,
                                 const extensions::Extension* extension,
                                 MediaGalleryScanResult* file_counts) {
  int gallery_count = 0;

  MediaGalleryPrefIdSet permitted_galleries =
      preferences->GalleriesForExtension(*extension);
  const MediaGalleriesPrefInfoMap& known_galleries =
      preferences->known_galleries();
  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
       it != known_galleries.end();
       ++it) {
    if (it->second.type == MediaGalleryPrefInfo::kScanResult &&
        !ContainsKey(permitted_galleries, it->first)) {
      gallery_count++;
      file_counts->audio_count += it->second.audio_count;
      file_counts->image_count += it->second.image_count;
      file_counts->video_count += it->second.video_count;
    }
  }
  return gallery_count;
}

int CountDirectoryEntries(const base::FilePath& path) {
  base::FileEnumerator dir_counter(
      path, false /*recursive*/, base::FileEnumerator::DIRECTORIES);
  int count = 0;
  base::FileEnumerator::FileInfo info;
  for (base::FilePath name = dir_counter.Next(); !name.empty();
       name = dir_counter.Next()) {
    if (!base::IsLink(name))
      ++count;
  }
  return count;
}

struct ContainerCount {
  int seen_count, entries_count;
  bool is_qualified;

  ContainerCount() : seen_count(0), entries_count(-1), is_qualified(false) {}
};

typedef std::map<base::FilePath, ContainerCount> ContainerCandidates;

}  // namespace

MediaScanManager::MediaScanManager()
    : scoped_extension_registry_observer_(this),
      weak_factory_(this) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}

MediaScanManager::~MediaScanManager() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}

void MediaScanManager::AddObserver(Profile* profile,
                                   MediaScanManagerObserver* observer) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(!ContainsKey(observers_, profile));
  observers_[profile].observer = observer;
}

void MediaScanManager::RemoveObserver(Profile* profile) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  bool scan_in_progress = ScanInProgress();
  observers_.erase(profile);
  DCHECK_EQ(scan_in_progress, ScanInProgress());
}

void MediaScanManager::CancelScansForProfile(Profile* profile) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  observers_[profile].scanning_extensions.clear();

  if (!ScanInProgress())
    folder_finder_.reset();
}

void MediaScanManager::StartScan(Profile* profile,
                                 const extensions::Extension* extension,
                                 bool user_gesture) {
  DCHECK(extension);
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  ScanObserverMap::iterator scans_for_profile = observers_.find(profile);
  // We expect that an MediaScanManagerObserver has already been registered.
  DCHECK(scans_for_profile != observers_.end());
  bool scan_in_progress = ScanInProgress();
  // Ignore requests for extensions that are already scanning.
  ScanningExtensionIdSet* scanning_extensions;
  scanning_extensions = &scans_for_profile->second.scanning_extensions;
  if (scan_in_progress && ContainsKey(*scanning_extensions, extension->id()))
    return;

  // Provide cached result if there is not already a scan in progress,
  // there is no user gesture, and the previous results are unexpired.
  MediaGalleriesPreferences* preferences =
      MediaGalleriesPreferencesFactory::GetForProfile(profile);
  base::TimeDelta time_since_last_scan =
      base::Time::Now() - preferences->GetLastScanCompletionTime();
  if (!scan_in_progress && !user_gesture && time_since_last_scan <
          base::TimeDelta::FromHours(kScanResultsExpiryTimeInHours)) {
    MediaGalleryScanResult file_counts;
    int gallery_count =
        CountScanResultsForExtension(preferences, extension, &file_counts);
    scans_for_profile->second.observer->OnScanStarted(extension->id());
    scans_for_profile->second.observer->OnScanFinished(extension->id(),
                                                       gallery_count,
                                                       file_counts);
    return;
  }

  // On first scan for the |profile|, register to listen for extension unload.
  if (scanning_extensions->empty())
    scoped_extension_registry_observer_.Add(ExtensionRegistry::Get(profile));

  scanning_extensions->insert(extension->id());
  scans_for_profile->second.observer->OnScanStarted(extension->id());

  if (folder_finder_)
    return;

  MediaFolderFinder::MediaFolderFinderResultsCallback callback =
      base::Bind(&MediaScanManager::OnScanCompleted,
                 weak_factory_.GetWeakPtr());
  if (testing_folder_finder_factory_.is_null()) {
    folder_finder_.reset(new MediaFolderFinder(callback));
  } else {
    folder_finder_.reset(testing_folder_finder_factory_.Run(callback));
  }
  scan_start_time_ = base::Time::Now();
  folder_finder_->StartScan();
}

void MediaScanManager::CancelScan(Profile* profile,
                                  const extensions::Extension* extension) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  // Erases the logical scan if found, early exit otherwise.
  ScanObserverMap::iterator scans_for_profile = observers_.find(profile);
  if (scans_for_profile == observers_.end() ||
      !scans_for_profile->second.scanning_extensions.erase(extension->id())) {
    return;
  }

  scans_for_profile->second.observer->OnScanCancelled(extension->id());

  // No more scanning extensions for |profile|, so stop listening for unloads.
  if (scans_for_profile->second.scanning_extensions.empty())
    scoped_extension_registry_observer_.Remove(ExtensionRegistry::Get(profile));

  if (!ScanInProgress()) {
    folder_finder_.reset();
    DCHECK(!scan_start_time_.is_null());
    UMA_HISTOGRAM_LONG_TIMES("MediaGalleries.ScanCancelTime",
                             base::Time::Now() - scan_start_time_);
    scan_start_time_ = base::Time();
  }
}

void MediaScanManager::SetMediaFolderFinderFactory(
    const MediaFolderFinderFactory& factory) {
  testing_folder_finder_factory_ = factory;
}

// A single directory may contain many folders with media in them, without
// containing any media itself. In fact, the primary purpose of that directory
// may be to contain media directories. This function tries to find those
// container directories.
MediaFolderFinder::MediaFolderFinderResults
MediaScanManager::FindContainerScanResults(
    const MediaFolderFinder::MediaFolderFinderResults& found_folders,
    const std::vector<base::FilePath>& sensitive_locations) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
  std::vector<base::FilePath> abs_sensitive_locations;
  for (size_t i = 0; i < sensitive_locations.size(); ++i) {
    base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]);
    if (!path.empty())
      abs_sensitive_locations.push_back(path);
  }
  // Recursively find parent directories with majority of media directories,
  // or container directories.
  // |candidates| keeps track of directories which might have enough
  // such directories to have us return them.
  typedef std::map<base::FilePath, ContainerCount> ContainerCandidates;
  ContainerCandidates candidates;
  for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
           found_folders.begin();
       it != found_folders.end();
       ++it) {
    base::FilePath child_directory = it->first;
    base::FilePath parent_directory = child_directory.DirName();

    // Parent of root is root.
    while (!parent_directory.empty() && child_directory != parent_directory) {
      // Skip sensitive folders and their ancestors.
      base::FilePath abs_parent_directory =
          base::MakeAbsoluteFilePath(parent_directory);
      if (abs_parent_directory.empty())
        break;
      bool is_sensitive = false;
      for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) {
        if (abs_parent_directory == abs_sensitive_locations[i] ||
            abs_parent_directory.IsParent(abs_sensitive_locations[i])) {
          is_sensitive = true;
          break;
        }
      }
      if (is_sensitive)
        break;

      // Don't bother with ones we already have.
      if (found_folders.find(parent_directory) != found_folders.end())
        continue;

      ContainerCandidates::iterator parent_it =
          candidates.find(parent_directory);
      if (parent_it == candidates.end()) {
        ContainerCount count;
        count.seen_count = 1;
        count.entries_count = CountDirectoryEntries(parent_directory);
        parent_it =
            candidates.insert(std::make_pair(parent_directory, count)).first;
      } else {
        ++candidates[parent_directory].seen_count;
      }
      // If previously sufficient, or not sufficient, bail.
      if (parent_it->second.is_qualified ||
          parent_it->second.seen_count * 100 / parent_it->second.entries_count <
              kContainerDirectoryMinimumPercent) {
        break;
      }
      // Otherwise, mark qualified and check parent.
      parent_it->second.is_qualified = true;
      child_directory = parent_directory;
      parent_directory = child_directory.DirName();
    }
  }
  MediaFolderFinder::MediaFolderFinderResults result;
  // Copy and return worthy results.
  for (ContainerCandidates::const_iterator it = candidates.begin();
       it != candidates.end();
       ++it) {
    if (it->second.is_qualified && it->second.seen_count >= 2)
      result[it->first] = MediaGalleryScanResult();
  }
  return result;
}

MediaScanManager::ScanObservers::ScanObservers() : observer(NULL) {}
MediaScanManager::ScanObservers::ScanObservers(const ScanObservers& other) =
    default;
MediaScanManager::ScanObservers::~ScanObservers() {}

void MediaScanManager::OnExtensionUnloaded(
    content::BrowserContext* browser_context,
    const extensions::Extension* extension,
    extensions::UnloadedExtensionInfo::Reason reason) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  CancelScan(Profile::FromBrowserContext(browser_context), extension);
}

bool MediaScanManager::ScanInProgress() const {
  for (ScanObserverMap::const_iterator it = observers_.begin();
       it != observers_.end();
       ++it) {
    if (!it->second.scanning_extensions.empty())
      return true;
  }
  return false;
}

void MediaScanManager::OnScanCompleted(
    bool success,
    const MediaFolderFinder::MediaFolderFinderResults& found_folders) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  if (!folder_finder_ || !success) {
    folder_finder_.reset();
    return;
  }

  UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanDirectoriesFound",
                             found_folders.size());
  DCHECK(!scan_start_time_.is_null());
  UMA_HISTOGRAM_LONG_TIMES("MediaGalleries.ScanFinishedTime",
                           base::Time::Now() - scan_start_time_);
  scan_start_time_ = base::Time();

  content::BrowserThread::PostTaskAndReplyWithResult(
      content::BrowserThread::FILE, FROM_HERE,
      base::Bind(FindContainerScanResults,
                 found_folders,
                 folder_finder_->graylisted_folders()),
      base::Bind(&MediaScanManager::OnFoundContainerDirectories,
                 weak_factory_.GetWeakPtr(),
                 found_folders));
}

void MediaScanManager::OnFoundContainerDirectories(
    const MediaFolderFinder::MediaFolderFinderResults& found_folders,
    const MediaFolderFinder::MediaFolderFinderResults& container_folders) {
  MediaFolderFinder::MediaFolderFinderResults folders;
  folders.insert(found_folders.begin(), found_folders.end());
  folders.insert(container_folders.begin(), container_folders.end());

  for (ScanObserverMap::iterator scans_for_profile = observers_.begin();
       scans_for_profile != observers_.end();
       ++scans_for_profile) {
    if (scans_for_profile->second.scanning_extensions.empty())
      continue;
    Profile* profile = scans_for_profile->first;
    MediaGalleriesPreferences* preferences =
        MediaGalleriesPreferencesFactory::GetForProfile(profile);
    ExtensionService* extension_service =
        extensions::ExtensionSystem::Get(profile)->extension_service();
    if (!extension_service)
      continue;

    AddScanResultsForProfile(preferences, folders);

    ScanningExtensionIdSet* scanning_extensions =
        &scans_for_profile->second.scanning_extensions;
    for (ScanningExtensionIdSet::const_iterator extension_id_it =
             scanning_extensions->begin();
         extension_id_it != scanning_extensions->end();
         ++extension_id_it) {
      const extensions::Extension* extension =
          extension_service->GetExtensionById(*extension_id_it, false);
      if (extension) {
        MediaGalleryScanResult file_counts;
        int gallery_count = CountScanResultsForExtension(preferences, extension,
                                                         &file_counts);
        scans_for_profile->second.observer->OnScanFinished(*extension_id_it,
                                                           gallery_count,
                                                           file_counts);
      }
    }
    scanning_extensions->clear();
    preferences->SetLastScanCompletionTime(base::Time::Now());
  }
  scoped_extension_registry_observer_.RemoveAll();
  folder_finder_.reset();
}


text:
@implementation BTCardNonce

- (instancetype)initWithNonce:(NSString *)nonce
                  cardNetwork:(BTCardNetwork)cardNetwork
              expirationMonth:(NSString *)expirationMonth
               expirationYear:(NSString *)expirationYear
               cardholderName:(NSString *)cardholderName
                      lastTwo:(NSString *)lastTwo
                     lastFour:(NSString *)lastFour
                    isDefault:(BOOL)isDefault
                     cardJSON:(BTJSON *)cardJSON
              authInsightJSON:(BTJSON *)authInsightJSON {
    self = [super initWithNonce:nonce
                           type:[BTCardNonce typeStringFromCardNetwork:cardNetwork]
                      isDefault:isDefault];
    if (self) {
        _cardNetwork = cardNetwork;
        _expirationMonth = expirationMonth;
        _expirationYear = expirationYear;
        _cardholderName = cardholderName;
        _lastTwo = lastTwo;
        _lastFour = lastFour;
        _binData = [[BTBinData alloc] initWithJSON:cardJSON[@"binData"]];
        if ([cardJSON[@"details"][@"bin"] asString]) {
            _bin = [cardJSON[@"details"][@"bin"] asString];
        } else if ([cardJSON[@"bin"] asString]) {
            _bin = [cardJSON[@"bin"] asString];
        }
        _threeDSecureInfo = [[BTThreeDSecureInfo alloc] initWithJSON:cardJSON[@"threeDSecureInfo"]];
        if (authInsightJSON) {
            _authenticationInsight = [[BTAuthenticationInsight alloc] initWithJSON:authInsightJSON];
        }
    }
    return self;
}

+ (NSString *)typeStringFromCardNetwork:(BTCardNetwork)cardNetwork {
    switch (cardNetwork) {
        case BTCardNetworkAMEX:
            return @"AMEX";
        case BTCardNetworkDinersClub:
            return @"DinersClub";
        case BTCardNetworkDiscover:
            return @"Discover";
        case BTCardNetworkMasterCard:
            return @"MasterCard";
        case BTCardNetworkVisa:
            return @"Visa";
        case BTCardNetworkJCB:
            return @"JCB";
        case BTCardNetworkLaser:
            return @"Laser";
        case BTCardNetworkMaestro:
            return @"Maestro";
        case BTCardNetworkUnionPay:
            return @"UnionPay";
        case BTCardNetworkHiper:
            return @"Hiper";
        case BTCardNetworkHipercard:
            return @"Hipercard";
        case BTCardNetworkSolo:
            return @"Solo";
        case BTCardNetworkSwitch:
            return @"Switch";
        case BTCardNetworkUKMaestro:
            return @"UKMaestro";
        case BTCardNetworkUnknown:
        default:
            return @"Unknown";
    }
}

+ (BTCardNetwork)cardNetworkFromGatewayCardType:(NSString *)string {
    // Normalize the card network string in cardJSON to be lowercase so that our enum mapping is case insensitive
    BTJSON *cardType = [[BTJSON alloc] initWithValue:string.lowercaseString];
    return [cardType asEnum:@{
        @"american express": @(BTCardNetworkAMEX),
        @"diners club": @(BTCardNetworkDinersClub),
        @"unionpay": @(BTCardNetworkUnionPay),
        @"discover": @(BTCardNetworkDiscover),
        @"maestro": @(BTCardNetworkMaestro),
        @"mastercard": @(BTCardNetworkMasterCard),
        @"jcb": @(BTCardNetworkJCB),
        @"hiper": @(BTCardNetworkHiper),
        @"hipercard": @(BTCardNetworkHipercard),
        @"laser": @(BTCardNetworkLaser),
        @"solo": @(BTCardNetworkSolo),
        @"switch": @(BTCardNetworkSwitch),
        @"uk maestro": @(BTCardNetworkUKMaestro),
        @"visa": @(BTCardNetworkVisa),}
                  orDefault:BTCardNetworkUnknown];
}

+ (instancetype)cardNonceWithJSON:(BTJSON *)cardJSON {
    BTJSON *authInsightJson;
    if ([cardJSON[@"authenticationInsight"] asDictionary]) {
        authInsightJson = cardJSON[@"authenticationInsight"];
    }

    return [[self.class alloc] initWithNonce:[cardJSON[@"nonce"] asString]
                                 cardNetwork:[self.class cardNetworkFromGatewayCardType:[cardJSON[@"details"][@"cardType"] asString]]
                             expirationMonth:[cardJSON[@"details"][@"expirationMonth"] asString]
                              expirationYear:[cardJSON[@"details"][@"expirationYear"] asString]
                              cardholderName:[cardJSON[@"details"][@"cardholderName"] asString]
                                     lastTwo:[cardJSON[@"details"][@"lastTwo"] asString]
                                    lastFour:[cardJSON[@"details"][@"lastFour"] asString]
                                   isDefault:[cardJSON[@"default"] isTrue]
                                    cardJSON:cardJSON
                             authInsightJSON:authInsightJson];
}

+ (instancetype)cardNonceWithGraphQLJSON:(BTJSON *)json {
    NSString *lastFour = @"";
    if ([json[@"creditCard"][@"last4"] asString]) {
        lastFour = [json[@"creditCard"][@"last4"] asString];
    }
    NSString *lastTwo = lastFour.length == 4 ? [lastFour substringFromIndex:2] : @"";

    BTJSON *authInsightJson;
    if ([json[@"authenticationInsight"] asDictionary]) {
        authInsightJson = json[@"authenticationInsight"];
    }

    return [[self.class alloc] initWithNonce:[json[@"token"] asString]
                                 cardNetwork:[self.class cardNetworkFromGatewayCardType:[json[@"creditCard"][@"brand"] asString]]
                             expirationMonth:[json[@"creditCard"][@"expirationMonth"] asString]
                              expirationYear:[json[@"creditCard"][@"expirationYear"] asString]
                              cardholderName:[json[@"creditCard"][@"cardholderName"] asString]
                                     lastTwo:lastTwo
                                    lastFour:lastFour
                                   isDefault:NO
                                    cardJSON:json[@"creditCard"]
                             authInsightJSON:authInsightJson];
}

@end

redpajama_set_name: RedPajamaGithub


text:
<?php
/**
 * The template for displaying search form
 *
 * @package WordPress
 * @subpackage FoundationPress
 * @since FoundationPress 1.0.0
 */

do_action( 'foundationpress_before_searchform' ); ?>
<form role="search" method="get" id="searchform" action="<?php echo home_url( '/' ); ?>">

		<?php do_action( 'foundationpress_searchform_top' ); ?>

			<input type="text" value="" name="s" id="s" placeholder="<?php esc_attr_e( 'Search', 'foundationpress' ); ?>">

		<?php do_action( 'foundationpress_searchform_before_search_button' ); ?>
		<?php do_action( 'foundationpress_searchform_after_search_button' ); ?>

</form>
<?php do_action( 'foundationpress_after_searchform' ); ?>


text:
import SystemHelper from '../../utils/system';
import { Instance as LoggingManager } from 'logging-manager';
import devDelay from '../../utils/devDelay.js';

export default req =>
  new Promise((resolve, reject) =>
    devDelay(2000).then(() => {
      const { newGroupName } = req.body;

      if (!newGroupName) {
        LoggingManager.debug('System', 'createNewGroup', 'Blank group name passed.');
        reject({
          status: 400,
          errorField: 'newGroupName',
          errorReason: 'No group name was passed to create request.'
        });
      } else if (newGroupName.length > 15) {
        LoggingManager.debug('System', 'createNewGroup', `Invalid group name passed: ${newGroupName}`);
        reject({
          status: 400,
          errorField: 'newGroupName',
          errorReason: 'The group name is invalid. It must be 15 characters or less.'
        });
      } else {
        LoggingManager.debug('System', 'createNewGroup', `Creating group using name: ${newGroupName}`);
        SystemHelper.createGroup(newGroupName)
        .then((newGroupId) => {
          resolve({
            newGroupId
          });
        }, (error) => {
          LoggingManager.error('System', 'createNewGroup', `Error occured creating group using name: ${newGroupName}`);
          LoggingManager.error('System', 'createNewGroup', error);
          reject({
            status: 500,
            errorField: 'newGroupName',
            errorReason: 'An error occured while trying to create group. Please check the config file as it may be out of sync and the application may require a restart.'
          });
        });
      }
    })
  );


text:
__author__ = 'e.lyzlov'
from model.address import add_address
import random

def test_delete_some_address(app, orm, check_ui):
    if len(orm.get_contact_list()) == 0:
        app.address.create(add_address(firstname="111"))
    old_contacts = orm.get_contact_list()
    contact = random.choice(old_contacts)
    app.address.delete_contact_by_id(contact.id)
    new_contacts = orm.get_contact_list()
    assert len(old_contacts) -1 == len(new_contacts)
    old_contacts.remove(contact)
    assert old_contacts == new_contacts
    if check_ui:
        assert sorted(new_contacts, key=add_address.id_or_max) == sorted(app.group.get_group_list(), key=add_address.id_or_max)


text:
@interface NWCollectionView()<UIScrollViewDelegate>
@end

#define BUFFER 30
#define SCROLL_THRESHOLD 10
#define TOTAL_ROW_LIMIT 10000
#define MAX_COLUMNS 10

@implementation NWCollectionView {
    NSMutableArray *_freeViews;
    NSMutableArray<NSNumber*> *_savedHeights;
    NSMutableArray *_collectionItems;
    NSMutableDictionary<NSNumber*,NWLayoutView*> *_activeViews;
    Byte _columnMap[TOTAL_ROW_LIMIT];
    CGPoint _originMap[TOTAL_ROW_LIMIT];
    UIScrollView *_scrollView;
    int _minRow;
    int _maxRow; // the maximum row number is _maxRow - 1

    CGFloat _lastScrollEvent;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        _freeViews = [NSMutableArray array];
        _activeViews = [NSMutableDictionary dictionary];
        _savedHeights = [NSMutableArray array];
        _collectionItems = [NSMutableArray array];
        _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
        _scrollView.scrollEnabled = YES;
        [self addSubview:_scrollView];
        _scrollView.delegate = self;
        _estimatedHeight = 100;
        _numColumns = 1;
        memset(_columnMap, -1, TOTAL_ROW_LIMIT);
    }
    return self;
}

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];
    _scrollView.frame = self.bounds;
    [self renderViews];
}

- (void)renderViews {
    CGFloat minY = 0, maxY = 0;
    CGFloat minColY[_numColumns];
    CGFloat maxColY[_numColumns];
    for (int i = 0; i < _numColumns; i++) minColY[i] = -999.0;
    memset(maxColY, 0, sizeof(maxColY));
    if (_maxRow > _minRow) {
        minY = _activeViews[@(_minRow)].frame.origin.y;
        minColY[_columnMap[_minRow]] = minY;
        maxY = CGRectGetMaxY(_activeViews[@(_maxRow - 1)].frame);
        maxColY[_columnMap[_maxRow - 1]] = maxY;
    }
    for (int i = _minRow; i < _maxRow; i++) {
        int col = _columnMap[i];
        if (minColY[col] == -999) {
            minColY[col] = _activeViews[@(i)].frame.origin.y;
        }
        maxColY[col] = fmax(CGRectGetMaxY(_activeViews[@(i)].frame), maxColY[col]);
    }
    CGFloat maxRequiredY = _scrollView.contentOffset.y + _scrollView.frame.size.height;
    int nextCol = 0;
    CGFloat nextColMaxY = maxColY[nextCol];
    while (maxY < maxRequiredY && _collectionItems.count > _maxRow) {
        for (int i = _numColumns - 1; i >= 0; i--) {
            if (maxColY[i] <= nextColMaxY) {
                nextColMaxY = maxColY[i];
                nextCol = i;
            }
        }
        NWLayoutView *view = [self viewForRow:_maxRow];
        _columnMap[_maxRow] = nextCol;
        view.frame = CGRectMake(nextCol * view.frame.size.width, nextColMaxY, view.frame.size.width, view.frame.size.height);
        _originMap[_maxRow] = view.frame.origin;
        nextColMaxY += view.frame.size.height;
        maxY = nextColMaxY;
        maxColY[nextCol] = nextColMaxY;
        if (_savedHeights.count > _maxRow) {
            _savedHeights[_maxRow] = @(view.frame.size.height);
        } else {
            [_savedHeights addObject:@(view.frame.size.height)];
        }
        for (int i = 0; i < _numColumns; i++) {
            maxY = fmin(maxY, maxColY[i]);
        }
        _maxRow++;
    }
    CGFloat minRequiredY = fmax(_scrollView.contentOffset.y - BUFFER, 0);
    for (int i = 0; i < _numColumns; i++) {
        minY = fmax(minY, minColY[i]);
    }
    while (minY > minRequiredY && _minRow > 0) {
        _minRow--;
        NWLayoutView *view = [self viewForRow:_minRow];
        int col = _columnMap[_minRow];
        CGRect frame = view.frame;
        frame.origin = _originMap[_minRow];
        minY = minColY[col] = frame.origin.y;
        for (int i = 0; i < _numColumns; i++) {
            minY = fmax(minY, minColY[i]);
        }
        if (_savedHeights.count > _minRow) {
            frame.size.height = _savedHeights[_minRow].floatValue;
        }
        view.frame = frame;
    }
    CGFloat totalHeight = 0;
    for (int i = _maxRow; i < _savedHeights.count; i++) maxColY[_columnMap[i]] += _savedHeights[i].floatValue;
    for (int i = 0; i < _numColumns; i++) totalHeight = fmax(totalHeight, maxColY[i]);
    totalHeight += _estimatedHeight * (_collectionItems.count - _savedHeights.count) / _numColumns;
    if (_scrollView.contentSize.height != totalHeight) {
        _scrollView.contentSize = CGSizeMake(self.frame.size.width, MAX(self.frame.size.height - self.contentInset.top - self.contentInset.bottom, totalHeight));
    }
}

- (void)recycleViews {
    CGFloat top = _scrollView.contentOffset.y;
    CGFloat bottom = top + _scrollView.frame.size.height;
    NSMutableArray *removeKeys = [NSMutableArray array];
    for (int i = _minRow; i < _maxRow; i++) {
        NSNumber *key = @(i);
        NWLayoutView *view = _activeViews[key];
        CGRect frame = view.frame;
        if (CGRectGetMaxY(frame) < top - BUFFER) {
            [_activeViews removeObjectForKey:key];
            [_freeViews addObject:view];
            _minRow++;
        } else {
            break;
        }
    }
    for (int i = _maxRow - 1; i >= _minRow; i--) {
        NSNumber *key = @(i);
        NWLayoutView *view = _activeViews[key];
        CGRect frame = view.frame;
        if (frame.origin.y > bottom + BUFFER) {
            [_activeViews removeObjectForKey:key];
            [_freeViews addObject:view];
            _maxRow--;
        } else {
            break;
        }
    }
    [_activeViews removeObjectsForKeys:removeKeys];
}

- (NWLayoutView *)viewForRow:(int)row {
    NWLayoutView *layoutView = _activeViews[@(row)];
    if (!layoutView) {
        if (_freeViews.count) {
            layoutView = _freeViews.lastObject;
            [_freeViews removeLastObject];
        } else {
            layoutView = [[NWLayoutView alloc] initWithLayout:_layoutName andFrame:CGRectMake(0, 0, self.frame.size.width / _numColumns, _estimatedHeight) andDelegate:self.delegate];
            [_scrollView addSubview:layoutView];
        }
        _activeViews[@(row)] = layoutView;
    }
    [layoutView setDictValues:_collectionItems[row]];
    [layoutView sizeToFit];
    return layoutView;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [UIView setAnimationsEnabled:NO];
    if (fabs(_lastScrollEvent - scrollView.contentOffset.y) > SCROLL_THRESHOLD) {
        if (_lastScrollEvent - scrollView.contentOffset.y > 200) {
            // Um, better reset and re-render from top
            _maxRow = 0;
            _minRow = 0;
            [_freeViews addObjectsFromArray:_activeViews.allValues];
            [_activeViews removeAllObjects];
        }
        [self recycleViews];
        [self renderViews];
        _lastScrollEvent = scrollView.contentOffset.y;
    }
    if (_collectionDelegate) [_collectionDelegate collectionViewDidScroll:self];
    [UIView setAnimationsEnabled:YES];
}

- (void)setCollectionItems:(NSArray<NSDictionary *> *)collectionItems {
    _scrollView.contentOffset = CGPointMake(0, -self.contentInset.top);
    _collectionItems = collectionItems.mutableCopy;
    _savedHeights = [NSMutableArray array];
    _minRow = 0;
    _maxRow = 0;
    [_freeViews addObjectsFromArray:_activeViews.allValues];
    [_activeViews removeAllObjects];
    [self renderViews];
}

- (void)addCollectionItem:(NSDictionary*)item {
    [_collectionItems addObject:item];
    [self renderViews];
}

- (void)prependCollectionItem:(NSDictionary *)item {
    [self insertCollectionItem:item atIndex:0];
}

- (void)insertCollectionItem:(NSDictionary *)item atIndex:(int)index {
    // TODO: this only supports index = 1 or index = 0, really
    _scrollView.contentOffset = CGPointMake(0, -self.contentInset.top);
    [_collectionItems insertObject:item atIndex:index];
    _savedHeights = [NSMutableArray array];

    memset(_columnMap, -1, TOTAL_ROW_LIMIT);
    for (int i = index; i < _collectionItems.count; i++) {
        _originMap[i] = CGPointZero;
    }
    _maxRow = 0;
    _minRow = 0;
    [_freeViews addObjectsFromArray:_activeViews.allValues];
    [_activeViews removeAllObjects];
    [self renderViews];
}

- (void)removeCollectionItemAtIndex:(int)index {
    [_savedHeights removeObjectsInRange:NSMakeRange(index, _savedHeights.count - index)];
    for (int i = index; i < _collectionItems.count; i++) {
        _columnMap[i] = -1;
        _originMap[i] = CGPointZero;
    }
    if (_maxRow > index) {
        // We have to throw out a view potentially. It's okay, we'll make a new one if needed
        [_activeViews[@(_maxRow - 1)] removeFromSuperview];
        [_activeViews removeObjectForKey:@(_maxRow - 1)];
        _maxRow--;
        for (int i = _maxRow - 1; i >= index && i >= _minRow; i--) {
            NSNumber *key = @(i);
            NWLayoutView *view = _activeViews[key];
            if (view) {
                [_activeViews removeObjectForKey:key];
                [_freeViews addObject:view];
            }
            _maxRow--;
        }
    }
    [_collectionItems removeObjectAtIndex:index];
    [self renderViews];
}

- (void)reloadItemAtIndex:(int)index {
    if (index >= _minRow && index < _maxRow) {
        [self viewForRow:index];
    }
}

// So you can include this whole thing in a layout xml and set the data array via collectionItems="{{ items }}"
- (void)apply_collectionItems:(id)items layoutView:(NWLayoutView*)layoutView {
    if ([items isKindOfClass:[NSArray class]]) {
        self.collectionItems = [items mutableCopy];
    }
}

- (void)setContentInset:(UIEdgeInsets)contentInset {
    _scrollView.contentInset = contentInset;
}

- (UIEdgeInsets)contentInset {
    return _scrollView.contentInset;
}

- (CGPoint)contentOffset {
    return _scrollView.contentOffset;
}

- (void)setContentOffset:(CGPoint)contentOffset {
    _scrollView.contentOffset = contentOffset;
}

- (CGSize)contentSize {
    return _scrollView.contentSize;
}

@end


text:
import Ember from "ember";
import {test, moduleForComponent} from "ember-qunit";

moduleForComponent('ember-right-menu',
                    'component to present a right menu with links to navigate between routes',
    {
        needs: []
    }
);

test('verify if tag name is blank', function(assert){
    var component = this.subject(),
        menus;

    Ember.run(() => {
        menus = [
            {
                'text': 'Page 1',
                'link': 'page1',
                'selected': false
            },
            {
                'text': 'Page 2',
                'link': 'page2',
                'selected': false
            }
        ];
        component
            .set(
                'menus',
                menus
            );
    });

    assert.equal(this.$().context.tagName, 'DIV');
});

test('verify if default options are correct', function(assert){
    var component = this.subject(),
        menus = [],
        optionsDefault = {
            'menu': {
                'background-color': '#F5F5F5',
                'width': '15%'
            },
            'title': {
                'border-bottom': 'solid 1px #f5da55',
                'color': '#000000'
            },
            'menuItem':{
                'color': '#8c8e87'
            },
            'menuItemSelected':{
                'color': '#000000',
                'background-color': '#FFFAF0',
                'border-left': 'solid 2px #f5da55'
            }
        };

    Ember.run(() => {
        component
            .set(
                'menus',
                menus
            );
    });

    assert
        .equal(
            JSON.stringify(component.optionsDefault),
            JSON.stringify(optionsDefault)
        );
});

test("verify if options are empty when it isn't informed", function(assert){
    var component = this.subject(),
        menus = [],
        options = {};

    Ember.run(() => {
        component
            .set(
                'menus',
                menus
            );
    });

    assert
        .equal(
            JSON.stringify(component.options),
            JSON.stringify(options)
        );
});

test('verify if style is correctly built when options are informed', function(assert){
    var component = this.subject(),
        menus = [],
        options = {
            'menu': {
                'background-color': '#FFFFFF',
                'width': '45%'
            },
            'title': {
                'border-bottom': 'solid 1px #f5da55',
                'color': '#FFFFFF'
            },
            'menuItem':{
                'color': '#8c8e87'
            },
            'menuItemSelected':{
                'color': '#000000',
                'background-color': '#000000',
                'border-left': 'solid 12px #f5da55'
            }
        },
        styles;

    Ember.run(() => {
        component
            .set(
                'options',
                options
            )
            .set(
                'menus',
                menus
            );

            styles = component.get('styles');
    });

    assert.equal(JSON.stringify(styles.menu), '"background-color:#FFFFFF; width:45%"');
    assert.equal(JSON.stringify(styles.title), '"border-bottom:solid 1px #f5da55; color:#FFFFFF"');
    assert.equal(JSON.stringify(styles.menuItem), '"color:#8c8e87"');
    assert.equal(JSON.stringify(styles.menuItemSelected), '"color:#000000; background-color:#000000; border-left:solid 12px #f5da55"');
});

test("verify if items are empty when it isn't informed", function(assert){
    var component = this.subject(),
        items;

    Ember.run(() => {
        items = component
                    .get(
                        'items'
                    );
    });

    assert.equal(items.length, 0);
});

test("verify if items are empty when menu is informed with an empty array", function(assert){
    var component = this.subject(),
        menus = [],
        items;

    Ember.run(() => {
        component
            .set(
                'menus',
                menus
            );

        items = component
                    .get(
                        'items'
                    );
    });

    assert.equal(items.length, 0);
});

test("verify if items are the same number of menus than the menus was informed to component", function(assert){
    var component = this.subject(),
        qty = Math.round(Math.random() * (100 - 1) + 1, 0),
        menus = [],
        items;

    for(let counter = 0; counter < qty; counter = counter + 1){
        let menu = {
            'text': 'Page ' + counter,
            'link': 'page' + counter,
            'selected': false
        };
        menus.push(menu);
    }

    Ember.run(() => {
        component
            .set(
                'menus',
                menus
            );

        items = component
                    .get(
                        'items'
                    );
    });

    assert.equal(items.length, qty);
});

test("verify when an item is clicked if it state change to selected", function(assert){
    var component = this.subject(),
        qty = Math.round(Math.random() * (100 - 1) + 1, 0),
        menus = [],
        items,
        index = Math.round(Math.random() * (qty - 1) + 1, 0);

    for(let counter = 0; counter < qty; counter = counter + 1){
        let menu = {
            'text': 'Page ' + counter,
            'link': 'page' + counter,
            'selected': false
        };
        menus.push(menu);
    }

    Ember.run(() => {
        component
            .set(
                'menus',
                menus
            );

        items = component
                    .get(
                        'items'
                    );
    });

    assert.ok(items[index].selected === false);

    component.send('select', index);

    items = component
                .get(
                    'items'
                );

    assert.ok(items[index].selected);
});


text:
SYNONYM

#### According to
Index Fungorum

#### Published in
Mycotaxon 11(1): 134 (1980)

#### Original name
Thelotrema leiostomum Tuck.

### Remarks
null


text:
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:orientation="vertical"
    android:background="@color/activity_background_orange"
    tools:context="com.example.a99460.smartnote.note_activity"
    >

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/edit"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    tools:context="com.example.a99460.smartnote.note_activity"
    >

    <include layout="@layout/title"
        android:id="@+id/include"/>

    <com.nightonke.boommenu.BoomMenuButton
        android:id="@+id/bmb_note"
        android:layout_width="54dp"
        android:layout_height="62dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="2dp"
        android:layout_marginRight="5dp"
        app:bmb_buttonEnum="simpleCircle"
        app:bmb_piecePlaceEnum="piecePlace_dot_3_2"
        app:bmb_highlightedColor="@color/titlecolor_orange"
        app:bmb_normalColor="@android:color/transparent"
        android:layout_alignParentEnd="true"/>
    <ScrollView
        android:id="@+id/scrollView"
        android:layout_marginTop="72dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_marginTop="10dp"
            android:id="@+id/picture"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:src="@drawable/app_icon"
            android:visibility="gone" />

        <EditText
            android:id="@+id/edit_note"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lineSpacingMultiplier="1.2"
            android:minLines="10"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/bmb_note"
            android:background="#fff2f0"
            android:gravity="top"
            android:hint="Please add your notes."
            android:paddingBottom="18dp"
            android:paddingLeft="14dp"
            android:paddingRight="8dp"
            android:paddingTop="12dp"
            android:textColor="#1a3939"
            android:textSize="20sp" />

    </LinearLayout>
</ScrollView>
<View
    android:visibility="gone"
    android:id="@+id/dark_view"
    android:background="@color/default_bmb_dimColor"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</RelativeLayout>

    <RelativeLayout
        android:focusableInTouchMode="true"
        android:id="@+id/record_layout"
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="#fbf4f4"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true">
        <ImageView
            android:background="#f1cfcf"
            android:layout_width="match_parent"
            android:layout_height="1dp" />
        <ImageButton
            android:id="@+id/ok_record"
            android:layout_alignParentRight="true"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_marginTop="2dp"
            android:visibility="gone"

            android:background="@drawable/save"/>

        <LinearLayout
            android:layout_marginTop="10dp"
            android:id="@+id/ll_rec"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_centerHorizontal="true"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="16dp"
                android:layout_height="16dp"
                android:layout_marginRight="5dp"
                android:src="@drawable/circle_black" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="REC"
                android:textSize="16sp" />
        </LinearLayout>

        <com.example.a99460.smartnote.WaveView
            android:layout_centerHorizontal="true"
            android:id="@+id/wave"
            android:visibility="gone"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginBottom="5dp"
            android:layout_alignParentBottom="true"/>

        <ImageButton
            android:id="@+id/change"
            android:background="@drawable/record1"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="60dp"
           android:layout_centerHorizontal="true"
            />

        <ImageButton
            android:visibility="gone"
            android:background="@drawable/delete"
            android:id="@+id/delete"
            android:layout_width="34dp"
            android:layout_height="34dp"
            android:layout_marginTop="3dp"
          />

        <TextView
            android:id="@+id/time"
            android:textColor="@color/black"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="17sp"
            android:text="00:00:00"
            android:layout_centerHorizontal="true"
           android:layout_marginTop="35dp"
             />

    </RelativeLayout>

</LinearLayout>


text:
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Multiverse;
using Axiom.MathLib;
using Axiom.Core;
using Axiom.Graphics;
using Multiverse.CollisionLib;

namespace Axiom.SceneManagers.Multiverse
{
    public class VegetationSemantic : IBoundarySemantic, IDisposable
    {
        private String name;
        private Boundary boundary = null;
        private List<PlantType> plantTypes;
        // private AxisAlignedBox bounds = null;

        public VegetationSemantic(String name, Boundary boundary)
        {
            this.name = name;
            this.boundary = boundary;
			plantTypes = new List<PlantType>();
        }

        public VegetationSemantic(XmlTextReader r)
        {
            plantTypes = new List<PlantType>();
            FromXML(r);
        }

        public string Type
        {
            get
            {
                return "VegetationSemantic";
            }
        }

        public void AddToBoundary(Boundary boundary)
        {
            this.boundary = boundary;
            TerrainManager.Instance.AddDetailVegetationSemantic(this);
        }

        public void RemoveFromBoundary()
        {
            TerrainManager.Instance.RemoveDetailVegetationSemantic(this);
            boundary = null;
        }

        /// <summary>
        /// Add a new type of grass to the boundary.
        /// </summary>
        public void AddPlantType(uint numInstances, string imageName,
								 float atlasStartX, float atlasWidthX,
								 float atlasStartY, float atlasWidthY,
                                 float scaleWidthLow, float scaleWidthHi,
                                 float scaleHeightLow, float scaleHeightHi, float windMagnitude)
        {
            AddPlantType(numInstances, imageName,
						 atlasStartX, atlasWidthX, atlasStartY, atlasWidthY,
						 scaleWidthLow, scaleWidthHi, scaleHeightLow, scaleHeightHi,
						 ColorEx.White, 1, 1, windMagnitude);
        }

        public void AddPlantType(uint numInstances, string imageName,
								 float atlasStartX, float atlasWidthX,
								 float atlasStartY, float atlasWidthY,
                                 float scaleWidthLow, float scaleWidthHi,
                                 float scaleHeightLow, float scaleHeightHi,
                                 ColorEx color, float colorMultLow, float colorMultHi, float windMagnitude)
        {
            PlantType plantType = new PlantType(numInstances, imageName,
												atlasStartX, atlasWidthX, atlasStartY, atlasWidthY,
                                                scaleWidthLow, scaleWidthHi, scaleHeightLow, scaleHeightHi,
                                                color, colorMultLow, colorMultHi, windMagnitude);
            AddPlantType(plantType);
        }

        public void AddPlantType(uint numInstances, string imageName,
                                 float scaleWidthLow, float scaleWidthHi,
                                 float scaleHeightLow, float scaleHeightHi,
                                 ColorEx color, float colorMultLow, float colorMultHi,
								 float windMagnitude)
        {
            PlantType plantType = new PlantType(numInstances, imageName,
                                                scaleWidthLow, scaleWidthHi, scaleHeightLow, scaleHeightHi,
                                                color, colorMultLow, colorMultHi, windMagnitude);
            AddPlantType(plantType);
        }

        public void AddPlantType(PlantType plantType)
		{
            plantTypes.Add(plantType);
            TerrainManager.Instance.RefreshVegetation();
		}

        public void RemovePlantType(PlantType plantType)
        {
            plantTypes.Remove(plantType);
            TerrainManager.Instance.RefreshVegetation();
        }

		public void ToXML(XmlTextWriter w)
        {
            w.WriteStartElement("boundarySemantic");
            w.WriteAttributeString("type", "VegetationSemantic");
            w.WriteElementString("name", name);

            foreach (PlantType t in plantTypes)
            {
                w.WriteStartElement("PlantType");
                w.WriteAttributeString("numInstances", t.NumInstances.ToString());
                w.WriteAttributeString("imageName", t.ImageName);
				w.WriteAttributeString("atlasStartX", t.AtlasStartX.ToString());
                w.WriteAttributeString("atlasEndX", t.AtlasEndX.ToString());
                w.WriteAttributeString("scaleWidthLow", t.ScaleWidthLow.ToString());
                w.WriteAttributeString("scaleWidthHi", t.ScaleWidthHi.ToString());
                w.WriteAttributeString("scaleHeightLow", t.ScaleHeightLow.ToString());
                w.WriteAttributeString("scaleHeightHi", t.ScaleHeightHi.ToString());
                w.WriteAttributeString("colorMultLow", t.ColorMultLow.ToString());
                w.WriteAttributeString("colorMultHi", t.ColorMultHi.ToString());
                w.WriteAttributeString("windMagnitude", t.WindMagnitude.ToString());
				w.WriteStartElement("color");
				w.WriteAttributeString("a", t.Color.a.ToString());
				w.WriteAttributeString("r", t.Color.r.ToString());
				w.WriteAttributeString("g", t.Color.g.ToString());
				w.WriteAttributeString("b", t.Color.b.ToString());
				w.WriteEndElement();
				w.WriteEndElement();
            }
            w.WriteEndElement();
        }

        protected void ParseElement(XmlTextReader r)
        {
            bool readEnd = true;

            // set the field in this object based on the element we just read
            switch (r.Name)
			{
			case "name":
				// read the value
				r.Read();
				if (r.NodeType != XmlNodeType.Text)
					return;
				name = r.Value;

				break;

			case "PlantType":
				uint numInstances = 0;
				string imageName = "";
				float atlasStartX = 0f;
				float atlasEndX = 1f;
				float atlasStartY = 0f;
				float atlasEndY = 1f;
				float scaleWidthLow = 0f;
				float scaleWidthHi = 0f;
				float scaleHeightLow = 0f;
				float scaleHeightHi = 0f;
				ColorEx color = new ColorEx();
				float colorMultLow = 0f;
				float colorMultHi = 0f;
				float windMagnitude = 0f;
				for (int i = 0; i < r.AttributeCount; i++)
				{
					r.MoveToAttribute(i);

					// set the field in this object based on the element we just read
					switch (r.Name)
					{
					case "numInstances":
						numInstances = uint.Parse(r.Value);
						break;
					case "imageName":
						imageName = r.Value;
						break;
					case "atlasStartX":
						atlasStartX = float.Parse(r.Value);
						break;
					case "atlasEndX":
						atlasEndX = float.Parse(r.Value);
						break;
					case "atlasStartY":
						atlasStartY = float.Parse(r.Value);
						break;
					case "atlasEndY":
						atlasEndY = float.Parse(r.Value);
						break;
					case "scaleWidthLow":
						scaleWidthLow = float.Parse(r.Value);
						break;
					case "scaleWidthHi":
						scaleWidthHi = float.Parse(r.Value);
						break;
					case "scaleHeightLow":
						scaleHeightLow = float.Parse(r.Value);
						break;
					case "scaleHeightHi":
						scaleHeightHi = float.Parse(r.Value);
						break;
					case "colorMultLow":
						colorMultLow = float.Parse(r.Value);
						break;
					case "colorMultHi":
						colorMultHi = float.Parse(r.Value);
						break;
					case "windMagnitude":
						windMagnitude = float.Parse(r.Value);
						break;
					}
				}
				r.MoveToElement();
				while (r.Read())
				{
					// look for the start of an element
					if (r.NodeType == XmlNodeType.Element)
					{
						// parse that element
						switch (r.Name)
						{
						case "color":
							float alpha = 0f;
							float red = 0f;
							float blue = 0f;
							float green = 0f;
							for (int j = 0; j < r.AttributeCount; j++)
							{
								r.MoveToAttribute(j);
								switch(r.Name)
								{
								case "a":
									alpha = float.Parse(r.Value);
									break;
								case "r":
									red = float.Parse(r.Value);
									break;
								case "g":
									green = float.Parse(r.Value);
									break;
								case "b":
									blue = float.Parse(r.Value);
									break;
								}
							}
							color = new ColorEx(alpha, red, green, blue);
							break;
						}
					}
					else
						break;
				}
				r.MoveToElement(); //Moves the reader back to the element node.
				AddPlantType(numInstances, imageName,
							 atlasStartX, atlasEndX, atlasStartY, atlasEndY,
							 scaleWidthLow, scaleWidthHi, scaleHeightLow, scaleHeightHi,
							 color, colorMultLow, colorMultHi, windMagnitude);
				readEnd = false;
				break;
			}
            if (readEnd)
            {
                // error out if we dont see an end element here
                r.Read();
                if (r.NodeType != XmlNodeType.EndElement)
                {
                    return;
                }
            }
		}

        private void FromXML(XmlTextReader r)
        {
            while (r.Read())
            {
                // look for the start of an element
                if (r.NodeType == XmlNodeType.Element)
                {
                    // parse that element
                    ParseElement(r);
                }
                else if (r.NodeType == XmlNodeType.EndElement)
                {
                    // if we found an end element, it means we are at the end of the terrain description
                    return;
                }
            }
        }

        public void BoundaryChange()
        {
            TerrainManager.Instance.RefreshVegetation();
        }

        public void Dispose()
        {
        }

        public void PerFrameProcessing(float time, Camera camera)
        {
        }

        public void PageShift()
        {
        }

        public List<PlantType> PlantTypes
        {
            get
            {
                return plantTypes;
            }

        }

		public Boundary BoundaryObject
		{
			get
			{
				return boundary;
			}
		}

	}
}


text:
A bundle of correlated maps are organized as a directory, with a structure like:

```txt
<map_dir>                        # Defined by FLAGS_map_dir
  |-- base_map.xml               # Defined by FLAGS_base_map_filename
  |-- routing_map.bin            # Defined by FLAGS_routing_map_filename
  |-- sim_map.bin                # Defined by FLAGS_sim_map_filename
  |-- default_end_way_point.txt  # Defined by FLAGS_end_way_point_filename
```

You can specify the map filenames as a list of candidates:

```txt
--base_map_filename="base.xml|base.bin|base.txt"
```

Then it will find the first available file to load. Generally we follow the
extension pattern of:

```txt
x.xml  # An OpenDrive formatted map.
x.bin  # A binary pb map.
x.txt  # A text pb map.
```

## Difference between base\_map, routing\_map and sim\_map
* `base_map` is the most complete map that has all roads, lane geometry and labels. The other maps are generated based on `base_map`.

* `routing_map` has the topology of the lanes in `base_map`. It can be generated by command:
  ```
   dir_name=modules/map/data/demo # example map directory
   ./scripts/generate_routing_topo_graph.sh --map_dir ${dir_name}
  ```

* `sim_map` is a light weight version of `base_map` for dreamview visualization. It has reduced data density for better runtime performance. It can be generated by command:
  ```
  dir_name=modules/map/data/demo # example map directory
  bazel-bin/modules/map/tools/sim_map_generator --map_dir=${dir_name} --output_dir=${dir_name}
  ```

## Use a different map

1. [Preferred] Change global flagfile: *modules/common/data/global_flagfile.txt*

   Note that it's the basement of all modules' flagfile, which keeps the whole
   system in one page.

1. Pass as flag, which only affects an individual process:

   ```bash
   <binary> --map_dir=/path/to/your/map
   ```

1. Override in the module's own flagfile, which is generally located at
   *modules/<module_name>/conf/<module_name>.conf*

   Obviously it also only affects a single module.

   ```txt
   --flagfile=modules/common/data/global_flagfile.txt

   # Override values from the global flagfile.
   --map_dir=/path/to/your/map
   ```


text:
package org.gdg.frisbee.android.chapter;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Plus;
import com.google.android.gms.plus.PlusOneButton;
import com.squareup.picasso.Picasso;

import org.gdg.frisbee.android.R;
import org.gdg.frisbee.android.api.model.plus.Activity;
import org.gdg.frisbee.android.api.model.plus.Attachment;
import org.gdg.frisbee.android.api.model.plus.Image;
import org.gdg.frisbee.android.api.model.plus.Thumbnail;
import org.gdg.frisbee.android.app.App;
import org.gdg.frisbee.android.utils.Utils;
import org.gdg.frisbee.android.widget.ResizableImageView;
import org.joda.time.DateTime;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {

    private static final int VIEW_TYPE_ARTICLE = 1;
    private static final int VIEW_TYPE_VIDEO = 2;
    private static final int VIEW_TYPE_PHOTO = 3;
    private static final int VIEW_TYPE_ALBUM = 4;
    private static final int VIEW_TYPE_EVENT = 5;
    private static final int ACTIVITY_REQUEST_CODE_GPLUS_BUTTON = 1;

    private final Context context;
    private final LayoutInflater inflater;
    private ArrayList<Item> activities;
    private final GoogleApiClient plusClient;
    private final Picasso picasso;

    NewsAdapter(Context context, GoogleApiClient plusClient) {
        this.context = context;
        this.plusClient = plusClient;
        inflater = LayoutInflater.from(this.context);
        activities = new ArrayList<>();
        picasso = App.from(context).getPicasso();

        setHasStableIds(true);
    }

    public void addAll(Collection<Activity> items) {
        for (Activity a : items) {
            activities.add(new Item(a));
        }
        notifyDataSetChanged();
    }

    public void replaceAll(Collection<Activity> items, int start) {
        for (Activity a : items) {

            if (start < activities.size()) {
                if (a.getId().equals(activities.get(start).getActivity().getId())) {
                    activities.set(start, new Item(a));
                } else {
                    activities.add(start, new Item(a));
                    start++;
                }
            } else {
                activities.add(new Item(a));
            }

            start++;
        }
        notifyDataSetChanged();
    }

    public void add(Activity item) {
        activities.add(new Item(item));
        notifyDataSetChanged();
    }

    public void clear() {
        activities.clear();
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return activities.size();
    }

    private Item getItemInternal(int i) {
        return activities.get(i);
    }

    @Override
    public long getItemId(int i) {
        return Utils.stringToLong(getItemInternal(i).getActivity().getId());
    }

    @Override
    public int getItemViewType(int position) {

        if (position >= 0) {
            if (position >= getItemCount()) {
                position = position % getItemCount();
            }
            Item item = getItemInternal(position);
            Activity activity = item.getActivity();

            if (activity.getObject().getAttachments() == null
                || activity.getObject().getAttachments().isEmpty()) {
                return 0;
            } else {
                Attachment attachment = activity.getObject().getAttachments().get(0);
                String objectType = attachment.getObjectType();

                switch (objectType) {
                    case "article":
                        return VIEW_TYPE_ARTICLE;
                    case "video":
                        return VIEW_TYPE_VIDEO;
                    case "photo":
                        return VIEW_TYPE_PHOTO;
                    case "album":
                        return VIEW_TYPE_ALBUM;
                    case "event":
                        return VIEW_TYPE_EVENT;
                }
            }
        }
        return 0;
    }

    public void updatePlusOne(ViewHolder viewHolder) {
        if (viewHolder != null) {
            if (shouldShowGPlusButton()) {
                viewHolder.plusButton.setVisibility(View.VISIBLE);
                viewHolder.plusButton.initialize(viewHolder.url, ACTIVITY_REQUEST_CODE_GPLUS_BUTTON);
            } else {
                viewHolder.plusButton.setVisibility(View.GONE);
            }
        }
    }

    private boolean shouldShowGPlusButton() {
        return plusClient != null && plusClient.hasConnectedApi(Plus.API);
    }

    @Override
    public NewsAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = inflater.inflate(R.layout.news_item_base, viewGroup, false);

        final ViewHolder viewHolder = new ViewHolder(v);
        viewHolder.content.setMovementMethod(LinkMovementMethod.getInstance());
        viewHolder.shareContent.setMovementMethod(LinkMovementMethod.getInstance());

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int i) {

        Item item = getItemInternal(i);
        final Activity activity = item.getActivity();

        holder.url = activity.getUrl();
        updatePlusOne(holder);
        if (activity.getPublished() != null) {
            holder.timeStamp.setVisibility(View.VISIBLE);
            holder.timeStamp.setText(
                Utils.toHumanTimePeriod(
                    context,
                    activity.getPublished(),
                    DateTime.now()
                )
            );
        } else {
            holder.timeStamp.setVisibility(View.GONE);
        }

        if (activity.getVerb().equals("share")) {
            populateShare(activity, holder);
        } else {
            holder.shareContainer.setVisibility(View.GONE);
            populatePost(activity, holder.content);
        }

        if (activity.getObject().getAttachments() != null && activity.getObject().getAttachments().size() > 0) {

            final Attachment attachment = activity.getObject().getAttachments().get(0);

            switch (getItemViewType(i)) {
                case VIEW_TYPE_ARTICLE:
                    // Article
                    populateArticle(holder, holder.container, attachment);
                    break;
                case VIEW_TYPE_VIDEO:
                    // Video
                    populateVideo(holder, holder.container, attachment);
                    break;
                case VIEW_TYPE_PHOTO:
                    // Photo
                    populatePhoto(holder, holder.container, attachment);
                    break;
                case VIEW_TYPE_ALBUM:
                    // Album
                    populateAlbum(holder, holder.container, attachment);
                    break;
                case VIEW_TYPE_EVENT:
                    // Event
                    populateEvent(holder, holder.container, attachment);
                    break;
            }
        }

        // That item will contain a special property that tells if it was freshly retrieved
//        if (!item.isConsumed()) {
//            item.setConsumed(true);
//            // In which case we magically instantiate our effect and launch it directly on the view
//            Animation animation = AnimationUtils.makeInChildBottomAnimation(context);
//            view.startAnimation(animation);
//        }
    }

    private View createAttachmentView(ViewHolder mViewHolder, ViewGroup container, int layout, int type) {
        View attachmentView;

        if (container.getChildCount() == 0) {
            attachmentView = inflater.inflate(layout, container, false);
            container.addView(attachmentView);

            switch (type) {
                case 1:
                    // Article
                    mViewHolder.articleImage = (ImageView) attachmentView.findViewById(R.id.image);
                    mViewHolder.title = (TextView) attachmentView.findViewById(R.id.displayName);
                    mViewHolder.attachmentContent = (TextView) attachmentView.findViewById(R.id.content);
                    break;
                case 2:
                    // Video
                    mViewHolder.poster = (ResizableImageView) attachmentView.findViewById(R.id.videoPoster);
                    break;
                case 3:
                    // Photo
                    mViewHolder.photo = (ResizableImageView) attachmentView.findViewById(R.id.photo);
                    break;
                case 4:
                    // Album
                    mViewHolder.pic1 = (ImageView) attachmentView.findViewById(R.id.pic1);
                    mViewHolder.pic2 = (ImageView) attachmentView.findViewById(R.id.pic2);
                    mViewHolder.pic3 = (ImageView) attachmentView.findViewById(R.id.pic3);
                    break;
                case 5:
                    // Event
                    mViewHolder.attachmentContent = (TextView) attachmentView.findViewById(R.id.content);
                    mViewHolder.attachmentTitle = (TextView) attachmentView.findViewById(R.id.title);
                    mViewHolder.articleImage = (ImageView) attachmentView.findViewById(R.id.image);
                    break;
            }
        } else {
            attachmentView = container.getChildAt(0);
        }

        return attachmentView;
    }

    private void populateArticle(ViewHolder mViewHolder,
                                 ViewGroup container,
                                 final Attachment attachment) {
        if (attachment == null) {
            return;
        }

        View attachmentView = createAttachmentView(mViewHolder, container, R.layout.news_item_article, 1);

        mViewHolder.title.setText(attachment.getDisplayName());
        try {
            mViewHolder.attachmentContent.setText(new URL(attachment.getUrl()).getHost());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        if (attachment.getImage() == null && attachment.getFullImage() == null) {
            mViewHolder.articleImage.setVisibility(View.GONE);
        } else {
            mViewHolder.articleImage.setImageDrawable(null);

            String imageUrl = getAttachmentImageUrl(attachment);
            if (imageUrl != null) {
                mViewHolder.articleImage.setVisibility(View.VISIBLE);
                picasso.load(imageUrl)
                    .into(mViewHolder.articleImage);
            } else {
                mViewHolder.articleImage.setVisibility(View.GONE);
            }
        }

        attachmentView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                context.startActivity(Utils.createExternalIntent(context, Uri.parse(attachment.getUrl())));
            }
        });
    }

    @Nullable
    private static String getAttachmentImageUrl(final Attachment attachment) {
        if (attachment.getFullImage() != null) {
            return attachment.getFullImage().getUrl();
        } else if (attachment.getImage() != null) {
            return attachment.getImage().getUrl();
        }
        return null;
    }

    private void populateVideo(ViewHolder mViewHolder,
                               ViewGroup container,
                               final Attachment attachment) {
        if (attachment == null) {
            return;
        }

        View attachmentView = createAttachmentView(mViewHolder, container, R.layout.news_item_video, 2);

        Image attachmentImage = attachment.getImage();
        if (attachmentImage != null) {
            mViewHolder.poster.setDimensions(attachmentImage.getWidth(), attachmentImage.getHeight());
            mViewHolder.poster.setImageDrawable(null);

            picasso.load(attachmentImage.getUrl())
                .into(mViewHolder.poster);
        }

        attachmentView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    String videoId = getVideoIdFrom(attachment);
                    if (videoId != null) {
                        Intent playVideoIntent = new Intent(context, YoutubeActivity.class);
                        playVideoIntent.putExtra(YoutubeActivity.EXTRA_VIDEO_ID, videoId);
                        context.startActivity(playVideoIntent);
                    } else {
                        Intent viewUrlIntent = Utils.createExternalIntent(context, Uri.parse(attachment.getUrl()));
                        if (Utils.canLaunch(context, viewUrlIntent)) {
                            context.startActivity(viewUrlIntent);
                        }
                    }
                } catch (UnsupportedEncodingException | MalformedURLException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private static String getVideoIdFrom(final Attachment attachment)
        throws UnsupportedEncodingException, MalformedURLException {

        return Utils.splitQuery(new URL(attachment.getUrl())).get("v");
    }

    private void populatePhoto(ViewHolder mViewHolder,
                               ViewGroup container,
                               Attachment attachment) {
        if (attachment == null) {
            return;
        }

        createAttachmentView(mViewHolder, container, R.layout.news_item_photo, 3);

        // Precalc Image Size
        if (attachment.getImage() != null
            && attachment.getImage().getUrl() != null
            && attachment.getImage().getWidth() != null) {
            mViewHolder.photo.setDimensions(attachment.getImage().getWidth(), attachment.getImage().getHeight());
        }

        mViewHolder.photo.setImageDrawable(null);

        picasso.load(attachment.getImage().getUrl())
            .into(mViewHolder.photo);

    }

    private void populateAlbum(ViewHolder mViewHolder,
                               ViewGroup container,
                               Attachment attachment) {
        if (attachment == null) {
            return;
        }

        createAttachmentView(mViewHolder, container, R.layout.news_item_album, 4);

        List<Thumbnail> thumbnails = attachment.getThumbnails();
        picasso.load(thumbnails.get(0).getImage().getUrl())
            .into(mViewHolder.pic1);

        if (thumbnails.size() > 1) {
            picasso.load(thumbnails.get(1).getImage().getUrl())
                .into(mViewHolder.pic2);
        }
        if (thumbnails.size() > 2) {
            picasso.load(thumbnails.get(2).getImage().getUrl())
                .into(mViewHolder.pic3);
        }
    }

    private void populateEvent(ViewHolder mViewHolder,
                               ViewGroup container,
                               final Attachment attachment) {
        createAttachmentView(mViewHolder, container, R.layout.news_item_event, 5);

        TextView title = mViewHolder.attachmentTitle;
        String name = attachment.getDisplayName();
        if (TextUtils.isEmpty(name)) {
            title.setVisibility(View.GONE);
        } else {
            title.setText(name);
            title.setClickable(true);
            View.OnClickListener mClickEvent = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    openEventInGPlus(attachment.getUrl());
                }
            };

            mViewHolder.articleImage.setOnClickListener(mClickEvent);
            title.setOnClickListener(mClickEvent);
        }

        TextView content = mViewHolder.attachmentContent;
        content.setText(attachment.getContent());
    }

    private void openEventInGPlus(String uri) {
        context.startActivity(Utils.createExternalIntent(context, Uri.parse(uri)));

    }

    private void populatePost(Activity item, TextView content) {
        content.setText(fromHtml(item.getObject().getContent()));
    }

    private void populateShare(Activity item, ViewHolder holder) {
        String originallyShared = "";

        if (item.getObject().getActor() != null && context != null) {
            originallyShared = ""
                + item.getObject().getActor().getDisplayName()
                + " " + context.getString(R.string.originally_shared) + "

";
        }

        if (item.getAnnotation() != null) {
            holder.content.setText(fromHtml(item.getAnnotation()));
            holder.shareContent.setText(fromHtml(originallyShared + item.getObject().getContent()));
            holder.shareContainer.setVisibility(View.VISIBLE);
        } else {
            holder.shareContainer.setVisibility(View.GONE);
            holder.content.setText(fromHtml(originallyShared + item.getObject().getContent()));
        }
    }

    private Spanned fromHtml(String html) {
        Spanned spanned = Html.fromHtml(html);

        if (spanned instanceof SpannableStringBuilder) {
            SpannableStringBuilder ssb = (SpannableStringBuilder) spanned;

            URLSpan[] urlspans = ssb.getSpans(0, ssb.length() - 1, URLSpan.class);
            for (URLSpan span : urlspans) {
                int start = ssb.getSpanStart(span);
                int end = ssb.getSpanEnd(span);
                final String url = span.getURL();

                ssb.removeSpan(span);

                ssb.setSpan(new ClickableSpan() {
                    @Override
                    public void onClick(View view) {
                        context.startActivity(Utils.createExternalIntent(context, Uri.parse(url)));
                    }
                }, start, end, 33);
            }
        }
        return spanned;
    }

    private static class Item {
        private Activity mActivity;
        private boolean mConsumed = false;

        Item(Activity a) {
            mActivity = a;
            mConsumed = false;
        }

        public Activity getActivity() {
            return mActivity;
        }

        public void setActivity(Activity mActivity) {
            this.mActivity = mActivity;
        }

        public boolean isConsumed() {
            return mConsumed;
        }

        public void setConsumed(boolean mConsumed) {
            this.mConsumed = mConsumed;
        }
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView attachmentTitle;
        @BindView(R.id.plus_one_button)
        PlusOneButton plusButton;
        @BindView(R.id.attachmentContainer)
        ViewGroup container;
        @BindView(R.id.shareContainer)
        ViewGroup shareContainer;
        @BindView(R.id.timestamp)
        TextView timeStamp;
        @BindView(R.id.content)
        TextView content;
        @BindView(R.id.shareContent)
        TextView shareContent;
        ImageView articleImage;
        TextView title;
        ResizableImageView poster;
        ResizableImageView photo;
        TextView attachmentContent;
        ImageView pic1;
        ImageView pic2;
        ImageView pic3;
        String url;

        ViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}


text:
import React, { Component } from 'react'
import Switch from './Switch'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native'

export default class Example extends Component {
  state={
    value: false,
    value1: true
  }

  render() {
    return (
      <View style={styles.container}>
        <Switch /><Text>uncontrolled</Text>
        <Switch label={2} value={this.state.value} style={{marginTop: 20}} onSyncPress={(value) => this.setState({value})} />
        <Text> two way binding</Text>
        <Switch label={3} value={this.state.value} style={{marginTop: 20}} />
        <Text> controlled by outside</Text>
        <Switch
          width={60}
          height={30}
          style={{marginTop: 20}}
          value={this.state.value}
          onAsyncPress={(callback) => {
            setTimeout(() => callback(true), 1000)
          }}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#5174a2',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('Example', () => Example)


text:
// Copyright (c) 2012 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.

// IPC messages for the media streaming.
// Multiply-included message file, hence no include guard.

#include <string>

#include "content/common/content_export.h"
#include "content/common/media/media_stream_options.h"
#include "ipc/ipc_message_macros.h"
#include "url/gurl.h"

#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START MediaStreamMsgStart

IPC_ENUM_TRAITS_MAX_VALUE(content::MediaStreamType,
                          content::NUM_MEDIA_TYPES - 1)

IPC_ENUM_TRAITS_MAX_VALUE(content::VideoFacingMode,
                          content::NUM_MEDIA_VIDEO_FACING_MODE - 1)

IPC_STRUCT_TRAITS_BEGIN(content::StreamOptions)
  IPC_STRUCT_TRAITS_MEMBER(audio_type)
  IPC_STRUCT_TRAITS_MEMBER(audio_device_id)
  IPC_STRUCT_TRAITS_MEMBER(video_type)
  IPC_STRUCT_TRAITS_MEMBER(video_device_id)
IPC_STRUCT_TRAITS_END()

IPC_STRUCT_TRAITS_BEGIN(content::StreamDeviceInfo)
  IPC_STRUCT_TRAITS_MEMBER(device.type)
  IPC_STRUCT_TRAITS_MEMBER(device.name)
  IPC_STRUCT_TRAITS_MEMBER(device.id)
  IPC_STRUCT_TRAITS_MEMBER(device.video_facing)
  IPC_STRUCT_TRAITS_MEMBER(device.matched_output_device_id)
  IPC_STRUCT_TRAITS_MEMBER(device.input.sample_rate)
  IPC_STRUCT_TRAITS_MEMBER(device.input.channel_layout)
  IPC_STRUCT_TRAITS_MEMBER(device.input.frames_per_buffer)
  IPC_STRUCT_TRAITS_MEMBER(device.matched_output.sample_rate)
  IPC_STRUCT_TRAITS_MEMBER(device.matched_output.channel_layout)
  IPC_STRUCT_TRAITS_MEMBER(device.matched_output.frames_per_buffer)
  IPC_STRUCT_TRAITS_MEMBER(in_use)
  IPC_STRUCT_TRAITS_MEMBER(session_id)
IPC_STRUCT_TRAITS_END()

// Message sent from the browser to the renderer

// The browser has generated a stream successfully.
IPC_MESSAGE_ROUTED4(MediaStreamMsg_StreamGenerated,
                    int /* request id */,
                    std::string /* label */,
                    content::StreamDeviceInfoArray /* audio_device_list */,
                    content::StreamDeviceInfoArray /* video_device_list */)

// The browser has failed to generate a stream.
IPC_MESSAGE_ROUTED1(MediaStreamMsg_StreamGenerationFailed,
                    int /* request id */)

// The browser requests to stop streaming.
// Note that this differs from MediaStreamHostMsg_StopGeneratedStream below
// which is a request from the renderer.
IPC_MESSAGE_ROUTED1(MediaStreamMsg_StopGeneratedStream,
                    std::string /* label */)

// The browser has enumerated devices successfully.
// Used by Pepper.
// TODO(vrk,wjia): Move this to pepper code.
IPC_MESSAGE_ROUTED3(MediaStreamMsg_DevicesEnumerated,
                    int /* request id */,
                    std::string /* label */,
                    content::StreamDeviceInfoArray /* device_list */)

// The browser has failed to enumerate devices.
IPC_MESSAGE_ROUTED1(MediaStreamMsg_DevicesEnumerationFailed,
                    int /* request id */)

// TODO(wjia): should DeviceOpen* messages be merged with
// StreamGenerat* ones?
// The browser has opened a device successfully.
IPC_MESSAGE_ROUTED3(MediaStreamMsg_DeviceOpened,
                    int /* request id */,
                    std::string /* label */,
                    content::StreamDeviceInfo /* the device */)

// The browser has failed to open a device.
IPC_MESSAGE_ROUTED1(MediaStreamMsg_DeviceOpenFailed,
                    int /* request id */)

// Response to enumerate devices request.
IPC_MESSAGE_CONTROL2(MediaStreamMsg_GetSourcesACK,
                     int /* request id */,
                     content::StreamDeviceInfoArray /* device_list */)

// Messages sent from the renderer to the browser.

// Request a new media stream.
IPC_MESSAGE_CONTROL4(MediaStreamHostMsg_GenerateStream,
                     int /* render view id */,
                     int /* request id */,
                     content::StreamOptions /* components */,
                     GURL /* security origin */)

// Request to cancel the request for a new media stream.
IPC_MESSAGE_CONTROL2(MediaStreamHostMsg_CancelGenerateStream,
                     int /* render view id */,
                     int /* request id */)

// Request to stop streaming from the media stream.
IPC_MESSAGE_CONTROL2(MediaStreamHostMsg_StopGeneratedStream,
                     int /* render view id */,
                     std::string /* label */)

// Request to enumerate devices.
// Used by Pepper.
// TODO(vrk,wjia): Move this to pepper code.
IPC_MESSAGE_CONTROL4(MediaStreamHostMsg_EnumerateDevices,
                     int /* render view id */,
                     int /* request id */,
                     content::MediaStreamType /* type */,
                     GURL /* security origin */)

// Request to open the device.
IPC_MESSAGE_CONTROL5(MediaStreamHostMsg_OpenDevice,
                     int /* render view id */,
                     int /* request id */,
                     std::string /* device_id */,
                     content::MediaStreamType /* type */,
                     GURL /* security origin */)

// Request to enumerate devices.
IPC_MESSAGE_CONTROL2(MediaStreamHostMsg_GetSources,
                     int /* request id */,
                     GURL /* origin */)


text:
package mqtt

type component string

// Component names for debug output
const (
	NET component = "[net]     "
	PNG component = "[pinger]  "
	CLI component = "[client]  "
	DEC component = "[decode]  "
	MES component = "[message] "
	STR component = "[store]   "
	MID component = "[msgids]  "
	TST component = "[test]    "
	STA component = "[state]   "
	ERR component = "[error]   "
)


text:
import           Control.Applicative
import           Control.Monad
import           Data.Array.IO
import qualified Data.ByteString       as BS
import qualified Data.ByteString.Char8 as C8
import           Data.List
import           Data.Maybe
import           Data.Tuple
import           Text.Printf

type Graph = IOArray Int [Int]
type VisitState = IOArray Int Bool

type TraversingGraph = (Graph, VisitState)

newGraph :: Int -> IO Graph
newGraph cnt = do
  edgeArray <- newArray (0, cnt-1) []
  return edgeArray

newVisitState :: Int -> IO VisitState
newVisitState cnt = newArray (0, cnt-1) False

connect :: Graph -> Int -> Int -> IO ()
connect g a b = do
  peers <- readArray g a
  writeArray g a (b:peers)

readIntPair :: IO (Int, Int)
readIntPair = do
  a:b:_ <- map (fst . fromJust . C8.readInt) . C8.words <$> BS.getLine
  return (a, b)

traverseDFS :: Graph -> IO [[Int]]
traverseDFS g = do
  (minBound, maxBound) <- getBounds g
  visitArray <- newVisitState (maxBound+1)
  res <- forM [0..maxBound] $ \idx -> do
    _traverseDFS g visitArray idx
  return $ filter ((>0) . length) res
  where
    _traverseDFS :: Graph -> VisitState -> Int -> IO [Int]
    _traverseDFS g va entry = do
      visited <- readArray va entry
      if visited then return [] else do
        writeArray va entry True
        (entry:) <$> (readArray g entry >>= fmap join . mapM (_traverseDFS g va) . sort)

traverseBFS :: Graph -> IO [[Int]]
traverseBFS g = do
  (minBound, maxBound) <- getBounds g
  visitArray <- newVisitState (maxBound+1)
  res <- forM [0..maxBound] $ \idx -> do
    _traverseBFS g visitArray [idx]
  return $ filter ((>0) . length) res
  where
    _traverseBFS :: Graph -> VisitState -> [Int] -> IO [Int]
    _traverseBFS g va [] = pure []
    _traverseBFS g va entries = do
      unvisitedEntries <- filterM (readArray va >=> return . not) entries
      forM unvisitedEntries $ (flip (writeArray va) True)
      peers <- nub . join <$> forM unvisitedEntries (readArray g >=> return . sort)
      (unvisitedEntries ++) <$> _traverseBFS g va peers

printResult :: [[Int]] -> IO ()
printResult = mapM_ (printf "{ %s }\n" . intercalate " " . map show)

main = do
  (vertexCount, edgeCount) <- readIntPair
  g <- newGraph vertexCount
  edges <- replicateM edgeCount readIntPair
  forM edges $ \edge -> do
    uncurry (connect g) edge
    uncurry (connect g) (swap edge)
  traverseDFS g >>= printResult
  traverseBFS g >>= printResult


text:
class CompanyJobId < ActiveRecord::Base
  self.table_name = :web_company_job_ids
  belongs_to :company

  validates_numericality_of :job_id, :only_integer => true
  validates_presence_of :company_id
  validate  :validate_length

  def validate_length
    # Can't use validates_length_of on numbers b/c it returns the storage size in bytes instead of the length of the number.
    unless self.job_id.to_i >= 100 && self.job_id.to_i <= 99999
      errors.add("job_id", "must be between 3 and 5 digits long")
    end
  end
end