text:
/**
 * @fileoverview Wrapper for the Google Civic Information Api.
 * @author jmwaura@google.com (Jesse Mwaura)
 */

goog.provide('vit.api.CivicInfo');
goog.provide('vit.api.CivicInfo.Status');

goog.require('goog.array');
goog.require('goog.string.path');
goog.require('vit.api.Api');
goog.require('vit.api.Distance');

/**
 * Create a wrapper for the Civic Information API.
 * @param {vit.context.Context} context The application context.
 * @constructor
 * @extends {vit.api.Api}
 */
vit.api.CivicInfo = function(context) {
  goog.base(this);

  /**
   * The application context context.
   * @type {vit.context.Context}
   * @private
   */
  this.context_ = context;

  /**
   * The election id to use for this instance.
   * @type {string}
   * @private
   */
  this.electionId_ = '';

  /**
   * Whether or not to request only official data.
   * @type {boolean}
   * @private
   */
  this.officialOnly_ = false;

  var config = this.context_.get(vit.context.CONFIG);
  if (goog.isDefAndNotNull(config)) {
    this.electionId_ = config[vit.context.ConfigName.ELECTION_ID];
    this.officialOnly_ = config[vit.context.ConfigName.OFFICIAL_ONLY];
  } else {
    throw Error('vit.api.CivicInfo instantiated before election_id ' +
        'is configured.');
  }

  /**
   * The api path to use for Civic Info requests.
   * @type {string}
   * @private
   */
  this.apiPath_ = goog.string.path.join(
      vit.api.CivicInfo.API_PATH,
      this.electionId_,
      'lookup');
};
goog.inherits(vit.api.CivicInfo, vit.api.Api);

/**
 * Look up polling location information.
 * @param {!string} address The address for which to fetch voter info.
 * @param {function((!vit.api.CivicInfo.Response|boolean), string)} callback
 *     The function to call when the request completes.
 */
vit.api.CivicInfo.prototype.lookup = function(address, callback) {
  var params = {'officialOnly': this.officialOnly_ ? 'true' : 'false'};
  var body = {'address': address};
  var responseTransformer = goog.bind(function(callback, response, raw) {
    callback(response ? this.transformResponse(response) : response, raw);
  }, this, callback);
  var distanceAppender = goog.bind(this.appendDistance,
      this, responseTransformer);
  this.request(this.apiPath_, vit.api.POST, params, body, distanceAppender);
};

/**
 * Transform raw object into Election.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Election} Transformed object.
 */
vit.api.CivicInfo.prototype.transformElection = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Election} */ (obj);
  }

  var out = {};
  out.id = obj['id'];
  out.name = obj['name'];
  out.electionDay = obj['electionDay'];
  return /** @type {vit.api.CivicInfo.Election} */ (out);
};

/**
 * Transform raw object into District.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.District} Transformed object.
 */
vit.api.CivicInfo.prototype.transformDistrict = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.District} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.scope = obj['scope'];
  out.id = obj['id'];
  return /** @type {vit.api.CivicInfo.District} */ (out);
};

/**
 * Transform raw object into Address.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Address} Transformed object.
 */
vit.api.CivicInfo.prototype.transformAddress = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Address} */ (obj);
  }

  var out = {};
  out.locationName = obj['locationName'];
  out.line1 = obj['line1'];
  out.line2 = obj['line2'];
  out.line3 = obj['line3'];
  out.city = obj['city'];
  out.state = obj['state'];
  out.zip = obj['zip'];
  return /** @type {vit.api.CivicInfo.Address} */ (out);
};

/**
 * Transform raw object into ElectionOfficial.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.ElectionOfficial} Transformed object.
 */
vit.api.CivicInfo.prototype.transformElectionOfficial = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.ElectionOfficial} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.title = obj['title'];
  out.officePhoneNumber = obj['officePhoneNumber'];
  out.faxNumber = obj['faxNumber'];
  out.emailAddress = obj['emailAddress'];
  return /** @type {vit.api.CivicInfo.ElectionOfficial} */ (out);
};

/**
 * Transform raw object into Contest.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Contest} Transformed object.
 */
vit.api.CivicInfo.prototype.transformContest = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Contest} */ (obj);
  }

  var out = {};
  out.type = obj['type'];
  out.primaryParty = obj['primaryParty'];
  out.electorateSpecifications = obj['electorateSpecifications'];
  out.special = obj['special'];
  out.office = obj['office'];
  out.level = obj['level'];
  out.district = this.transformDistrict(obj['district']);
  out.numberElected = obj['numberElected'];
  out.numberVotingFor = obj['numberVotingFor'];
  out.ballotPlacement = obj['ballotPlacement'];

  if (goog.isDefAndNotNull(obj['candidates'])) {
    var len = obj['candidates'].length;
    /** @type {Array.<vit.api.CivicInfo.Candidate>} */
    var candidatesArray = [];
    for (var i = 0; i < len; i++) {
      candidatesArray[i] = this.transformCandidate(obj['candidates'][i]);
    }
    out.candidates = candidatesArray;
  }

  if (goog.isDefAndNotNull(obj['sources'])) {
    len = obj['sources'].length;
    /** @type {Array.<vit.api.CivicInfo.Source>} */
    var sourcesArray = [];
    for (var i = 0; i < len; i++) {
      sourcesArray[i] = this.transformSource(obj['sources'][i]);
    }
    out.sources = sourcesArray;
  }
  return /** @type {vit.api.CivicInfo.Contest} */ (out);
};

/**
 * Transform raw object into Channel.
 * @param {Array.<Object>} channels Raw object to transform.
 * @return {vit.api.CivicInfo.Channels} Transformed object.
 */
vit.api.CivicInfo.prototype.transformChannels = function(channels) {
  if (!goog.isDefAndNotNull(channels)) {
    return /** @type {vit.api.CivicInfo.Channels} */ (channels);
  }

  var out = {};
  var len = channels.length;
  for (var i = 0; i < len; i++) {
    var channelType = channels[i]['type'].toLowerCase();
    var channelId = channels[i]['id'];
    if (channelType == 'googleplus') {
      out.googleplus = channelId;
    } else if (channelType == 'youtube') {
      out.youtube = channelId;
    } else if (channelType == 'facebook') {
      out.facebook = channelId;
    } else if (channelType == 'twitter') {
      out.twitter = channelId;
    }
  }
  return /** @type {vit.api.CivicInfo.Channels} */ (out);
};

/**
 * Transform raw object into PollingLocation.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.PollingLocation} Transformed object.
 */
vit.api.CivicInfo.prototype.transformPollingLocation = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.PollingLocation} */ (obj);
  }

  var out = {};
  out.address = this.transformAddress(obj['address']);

  // TODO(jmwaura): This is a hack to get rid of " - " polling hours.
  // The number 5 is mostly arbitrary, but anything less than 5 chars is almost
  // definitely wrong. Prefer false negatives. Fix this.
  out.pollingHours = (obj['pollingHours'] && obj['pollingHours'].length > 5) ?
      obj['pollingHours'] : null;

  out.name = obj['name'];
  out.notes = obj['notes'];
  out.voterServices = obj['voterServices'];
  out.startDate = obj['startDate'];
  out.endDate = obj['endDate'];
  out.distance = obj['distance'];
  out.duration = obj['duration'];

  if (goog.isDefAndNotNull(obj['sources'])) {
    var len = obj['sources'].length;
    /** @type {Array.<vit.api.CivicInfo.Source>} */
    var sourcesArray = [];
    for (var i = 0; i < len; i++) {
      sourcesArray[i] = this.transformSource(obj['sources'][i]);
    }
    out.sources = sourcesArray;
  }
  return /** @type {vit.api.CivicInfo.PollingLocation} */ (out);
};

/**
 * Transform raw object into Candidate.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Candidate} Transformed object.
 */
vit.api.CivicInfo.prototype.transformCandidate = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Candidate} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.party = obj['party'];
  out.candidateUrl = obj['candidateUrl'];
  out.phone = obj['phone'];
  out.photoUrl = obj['photoUrl'];
  out.email = obj['email'];
  out.orderOnBallot = obj['orderOnBallot'];
  out.channels = this.transformChannels(obj['channels']);
  return /** @type {vit.api.CivicInfo.Candidate} */ (out);
};

/**
 * Transform raw object into AdministrationRegion.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.AdministrationRegion} Transformed object.
 */
vit.api.CivicInfo.prototype.transformAdministrationRegion = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.AdministrationRegion} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.electionAdministrationBody = this.transformElectionAdministrationBody(
      obj['electionAdministrationBody']);
  out.local_jurisdiction = this.transformAdministrationRegion(
      obj['local_jurisdiction']);

  if (goog.isDefAndNotNull(obj['sources'])) {
    var len = obj['sources'].length;
    /** @type {Array.<vit.api.CivicInfo.Source>} */
    var sourcesArray = [];
    for (var i = 0; i < len; i++) {
      sourcesArray[i] = this.transformSource(obj['sources'][i]);
    }
    out.sources = sourcesArray;
  }
  return /** @type {vit.api.CivicInfo.AdministrationRegion} */ (out);
};

/**
 * Transform raw object into ElectionAdministrationBody.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.ElectionAdministrationBody} Transformed object.
 */
vit.api.CivicInfo.prototype.transformElectionAdministrationBody =
    function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.ElectionAdministrationBody} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.electionInfoUrl = obj['electionInfoUrl'];
  out.electionRegistrationUrl = obj['electionRegistrationUrl'];
  out.electionRegistrationConfirmationUrl =
      obj['electionRegistrationConfirmationUrl'];
  out.absenteeVotingInfoUrl = obj['absenteeVotingInfoUrl'];
  out.votingLocationFinderUrl = obj['votingLocationFinderUrl'];
  out.ballotInfoUrl = obj['ballotInfoUrl'];
  out.electionRulesUrl = obj['electionRulesUrl'];
  out.voter_services = obj['voter_services'];
  out.hoursOfOperation = obj['hoursOfOperation'];
  out.correspondenceAddress = this.transformAddress(
      obj['correspondenceAddress']);
  out.physicalAddress = this.transformAddress(obj['physicalAddress']);

  if (goog.isDefAndNotNull(obj['electionOfficials'])) {
    var len = obj['electionOfficials'].length;
    /** @type {Array.<vit.api.CivicInfo.ElectionOfficial>} */
    var electionOfficialsArray = [];
    for (var i = 0; i < len; i++) {
      electionOfficialsArray[i] = this.transformElectionOfficial(
          obj['electionOfficials'][i]);
    }
    out.electionOfficials = electionOfficialsArray;
  }

  if (goog.isDefAndNotNull(obj['sources'])) {
    len = obj['sources'].length;
    /** @type {Array.<vit.api.CivicInfo.Source>} */
    var sourcesArray = [];
    for (var i = 0; i < len; i++) {
      sourcesArray[i] = this.transformSource(obj['sources'][i]);
    }
    out.sources = sourcesArray;
  }
  return /** @type {vit.api.CivicInfo.ElectionAdministrationBody} */ (out);
};

/**
 * Transform raw object into Source.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Source} Transformed object.
 */
vit.api.CivicInfo.prototype.transformSource = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Source} */ (obj);
  }

  var out = {};
  out.name = obj['name'];
  out.official = obj['official'];
  return /** @type {vit.api.CivicInfo.Source} */ (out);
};

/**
 * Transform raw object into Response.
 * @param {Object} obj Raw object to transform.
 * @return {vit.api.CivicInfo.Response} Transformed object.
 */
vit.api.CivicInfo.prototype.transformResponse = function(obj) {
  if (!goog.isDefAndNotNull(obj)) {
    return /** @type {vit.api.CivicInfo.Response} */ (obj);
  }

  var out = {};
  // TODO(jmwaura): No transform method for status. Treating as literal.
  out.status = obj['status'];
  out.election = this.transformElection(obj['election']);
  out.normalizedInput = this.transformAddress(obj['normalizedInput']);

  var len;

  if (goog.isDefAndNotNull(obj['pollingLocations'])) {
    len = obj['pollingLocations'].length;
    /** @type {Array.<vit.api.CivicInfo.PollingLocation>} */
    var pollingLocationsArray = [];
    for (var i = 0; i < len; i++) {
      pollingLocationsArray[i] = this.transformPollingLocation(
          obj['pollingLocations'][i]);
    }
    out.pollingLocations = pollingLocationsArray.sort(
        vit.api.CivicInfo.comparePollingLocations);
  }

  if (goog.isDefAndNotNull(obj['earlyVoteSites'])) {
    len = obj['earlyVoteSites'].length;
    /** @type {Array.<vit.api.CivicInfo.PollingLocation>} */
    var earlyVoteSitesArray = [];
    for (var i = 0; i < len; i++) {
      earlyVoteSitesArray[i] = this.transformPollingLocation(
        obj['earlyVoteSites'][i]);
    }
    out.earlyVoteSites = earlyVoteSitesArray.sort(
        vit.api.CivicInfo.comparePollingLocations);
  }

  if (goog.isDefAndNotNull(obj['contests'])) {
    len = obj['contests'].length;
    /** @type {Array.<vit.api.CivicInfo.Contest>} */
    var contestsArray = [];
    for (var i = 0; i < len; i++) {
      contestsArray[i] = this.transformContest(obj['contests'][i]);
    }
    contestsArray = goog.array.filter(contestsArray, function(contest) {
      return (contest.candidates && contest.candidates.length) ? true : false;
    });
    out.contests = contestsArray.sort(function(a, b) {
      // Sort by level.
      var comparison = (a && a.level &&
          vit.api.CivicInfo.LEVEL_ORDER[a.level] ||
          Number.MAX_VALUE) - (b && b.level &&
          vit.api.CivicInfo.LEVEL_ORDER[b.level] || Number.MAX_VALUE);
      if (comparison != 0) {
        return comparison;
      }

      // Then by scope.
      comparison = (a && a.district && a.district.scope &&
          vit.api.CivicInfo.SCOPE_ORDER[a.district.scope] ||
          Number.MAX_VALUE) - (b && b.district && b.district.scope &&
          vit.api.CivicInfo.SCOPE_ORDER[b.district.scope] ||
          Number.MAX_VALUE);
      if (comparison != 0) {
        return comparison;
      }

      // then by ballot placement.
      comparison = (a && a.ballotPlacement || Number.MAX_VALUE) -
          (b && b.ballotPlacement || Number.MAX_VALUE);
      if (comparison != 0) {
        return comparison;
      }

      // TODO(jmwaura): The rest of these are a hack and need to be cleaned up.
      // President
      if (a && a.office && a.office.toLowerCase().indexOf('president') >= 0) {
        return -1;
      } else if (b && b.office &&
          b.office.toLowerCase().indexOf('president') >= 0) {
        return 1;
      }
      // Governor
      if (a && a.office && a.office.toLowerCase().indexOf('governor') >= 0) {
        return -1;
      } else if (b && b.office &&
          b.office.toLowerCase().indexOf('governor') >= 0) {
        return 1;
      }
      // Senator
      if (a && a.office && a.office.toLowerCase().indexOf('senat') >= 0) {
        return -1;
      } else if (b && b.office &&
          b.office.toLowerCase().indexOf('senat') >= 0) {
        return 1;
      }
      // Representative
      if (a && a.office && a.office.toLowerCase().indexOf('represent') >= 0) {
        return -1;
      } else if (b && b.office &&
          b.office.toLowerCase().indexOf('represent') >= 0) {
        return 1;
      }
      // Representative
      if (a && a.office && a.office.toLowerCase().indexOf('chair') >= 0) {
        return -1;
      } else if (b && b.office &&
          b.office.toLowerCase().indexOf('chair') >= 0) {
        return 1;
      }

      return 0;
    });
  }

  if (goog.isDefAndNotNull(obj['state'])) {
    len = obj['state'].length;
    /** @type {Array.<vit.api.CivicInfo.AdministrationRegion>} */
    var stateArray = [];
    for (var i = 0; i < len; i++) {
      stateArray[i] = this.transformAdministrationRegion(obj['state'][i]);
    }
    out.state = stateArray;
  }
  return /** @type {vit.api.CivicInfo.Response} */ (out);
};

/**
 * Sort polling locations and early vote sites by distance.
 * This method will also append the distance data to the Polling Locations.
 * @param {function((!Object|boolean), string)} callback The function to call
 *   when the sorting completes.
 * @param {!Object|boolean} civicInfo The response object
 *   whose locations to sort.
 * @param {string} raw The raw API response to pass through to the callback.
 */
vit.api.CivicInfo.prototype.appendDistance =
    function(callback, civicInfo, raw) {
  if ((civicInfo['pollingLocations'] && civicInfo['pollingLocations'].length) ||
    (civicInfo['earlyVoteSites'] && civicInfo['earlyVoteSites'].length)) {
    // Add polling locations and early vote sites to an array.
    var locationArray = [];
    var addressArray = [];
    if (civicInfo['pollingLocations'] && civicInfo['pollingLocations'].length) {
      goog.array.extend(locationArray, civicInfo['pollingLocations']);
    }
    if (civicInfo['earlyVoteSites'] && civicInfo['earlyVoteSites'].length) {
      goog.array.extend(locationArray, civicInfo['earlyVoteSites']);
    }
    for (var i = 0; i < locationArray.length; i++) {
      if (locationArray[i].address) {
        addressArray.push(vit.api.CivicInfo.addressToString(
            locationArray[i].address, true, true));
      } else {
        // Abort.
        callback(civicInfo, raw);
      }
    }

    var origin = vit.api.CivicInfo.addressToString(
        civicInfo['normalizedInput']);

    var distanceService = vit.api.Distance.getInstance();
    distanceService.getDistances(origin, addressArray, function(distances) {
      if (!distances || !distances.length) {
        // There was an issue getting distances. Abort.
        callback(civicInfo, raw);
      } else {
        for (var i = 0; i < distances.length; i++) {
          locationArray[i]['distance'] = distances[i]['distance'];
          locationArray[i]['duration'] = distances[i]['duration'];
        }
        callback(civicInfo, raw);
      }
    });

  } else {
    callback(civicInfo, raw);
  }
};

/**
 * @override
 */
vit.api.CivicInfo.prototype.disposeInternal = function() {
  this.context_ = null;

  goog.base(this, 'disposeInternal');
};

/**
 * Formats an address object as a string.
 * @param {vit.api.CivicInfo.Address} address Address to format.
 * @param {boolean=} opt_ignoreLocationName Whether to ignore the location name.
 * @param {boolean=} opt_ignoreZip Whether to ignore the zip code.
 * @return {string} The string representation of the address.
 */
vit.api.CivicInfo.addressToString = function(address, opt_ignoreLocationName,
    opt_ignoreZip) {
  var addressStr = '';
  if (!address) {
    return addressStr;
  }

  if (!opt_ignoreLocationName) {
    addressStr += address.locationName ? address.locationName + ', ' : '';
  }
  addressStr += address.line1 ? address.line1 + ', ' : '';
  addressStr += address.line2 ? address.line2 + ', ' : '';
  addressStr += address.line3 ? address.line3 + ', ' : '';
  addressStr += address.city ? address.city + ', ' : '';
  addressStr += address.state ? address.state + ' ' : '';
  if (!opt_ignoreZip) {
    addressStr += address.zip ? address.zip : '';
  }

  // Remove trailing characters.
  addressStr = goog.string.trim(addressStr);
  if (addressStr.charAt(addressStr.length - 1) == ',') {
    addressStr = addressStr.substring(0, addressStr.length - 1);
  }
  return addressStr;
};

/**
 * Compares two polling locations for sorting.
 * @param {vit.api.CivicInfo.PollingLocation} a First polling location.
 * @param {vit.api.CivicInfo.PollingLocation} b Second polling location.
 * @return {number} a - b.
 */
vit.api.CivicInfo.comparePollingLocations = function(a, b) {
  return (a && a.distance && a.distance.value || Number.MAX_VALUE) -
      (b && b.distance && b.distance.value || Number.MAX_VALUE);
};

/**
 * The order by which to sort office levels in contests.
 * @type {Object.<string, number>}
 * @const
 */
vit.api.CivicInfo.LEVEL_ORDER = {
  'federal': 1,
  'state': 2,
  'county': 3,
  'city': 4,
  'other': 5
};

/**
 * The order by which to sort scoped contests.
 * @type {Object.<string, number>}
 * @const
 */
vit.api.CivicInfo.SCOPE_ORDER = {
  'statewide': 1,
  'congressional': 2,
  'stateUpper': 3,
  'stateLower': 4,
  'countywide': 5,
  'judicial': 6,
  'schoolBoard': 7,
  'cityWide': 8,
  'special': 9
};

/**
 * The default API path.
 * @type {string}
 * @const
 * TODO(jmwaura): make api version configurable.
 */
vit.api.CivicInfo.API_PATH = '/civicinfo/us_v1/voterinfo';

/**
 * Enum of the potential values for status.
 * @enum {string}
 */
vit.api.CivicInfo.Status = {
  SUCCESS: 'success',
  NO_STREET_SEGMENT_FOUND: 'noStreetSegmentFound',
  ADDRESS_UNPARSEABLE: 'addressUnparseable',
  NO_ADDRESS_PARAMETER: 'noAddressParameter',
  MULTIPLE_STREET_SEGMENTS_FOUND: 'multipleStreetSegmentsFound',
  ELECTION_OVER: 'electionOver',
  ELECTION_UNKNOWN: 'electionUnknown',
  INTERNAL_LOOKUP_FAILURE: 'internalLookupFailure',
  REQUEST_FAILURE: 'REQUEST_FAILURE'
};

/**
 * Type definition of Civic Info response.
 * @typedef {{
 *   requestTrigger: string,
 *   status: vit.api.CivicInfo.Status,
 *   election: vit.api.CivicInfo.Election,
 *   normalizedInput: vit.api.CivicInfo.Address,
 *   pollingLocations: Array.<vit.api.CivicInfo.PollingLocation>,
 *   earlyVoteSites: Array.<vit.api.CivicInfo.PollingLocation>,
 *   contests: Array.<vit.api.CivicInfo.Contest>,
 *   state: Array.<vit.api.CivicInfo.AdministrationRegion>
 * }}
 */
vit.api.CivicInfo.Response;

/**
 * Type definition of Election.
 * @typedef {{
 *   id: number,
 *   name: string,
 *   electionDay: string
 * }}
 */
vit.api.CivicInfo.Election;

/**
 * Type definition of Address.
 * @typedef {{
 *   locationName: string,
 *   line1: string,
 *   line2: string,
 *   line3: string,
 *   city: string,
 *   state: string,
 *   zip: string
 * }}
 */
vit.api.CivicInfo.Address;

/**
 * Type definition of PollingLocation.
 * @typedef {{
 *   address: vit.api.CivicInfo.Address,
 *   notes: string,
 *   pollingHours: string,
 *   name: string,
 *   voterServices: string,
 *   startDate: string,
 *   endDate: string,
 *   sources: Array.<vit.api.CivicInfo.Source>,
 *   distance: google.maps.Distance,
 *   duration: google.maps.Duration
 * }}
 */
vit.api.CivicInfo.PollingLocation;

/**
 * Type definition of Contest.
 * @typedef {{
 *   type: string,
 *   primaryParty: string,
 *   electorateSpecifications: string,
 *   special: string,
 *   office: string,
 *   level: string,
 *   district: vit.api.CivicInfo.District,
 *   numberElected: number,
 *   numberVotingFor: number,
 *   ballotPlacement: number,
 *   candidates: Array.<vit.api.CivicInfo.Candidate>,
 *   sources: Array.<vit.api.CivicInfo.Source>
 * }}
 */
vit.api.CivicInfo.Contest;

/**
 * Type definition of District.
 * @typedef {{
 *   name: string,
 *   scope: string,
 *   id: string
 * }}
 */
vit.api.CivicInfo.District;

/**
 * Type definition of Candidate.
 * @typedef {{
 *   name: string,
 *   party: string,
 *   candidateUrl: string,
 *   phone: string,
 *   photoUrl: string,
 *   email: string,
 *   orderOnBallot: number,
 *   channels: vit.api.CivicInfo.Channels
 * }}
 */
vit.api.CivicInfo.Candidate;

/**
 * Type definition of Channel.
 * @typedef {{
 *   googleplus: string,
 *   youtube: string,
 *   facebook: string,
 *   twitter: string
 * }}
 */
vit.api.CivicInfo.Channels;

/**
 * Type definition of Source.
 * @typedef {{
 *   name: string,
 *   official: boolean
 * }}
 */
vit.api.CivicInfo.Source;

/**
 * Type definition of AdministrationRegion.
 * @typedef {{
 *   name: string,
 *   electionAdministrationBody: vit.api.CivicInfo.ElectionAdministrationBody,
 *   local_jurisdiction: vit.api.CivicInfo.AdministrationRegion,
 *   sources: Array.<vit.api.CivicInfo.Source>
 * }}
 */
vit.api.CivicInfo.AdministrationRegion;

/**
 * Type definition of ElectionAdministrationBody.
 * @typedef {{
 *   name: string,
 *   electionInfoUrl: string,
 *   electionRegistrationUrl: string,
 *   electionRegistrationConfirmationUrl: string,
 *   absenteeVotingInfoUrl: string,
 *   votingLocationFinderUrl: string,
 *   ballotInfoUrl: string,
 *   electionRulesUrl: string,
 *   voter_services: Array.<string>,
 *   hoursOfOperation: string,
 *   correspondenceAddress: vit.api.CivicInfo.Address,
 *   physicalAddress: vit.api.CivicInfo.Address,
 *   electionOfficials: Array.<vit.api.CivicInfo.ElectionOfficial>,
 *   sources: Array.<vit.api.CivicInfo.Source>
 * }}
 */
vit.api.CivicInfo.ElectionAdministrationBody;

/**
 * Type definition of ElectionOfficial.
 * @typedef {{
 *   name: string,
 *   title: string,
 *   officePhoneNumber: string,
 *   faxNumber: string,
 *   emailAddress: string
 * }}
 */
vit.api.CivicInfo.ElectionOfficial;


text:
package com.qlm.similitude.lsh.measure;

import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentSkipListSet;

public class HistogramStatistics
{
  public static Double average(final Map<Integer, Integer> histogram) {
    return HistogramStatistics.mean(histogram);
  }

  public static Double mean(final Map<Integer, Integer> histogram) {
    double sum = 0L;
    for (Integer value : histogram.keySet()) {
      sum += (value * histogram.get(value));
    }

    return sum / (double) HistogramStatistics.count(histogram);
  }

  public static Double percentile(final Map<Integer, Integer> histogram, final double percent) {
    if ((percent < 0d) || (percent > 1d)) {
      throw new IllegalArgumentException("Percentile must be between 0.00 and 1.00.");
    }

    if ((histogram == null) || histogram.isEmpty()) {
      return null;
    }

    double n = (percent * (HistogramStatistics.count(histogram).doubleValue() - 1d)) + 1d;
    double d = n - Math.floor(n);
    SortedSet<Integer> bins = new ConcurrentSkipListSet<>(histogram.keySet());
    long observationsBelowBinInclusive = 0L;
    Integer lowBin = bins.first();
    Double valuePercentile = null;

    for (Integer highBin : bins) {
      observationsBelowBinInclusive += histogram.get(highBin);

      if (n <= observationsBelowBinInclusive) {
        if ((d == 0f) || (histogram.get(highBin) > 1L)) {
          lowBin = highBin;
        }
        valuePercentile = lowBin.doubleValue() + ((highBin - lowBin) * d);
        break;
      }
      lowBin = highBin;
    }
    return valuePercentile;
  }

  public static Long count(final Map<Integer, Integer> histogram) {
    long observations = 0L;
    for (Integer value : histogram.keySet()) {
      observations += histogram.get(value);
    }

    return observations;
  }
}

redpajama_set_name: RedPajamaGithub


text:
/*!
Video.js Default Styles (http://videojs.com)
Version 4.1.0
Create your own skin at http://designer.videojs.com
*/
/* SKIN
================================================================================
The main class name for all skin-specific styles. To make your own skin,
replace all occurances of 'vjs-default-skin' with a new name. Then add your new
skin name to your video tag instead of the default skin.
e.g. <video class="video-js my-skin-name">
*/
.vjs-default-skin {
    color: #888888;
}
/* Custom Icon Font
--------------------------------------------------------------------------------
The control icons are from a custom font. Each icon corresponds to a character
(e.g. "\e001"). Font icons allow for easy scaling and coloring of icons.
*/
@font-face {
    font-family: 'VideoJS';
    src: url('font/vjs.eot');
    src: url('font/vjs.eot?#iefix') format('embedded-opentype'), url('font/vjs.woff') format('woff'), url('font/vjs.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

/* Base UI Component Classes
--------------------------------------------------------------------------------
*/
/* Slider - used for Volume bar and Seek bar */
.vjs-default-skin .vjs-slider {
    /* Replace browser focus hightlight with handle highlight */
    outline: 0;
    position: relative;
    cursor: pointer;
    padding: 0;
    /* background-color-with-alpha */
    background-color: #333333;
    background-color: rgba(51, 51, 51, 0.9);
}
.vjs-default-skin .vjs-slider:focus {
    /* box-shadow */
    -webkit-box-shadow: 0 0 2em #ffffff;
    -moz-box-shadow: 0 0 2em #ffffff;
    box-shadow: 0 0 2em #ffffff;
}
.vjs-default-skin .vjs-slider-handle {
    position: absolute;
    /* Needed for IE6 */
    left: 0;
    top: 0;
}
.vjs-default-skin .vjs-slider-handle:before {
    content: "\e009";
    font-family: VideoJS;
    font-size: 1em;
    line-height: 1;
    text-align: center;
    text-shadow: 0em 0em 1em #fff;
    position: absolute;
    top: 0;
    left: 0;
    /* Rotate the square icon to make a diamond */
    /* transform */
    -webkit-transform: rotate(-45deg);
    -moz-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    -o-transform: rotate(-45deg);
    transform: rotate(-45deg);
    color: #fff;
}
/* Control Bar
--------------------------------------------------------------------------------
The default control bar that is a container for most of the controls.
*/
.vjs-default-skin .vjs-control-bar {
    /* Start hidden */
    display: none;
    position: absolute;
    /* Place control bar at the bottom of the player box/video.
    If you want more margin below the control bar, add more height. */
    bottom: 0;
    /* Use left/right to stretch to 100% width of player div */
    left: 0;
    right: 0;
    /* Height includes any margin you want above or below control items */
    height: 3.3em;
    /* background-color-with-alpha */
    background-color: #333333;
    background-color: rgba(51, 51, 51, 0.7);
}
/* General styles for individual controls. */
.vjs-default-skin .vjs-control {
    outline: none;
    position: relative;
    float: left;
    text-align: center;
    margin: 0;
    padding: 0;
    height: 3.0em;
    width: 4em;
}
/* FontAwsome button icons */
.vjs-default-skin .vjs-control:before {
    font-family: VideoJS;
    font-size: 1.5em;
    line-height: 2;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    text-align: center;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}
/* Replacement for focus outline */
.vjs-default-skin .vjs-control:focus:before,
.vjs-default-skin .vjs-control:hover:before {
    color: #fff;
    text-shadow: 0em 0em 1em #ffffff;
}
.vjs-default-skin .vjs-control:focus {
    /*  outline: 0; */
    /* keyboard-only users cannot see the focus on several of the UI elements when
    this is set to 0 */
}
/* Hide control text visually, but have it available for screenreaders */
.vjs-default-skin .vjs-control-text {
    /* hide-visually */
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
}
/* Play/Pause
--------------------------------------------------------------------------------
*/
.vjs-default-skin .vjs-play-control {
    width: 5em;
    cursor: pointer;
}
.vjs-default-skin .vjs-play-control:before {
    content: "\e001";
}
.vjs-default-skin.vjs-playing .vjs-play-control:before {
    content: "\e002";
}
/* Volume/Mute
-------------------------------------------------------------------------------- */
.vjs-default-skin .vjs-mute-control,
.vjs-default-skin .vjs-volume-menu-button {
    cursor: pointer;
    float: right;
}
.vjs-default-skin .vjs-mute-control:before,
.vjs-default-skin .vjs-volume-menu-button:before {
    content: "\e006";
}
.vjs-default-skin .vjs-mute-control.vjs-vol-0:before,
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-0:before {
    content: "\e003";
}
.vjs-default-skin .vjs-mute-control.vjs-vol-1:before,
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-1:before {
    content: "\e004";
}
.vjs-default-skin .vjs-mute-control.vjs-vol-2:before,
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-2:before {
    content: "\e005";
}
.vjs-default-skin .vjs-volume-control {
    width: 5em;
    float: right;
}
.vjs-default-skin .vjs-volume-bar {
    width: 5em;
    height: 0.6em;
    margin: 1.1em auto 0;
}
.vjs-default-skin .vjs-volume-menu-button .vjs-menu-content {
    height: 2.9em;
}
.vjs-default-skin .vjs-volume-level {
    position: absolute;
    top: 0;
    left: 0;
    height: 0.5em;
    background: #b40c1e url() -50% 0 repeat;
}
.vjs-default-skin .vjs-volume-bar .vjs-volume-handle {
    width: 0.5em;
    height: 0.5em;
}
.vjs-default-skin .vjs-volume-handle:before {
    font-size: 0.9em;
    top: -0.2em;
    left: -0.2em;
    width: 1em;
    height: 1em;
}
.vjs-default-skin .vjs-volume-menu-button .vjs-menu .vjs-menu-content {
    width: 6em;
    left: -4em;
}
/* Progress
--------------------------------------------------------------------------------
*/
.vjs-default-skin .vjs-progress-control {
    position: absolute;
    left: 0;
    right: 0;
    width: auto;
    font-size: 0.3em;
    height: 1em;
    /* Set above the rest of the controls. */
    top: -1em;
    /* Shrink the bar slower than it grows. */
    /* transition */
    -webkit-transition: all 0.4s;
    -moz-transition: all 0.4s;
    -o-transition: all 0.4s;
    transition: all 0.4s;
}
/* On hover, make the progress bar grow to something that's more clickable.
This simply changes the overall font for the progress bar, and this
updates both the em-based widths and heights, as wells as the icon font */
.vjs-default-skin:hover .vjs-progress-control {
    font-size: .9em;
    /* Even though we're not changing the top/height, we need to include them in
    the transition so they're handled correctly. */
    /* transition */
    -webkit-transition: all 0.2s;
    -moz-transition: all 0.2s;
    -o-transition: all 0.2s;
    transition: all 0.2s;
}
/* Box containing play and load progresses. Also acts as seek scrubber. */
.vjs-default-skin .vjs-progress-holder {
    height: 100%;
}
/* Progress Bars */
.vjs-default-skin .vjs-progress-holder .vjs-play-progress,
.vjs-default-skin .vjs-progress-holder .vjs-load-progress {
    position: absolute;
    display: block;
    height: 100%;
    margin: 0;
    padding: 0;
    /* Needed for IE6 */
    left: 0;
    top: 0;
}
.vjs-default-skin .vjs-play-progress {
    /*
    Using a data URI to create the white diagonal lines with a transparent
    background. Surprisingly works in IE8.
    Created using http://www.patternify.com
    Changing the first color value will change the bar color.
    Also using a paralax effect to make the lines move backwards.
    The -50% left position makes that happen.
    */
    background: #b40c1e url() -50% 0 repeat;
}
.vjs-default-skin .vjs-load-progress {
    background: #757575;
}
.vjs-default-skin .vjs-seek-handle {
    width: 1.5em;
    height: 100%;
}
.vjs-default-skin .vjs-seek-handle:before {
    padding-top: 0.1em /* Minor adjustment */;
}
/* Time Display
--------------------------------------------------------------------------------
*/
.vjs-default-skin .vjs-time-controls {
    font-size: 1em;
    /* Align vertically by making the line height the same as the control bar */
    line-height: 3em;
}
.vjs-default-skin .vjs-current-time {
    float: left;
}
.vjs-default-skin .vjs-duration {
    float: left;
}
/* Remaining time is in the HTML, but not included in default design */
.vjs-default-skin .vjs-remaining-time {
    display: none;
    float: left;
}
.vjs-time-divider {
    float: left;
    line-height: 3em;
}
/* Fullscreen
--------------------------------------------------------------------------------
*/
.vjs-default-skin .vjs-fullscreen-control {
    cursor: pointer;
    float: right;
}
.vjs-default-skin .vjs-fullscreen-control:before {
    content: "\e000";
}
/* Switch to the exit icon when the player is in fullscreen */
.vjs-default-skin.vjs-fullscreen .vjs-fullscreen-control:before {
    content: "\e00b";
}
/* Big Play Button (play button at start)
--------------------------------------------------------------------------------
Positioning of the play button in the center or other corners can be done more
easily in the skin designer. http://designer.videojs.com/
*/
.vjs-default-skin .vjs-big-play-button {
    /* Center it horizontally */
    left: 50%;
    margin-left: -1em;
    /* Center it vertically */
    top: 50%;
    margin-top: -0.6em;
    font-size: 5em;
    color: #fff;
    display: block;
    z-index: 2;
    position: absolute;
    width: 2em;
    height: 1.2em;
    text-align: center;
    vertical-align: middle;
    cursor: pointer;
    opacity: 1;
    /* Need a slightly gray bg so it can be seen on black backgrounds */
    /* background-color-with-alpha */
    background-color: #b40c1e;
    border: 0em solid #3b4249;
    /* border-radius */
    -webkit-border-radius: 0.3em;
    -moz-border-radius: 0.3em;
    border-radius: 0.3em;
    /* box-shadow */
    -webkit-box-shadow: 0px 0px 1em rgba(255, 255, 255, 0.25);
    -moz-box-shadow: 0px 0px 1em rgba(255, 255, 255, 0.25);
    box-shadow: 0px 0px 1em rgba(255, 255, 255, 0.25);
    /* transition */
    -webkit-transition: all 0.4s;
    -moz-transition: all 0.4s;
    -o-transition: all 0.4s;
    transition: all 0.4s;
}
.vjs-default-skin:hover .vjs-big-play-button,
.vjs-default-skin .vjs-big-play-button:focus {
    outline: 0;
    border-color: #fff;
    /* IE8 needs a non-glow hover state */
    background-color: #505050;
    background-color: rgba(50, 50, 50, 0.75);
    /* box-shadow */
    -webkit-box-shadow: 0 0 3em #ffffff;
    -moz-box-shadow: 0 0 3em #ffffff;
    box-shadow: 0 0 3em #ffffff;
    /* transition */
    -webkit-transition: all 0s;
    -moz-transition: all 0s;
    -o-transition: all 0s;
    transition: all 0s;
}
.vjs-default-skin .vjs-big-play-button:before {
    content: "\e001";
    font-family: VideoJS;
    /* In order to center the play icon vertically we need to set the line height
    to the same as the button height */
    line-height: 1.2em;
    text-shadow: none;
    text-align: center /* Needed for IE8 */;
    position: absolute;
    left: 0;
    width: 100%;
    height: 100%;
}
/* Loading Spinner
--------------------------------------------------------------------------------
*/
.vjs-loading-spinner {
    display: none;
    position: absolute;
    top: 50%;
    left: 50%;
    font-size: 5em;
    line-height: 1;
    width: 1em;
    height: 1em;
    margin-left: -0.5em;
    margin-top: -0.5em;
    opacity: 0.75;
    /* animation */
    -webkit-animation: spin 1.5s infinite linear;
    -moz-animation: spin 1.5s infinite linear;
    -o-animation: spin 1.5s infinite linear;
    animation: spin 1.5s infinite linear;
}
.vjs-default-skin .vjs-loading-spinner:before {
    content: "\e00a";
    font-family: VideoJS;
    position: absolute;
    width: 1em;
    height: 1em;
    text-align: center;
    text-shadow: 0em 0em 0.1em #000;
}
/* Add a gradient to the spinner by overlaying another copy.
Text gradient plus a text shadow doesn't work
and `background-clip: text` only works in Webkit. */
.vjs-default-skin .vjs-loading-spinner:after {
    content: "\e00a";
    /* Loading spinner icon */
    font-family: VideoJS;
    position: absolute;
    width: 1em;
    height: 1em;
    text-align: center;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}
@-moz-keyframes spin {
    0% {
        -moz-transform: rotate(0deg);
    }
    100% {
        -moz-transform: rotate(359deg);
    }
}
@-webkit-keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(359deg);
    }
}
@-o-keyframes spin {
    0% {
        -o-transform: rotate(0deg);
    }
    100% {
        -o-transform: rotate(359deg);
    }
}
@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(359deg);
    }
}
/* Menu Buttons (Captions/Subtitles/etc.)
--------------------------------------------------------------------------------
*/
.vjs-default-skin .vjs-menu-button {
    float: right;
    cursor: pointer;
}
.vjs-default-skin .vjs-menu {
    display: none;
    position: absolute;
    bottom: 0;
    left: 0em;
    /* (Width of vjs-menu - width of button) / 2 */
    width: 0em;
    height: 0em;
    margin-bottom: 3em;
    border-left: 2em solid transparent;
    border-right: 2em solid transparent;
    border-top: 1.55em solid #000000;
    /* Same width top as ul bottom */
    border-top-color: rgba(7, 40, 50, 0.5);
    /* Same as ul background */
}
/* Button Pop-up Menu */
.vjs-default-skin .vjs-menu-button .vjs-menu .vjs-menu-content {
    display: block;
    padding: 0;
    margin: 0;
    position: absolute;
    width: 10em;
    bottom: 1.5em;
    /* Same bottom as vjs-menu border-top */
    max-height: 15em;
    overflow: auto;
    left: -5em;
    /* Width of menu - width of button / 2 */
    /* background-color-with-alpha */
    background-color: #333333;
    background-color: rgba(51, 51, 51, 0.7);
    /* box-shadow */
    -webkit-box-shadow: -0.2em -0.2em 0.3em rgba(255, 255, 255, 0.2);
    -moz-box-shadow: -0.2em -0.2em 0.3em rgba(255, 255, 255, 0.2);
    box-shadow: -0.2em -0.2em 0.3em rgba(255, 255, 255, 0.2);
}
.vjs-default-skin .vjs-menu-button:hover .vjs-menu {
    display: block;
}
.vjs-default-skin .vjs-menu-button ul li {
    list-style: none;
    margin: 0;
    padding: 0.3em 0 0.3em 0;
    line-height: 1.4em;
    font-size: 1.2em;
    text-align: center;
    text-transform: lowercase;
}
.vjs-default-skin .vjs-menu-button ul li.vjs-selected {
    background-color: #000;
}
.vjs-default-skin .vjs-menu-button ul li:focus,
.vjs-default-skin .vjs-menu-button ul li:hover,
.vjs-default-skin .vjs-menu-button ul li.vjs-selected:focus,
.vjs-default-skin .vjs-menu-button ul li.vjs-selected:hover {
    outline: 0;
    color: #111;
    /* background-color-with-alpha */
    background-color: #ffffff;
    background-color: rgba(255, 255, 255, 0.75);
    /* box-shadow */
    -webkit-box-shadow: 0 0 1em #ffffff;
    -moz-box-shadow: 0 0 1em #ffffff;
    box-shadow: 0 0 1em #ffffff;
}
.vjs-default-skin .vjs-menu-button ul li.vjs-menu-title {
    text-align: center;
    text-transform: uppercase;
    font-size: 1em;
    line-height: 2em;
    padding: 0;
    margin: 0 0 0.3em 0;
    font-weight: bold;
    cursor: default;
}
/* Subtitles Button */
.vjs-default-skin .vjs-subtitles-button:before {
    content: "\e00c";
}
/* Captions Button */
.vjs-default-skin .vjs-captions-button:before {
    content: "\e008";
}
/* Replacement for focus outline */
.vjs-default-skin .vjs-captions-button:focus .vjs-control-content:before,
.vjs-default-skin .vjs-captions-button:hover .vjs-control-content:before {
    /* box-shadow */
    -webkit-box-shadow: 0 0 1em #ffffff;
    -moz-box-shadow: 0 0 1em #ffffff;
    box-shadow: 0 0 1em #ffffff;
}
/*
REQUIRED STYLES (be careful overriding)
================================================================================
When loading the player, the video tag is replaced with a DIV,
that will hold the video tag or object tag for other playback methods.
The div contains the video playback element (Flash or HTML5) and controls,
and sets the width and height of the video.

** If you want to add some kind of border/padding (e.g. a frame), or special
positioning, use another containing element. Otherwise you risk messing up
control positioning and full window mode. **
*/
.video-js {
    background-color: #000;
    position: relative;
    padding: 0;
    /* Start with 10px for base font size so other dimensions can be em based and
    easily calculable. */
    font-size: 10px;
    /* Allow poster to be vertially aligned. */
    vertical-align: middle;
    /*  display: table-cell; */
    /*This works in Safari but not Firefox.*/
    /* Provide some basic defaults for fonts */
    font-weight: normal;
    font-style: normal;
    /* Avoiding helvetica: issue #376 */
    font-family: Arial, sans-serif;
    /* Turn off user selection (text highlighting) by default.
    The majority of player components will not be text blocks.
    Text areas will need to turn user selection back on. */
    /* user-select */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
/* Playback technology elements expand to the width/height of the containing div
<video> or <object> */
.video-js .vjs-tech {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
checking fullScreenEnabled. */
.video-js:-moz-full-screen {
    position: absolute;
}
/* Fullscreen Styles */
body.vjs-full-window {
    padding: 0;
    margin: 0;
    height: 100%;
    /* Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html */
    overflow-y: auto;
}
.video-js.vjs-fullscreen {
    position: fixed;
    overflow: hidden;
    z-index: 1000;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    width: 100% !important;
    height: 100% !important;
    /* IE6 full-window (underscore hack) */
    _position: absolute;
}
.video-js:-webkit-full-screen {
    width: 100% !important;
    height: 100% !important;
}
/* Poster Styles */
.vjs-poster {
    background-repeat: no-repeat;
    background-position: 50% 50%;
    background-size: contain;
    cursor: pointer;
    height: 100%;
    margin: 0;
    padding: 0;
    position: relative;
    width: 100%;
}
.vjs-poster img {
    display: block;
    margin: 0 auto;
    max-height: 100%;
    padding: 0;
    width: 100%;
}
/* Text Track Styles */
/* Overall track holder for both captions and subtitles */
.video-js .vjs-text-track-display {
    text-align: center;
    position: absolute;
    bottom: 4em;
    /* Leave padding on left and right */
    left: 1em;
    right: 1em;
}
/* Individual tracks */
.video-js .vjs-text-track {
    display: none;
    font-size: 1.4em;
    text-align: center;
    margin-bottom: 0.1em;
    /* Transparent black background, or fallback to all black (oldIE) */
    /* background-color-with-alpha */
    /*background-color: #000000;*/
    /*background-color: rgba(0, 0, 0, 0.5);*/
}
.video-js .vjs-subtitles {
    color: #ffffff /* Subtitles are white */;
}
.video-js .vjs-captions {
    color: #ffcc66 /* Captions are yellow */;
}
.vjs-tt-cue {
    display: block;
}
/* Fading sytles, used to fade control bar. */
.vjs-fade-in {
    display: block !important;
    /* Visibility needed to make sure things hide in older browsers too. */
    visibility: visible;
    opacity: 1;
    /* transition */
    -webkit-transition: visibility 0.1s, opacity 0.1s;
    -moz-transition: visibility 0.1s, opacity 0.1s;
    -o-transition: visibility 0.1s, opacity 0.1s;
    transition: visibility 0.1s, opacity 0.1s;
}
.vjs-fade-out {
    display: block !important;
    visibility: hidden;
    opacity: 0;
    /* transition */
    -webkit-transition: visibility 1.5s, opacity 1.5s;
    -moz-transition: visibility 1.5s, opacity 1.5s;
    -o-transition: visibility 1.5s, opacity 1.5s;
    transition: visibility 1.5s, opacity 1.5s;
    /* Wait a moment before fading out the control bar */
    /* transition-delay */
    /*
    -webkit-transition-delay: 2s;
    -moz-transition-delay: 2s;
    -o-transition-delay: 2s;
    transition-delay: 2s;
    */
}
/* Hide disabled or unsupported controls */
.vjs-default-skin .vjs-hidden {
    display: none;
}
.vjs-lock-showing {
    display: block !important;
    opacity: 1;
    visibility: visible;
}
/* -----------------------------------------------------------------------------
The original source of this file lives at
https://github.com/videojs/video.js/blob/master/src/css/video-js.less */

/* More buttons */
@font-face {
    font-family: 'glyphicons';
    src: url('/fonts/glyphicons-halflings-regular.eot');
    src: url('/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('/fonts/glyphicons-halflings-regular.woff') format('woff'), url('/fonts/glyphicons-halflings-regular.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

.vjs-default-skin .vjs-fontsize-button {
    width: 5em;
    cursor: pointer;
}
.vjs-default-skin .vjs-fontsize-button:before {
    font-family: glyphicons !important;
    content: "\e050";
    margin-top: 1px;
    font-size:  14px !important;
}

.vjs-default-skin .vjs-fontcolor-button:before {
    font-family: glyphicons !important;
    content: "\e048";
    margin-top: 1px;
    font-size:  14px !important;
}


text:
uint32_t _crc32(uint32_t crc,const void *buf,size_t size);
long _stripwhite(char *buf,int accept);
#define nn_errstr() nn_strerror(nn_errno())
#define SUPERNET_APIENDPOINT "tcp://127.0.0.1:7776"
char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params);
#define issue_POST(url,cmdstr) bitcoind_RPC(0,"curl",url,0,0,cmdstr)
char *os_compatible_path(char *str);
void randombytes(unsigned char *x,long xlen);

void process_json(cJSON *json,char *remoteaddr,int32_t localaccess)
{
    int32_t sock,len,checklen,sendtimeout,recvtimeout; uint32_t apitag; uint64_t tag;
    char endpoint[128],numstr[64],*resultstr,*jsonstr;
    jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' ');
    len = (int32_t)strlen(jsonstr)+1;
    apitag = _crc32(0,jsonstr,len);
    sprintf(endpoint,"ipc://api.%u",apitag);
    free(jsonstr);
    recvtimeout = get_API_int(cJSON_GetObjectItem(json,"timeout"),30000);
    sendtimeout = 30000;
    randombytes((uint8_t *)&tag,sizeof(tag));
    if ( cJSON_GetObjectItem(json,"tag") == 0 )
        sprintf(numstr,"%llu",(long long)tag), cJSON_AddItemToObject(json,"tag",cJSON_CreateString(numstr));
    if ( cJSON_GetObjectItem(json,"apitag") == 0 )
        cJSON_AddItemToObject(json,"apitag",cJSON_CreateString(endpoint));
    if ( remoteaddr != 0 )
        cJSON_AddItemToObject(json,"broadcast",cJSON_CreateString("remoteaccess"));
    if ( localaccess != 0 )
        cJSON_AddItemToObject(json,"localaccess",cJSON_CreateNumber(1));
    jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' ');
    //fprintf(stderr,"localacess.%d remote.(%s) jsonstr.(%s)\r\n",localaccess,remoteaddr!=0?remoteaddr:"",jsonstr);
    len = (int32_t)strlen(jsonstr)+1;
    if ( jsonstr != 0 )
    {
        if ( (sock= nn_socket(AF_SP,NN_PAIR)) >= 0 )
        {
            if ( sendtimeout > 0 && nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&sendtimeout,sizeof(sendtimeout)) < 0 )
                fprintf(stderr,"error setting sendtimeout %s\n",nn_errstr());
            if ( nn_connect(sock,SUPERNET_APIENDPOINT) < 0 )
                printf("error connecting to apiendpoint sock.%d type.%d (%s) %s\r\n",sock,NN_PUSH,SUPERNET_APIENDPOINT,nn_errstr());
            else if ( (checklen= nn_send(sock,jsonstr,len,0)) != len )
                printf("checklen.%d != len.%d for nn_send to (%s)\r\n",checklen,len,SUPERNET_APIENDPOINT);
            else
            {
                if ( recvtimeout > 0 && nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&recvtimeout,sizeof(recvtimeout)) < 0 )
                    fprintf(stderr,"error setting sendtimeout %s\n",nn_errstr());
                if ( nn_recv(sock,&resultstr,NN_MSG,0) > 0 )
                {
                    printf("Content-Length: %ld\r\n\r\n",strlen(resultstr)+2);
                    printf("%s\r\n",resultstr);
                    nn_freemsg(resultstr);
                } else printf("error getting results %s\r\n",nn_errstr());
            }
            nn_shutdown(sock,0);
        } else printf("error getting pushsock.%s\r\n",nn_errstr());
    }
    free(jsonstr);
}

int32_t setnxturl(char *urlbuf)
{
    FILE *fp; cJSON *json; char confname[512],buf[65536];
    strcpy(confname,"../../SuperNET.conf"), os_compatible_path(confname);
    urlbuf[0] = 0;
    if ( (fp= fopen(confname,"rb")) != 0 )
    {
        if ( fread(buf,1,sizeof(buf),fp) > 0 )
        {
            if ( (json= cJSON_Parse(buf)) != 0 )
            {
                copy_cJSON(urlbuf,cJSON_GetObjectItem(json,"NXTAPIURL"));
fprintf(stderr,"set NXTAPIURL.(%s)\n",urlbuf);
                free_json(json);
            } else fprintf(stderr,"setnxturl parse error.(%s)\n",buf);
        } else fprintf(stderr,"setnxturl error reading.(%s)\n",confname);
        fclose(fp);
    } else fprintf(stderr,"setnxturl cant open.(%s)\n",confname);
    return((int32_t)strlen(urlbuf));
}

int main(int argc, char **argv)
{
    void portable_OS_init();
    CGI_varlist *varlist; const char *name; char urlbuf[512],namebuf[512],postbuf[65536],*remoteaddr,*str=0,*retstr,*delim,*url = 0;
    int i,j,iter,localaccess=0,doneflag=0,portflag = 0; cJSON *json; long offset; CGI_value  *value;
    portable_OS_init();
    setenv("CONTENT_TYPE", "application/x-www-form-urlencoded", 1);
    json = cJSON_CreateObject();
    if ( (remoteaddr= getenv("REMOTE_ADDR")) == 0 || strncmp("127.0.0.1",remoteaddr,strlen("127.0.0.1")) == 0 )
        remoteaddr = 0,localaccess = 1;
    else cJSON_AddItemToObject(json,"remoteaddr",cJSON_CreateString(remoteaddr));
    for (i=j=0; argv[0][i]!=0; i++)
        if ( argv[0][i] == '/' || argv[0][i] == '\\' )
            j = i+1;
    strcpy(namebuf,&argv[0][j]);
    offset = strlen(namebuf) - 4;
    if ( offset > 0 && strcmp(".exe",namebuf + offset) == 0 )
        namebuf[offset] = 0;
    if ( strcmp(namebuf,"init") == 0 || strcmp(namebuf,"") == 0 || strcmp(namebuf,"index.cgi") == 0 )
    {
        // "http://178.63.60.131/init/?requestType=status&coin=VRC"
        //"http://78.47.115.250:7777/public?plugin=relay&method=busdata&servicename=MGW&serviceNXT=8119557380101451968&destplugin=MGW&submethod=status&coin=BTC"
        if ( strcmp(namebuf,"api") != 0 )
            cJSON_AddItemToObject(json,"agent",cJSON_CreateString(namebuf));
        cJSON_AddItemToObject(json,"plugin",cJSON_CreateString("relay"));
        cJSON_AddItemToObject(json,"method",cJSON_CreateString("busdata"));
        cJSON_AddItemToObject(json,"servicename",cJSON_CreateString("MGW"));
        cJSON_AddItemToObject(json,"serviceNXT",cJSON_CreateString("8119557380101451968"));
        cJSON_AddItemToObject(json,"destplugin",cJSON_CreateString("MGW"));
        if ( jstr(json,"requestType") != 0 )
            cJSON_AddItemToObject(json,"submethod",cJSON_CreateString(jstr(json,"requestType")));
    }
    if ( strcmp("nxt",namebuf) == 0 )
    {
        if ( setnxturl(urlbuf) != 0 )
            url = urlbuf;
        else url = "http://127.0.0.1:7876/nxt";
    }
    else if ( strcmp("nxts",namebuf) == 0 )
        url = "https://127.0.0.1:7876/nxt";
    else if ( strcmp("port",namebuf) == 0 )
        url = "http://127.0.0.1", portflag = 1;
    else if ( strcmp("ports",namebuf) == 0 )
        url = "https://127.0.0.1", portflag = 1;
    fprintf(stderr,"namebuf.(%s)\n",namebuf);
    if ( url != 0 )
         postbuf[0] = 0, delim = "";
    for (iter=0; iter<3; iter++)
    {
        if ( (varlist= ((iter==0) ? CGI_get_post(0,0) : ((iter==1) ? CGI_get_query(0) : CGI_get_cookie(0)))) != 0 )
        {
            for (name=CGI_first_name(varlist); name!=0&&doneflag==0; name=CGI_next_name(varlist))
            {
                value = CGI_lookup_all(varlist,0);
                for (i=0; value[i]!=0; i++)
                {
                fprintf(stderr,"iter.%d %s [%d] = %s\r\n",iter,name,i,value[i]);
                    if ( i == 0 )
                    {
                        if ( url == 0 )
                        {
                            if ( strcmp(name,"stringified") == 0 || strcmp(namebuf,"stringified") == 0 )
                            {
                                char *unstringify(char *str);
                                cJSON *obj;
                                if ( (obj= cJSON_Parse(name)) == 0 )
                                {
                                    str = malloc(strlen(value[i])+1);
                                    strcpy(str,value[i]);
                                    unstringify(str);
                                    printf("unstringify (%s) -> (%s)\n",value[i],str);
                                    obj= cJSON_Parse(str);
                                }
                                if ( obj != 0 )
                                {
                                    //unstringified ((null)) -> ({"stringified":{"method":"orderbook","baseid":"12071612744977229797","relid":"5527630","maxdepth":"1"},"agent":"InstantDEX"})
                                    free_json(json);
                                    if ( jobj(obj,"stringified") != 0 )
                                        json = cJSON_Duplicate(jobj(obj,"stringified"),1), free_json(obj);
                                    else json = obj;
                                    cJSON_AddItemToObject(json,"agent",cJSON_CreateString("InstantDEX"));
                                    if ( remoteaddr != 0 && remoteaddr[0] != 0 )
                                        cJSON_AddItemToObject(json,"remoteaddr",cJSON_CreateString(remoteaddr));
                                    fprintf(stderr,"unstringified (%s) -> (%s)\n",str!=0?str:"",jprint(json,0));
                                    if ( str != 0 )
                                        free(str);
                                    doneflag = 1;
                                    break;
                                }
                            }
                            cJSON_AddItemToObject(json,name,cJSON_CreateString(value[i]));
                        }
                        else
                        {
                            if ( portflag != 0 && strncmp(name,"port",strlen("port")) == 0 )
                                sprintf(urlbuf,"%s:%s",url,value[i]), url = urlbuf, portflag = 0;
                            else sprintf(postbuf + strlen(postbuf),"%s%s=%s",delim,name,value[i]), delim = "&";
                        }
                    }
                }
            }
        }
        CGI_free_varlist(varlist);
    }
    if ( localaccess == 0 )
        fputs("Access-Control-Allow-Origin: *\r\n",stdout);
    else fputs("Access-Control-Allow-Origin: null\r\n",stdout);
    fputs("Access-Control-Allow-Credentials: true\r\n",stdout);
    fputs("Access-Control-Allow-Headers: Authorization, Content-Type\r\n",stdout);
    fputs("Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n",stdout);
    fputs("Cache-Control: no-cache, no-store, must-revalidate\r\n",stdout);
    fputs("Content-type: text/plain\r\n",stdout);
    if ( url != 0 )
    {
fprintf(stderr,"url.(%s) (%s)\n",url,postbuf);
        if ( (retstr= issue_POST(url,postbuf)) != 0 )
        {
            //fprintf(stderr,"%s",retstr);
            printf("Content-Length: %ld\r\n\r\n",strlen(retstr)+2);
            printf("%s\r\n",retstr);
            free(retstr);
        } else printf("{\"error\":\"null return from issue_NXTPOST\"}\r\n");
    }
    else
    {
        if ( jobj(json,"agent") == 0 && strcmp(namebuf,"api") != 0 )
            cJSON_AddItemToObject(json,"agent",cJSON_CreateString(namebuf));
        fprintf(stderr,"PROCESS.(%s)\n",jprint(json,0));
        process_json(json,remoteaddr,localaccess);
    }
    free_json(json);
    return 0;
}


text:
function deletefiles = spm_cfg_deletefiles
% SPM Configuration file for 'rm'
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% $Id: spm_cfg_deletefiles.m 4907 2012-09-06 19:33:21Z guillaume $

rev = '$Rev: 4907 $';
% ---------------------------------------------------------------------
% deletefiles Files to delete
% ---------------------------------------------------------------------
deletefiles1         = cfg_files;
deletefiles1.tag     = 'deletefiles';
deletefiles1.name    = 'Files to delete';
deletefiles1.help    = {'Select files to delete.'};
deletefiles1.filter = 'any';
deletefiles1.ufilter = '.*';
deletefiles1.num     = [0 Inf];
% ---------------------------------------------------------------------
% deletefiles Delete Files (Deprecated)
% ---------------------------------------------------------------------
deletefiles         = cfg_exbranch;
deletefiles.tag     = 'deletefiles';
deletefiles.name    = 'Delete Files (DEPRECATED)';
deletefiles.val     = {deletefiles1 };
deletefiles.help    = {
    'This module is DEPRECATED and has been moved to BasicIO.'
    'Jobs which are ready to run may continue using it, but the module inputs can not be changed via GUI.'
    'Please switch to the BasicIO module instead.'
    'This module will be REMOVED in the next major release of SPM.'
    ''
    'This facility allows to delete files in a batch. Note that deleting files will not make them disappear from file selection lists.'
    'Therefore one has to be careful not to select the original files after they have been programmed to be deleted.'
    'If image files (.img or .nii) are selected, corresponding .hdr or .mat files will be deleted as well, if they exist.'
};
deletefiles.prog = @my_deletefiles;
deletefiles.hidden = true;
%------------------------------------------------------------------------
function my_deletefiles(varargin)
warning('"spm.util.deletefiles" is DEPRECATED and will be REMOVED in the next major release of SPM. Use BasicIO instead.');
job = varargin{1};
for k = 1:numel(job.deletefiles)
    [p, n, e] = spm_fileparts(job.deletefiles{k});
    if strcmp(e,'.img') || strcmp(e,'.nii')
        spm_unlink(fullfile(p,[n '.hdr']));
        spm_unlink(fullfile(p,[n '.mat']));
    end
    spm_unlink(fullfile(p,[n e]));
end


text:
package ua.kata;

import java.util.Map;
import java.util.function.IntBinaryOperator;

public class StringCalc {

  public int compute(String src) {
    return new Parser(src).parseExpression();
  }

  private static class Parser {
    private final Map<Character, IntBinaryOperator> lowOrderOperations = Map.ofEntries(
        Map.entry('+', (a, b) -> a + b),
        Map.entry('-', (a, b) -> a - b)
    );

    private final Map<Character, IntBinaryOperator> highOrderOperations = Map.ofEntries(
        Map.entry('*', (a, b) -> a * b),
        Map.entry('/', (a, b) -> a / b)
    );

    private final String src;
    private int index;

    Parser(String src) {
      this.src = src;
    }

    private int parseExpression() {
      int num = parseTerm();
      IntBinaryOperator operation;
      while ((operation = lowOrderOperations.get(parseOperator())) != null) {
        skip();
        num = operation.applyAsInt(num, parseTerm());
      }
      return num;
    }

    int parseTerm() {
      int num = parseArgument();
      IntBinaryOperator operation;
      while ((operation = highOrderOperations.get(parseOperator())) != null) {
        skip();
        num = operation.applyAsInt(num, parseArgument());
      }
      return num;
    }

    int parseArgument() {
      if (isSubexpression()) {
        skip();
        int ret = parseExpression();
        skip();
        return ret;
      } else {
        int start = index;
        int end = findEndOfNumber();
        index = end;
        return Integer.parseInt(src.substring(start, end));
      }
    }

    private int findEndOfNumber() {
      int end = src.charAt(index) == '-' ? index + 1 : index;
      while (end < src.length() && Character.isDigit(src.charAt(end))) {
        end++;
      }
      return end;
    }

    private boolean isSubexpression() {
      return src.charAt(index) == '(';
    }

    private char parseOperator() {
      if (index >= src.length()) return 0;
      else return src.charAt(index);
    }

    private void skip() {
      index++;
    }
  }
}


text:
class CSoundPatch;

// Information about music tracks
struct TrackInfo_t
{
	TrackInfo_t();
	TrackInfo_t( const char *szFilename, const char *szHexname, const char *szAlbum, const char *szArtist, const char *szGenre );

	string_t	m_szHexname;
	string_t	m_szFilename;
	string_t	m_szAlbum;
	string_t	m_szArtist;
	string_t	m_szGenre;
	bool		m_bIsMarkedForDeletion;

	bool	operator==( const TrackInfo_t& rhs ) const;
	void	PrepareKVForListView( KeyValues *kv );
};

struct ID3Info_t;

//-----------------------------------------------------------------------------
// Purpose: Lets a client define a playlist to use for various music events in game.
//-----------------------------------------------------------------------------
class CASWJukeboxPlaylist : public CGameEventListener, public CAutoGameSystem
{
public:
	void AddMusicToPlaylist( const char *szFilename, const char *szHexname, const char *szAlbum, const char *szArtist, const char *szGenre );
	void MarkTrackForDeletion( int index );

	// CAutoGameSystem methods
	virtual bool Init( void );
	virtual void Shutdown( void );
	virtual void LevelInitPostEntity( void );
	virtual void LevelShutdownPostEntity( void );

	// CGameEventListener methods
	virtual void FireGameEvent( IGameEvent *event );
	void StopTrack( bool immediate = true, float fadeOutTime = 1.0f );
	void SavePlaylist( void );
	const char *GetTrackName( int index );
	const char *GetTrackArtist( int index );
	const char *GetTrackAlbum( int index );
	const char *GetTrackGenre( int index );
	void PrepareTrackKV( int index, KeyValues *pKV );
	int GetTrackCount( void );
	void Cleanup( void );
	bool IsMusicPlaying( void );

private:
	void RemoveAllMusic( void );
	void RemoveMusicFromPlaylist( const char* szHexnameToRemove );
	void LoadPlaylistKV( void );
	void ExportPlayistKV( void );
	void PlayRandomTrack( float fadeInTime = 1.0f, const char *szDefaultTrack = null );

	typedef CUtlVector< TrackInfo_t > TrackList_t;
	TrackList_t		m_CombatMusicPlaylist;
	CSoundPatch		*m_pCombatMusic; // The current combat music that's playing
	int				m_iCurrentTrack; // The index of the current track being played
};

extern CASWJukeboxPlaylist g_ASWJukebox;

#endif // #ifndef _DEFINED_C_ASW_JUKEBOX_H


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Ann. Mag. nat. Hist. , Ser. 1 9: 444 (1842)

#### Original name
Hexagonia fasciata Berk.

### Remarks
null


text:
cd /interop/server/

echo "Testing server..."

source venv/bin/activate
python manage.py test
server=$?
deactivate

echo -e "\n=====================================================================\n"

# Client
cd /interop/client/

echo "Testing Python 2 client..."

source venv2/bin/activate
nosetests interop
py2client=$?
deactivate

echo -e "\n=====================================================================\n"

echo "Testing Python 3 client..."

source venv3/bin/activate
nosetests interop
py3client=$?
deactivate

echo -e "\n=====================================================================\n"

# Frontend
cd /interop/server/auvsi_suas/static/auvsi_suas

echo "Testing JavaScript Frontend..."

bash test_with_phantomjs.sh
frontend=$?

echo -e "\n=====================================================================\n"

exit_code=0

if [[ ${server} == "0" ]]; then
    echo "Server PASSED"
else
    echo "Server FAILED"
    exit_code=1
fi

if [[ ${py2client} == "0" ]]; then
    echo "Python 2 client PASSED"
else
    echo "Python 2 client FAILED"
    exit_code=1
fi

if [[ ${py3client} == "0" ]]; then
    echo "Python 3 client PASSED"
else
    echo "Python 3 client FAILED"
    exit_code=1
fi

if [[ ${frontend} == "0" ]]; then
    echo "JavaScript Frontend PASSED"
else
    echo "JavaScript Frontend FAILED"
    exit_code=1
fi

exit ${exit_code}


text:
sa-vpn-softether
================

[![Build Status](https://travis-ci.org/softasap/sa-vpn-softether.svg?branch=master)](https://travis-ci.org/softasap/sa-vpn-softether)

Example of use: check box-example

Possible configuration:
```YAML

softether_option_securenat: true
softether_option_bridge: false

softether_location: /opt
softether_home: "{{softether_location}}/vpnserver"
softether_lang: en
softether_fqdn: "{{ansible_host}}"

# ============== IPSEC ===================
softether_option_ipsec: true
softether_ipsec_l2tp: yes
softether_ipsec_l2tpraw: yes
softether_ipsec_etherip: no
softether_ipsec_presharedkey: "zzz"
# /============== IPSEC ===================

# ============== OPENVPN ===================
softether_option_openvpn: true
softether_openvpn_port: 1194
softether_openvpn_config: "{{softether_home}}/generated/openvpn_config.zip"
# /============== OPENVPN ===================

# ============== Bridge ===================
softether_bridge_device: soft
softether_bridge_tap: no
# ============== /Bridge ===================

# ============== Users ===================
softether_vpn_users:
  - {
      name: "test",
      password: "test"
    }
# ============== /Users ===================

softether_sysctl_conf_lines:
  - {
      name: 'net.ipv4.ip_forward',
      value: '1'
    }

```

Simple:

```YAML

vars:
     - my_softether_vpn_users:
        - {
            name: "my_user",
            password: "my_password"
          }

     - my_softether_ipsec_presharedkey: "[1KH;+r-X#cvhpv7Y6=#;[{u"

roles:

     - {
         role: "sa-vpn-softether",
         softether_vpn_users: "{{my_softether_vpn_users}}",
         softether_ipsec_presharedkey: "{{my_softether_ipsec_presharedkey}}"
       }

```

Advanced:

```YAML

vars:
     - my_softether_vpn_users:
        - {
            name: "my_user",
            password: "my_password"
          }

     - my_softether_ipsec_presharedkey: "[1KH;+r-X#cvhpv7Y6=#;[{u"

roles:
     - {
         role: "sa-vpn-softether",

         softether_vpn_users: "{{my_softether_vpn_users}}",
         softether_ipsec_presharedkey: "{{my_softether_ipsec_presharedkey}}"

         softether_option_securenat: true,
         softether_option_bridge: false,
         softether_fqdn: "{{ansible_host}}",

         # ============== IPSEC ===================
         softether_option_ipsec: true,
         softether_ipsec_l2tp: yes,
         softether_ipsec_l2tpraw: yes,
         softether_ipsec_etherip: no,
         # /============== IPSEC ===================

         # ============== OPENVPN ===================
         softether_option_openvpn: true,
         softether_openvpn_port: 1194,
         softether_openvpn_config: "{{softether_home}}/generated/openvpn_config.zip",
         # /============== OPENVPN ===================

         # ============== Bridge ===================
         softether_bridge_device: soft,
         softether_bridge_tap: no
         # ============== /Bridge ===================

       }

```

If you ever needed to setup vpnserver on your own on later stage:

```
  softether_init_script: scenarios/dummy
```

Usage with ansible galaxy workflow
----------------------------------

If you installed the sa-vpn-softether role using the command

`
   ansible-galaxy install softasap.sa-vpn-softether
`

the role will be available in the folder library/softasap.sa-vpn-softether
Please adjust the path accordingly.

```YAML

     - {
         role: "softasap.sa-vpn-softether"
       }

```

Connecting to OpenVPN from client box
=====================================

If you executed last step of play, you have now cer file for ipsec + zip with openvpn configuration.

Once unpacked, ensure you have GUI ready for openvpn. If menu "Import saved vpn configuration" missing, proceed with

```bash
sudo apt install network-manager-openvpn network-manager-openvpn-gnome network-manager-pptp network-manager-vpnc
```

After logout/login or reboot you will have menu option "Import saved vpn configuration".

Import file named `yourhostname_l3.ovpn`

use your `user@vpn` , for example `test@vpn` followed by password, like `test` ;
If you have only one hub created, than you can use only username.

To troubleshoot you might use interactive session native ovpn client, like

`sudo openvpn --config my.ovpn`

Connecting to OpenVPN full story
================================

1. About Files
--------------

When you open the ZIP archive, the following files with the
structured-directory will be expanded.
Extract there files including sub-directory structure toward any destination
directory, and use parts according to your necessary.

< The Configuration File for L3 (IP Routing) >
  openvpn_remote_access_l3.ovpn

< The Configuration File for L2 (Ethernet Bridging) >
  openvpn_site_to_site_bridge_l2.ovpn

The extension ".ovpn" means a configuration file. You can specify the
configuration file into OpenVPN to initiate a VPN connection.

2. How Different between L3 and L2?
-----------------------------------

Use L3 (IP Routing) if you want to install OpenVPN on the normal computer (for
example, a lap top PC), and make it connect to PacketiX VPN Server or SoftEther
VPN Server for the purpose of establishing a "Remote-Access VPN Connection" .
In this case, the IP address will be assigned on the virtual network adapter
of OpenVPN automatically when the OpenVPN will connect to the Virtual HUB on
the VPN Server successfully and request an IP address and other network
parameters (e.g. DNS server address).

In other hand, if you want to build a "Site-to-Site VPN Connection" ,
use L2 (Ethernet Bridging) for OpenVPN on the computer which is set up on the
remote place for bridging. No IP-specific treatment will be done. All Ethernet
packets (MAC frames) will exchanged transparently between two or more sites.
Any computers or network equipments (e.g. routers) will be able to communicate
to other sites mutually.

VPN Server will treat a virtual VPN session from L3-mode OpenVPN as
a "VPN Client" session.
VPN Server will treat a virtual VPN session from L2-mode OpenVPN as
a "VPN Bridge" session.

3. How to Specify the Username and Password?
--------------------------------------------

The prompt of username and password will be shown when you try to use this
configuration. You have to enter the same username and password which has
already been defined on the Virtual HUB of VPN Server.

Please note that you have to create an user on the Virtual HUB in advance.

If there are two or more Virtual HUBs on the VPN Server, you have to specify
the username as:

  "Username@Virtual-HUB-Name"

or:

  "Virtual-HUB-Name\Username"

to choose which Virtual HUB to be connected. You can also choose which
Virtual HUB should be elected as a "Default HUB" when the specification of
the name of Virtual HUB will be omitted.

Please be advised that you can make OpenVPN to enter the username and password
automatically without showing a prompt. How to do it is described on the
OpenVPN manual.

* 4. About Protocol and Port Number
Both TCP and UDP are available to connect to the VPN Server by OpenVPN.

If you use TCP, the port number is same as any of the "TCP Listener Port" on
the VPN Server which is originally defined in order to accept inbound
TCP-based VPN Client session.

If you use UDP, the port number must be one of UDP ports which are defined on
the VPN Server configuration in advance. Do not confuse between TCP and UDP
since they are not concerned mutually.

You can also specify the proxy-server address if the connection should be
relayed by the proxy-server. Specify it on the configuration file.

Copyright and license
---------------------

Code licensed under the [BSD 3 clause] (https://opensource.org/licenses/BSD-3-Clause) or the [MIT License] (http://opensource.org/licenses/MIT).

Subscribe for roles updates at [FB] (https://www.facebook.com/SoftAsap/)


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Peersview</title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="css/peersview.css" />

        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-controls="navbar"> Toggle navigation    </button>

SIGN IN

      <hgroup class="landing-header">

SIGN UP

      </hgroup>

            <form>
              <input type="text" class="form-control" placeholder="Full Name" />
              <input type="text" class="form-control" placeholder="Email" />
              <input type="password" class="form-control" placeholder="Password" />
              <input type="password" class="form-control" placeholder="Confirm Password" />
              <input type="button" class="btn btn-blue" value="Sign Up" />
            </form>

              <input type="checkbox" />
              I agree to the Terms & Conditions, Privacy Policy and Code of Conduct


text:
<!DOCTYPE html>
<title>sdktools_engine.inc</title>
<link rel="stylesheet" href="style.css"/>

/**
 * vim: set ts=4 :
 * =============================================================================
 * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
 * =============================================================================
 *
 * This file is part of the SourceMod/SourcePawn SDK.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, version 3.0, as published by the
 * Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * As a special exception, AlliedModders LLC gives you permission to link the
 * code of this program (as well as its derivative works) to "Half-Life 2," the
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 * by the Valve Corporation.  You must obey the GNU General Public License in
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
 * this exception to all derivative works.  AlliedModders LLC defines further
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 * or <http://www.sourcemod.net/license.php>.
 *
 * Version: $Id$
 */

#if defined _sdktools_engine_included
  #endinput
#endif
#define _sdktools_engine_included

#define MAX_LIGHTSTYLES			64

/**
 * Sets a client's "viewing entity."
 *
 * @param client		Client index.
 * @param entity		Entity index.
 * @noreturn
 * @error				Invalid client or entity, lack of mod support, or client not in
 *						game.
 */
native SetClientViewEntity(client, entity);

/**
 * Sets a light style.
 *
 * @param style			Light style (from 0 to MAX_LIGHTSTYLES-1)
 * @param value			Light value string (see world.cpp/light.cpp in dlls)
 * @noreturn
 * @error				Light style index is out of range.
 */
native SetLightStyle(style, const String:value[]);

/**
 * Returns the client's eye position.
 *
 * @param client		Player's index.
 * @param pos			Destination vector to store the client's eye position.
 * @noreturn
 * @error				Invalid client index, client not in game, or no mod support.
 */
native GetClientEyePosition(client, Float:pos[3]);


text:
#ifndef LIEF_ELF_DYNAMIC_ENTRY_H_
#define LIEF_ELF_DYNAMIC_ENTRY_H_

#include <string>
#include <vector>
#include <iostream>

#include "LIEF/visibility.h"
#include "LIEF/Object.hpp"

#include "LIEF/ELF/enums.hpp"

namespace LIEF {
namespace ELF {
namespace details {
struct Elf64_Dyn;
struct Elf32_Dyn;
}

//! Class which represents an entry in the dynamic table
//! These entries are located in the ``.dynamic`` section or the ``PT_DYNAMIC`` segment
class LIEF_API DynamicEntry : public Object {
  public:

  DynamicEntry(const details::Elf64_Dyn& header);
  DynamicEntry(const details::Elf32_Dyn& header);
  DynamicEntry();
  DynamicEntry(DYNAMIC_TAGS tag, uint64_t value);

  DynamicEntry& operator=(const DynamicEntry&);
  DynamicEntry(const DynamicEntry&);
  virtual ~DynamicEntry();

  //! Tag of the current entry. The most common tags are:
  //! DT_NEEDED, DT_INIT, ...
  DYNAMIC_TAGS tag() const;

  //! Return the entry's value
  //!
  //! The meaning of the value strongly depends on the tag.
  //! It can be an offset, an index, a flag, ...
  uint64_t value() const;

  void tag(DYNAMIC_TAGS tag);
  void value(uint64_t value);

  void accept(Visitor& visitor) const override;

  virtual std::ostream& print(std::ostream& os) const;

  bool operator==(const DynamicEntry& rhs) const;
  bool operator!=(const DynamicEntry& rhs) const;

  LIEF_API friend std::ostream& operator<<(std::ostream& os, const DynamicEntry& entry);

  protected:
  DYNAMIC_TAGS tag_;
  uint64_t     value_;
};
}
}
#endif


text:
CREATE SEQUENCE SEQ_IACUC_PROT_AMND_REN_ID INCREMENT BY 1 START WITH 1 NOCACHE
/


text:
<?php

/**
 * Configuration for DEVELOPMENT environment
 * To create another configuration set just copy this file to config.production.php etc. You get the idea :)
 */

/**
 * Configuration for: Error reporting
 * Useful to show every little problem during development, but only show hard / no errors in production.
 * It's a little bit dirty to put this here, but who cares. For development purposes it's totally okay.
 */
error_reporting(E_ALL);
ini_set("display_errors", 1);

/**
 * Configuration for cookie security
 * Quote from PHP manual: Marks the cookie as accessible only through the HTTP protocol. This means that the cookie
 * won't be accessible by scripting languages, such as JavaScript. This setting can effectively help to reduce identity
 * theft through XSS attacks (although it is not supported by all browsers).
 *
 * IMPORTANT: This will
 *
 * @see php.net/manual/en/session.configuration.php#ini.session.cookie-httponly
 */
ini_set('session.cookie_httponly', 1);

/**
 * Returns the full configuration.
 * This is used by the core/Config class.
 */
return array(
	/**
	 * Configuration for: Base URL
	 * This detects your URL/IP incl. sub-folder automatically. You can also deactivate auto-detection and provide the
	 * URL manually. This should then look like 'http://192.168.33.44/' ! Note the slash in the end.
	 */
	'URL' => 'http://' . $_SERVER['HTTP_HOST'] . str_replace('public', '', dirname($_SERVER['SCRIPT_NAME'])),
	/**
	 * Configuration for: Folders
	 * Usually there's no reason to change this.
	 */
	'PATH_CONTROLLER' => realpath(dirname(__FILE__).'/../../') . '/application/controller/',
	'PATH_VIEW' => realpath(dirname(__FILE__).'/../../') . '/application/view/',
	/**
	 * Configuration for: Avatar paths
	 * Internal path to save avatars. Make sure this folder is writable. The slash at the end is VERY important!
	 */
	'PATH_AVATARS' => realpath(dirname(__FILE__).'/../../') . '/public/avatars/',
	'PATH_AVATARS_PUBLIC' => 'avatars/',
	/**
	 * Configuration for: Default controller and action
	 */
	'DEFAULT_CONTROLLER' => 'index',
	'DEFAULT_ACTION' => 'index',
	/**
	 * Configuration for: Database
	 * DB_TYPE The used database type. Note that other types than "mysql" might break the db construction currently.
	 * DB_HOST The mysql hostname, usually localhost or 127.0.0.1
	 * DB_NAME The database name
	 * DB_USER The username
	 * DB_PASS The password
	 * DB_PORT The mysql port, 3306 by default (?), find out via phpinfo() and look for mysqli.default_port.
	 * DB_CHARSET The charset, necessary for security reasons. Check Database.php class for more info.
	 */
	'DB_TYPE' => 'mysql',
	'DB_HOST' => 'mysql', // The name of the linked container
	'DB_NAME' => 'huge',
	'DB_USER' => 'root',
	'DB_PASS' => 'example_password',
	'DB_PORT' => '3306',
	'DB_CHARSET' => 'utf8',
	/**
	 * Configuration for: Captcha size
	 * The currently used Captcha generator (https://github.com/Gregwar/Captcha) also runs without giving a size,
	 * so feel free to use ->build(); inside CaptchaModel.
	 */
	'CAPTCHA_WIDTH' => 359,
	'CAPTCHA_HEIGHT' => 100,
	/**
	 * Configuration for: Cookies
	 * 1209600 seconds = 2 weeks
	 * COOKIE_PATH is the path the cookie is valid on, usually "/" to make it valid on the whole domain.
	 * @see http://stackoverflow.com/q/9618217/1114320
	 * @see php.net/manual/en/function.setcookie.php
     *
     * COOKIE_DOMAIN: The domain where the cookie is valid for.
     *      COOKIE_DOMAIN mightn't work with "localhost", ".localhost", "127.0.0.1", or ".127.0.0.1". If so, leave it as empty string, false or null.
     *      @see http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
     *      @see http://php.net/manual/en/function.setcookie.php#73107
     *
     * COOKIE_SECURE: If the cookie will be transferred through secured connection(SSL). It's highly recommended to set it to true if you have secured connection.
     * COOKIE_HTTP: If set to true, Cookies that can't be accessed by JS - Highly recommended!
     * SESSION_RUNTIME: How long should a session cookie be valid by seconds, 604800 = 1 week.
	 */
	'COOKIE_RUNTIME' => 1209600,
	'COOKIE_PATH' => '/',
    'COOKIE_DOMAIN' => "",
    'COOKIE_SECURE' => false,
    'COOKIE_HTTP' => true,
    'SESSION_RUNTIME' => 604800,
	/**
	 * Configuration for: Avatars/Gravatar support
	 * Set to true if you want to use "Gravatar(s)", a service that automatically gets avatar pictures via using email
	 * addresses of users by requesting images from the gravatar.com API. Set to false to use own locally saved avatars.
	 * AVATAR_SIZE set the pixel size of avatars/gravatars (will be 44x44 by default). Avatars are always squares.
	 * AVATAR_DEFAULT_IMAGE is the default image in public/avatars/
	 */
	'USE_GRAVATAR' => false,
	'GRAVATAR_DEFAULT_IMAGESET' => 'mm',
	'GRAVATAR_RATING' => 'pg',
	'AVATAR_SIZE' => 44,
	'AVATAR_JPEG_QUALITY' => 85,
	'AVATAR_DEFAULT_IMAGE' => 'default.jpg',
    /**
     * Configuration for: Encryption Keys
     *
     */
    'ENCRYPTION_KEY' => '6#x0gÊìf^25cL1f$08&',
    'HMAC_SALT' => '8qk9c^4L6d#15tM8z7n0%',
	/**
	 * Configuration for: Email server credentials
	 *
	 * Here you can define how you want to send emails.
	 * If you have successfully set up a mail server on your linux server and you know
	 * what you do, then you can skip this section. Otherwise please set EMAIL_USE_SMTP to true
	 * and fill in your SMTP provider account data.
	 *
	 * EMAIL_USED_MAILER: Check Mail class for alternatives
	 * EMAIL_USE_SMTP: Use SMTP or not
	 * EMAIL_SMTP_AUTH: leave this true unless your SMTP service does not need authentication
	 */
	'EMAIL_USED_MAILER' => 'phpmailer',
	'EMAIL_USE_SMTP' => false,
	'EMAIL_SMTP_HOST' => 'yourhost',
	'EMAIL_SMTP_AUTH' => true,
	'EMAIL_SMTP_USERNAME' => 'yourusername',
	'EMAIL_SMTP_PASSWORD' => 'yourpassword',
	'EMAIL_SMTP_PORT' => 465,
	'EMAIL_SMTP_ENCRYPTION' => 'ssl',
	/**
	 * Configuration for: Email content data
	 */
	'EMAIL_PASSWORD_RESET_URL' => 'login/verifypasswordreset',
	'EMAIL_PASSWORD_RESET_FROM_EMAIL' => 'no-reply@example.com',
	'EMAIL_PASSWORD_RESET_FROM_NAME' => 'My Project',
	'EMAIL_PASSWORD_RESET_SUBJECT' => 'Password reset for PROJECT XY',
	'EMAIL_PASSWORD_RESET_CONTENT' => 'Please click on this link to reset your password: ',
	'EMAIL_VERIFICATION_URL' => 'login/verify',
	'EMAIL_VERIFICATION_FROM_EMAIL' => 'no-reply@example.com',
	'EMAIL_VERIFICATION_FROM_NAME' => 'My Project',
	'EMAIL_VERIFICATION_SUBJECT' => 'Account activation for PROJECT XY',
	'EMAIL_VERIFICATION_CONTENT' => 'Please click on this link to activate your account: ',
);


text:
module Neo4j::ActiveRel
  module Persistence
    extend ActiveSupport::Concern
    include Neo4j::Shared::Cypher::RelIdentifiers
    include Neo4j::Shared::Persistence

    class RelInvalidError < RuntimeError; end
    class ModelClassInvalidError < RuntimeError; end
    class RelCreateFailedError < RuntimeError; end

    def from_node_identifier
      @from_node_identifier || :from_node
    end

    def to_node_identifier
      @to_node_identifier || :to_node
    end

    def from_node_identifier=(id)
      @from_node_identifier = id.to_sym
    end

    def to_node_identifier=(id)
      @to_node_identifier = id.to_sym
    end

    def cypher_identifier
      @cypher_identifier || :rel
    end

    def save(*)
      create_or_update
    end

    def save!(*args)
      save(*args) or fail(RelInvalidError, inspect) # rubocop:disable Style/AndOr
    end

    # Increments concurrently a numeric attribute by a centain amount
    # @param [Symbol, String] name of the attribute to increment
    # @param [Integer, Float] amount to increment
    def concurrent_increment!(attribute, by = 1)
      query_rel = Neo4j::Session.query.match('()-[n]-()').where(n: {neo_id: neo_id})
      increment_by_query! query_rel, attribute, by
    end

    def create_model
      validate_node_classes!
      rel = _create_rel
      return self unless rel.respond_to?(:props)
      init_on_load(rel, from_node, to_node, @rel_type)
      true
    end

    module ClassMethods
      # Creates a new relationship between objects
      # @param [Hash] props the properties the new relationship should have
      def create(props = {})
        relationship_props = extract_association_attributes!(props) || {}
        new(props).tap do |obj|
          relationship_props.each do |prop, value|
            obj.send("#{prop}=", value)
          end
          obj.save
        end
      end

      # Same as #create, but raises an error if there is a problem during save.
      def create!(*args)
        props = args[0] || {}
        relationship_props = extract_association_attributes!(props) || {}
        new(props).tap do |obj|
          relationship_props.each do |prop, value|
            obj.send("#{prop}=", value)
          end
          obj.save!
        end
      end

      def create_method
        creates_unique? ? :create_unique : :create
      end

      def load_entity(id)
        Neo4j::Relationship.load(id)
      end
    end

    def create_method
      self.class.create_method
    end

    private

    def validate_node_classes!
      [from_node, to_node].each do |node|
        type = from_node == node ? :_from_class : :_to_class
        type_class = self.class.send(type)

        unless valid_type?(type_class, node)
          fail ModelClassInvalidError, type_validation_error_message(node, type_class)
        end
      end
    end

    def valid_type?(type_object, node)
      case type_object
      when false, :any
        true
      when Array
        type_object.any? { |c| valid_type?(c, node) }
      else
        node.class.mapped_label_names.include?(type_object.to_s.constantize.mapped_label_name)
      end
    end

    def type_validation_error_message(node, type_class)
      "Node class was #{node.class} (#{node.class.object_id}), expected #{type_class} (#{type_class.object_id})"
    end

    def _create_rel
      factory = QueryFactory.new(from_node, to_node, self)
      factory.build!
      factory.unwrapped_rel
    end
  end
end


text:
'use strict';

var should = require('should');
var app = require('../../app');
var request = require('supertest');
/*
describe('GET /api/login', function() {

  it('should respond with JSON array', function(done) {
    request(app)
      .get('/api/login')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function(err, res) {
        if (err) return done(err);
        console.log(res);
        //res.body.should.be.instanceof(Array);
        done();
      });
  });
});
*/


text:
package net.sansa_stack.hadoop;

import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import net.sansa_stack.hadoop.format.gson.json.FileInputFormatJsonArray;
import net.sansa_stack.hadoop.format.gson.json.RecordReaderJsonArray;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.InputFormat;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Test cases for the {@link RecordReaderJsonArray}:
 * A given set of test datasets (represented as trig files) is first split into a configurable
 * number of splits from which the overall graph is then reassembled.
 * The reassembled dataset must match the one of the original file.
 *
 * @author Lorenz Buehmann
 * @author Claus Stadler
 */
public abstract class RecordReaderJsonArrayTestBase {

    private static final Logger logger = LoggerFactory.getLogger(RecordReaderJsonArrayTestBase.class);

    public static List<Object[]> createParameters(Map<String, Range<Integer>> fileToNumSplits) {

        // Post process the map into junit params by enumerating the ranges
        // and creating a test case for each obtained value
        List<Object[]> result = fileToNumSplits.entrySet().stream()
                .flatMap(e -> ContiguousSet.create(e.getValue(), DiscreteDomain.integers()).stream()
                        .map(numSplits -> new Object[]{e.getKey(), numSplits}))
                .collect(Collectors.toList());

        return result;
    }

    protected String file;
    protected int numSplits;

    public RecordReaderJsonArrayTestBase(String file, int numSplits) {
        this.file = file;
        this.numSplits = numSplits;
    }

    // protected abstract InputFormat<?, T> createInputFormat();

    /** Override this for custom hadoop configuration */
    protected void configureHadoop(Configuration conf) {};

    /**
     * Conventional auto-decoding using commons-compress.
     * Returns the given stream as-is if no decoder is applicable
     */
    public static InputStream autoDecode(InputStream in) {

        if (!in.markSupported()) {
            in = new BufferedInputStream(in);
        }

        InputStream result;
        try {
            result = CompressorStreamFactory.getSingleton().createCompressorInputStream(in);
        } catch (CompressorException e) {
            result = in;
        }
        return result;
    }

    @Test
    public void test() throws IOException, InterruptedException, CompressorException {

        Configuration conf = new Configuration(false);
        conf.set("fs.defaultFS", "file:///");
        conf.set(RecordReaderJsonArray.RECORD_MAXLENGTH_KEY, "1000000");
        conf.set(RecordReaderJsonArray.RECORD_PROBECOUNT_KEY, "300");

        configureHadoop(conf);

        Path referencePath = Paths.get(file).toAbsolutePath();
        Path testPath = referencePath;

        JsonElement expected;
        Gson gson = new Gson();

        try (Reader reader = new InputStreamReader(autoDecode(Files.newInputStream(referencePath)))) {
            expected = gson.fromJson(reader, JsonElement.class);
        }
        ;

        long fileLengthTotal = Files.size(testPath);

        Job job = Job.getInstance(conf);
        // TrigFileInputFormat inputFormat = new TrigFileInputFormat();
        InputFormat<?, JsonElement> inputFormat = new FileInputFormatJsonArray();

        // add input path of the file
        org.apache.hadoop.fs.Path testHadoopPath = new org.apache.hadoop.fs.Path(testPath.toString());
        FileInputFormat.addInputPath(job, testHadoopPath);

        // call once to compute the prefixes
        // inputFormat.getSplits(job);

        JsonArray actual = new JsonArray();
        RecordReaderRdfTestBase.testSplit(job, inputFormat, testHadoopPath, fileLengthTotal, numSplits)
                .forEach(actual::add);

        Assert.assertEquals(expected, actual);

                // .forEach(record -> accumulate(actualDataset, record));

        /**
         * Testing n splits by manually created RecordReader
         * Ensure to start the loop from 1 for full testing. Takes quite long.
         */
        // compare with target dataset
        /*
        Dataset actualDataset = createDataset();

        testSplit(job, inputFormat, testHadoopPath, fileLengthTotal, numSplits)
                .forEach(record -> accumulate(actualDataset, record));
        logger.info(String.format("Named graph counts expected/actual: %d/%d",
                Iterators.size(expectedDataset.listNames()),
                Iterators.size(actualDataset.listNames())));

        logger.info(String.format("Quad counts expected/actual: %d/%d",
                Iterators.size(expectedDataset.asDatasetGraph().find()),
                Iterators.size(actualDataset.asDatasetGraph().find())));

        // compareDatasets(expectedDataset, actualDataset);
        assertIsIsomorphic(expectedDataset, actualDataset);
         */

    }
}


text:
#ifndef _HEAVY_CONTROL_CAST_H_
#define _HEAVY_CONTROL_CAST_H_

#include "HvHeavyInternal.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum CastType {
  HV_CAST_BANG,
  HV_CAST_FLOAT,
  HV_CAST_SYMBOL
} CastType;

void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m,
    void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));

#ifdef __cplusplus
} // extern "C"
#endif

#endif // _HEAVY_CONTROL_CAST_H_