With all the Johnny-O! cigars in current passes, I contacted John for complete pricing.
Please keep in mind, this is a work in progress and will be updated and changed periodically.
Pricing is for bundles of 25, 24 for the (8) culebras. Wrappers vary in each size...natural, medium chocolate brown, Colorado, dark chocolate brown. When putting a Johnny-O! cigar in a pass, please put a blank label on each cigar stating it's name, size, and date bought from John.
No fake dates please, those of us that smoke a good amount of his cigars will know immediately if the date stated is wrong!
* Please be aware that John has started offering bundles of 20 cigars recently. If you are trying to value a Johnny-O! cigar for a Pass and you use one of his recent posts for bundle pricing, please be aware of the bundle quantity when doing your math.
Short Behique (4 1/4 X 52) - No Price, Legendary!
Corona Larga (5 3/4 X 44) Pigtail/Shagfoot - $?
Especiales Figurado (5 5/8 X 46) a double figurado - ?
Forbidden Xtasy VBMF (7 1/2 x 52)-similar to Fuentes Forbiden X BBMF - ?
Tall Story (4.75 X 55)...$???
That'll definitely help, Gary. Good thinking.
With all the Johnny-O! sticks in current passes, I contacted John for complete pricing. I searched around and didn't find all the prices in one spot.
Pricing is for bundles of 25, 24 for the (8) culebras.
Corona?!? Oh Joooohn! I need some Corooooonnnaaas!
On second thought, how about Marevas? Any Marevas? Would sure love some Marevas!
Behike maddies were $300 for a bundles of 25.
Great resource for the board Gary.
Although you could've just contacted Greg for pricing. I'm pretty sure he has a bundle of each.
I'm sorry to ask this question, as it seems silly, but could someone please explain to me what a Johnny-O stick is? I have come across this reference on several posts, but it is not totally clear to me. Thank you.
One day i will have to get one. i have been dying to try one for a while now.
Would love to see the Marevas again!
That sounds really good. I can't wait to try it!
I searched and didn't find much. Some site said that they were an "American based roller that rolls farm rolled custom cigars in small batches". This is all I could find from an informational standpoint but then I see that this topic is the in Cuban section. Something isn't adding up. ???
Do the cigars come with a band on them?
Maybe someone can upload some pics of this cigars.
I hear only good things about them and I'm thinking on ordering a sampler or a box.
No band for me. Can't really say about a box because I got a sampler.


People loved my sweet potato chips, which I make a lot at home. In that photo above, I ate them with a black bean burger, avocado and a pile of Pico de Gallo. They're a fun way to mix things up, and I actually like to top them with traditional nacho toppings too, as a better-for-you nacho option. So that's what we're making today!
You don't need to peel the potatoes, just slice them up. If you don't have a mandolin, I highly recommend one! This is the perfect use. Unless you have ridiculous knife skills, it's hard to cut uniformly and thinly- especially with something like a sweet potato, but you can definitely try. This is the mandolin I have (well, the newer model of the one I have). It was less than 30 bucks and it's been slicing like a mad man for years now. It's a great buy.
I use the thin setting and you'll get perfect little rounds.
Place the potato slices in a bowl and drizzle some extra virgin olive oil on them.
Roasted sweet potatoes is probably one of my top 3 favorite ways to use our flavored olive oils. These ones below are my faves in this recipe- I probably use the bacon and garlic the most with these, but Spicy Chili, regular Extra Virgin, Lime, and Jalapeno are also all awesome here.
Once you drizzle on the oil, use your hands to rub all of the little slices down. Then you'll sprinkle on a spice mix of smoked paprika, cumin, garlic, kosher salt, and pepper. You can definitely play around with spices in this recipe and come up with different combos you like. Use your hands again to mix those up. I like to sprinkle a little, then toss a little, sprinkle some more, toss some more…you get the idea.
Then you'll lay them flat on a foil-lined baking sheet. It's okay if they overlap just a little bit, but for the most part you'll want them in a single layer. You may need more than one sheet.
Keep in mind as they cool a bit, they also crisp up.
When they're done, load them onto a big plate and top them with your favorite toppings. I saw this at the store the other day and I grabbed it to save time. It actually was pretty good. Not nearly as good as a home-cooked roast, obviously, but not bad in a pinch and made things super fast. Just FYI in case you've ever wondered about those; I hadn't seen it before.
We topped ours with that pork, pico de gallo, avocado, and crumbled feta.
I know feta seems weird, but I love it with latin food. I like queso fresco and cotija, but the flavor of both of those is so mild that I often find it doesn't add much to the dish. Feta has a nice sharp bite, so I like the tang it adds.
You don't want to load them too heavy because sweet potatoes are obviously a lot softer than a regular chip, but it makes a nice little bite.
A fun and healthy twist on traditional nachos. Sweet and savory roasted sweet potatoes are the perfect base for your favorite Latin toppings!
Preheat oven to 425 degrees. Line 1 or 2 baking sheets with foil and spray generously with non-stick spray. Set aside.
Mix smoked paprika, garlic, cumin, salt, and pepper in a small bowl.
Use a mandolin to slice sweet potatoes into thin, even slices. Place sweet potatoes in bowl and drizzle with olive oil, using your hands to coat the slices on both sides. Sprinkle seasonings over and toss again.
Lay potatoes in a single layer (overlapping a tiny bit is fine). Place in oven for 20 minutes an peek. Depending on thickness, they usually take 20-30 minutes. Look for browning around the edges.
Remove from oven and let sit for a few minutes. Potatoes will firm up while sitting. Place on a large plate or platter. Top with favorite nacho toppings (Shredded meat, pico de gallo, guacamole, etc) and serve.
I seriously love me a crispy roasted sweet potato. The addition of smoked paprika to the seasonings I use has been a game changer. Thanks to you guys for that idea! So dang good. These look like the perfect lunch. I need to get myself a mandolin!
I got really curious about these flavoured olive oils 🙂 Difficult to find them in the UK.
Those look awesome!!! I definitely want to give them a try. My favorite part of this post is how you used your own beloved olive oil, each bottle used to a different degree, instead of using fresh new bottles. It felt so real and artistic. Which is a good description of you…which is why I love you so much!!!
Also, while I am at it I should mention that I adored your post about handwriting and would love to take up that pursuit. When I looked up your actual handwriting made into a font I recognized it…its like Utah handwriting or Mormon handwriting, or maybe since we are about the same age its a generational thing….but it looked so familiar. I loved your handwriting!!!! And I love how you work on a new skill every year. No idea how you accomplish so much and make everything work. Very impressive!!!!!!
Danielle you are too kind!
I can't figure out any other way to notify you, but the "Older Posts" link is not working. Just thought I'd let you know. I was trying to look back at some posts I've missed.
Thanks, we'll look into it!
These look delicious! And we have a bunch of sweet potatoes in the fridge right now that we need to use up!


text:
Q: How can I show a rectangle on mouse over? In a few words, how do I show a rectangle when the user moves the mouse over, inside of the rectangle I must show a user control.
I have no idea how to do that. Thanks for everything community.

A: If you mean that the user control should be seen all the time and the rectangle should only be seen when the mouse is over it? Then this works: (Border is used to draw a rectangle round another control.)
<Border Border.Background="Transparent" Border.BorderThickness="3">
    <Border.Style>
        <Style>
            <Setter Property="Border.BorderBrush" Value="Transparent"/>
            <Style.Triggers>
                <Trigger Property="Border.IsMouseOver" Value="True">
                    <Setter Property="Border.BorderBrush" Value="Green" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="X" />
</Border>

(Make the border background transparent in order to capture mouse events inside the border)

redpajama_set_name: RedPajamaStackExchange


Happy New Year to sponsors, partners, and those who follow news about the New Hope for Children Orphanages in India!
Diane and Winston felt God's call to help Pastor George Fernandes with his ministry when they first visited India a couple of years ago. They learned about Helping Hands India and New Hope Orphanages through their daughter Hannah, who served as a volunteer there for about five months.
Our plan is that a new 501(c)(3) organization established by the Scotts will become the official international partner for Pastor George and Helping Hands India. The new organization, Helping Hands India International, has taken responsibility for the Helping Hands India website, and you will find more information about their mission here: www.HelpingHandsIndia.org . The website is still under construction.
Does this mean that sponsors and partners with New Hope for Children Orphanages will have to change anything? No, you can continue your child sponsorship through Big Family Mission. We expect that new sponsorships will soon begin to be processed through HHI International.
I (Ken) will continue to help with the orphan ministry in India as we go through the transition... and after that as the Lord leads.
Please keep Winston and Diane in your prayers! They are just returning from India after a 3-week visit.
Thank you, Winston and Diane, for your service and your obedience to our Lord's sovereign will!
P.S. We still have 29 children at New Hope for Children who need sponsors. If you are not already sponsoring, NOW would be a great time to begin. You can see photos and read brief bios about the children here: Children at New Hope who still need sponsors.


Why should non-diabetics get informed? Because as much as we know about diabetes treatment today, the support from our family and friends still plays a part in how healthy we are. An understanding approach from someone who cares means everything to us. Your diabetic friend or relative counts on you to be the person in their life that "gets it" when no one else does. This book will tell you what you can do to help. Things like what you should (and shouldn't) say, what you should learn to truly be supportive, and even how you can help in the fight for a cure. 21 Simple Things You Can Do To Help Someone With Diabetes will point you in the right direction so you can truly support your diabetic friend.


text:
/*! @name m3u8-parser @version 4.8.0 @license Apache-2.0 */
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _inheritsLoose = require('@babel/runtime/helpers/inheritsLoose');
var Stream = require('@videojs/vhs-utils/cjs/stream.js');
var _extends = require('@babel/runtime/helpers/extends');
var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized');
var decodeB64ToUint8Array = require('@videojs/vhs-utils/cjs/decode-b64-to-uint8-array.js');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var _inheritsLoose__default = /*#__PURE__*/_interopDefaultLegacy(_inheritsLoose);
var Stream__default = /*#__PURE__*/_interopDefaultLegacy(Stream);
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized);
var decodeB64ToUint8Array__default = /*#__PURE__*/_interopDefaultLegacy(decodeB64ToUint8Array);

/**
 * A stream that buffers string input and generates a `data` event for each
 * line.
 *
 * @class LineStream
 * @extends Stream
 */

var LineStream = /*#__PURE__*/function (_Stream) {
  _inheritsLoose__default['default'](LineStream, _Stream);

  function LineStream() {
    var _this;

    _this = _Stream.call(this) || this;
    _this.buffer = '';
    return _this;
  }
  /**
   * Add new data to be parsed.
   *
   * @param {string} data the text to process
   */

  var _proto = LineStream.prototype;

  _proto.push = function push(data) {
    var nextNewline;
    this.buffer += data;
    nextNewline = this.buffer.indexOf('\n');

    for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) {
      this.trigger('data', this.buffer.substring(0, nextNewline));
      this.buffer = this.buffer.substring(nextNewline + 1);
    }
  };

  return LineStream;
}(Stream__default['default']);

var TAB = String.fromCharCode(0x09);

var parseByterange = function parseByterange(byterangeString) {
  // optionally match and capture 0+ digits before `@`
  // optionally match and capture 0+ digits after `@`
  var match = /([0-9.]*)?@?([0-9.]*)?/.exec(byterangeString || '');
  var result = {};

  if (match[1]) {
    result.length = parseInt(match[1], 10);
  }

  if (match[2]) {
    result.offset = parseInt(match[2], 10);
  }

  return result;
};
/**
 * "forgiving" attribute list psuedo-grammar:
 * attributes -> keyvalue (',' keyvalue)*
 * keyvalue   -> key '=' value
 * key        -> [^=]*
 * value      -> '"' [^"]* '"' | [^,]*
 */

var attributeSeparator = function attributeSeparator() {
  var key = '[^=]*';
  var value = '"[^"]*"|[^,]*';
  var keyvalue = '(?:' + key + ')=(?:' + value + ')';
  return new RegExp('(?:^|,)(' + keyvalue + ')');
};
/**
 * Parse attributes from a line given the separator
 *
 * @param {string} attributes the attribute line to parse
 */

var parseAttributes = function parseAttributes(attributes) {
  // split the string using attributes as the separator
  var attrs = attributes.split(attributeSeparator());
  var result = {};
  var i = attrs.length;
  var attr;

  while (i--) {
    // filter out unmatched portions of the string
    if (attrs[i] === '') {
      continue;
    } // split the key and value

    attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1); // trim whitespace and remove optional quotes around the value

    attr[0] = attr[0].replace(/^\s+|\s+$/g, '');
    attr[1] = attr[1].replace(/^\s+|\s+$/g, '');
    attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1');
    result[attr[0]] = attr[1];
  }

  return result;
};
/**
 * A line-level M3U8 parser event stream. It expects to receive input one
 * line at a time and performs a context-free parse of its contents. A stream
 * interpretation of a manifest can be useful if the manifest is expected to
 * be too large to fit comfortably into memory or the entirety of the input
 * is not immediately available. Otherwise, it's probably much easier to work
 * with a regular `Parser` object.
 *
 * Produces `data` events with an object that captures the parser's
 * interpretation of the input. That object has a property `tag` that is one
 * of `uri`, `comment`, or `tag`. URIs only have a single additional
 * property, `line`, which captures the entirety of the input without
 * interpretation. Comments similarly have a single additional property
 * `text` which is the input without the leading `#`.
 *
 * Tags always have a property `tagType` which is the lower-cased version of
 * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
 * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
 * tags are given the tag type `unknown` and a single additional property
 * `data` with the remainder of the input.
 *
 * @class ParseStream
 * @extends Stream
 */

var ParseStream = /*#__PURE__*/function (_Stream) {
  _inheritsLoose__default['default'](ParseStream, _Stream);

  function ParseStream() {
    var _this;

    _this = _Stream.call(this) || this;
    _this.customParsers = [];
    _this.tagMappers = [];
    return _this;
  }
  /**
   * Parses an additional line of input.
   *
   * @param {string} line a single line of an M3U8 file to parse
   */

  var _proto = ParseStream.prototype;

  _proto.push = function push(line) {
    var _this2 = this;

    var match;
    var event; // strip whitespace

    line = line.trim();

    if (line.length === 0) {
      // ignore empty lines
      return;
    } // URIs

    if (line[0] !== '#') {
      this.trigger('data', {
        type: 'uri',
        uri: line
      });
      return;
    } // map tags

    var newLines = this.tagMappers.reduce(function (acc, mapper) {
      var mappedLine = mapper(line); // skip if unchanged

      if (mappedLine === line) {
        return acc;
      }

      return acc.concat([mappedLine]);
    }, [line]);
    newLines.forEach(function (newLine) {
      for (var i = 0; i < _this2.customParsers.length; i++) {
        if (_this2.customParsers[i].call(_this2, newLine)) {
          return;
        }
      } // Comments

      if (newLine.indexOf('#EXT') !== 0) {
        _this2.trigger('data', {
          type: 'comment',
          text: newLine.slice(1)
        });

        return;
      } // strip off any carriage returns here so the regex matching
      // doesn't have to account for them.

      newLine = newLine.replace('\r', ''); // Tags

      match = /^#EXTM3U/.exec(newLine);

      if (match) {
        _this2.trigger('data', {
          type: 'tag',
          tagType: 'm3u'
        });

        return;
      }

      match = /^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'inf'
        };

        if (match[1]) {
          event.duration = parseFloat(match[1]);
        }

        if (match[2]) {
          event.title = match[2];
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'targetduration'
        };

        if (match[1]) {
          event.duration = parseInt(match[1], 10);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'version'
        };

        if (match[1]) {
          event.version = parseInt(match[1], 10);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'media-sequence'
        };

        if (match[1]) {
          event.number = parseInt(match[1], 10);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'discontinuity-sequence'
        };

        if (match[1]) {
          event.number = parseInt(match[1], 10);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'playlist-type'
        };

        if (match[1]) {
          event.playlistType = match[1];
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-BYTERANGE:?(.*)?$/.exec(newLine);

      if (match) {
        event = _extends__default['default'](parseByterange(match[1]), {
          type: 'tag',
          tagType: 'byterange'
        });

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'allow-cache'
        };

        if (match[1]) {
          event.allowed = !/NO/.test(match[1]);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-MAP:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'map'
        };

        if (match[1]) {
          var attributes = parseAttributes(match[1]);

          if (attributes.URI) {
            event.uri = attributes.URI;
          }

          if (attributes.BYTERANGE) {
            event.byterange = parseByterange(attributes.BYTERANGE);
          }
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'stream-inf'
        };

        if (match[1]) {
          event.attributes = parseAttributes(match[1]);

          if (event.attributes.RESOLUTION) {
            var split = event.attributes.RESOLUTION.split('x');
            var resolution = {};

            if (split[0]) {
              resolution.width = parseInt(split[0], 10);
            }

            if (split[1]) {
              resolution.height = parseInt(split[1], 10);
            }

            event.attributes.RESOLUTION = resolution;
          }

          if (event.attributes.BANDWIDTH) {
            event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
          }

          if (event.attributes['FRAME-RATE']) {
            event.attributes['FRAME-RATE'] = parseFloat(event.attributes['FRAME-RATE']);
          }

          if (event.attributes['PROGRAM-ID']) {
            event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);
          }
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-MEDIA:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'media'
        };

        if (match[1]) {
          event.attributes = parseAttributes(match[1]);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-ENDLIST/.exec(newLine);

      if (match) {
        _this2.trigger('data', {
          type: 'tag',
          tagType: 'endlist'
        });

        return;
      }

      match = /^#EXT-X-DISCONTINUITY/.exec(newLine);

      if (match) {
        _this2.trigger('data', {
          type: 'tag',
          tagType: 'discontinuity'
        });

        return;
      }

      match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'program-date-time'
        };

        if (match[1]) {
          event.dateTimeString = match[1];
          event.dateTimeObject = new Date(match[1]);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-KEY:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'key'
        };

        if (match[1]) {
          event.attributes = parseAttributes(match[1]); // parse the IV string into a Uint32Array

          if (event.attributes.IV) {
            if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {
              event.attributes.IV = event.attributes.IV.substring(2);
            }

            event.attributes.IV = event.attributes.IV.match(/.{8}/g);
            event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);
            event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);
            event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);
            event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);
            event.attributes.IV = new Uint32Array(event.attributes.IV);
          }
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-START:?(.*)$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'start'
        };

        if (match[1]) {
          event.attributes = parseAttributes(match[1]);
          event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']);
          event.attributes.PRECISE = /YES/.test(event.attributes.PRECISE);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'cue-out-cont'
        };

        if (match[1]) {
          event.data = match[1];
        } else {
          event.data = '';
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'cue-out'
        };

        if (match[1]) {
          event.data = match[1];
        } else {
          event.data = '';
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(newLine);

      if (match) {
        event = {
          type: 'tag',
          tagType: 'cue-in'
        };

        if (match[1]) {
          event.data = match[1];
        } else {
          event.data = '';
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-SKIP:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'skip'
        };
        event.attributes = parseAttributes(match[1]);

        if (event.attributes.hasOwnProperty('SKIPPED-SEGMENTS')) {
          event.attributes['SKIPPED-SEGMENTS'] = parseInt(event.attributes['SKIPPED-SEGMENTS'], 10);
        }

        if (event.attributes.hasOwnProperty('RECENTLY-REMOVED-DATERANGES')) {
          event.attributes['RECENTLY-REMOVED-DATERANGES'] = event.attributes['RECENTLY-REMOVED-DATERANGES'].split(TAB);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-PART:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'part'
        };
        event.attributes = parseAttributes(match[1]);
        ['DURATION'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = parseFloat(event.attributes[key]);
          }
        });
        ['INDEPENDENT', 'GAP'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = /YES/.test(event.attributes[key]);
          }
        });

        if (event.attributes.hasOwnProperty('BYTERANGE')) {
          event.attributes.byterange = parseByterange(event.attributes.BYTERANGE);
        }

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-SERVER-CONTROL:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'server-control'
        };
        event.attributes = parseAttributes(match[1]);
        ['CAN-SKIP-UNTIL', 'PART-HOLD-BACK', 'HOLD-BACK'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = parseFloat(event.attributes[key]);
          }
        });
        ['CAN-SKIP-DATERANGES', 'CAN-BLOCK-RELOAD'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = /YES/.test(event.attributes[key]);
          }
        });

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-PART-INF:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'part-inf'
        };
        event.attributes = parseAttributes(match[1]);
        ['PART-TARGET'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = parseFloat(event.attributes[key]);
          }
        });

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-PRELOAD-HINT:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'preload-hint'
        };
        event.attributes = parseAttributes(match[1]);
        ['BYTERANGE-START', 'BYTERANGE-LENGTH'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = parseInt(event.attributes[key], 10);
            var subkey = key === 'BYTERANGE-LENGTH' ? 'length' : 'offset';
            event.attributes.byterange = event.attributes.byterange || {};
            event.attributes.byterange[subkey] = event.attributes[key]; // only keep the parsed byterange object.

            delete event.attributes[key];
          }
        });

        _this2.trigger('data', event);

        return;
      }

      match = /^#EXT-X-RENDITION-REPORT:(.*)$/.exec(newLine);

      if (match && match[1]) {
        event = {
          type: 'tag',
          tagType: 'rendition-report'
        };
        event.attributes = parseAttributes(match[1]);
        ['LAST-MSN', 'LAST-PART'].forEach(function (key) {
          if (event.attributes.hasOwnProperty(key)) {
            event.attributes[key] = parseInt(event.attributes[key], 10);
          }
        });

        _this2.trigger('data', event);

        return;
      } // unknown tag type

      _this2.trigger('data', {
        type: 'tag',
        data: newLine.slice(4)
      });
    });
  }
  /**
   * Add a parser for custom headers
   *
   * @param {Object}   options              a map of options for the added parser
   * @param {RegExp}   options.expression   a regular expression to match the custom header
   * @param {string}   options.customType   the custom type to register to the output
   * @param {Function} [options.dataParser] function to parse the line into an object
   * @param {boolean}  [options.segment]    should tag data be attached to the segment object
   */
  ;

  _proto.addParser = function addParser(_ref) {
    var _this3 = this;

    var expression = _ref.expression,
        customType = _ref.customType,
        dataParser = _ref.dataParser,
        segment = _ref.segment;

    if (typeof dataParser !== 'function') {
      dataParser = function dataParser(line) {
        return line;
      };
    }

    this.customParsers.push(function (line) {
      var match = expression.exec(line);

      if (match) {
        _this3.trigger('data', {
          type: 'custom',
          data: dataParser(line),
          customType: customType,
          segment: segment
        });

        return true;
      }
    });
  }
  /**
   * Add a custom header mapper
   *
   * @param {Object}   options
   * @param {RegExp}   options.expression   a regular expression to match the custom header
   * @param {Function} options.map          function to translate tag into a different tag
   */
  ;

  _proto.addTagMapper = function addTagMapper(_ref2) {
    var expression = _ref2.expression,
        map = _ref2.map;

    var mapFn = function mapFn(line) {
      if (expression.test(line)) {
        return map(line);
      }

      return line;
    };

    this.tagMappers.push(mapFn);
  };

  return ParseStream;
}(Stream__default['default']);

var camelCase = function camelCase(str) {
  return str.toLowerCase().replace(/-(\w)/g, function (a) {
    return a[1].toUpperCase();
  });
};

var camelCaseKeys = function camelCaseKeys(attributes) {
  var result = {};
  Object.keys(attributes).forEach(function (key) {
    result[camelCase(key)] = attributes[key];
  });
  return result;
}; // set SERVER-CONTROL hold back based upon targetDuration and partTargetDuration
// we need this helper because defaults are based upon targetDuration and
// partTargetDuration being set, but they may not be if SERVER-CONTROL appears before
// target durations are set.

var setHoldBack = function setHoldBack(manifest) {
  var serverControl = manifest.serverControl,
      targetDuration = manifest.targetDuration,
      partTargetDuration = manifest.partTargetDuration;

  if (!serverControl) {
    return;
  }

  var tag = '#EXT-X-SERVER-CONTROL';
  var hb = 'holdBack';
  var phb = 'partHoldBack';
  var minTargetDuration = targetDuration && targetDuration * 3;
  var minPartDuration = partTargetDuration && partTargetDuration * 2;

  if (targetDuration && !serverControl.hasOwnProperty(hb)) {
    serverControl[hb] = minTargetDuration;
    this.trigger('info', {
      message: tag + " defaulting HOLD-BACK to targetDuration * 3 (" + minTargetDuration + ")."
    });
  }

  if (minTargetDuration && serverControl[hb] < minTargetDuration) {
    this.trigger('warn', {
      message: tag + " clamping HOLD-BACK (" + serverControl[hb] + ") to targetDuration * 3 (" + minTargetDuration + ")"
    });
    serverControl[hb] = minTargetDuration;
  } // default no part hold back to part target duration * 3

  if (partTargetDuration && !serverControl.hasOwnProperty(phb)) {
    serverControl[phb] = partTargetDuration * 3;
    this.trigger('info', {
      message: tag + " defaulting PART-HOLD-BACK to partTargetDuration * 3 (" + serverControl[phb] + ")."
    });
  } // if part hold back is too small default it to part target duration * 2

  if (partTargetDuration && serverControl[phb] < minPartDuration) {
    this.trigger('warn', {
      message: tag + " clamping PART-HOLD-BACK (" + serverControl[phb] + ") to partTargetDuration * 2 (" + minPartDuration + ")."
    });
    serverControl[phb] = minPartDuration;
  }
};
/**
 * A parser for M3U8 files. The current interpretation of the input is
 * exposed as a property `manifest` on parser objects. It's just two lines to
 * create and parse a manifest once you have the contents available as a string:
 *
 * ```js
 * var parser = new m3u8.Parser();
 * parser.push(xhr.responseText);
 * ```
 *
 * New input can later be applied to update the manifest object by calling
 * `push` again.
 *
 * The parser attempts to create a usable manifest object even if the
 * underlying input is somewhat nonsensical. It emits `info` and `warning`
 * events during the parse if it encounters input that seems invalid or
 * requires some property of the manifest object to be defaulted.
 *
 * @class Parser
 * @extends Stream
 */

var Parser = /*#__PURE__*/function (_Stream) {
  _inheritsLoose__default['default'](Parser, _Stream);

  function Parser() {
    var _this;

    _this = _Stream.call(this) || this;
    _this.lineStream = new LineStream();
    _this.parseStream = new ParseStream();

    _this.lineStream.pipe(_this.parseStream);
    /* eslint-disable consistent-this */

    var self = _assertThisInitialized__default['default'](_this);
    /* eslint-enable consistent-this */

    var uris = [];
    var currentUri = {}; // if specified, the active EXT-X-MAP definition

    var currentMap; // if specified, the active decryption key

    var _key;

    var hasParts = false;

    var noop = function noop() {};

    var defaultMediaGroups = {
      'AUDIO': {},
      'VIDEO': {},
      'CLOSED-CAPTIONS': {},
      'SUBTITLES': {}
    }; // This is the Widevine UUID from DASH IF IOP. The same exact string is
    // used in MPDs with Widevine encrypted streams.

    var widevineUuid = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'; // group segments into numbered timelines delineated by discontinuities

    var currentTimeline = 0; // the manifest is empty until the parse stream begins delivering data

    _this.manifest = {
      allowCache: true,
      discontinuityStarts: [],
      segments: []
    }; // keep track of the last seen segment's byte range end, as segments are not required
    // to provide the offset, in which case it defaults to the next byte after the
    // previous segment

    var lastByterangeEnd = 0; // keep track of the last seen part's byte range end.

    var lastPartByterangeEnd = 0;

    _this.on('end', function () {
      // only add preloadSegment if we don't yet have a uri for it.
      // and we actually have parts/preloadHints
      if (currentUri.uri || !currentUri.parts && !currentUri.preloadHints) {
        return;
      }

      if (!currentUri.map && currentMap) {
        currentUri.map = currentMap;
      }

      if (!currentUri.key && _key) {
        currentUri.key = _key;
      }

      if (!currentUri.timeline && typeof currentTimeline === 'number') {
        currentUri.timeline = currentTimeline;
      }

      _this.manifest.preloadSegment = currentUri;
    }); // update the manifest with the m3u8 entry from the parse stream

    _this.parseStream.on('data', function (entry) {
      var mediaGroup;
      var rendition;
      ({
        tag: function tag() {
          // switch based on the tag type
          (({
            version: function version() {
              if (entry.version) {
                this.manifest.version = entry.version;
              }
            },
            'allow-cache': function allowCache() {
              this.manifest.allowCache = entry.allowed;

              if (!('allowed' in entry)) {
                this.trigger('info', {
                  message: 'defaulting allowCache to YES'
                });
                this.manifest.allowCache = true;
              }
            },
            byterange: function byterange() {
              var byterange = {};

              if ('length' in entry) {
                currentUri.byterange = byterange;
                byterange.length = entry.length;

                if (!('offset' in entry)) {
                  /*
                   * From the latest spec (as of this writing):
                   * https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.2
                   *
                   * Same text since EXT-X-BYTERANGE's introduction in draft 7:
                   * https://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.1)
                   *
                   * "If o [offset] is not present, the sub-range begins at the next byte
                   * following the sub-range of the previous media segment."
                   */
                  entry.offset = lastByterangeEnd;
                }
              }

              if ('offset' in entry) {
                currentUri.byterange = byterange;
                byterange.offset = entry.offset;
              }

              lastByterangeEnd = byterange.offset + byterange.length;
            },
            endlist: function endlist() {
              this.manifest.endList = true;
            },
            inf: function inf() {
              if (!('mediaSequence' in this.manifest)) {
                this.manifest.mediaSequence = 0;
                this.trigger('info', {
                  message: 'defaulting media sequence to zero'
                });
              }

              if (!('discontinuitySequence' in this.manifest)) {
                this.manifest.discontinuitySequence = 0;
                this.trigger('info', {
                  message: 'defaulting discontinuity sequence to zero'
                });
              }

              if (entry.duration > 0) {
                currentUri.duration = entry.duration;
              }

              if (entry.duration === 0) {
                currentUri.duration = 0.01;
                this.trigger('info', {
                  message: 'updating zero segment duration to a small value'
                });
              }

              this.manifest.segments = uris;
            },
            key: function key() {
              if (!entry.attributes) {
                this.trigger('warn', {
                  message: 'ignoring key declaration without attribute list'
                });
                return;
              } // clear the active encryption key

              if (entry.attributes.METHOD === 'NONE') {
                _key = null;
                return;
              }

              if (!entry.attributes.URI) {
                this.trigger('warn', {
                  message: 'ignoring key declaration without URI'
                });
                return;
              }

              if (entry.attributes.KEYFORMAT === 'com.apple.streamingkeydelivery') {
                this.manifest.contentProtection = this.manifest.contentProtection || {}; // TODO: add full support for this.

                this.manifest.contentProtection['com.apple.fps.1_0'] = {
                  attributes: entry.attributes
                };
                return;
              }

              if (entry.attributes.KEYFORMAT === 'com.microsoft.playready') {
                this.manifest.contentProtection = this.manifest.contentProtection || {}; // TODO: add full support for this.

                this.manifest.contentProtection['com.microsoft.playready'] = {
                  uri: entry.attributes.URI
                };
                return;
              } // check if the content is encrypted for Widevine
              // Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf

              if (entry.attributes.KEYFORMAT === widevineUuid) {
                var VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC'];

                if (VALID_METHODS.indexOf(entry.attributes.METHOD) === -1) {
                  this.trigger('warn', {
                    message: 'invalid key method provided for Widevine'
                  });
                  return;
                }

                if (entry.attributes.METHOD === 'SAMPLE-AES-CENC') {
                  this.trigger('warn', {
                    message: 'SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead'
                  });
                }

                if (entry.attributes.URI.substring(0, 23) !== 'data:text/plain;base64,') {
                  this.trigger('warn', {
                    message: 'invalid key URI provided for Widevine'
                  });
                  return;
                }

                if (!(entry.attributes.KEYID && entry.attributes.KEYID.substring(0, 2) === '0x')) {
                  this.trigger('warn', {
                    message: 'invalid key ID provided for Widevine'
                  });
                  return;
                } // if Widevine key attributes are valid, store them as `contentProtection`
                // on the manifest to emulate Widevine tag structure in a DASH mpd

                this.manifest.contentProtection = this.manifest.contentProtection || {};
                this.manifest.contentProtection['com.widevine.alpha'] = {
                  attributes: {
                    schemeIdUri: entry.attributes.KEYFORMAT,
                    // remove '0x' from the key id string
                    keyId: entry.attributes.KEYID.substring(2)
                  },
                  // decode the base64-encoded PSSH box
                  pssh: decodeB64ToUint8Array__default['default'](entry.attributes.URI.split(',')[1])
                };
                return;
              }

              if (!entry.attributes.METHOD) {
                this.trigger('warn', {
                  message: 'defaulting key method to AES-128'
                });
              } // setup an encryption key for upcoming segments

              _key = {
                method: entry.attributes.METHOD || 'AES-128',
                uri: entry.attributes.URI
              };

              if (typeof entry.attributes.IV !== 'undefined') {
                _key.iv = entry.attributes.IV;
              }
            },
            'media-sequence': function mediaSequence() {
              if (!isFinite(entry.number)) {
                this.trigger('warn', {
                  message: 'ignoring invalid media sequence: ' + entry.number
                });
                return;
              }

              this.manifest.mediaSequence = entry.number;
            },
            'discontinuity-sequence': function discontinuitySequence() {
              if (!isFinite(entry.number)) {
                this.trigger('warn', {
                  message: 'ignoring invalid discontinuity sequence: ' + entry.number
                });
                return;
              }

              this.manifest.discontinuitySequence = entry.number;
              currentTimeline = entry.number;
            },
            'playlist-type': function playlistType() {
              if (!/VOD|EVENT/.test(entry.playlistType)) {
                this.trigger('warn', {
                  message: 'ignoring unknown playlist type: ' + entry.playlist
                });
                return;
              }

              this.manifest.playlistType = entry.playlistType;
            },
            map: function map() {
              currentMap = {};

              if (entry.uri) {
                currentMap.uri = entry.uri;
              }

              if (entry.byterange) {
                currentMap.byterange = entry.byterange;
              }

              if (_key) {
                currentMap.key = _key;
              }
            },
            'stream-inf': function streamInf() {
              this.manifest.playlists = uris;
              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;

              if (!entry.attributes) {
                this.trigger('warn', {
                  message: 'ignoring empty stream-inf attributes'
                });
                return;
              }

              if (!currentUri.attributes) {
                currentUri.attributes = {};
              }

              _extends__default['default'](currentUri.attributes, entry.attributes);
            },
            media: function media() {
              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;

              if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) {
                this.trigger('warn', {
                  message: 'ignoring incomplete or missing media group'
                });
                return;
              } // find the media group, creating defaults as necessary

              var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];
              mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {};
              mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']]; // collect the rendition metadata

              rendition = {
                default: /yes/i.test(entry.attributes.DEFAULT)
              };

              if (rendition.default) {
                rendition.autoselect = true;
              } else {
                rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT);
              }

              if (entry.attributes.LANGUAGE) {
                rendition.language = entry.attributes.LANGUAGE;
              }

              if (entry.attributes.URI) {
                rendition.uri = entry.attributes.URI;
              }

              if (entry.attributes['INSTREAM-ID']) {
                rendition.instreamId = entry.attributes['INSTREAM-ID'];
              }

              if (entry.attributes.CHARACTERISTICS) {
                rendition.characteristics = entry.attributes.CHARACTERISTICS;
              }

              if (entry.attributes.FORCED) {
                rendition.forced = /yes/i.test(entry.attributes.FORCED);
              } // insert the new rendition

              mediaGroup[entry.attributes.NAME] = rendition;
            },
            discontinuity: function discontinuity() {
              currentTimeline += 1;
              currentUri.discontinuity = true;
              this.manifest.discontinuityStarts.push(uris.length);
            },
            'program-date-time': function programDateTime() {
              if (typeof this.manifest.dateTimeString === 'undefined') {
                // PROGRAM-DATE-TIME is a media-segment tag, but for backwards
                // compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag
                // to the manifest object
                // TODO: Consider removing this in future major version
                this.manifest.dateTimeString = entry.dateTimeString;
                this.manifest.dateTimeObject = entry.dateTimeObject;
              }

              currentUri.dateTimeString = entry.dateTimeString;
              currentUri.dateTimeObject = entry.dateTimeObject;
            },
            targetduration: function targetduration() {
              if (!isFinite(entry.duration) || entry.duration < 0) {
                this.trigger('warn', {
                  message: 'ignoring invalid target duration: ' + entry.duration
                });
                return;
              }

              this.manifest.targetDuration = entry.duration;
              setHoldBack.call(this, this.manifest);
            },
            start: function start() {
              if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) {
                this.trigger('warn', {
                  message: 'ignoring start declaration without appropriate attribute list'
                });
                return;
              }

              this.manifest.start = {
                timeOffset: entry.attributes['TIME-OFFSET'],
                precise: entry.attributes.PRECISE
              };
            },
            'cue-out': function cueOut() {
              currentUri.cueOut = entry.data;
            },
            'cue-out-cont': function cueOutCont() {
              currentUri.cueOutCont = entry.data;
            },
            'cue-in': function cueIn() {
              currentUri.cueIn = entry.data;
            },
            'skip': function skip() {
              this.manifest.skip = camelCaseKeys(entry.attributes);
              this.warnOnMissingAttributes_('#EXT-X-SKIP', entry.attributes, ['SKIPPED-SEGMENTS']);
            },
            'part': function part() {
              var _this2 = this;

              hasParts = true; // parts are always specifed before a segment

              var segmentIndex = this.manifest.segments.length;
              var part = camelCaseKeys(entry.attributes);
              currentUri.parts = currentUri.parts || [];
              currentUri.parts.push(part);

              if (part.byterange) {
                if (!part.byterange.hasOwnProperty('offset')) {
                  part.byterange.offset = lastPartByterangeEnd;
                }

                lastPartByterangeEnd = part.byterange.offset + part.byterange.length;
              }

              var partIndex = currentUri.parts.length - 1;
              this.warnOnMissingAttributes_("#EXT-X-PART #" + partIndex + " for segment #" + segmentIndex, entry.attributes, ['URI', 'DURATION']);

              if (this.manifest.renditionReports) {
                this.manifest.renditionReports.forEach(function (r, i) {
                  if (!r.hasOwnProperty('lastPart')) {
                    _this2.trigger('warn', {
                      message: "#EXT-X-RENDITION-REPORT #" + i + " lacks required attribute(s): LAST-PART"
                    });
                  }
                });
              }
            },
            'server-control': function serverControl() {
              var attrs = this.manifest.serverControl = camelCaseKeys(entry.attributes);

              if (!attrs.hasOwnProperty('canBlockReload')) {
                attrs.canBlockReload = false;
                this.trigger('info', {
                  message: '#EXT-X-SERVER-CONTROL defaulting CAN-BLOCK-RELOAD to false'
                });
              }

              setHoldBack.call(this, this.manifest);

              if (attrs.canSkipDateranges && !attrs.hasOwnProperty('canSkipUntil')) {
                this.trigger('warn', {
                  message: '#EXT-X-SERVER-CONTROL lacks required attribute CAN-SKIP-UNTIL which is required when CAN-SKIP-DATERANGES is set'
                });
              }
            },
            'preload-hint': function preloadHint() {
              // parts are always specifed before a segment
              var segmentIndex = this.manifest.segments.length;
              var hint = camelCaseKeys(entry.attributes);
              var isPart = hint.type && hint.type === 'PART';
              currentUri.preloadHints = currentUri.preloadHints || [];
              currentUri.preloadHints.push(hint);

              if (hint.byterange) {
                if (!hint.byterange.hasOwnProperty('offset')) {
                  // use last part byterange end or zero if not a part.
                  hint.byterange.offset = isPart ? lastPartByterangeEnd : 0;

                  if (isPart) {
                    lastPartByterangeEnd = hint.byterange.offset + hint.byterange.length;
                  }
                }
              }

              var index = currentUri.preloadHints.length - 1;
              this.warnOnMissingAttributes_("#EXT-X-PRELOAD-HINT #" + index + " for segment #" + segmentIndex, entry.attributes, ['TYPE', 'URI']);

              if (!hint.type) {
                return;
              } // search through all preload hints except for the current one for
              // a duplicate type.

              for (var i = 0; i < currentUri.preloadHints.length - 1; i++) {
                var otherHint = currentUri.preloadHints[i];

                if (!otherHint.type) {
                  continue;
                }

                if (otherHint.type === hint.type) {
                  this.trigger('warn', {
                    message: "#EXT-X-PRELOAD-HINT #" + index + " for segment #" + segmentIndex + " has the same TYPE " + hint.type + " as preload hint #" + i
                  });
                }
              }
            },
            'rendition-report': function renditionReport() {
              var report = camelCaseKeys(entry.attributes);
              this.manifest.renditionReports = this.manifest.renditionReports || [];
              this.manifest.renditionReports.push(report);
              var index = this.manifest.renditionReports.length - 1;
              var required = ['LAST-MSN', 'URI'];

              if (hasParts) {
                required.push('LAST-PART');
              }

              this.warnOnMissingAttributes_("#EXT-X-RENDITION-REPORT #" + index, entry.attributes, required);
            },
            'part-inf': function partInf() {
              this.manifest.partInf = camelCaseKeys(entry.attributes);
              this.warnOnMissingAttributes_('#EXT-X-PART-INF', entry.attributes, ['PART-TARGET']);

              if (this.manifest.partInf.partTarget) {
                this.manifest.partTargetDuration = this.manifest.partInf.partTarget;
              }

              setHoldBack.call(this, this.manifest);
            }
          })[entry.tagType] || noop).call(self);
        },
        uri: function uri() {
          currentUri.uri = entry.uri;
          uris.push(currentUri); // if no explicit duration was declared, use the target duration

          if (this.manifest.targetDuration && !('duration' in currentUri)) {
            this.trigger('warn', {
              message: 'defaulting segment duration to the target duration'
            });
            currentUri.duration = this.manifest.targetDuration;
          } // annotate with encryption information, if necessary

          if (_key) {
            currentUri.key = _key;
          }

          currentUri.timeline = currentTimeline; // annotate with initialization segment information, if necessary

          if (currentMap) {
            currentUri.map = currentMap;
          } // reset the last byterange end as it needs to be 0 between parts

          lastPartByterangeEnd = 0; // prepare for the next URI

          currentUri = {};
        },
        comment: function comment() {// comments are not important for playback
        },
        custom: function custom() {
          // if this is segment-level data attach the output to the segment
          if (entry.segment) {
            currentUri.custom = currentUri.custom || {};
            currentUri.custom[entry.customType] = entry.data; // if this is manifest-level data attach to the top level manifest object
          } else {
            this.manifest.custom = this.manifest.custom || {};
            this.manifest.custom[entry.customType] = entry.data;
          }
        }
      })[entry.type].call(self);
    });

    return _this;
  }

  var _proto = Parser.prototype;

  _proto.warnOnMissingAttributes_ = function warnOnMissingAttributes_(identifier, attributes, required) {
    var missing = [];
    required.forEach(function (key) {
      if (!attributes.hasOwnProperty(key)) {
        missing.push(key);
      }
    });

    if (missing.length) {
      this.trigger('warn', {
        message: identifier + " lacks required attribute(s): " + missing.join(', ')
      });
    }
  }
  /**
   * Parse the input string and update the manifest object.
   *
   * @param {string} chunk a potentially incomplete portion of the manifest
   */
  ;

  _proto.push = function push(chunk) {
    this.lineStream.push(chunk);
  }
  /**
   * Flush any remaining input. This can be handy if the last line of an M3U8
   * manifest did not contain a trailing newline but the file has been
   * completely received.
   */
  ;

  _proto.end = function end() {
    // flush any buffered input
    this.lineStream.push('\n');
    this.trigger('end');
  }
  /**
   * Add an additional parser for non-standard tags
   *
   * @param {Object}   options              a map of options for the added parser
   * @param {RegExp}   options.expression   a regular expression to match the custom header
   * @param {string}   options.type         the type to register to the output
   * @param {Function} [options.dataParser] function to parse the line into an object
   * @param {boolean}  [options.segment]    should tag data be attached to the segment object
   */
  ;

  _proto.addParser = function addParser(options) {
    this.parseStream.addParser(options);
  }
  /**
   * Add a custom header mapper
   *
   * @param {Object}   options
   * @param {RegExp}   options.expression   a regular expression to match the custom header
   * @param {Function} options.map          function to translate tag into a different tag
   */
  ;

  _proto.addTagMapper = function addTagMapper(options) {
    this.parseStream.addTagMapper(options);
  };

  return Parser;
}(Stream__default['default']);

exports.LineStream = LineStream;
exports.ParseStream = ParseStream;
exports.Parser = Parser;

redpajama_set_name: RedPajamaGithub


Step 1 Season pork medallions with cracked black pepper; set aside. Place potatoes and cauliflower in a medium saucepan (which has a lid), cover with water and set over high heat; boil for 15–20 minutes, or until tender. Drain veg, return to pan, cover and set aside.
Step 2 Meanwhile, add wine, cranberry sauce and 1/4 cup water to a small saucepan set over medium heat; bring to the boil. Reduce heat to low and simmer for 10 minutes, or until sauce thickens; set aside.
Step 3 Set a large non-stick frying pan (with a lid) over medium–high heat. Heat half the olive oil. Add pork and cook for 3–4 minutes per side, or until cooked through. Remove pork from pan, cover with foil and leave to rest.
Step 4 Place shredded greens, garlic and remaining olive oil in same frying pan; cover and cook for 2–3 minutes, or until greens wilt.
Step 5 Add sour cream to reserved potatoes and cauliflower; mash until smooth and season with cracked black pepper.
Step 6 Divide pork, vegie mash and wilted greens among 4 plates. Pour cranberry sauce over pork, garnish with parsley and serve.


text:
Free and legal MP3: Younghusband (deft re-intepretation of lost classic)
Unearthing forgotten Christmas classics is a holiday tradition that never grows old to me, especially when the new interpretation is this deft and the forgotten song this worth remembering.
"I Don't Intend to Spend Christmas Without You" – Younghusband
Unearthing forgotten Christmas classics is a holiday tradition that never grows old to me, especially when the new interpretation is this deft and the forgotten song this worthy. "I Don't Intend to Spend Christmas Without You" is an overlooked nugget from the overlooked '60s singer/songwriter Margo Guryan, which surfaced on a fan club recording by St. Etienne in 1998 but has otherwise been waiting for a wider audience. In a just world, this is the version that does it, starting right now with this post. (Side note: the world may not be entirely just.)
What I particularly love here is how the British band Younghusband has managed to disclose the otherwise unapparent Ramones-y heart of Guryan's rather more Bacharach-y original. The song's chunky, fitful melody was never as light and breezy as the songwriter professed in her own version; the band here exploits its truer nature by giving it a bottom-heavy feel and converting a light-as-air riff filled with la-la-las into a decisive, lower-register instrumental melody. There is something inescapably Phil Spector-ish in the air here too, as the bashy, reverbed, elusively constructed background sound feels like a tasty homage to a master who himself of course is associated memorably with Christmas music.
Meanwhile—Margo Guryan? I had never heard of her before, and yet wow, there she is, a singer/songwriter who wrote and performed in that wispy, sunshine-y style perhaps more widely associated with the likes of Claudine Longet or even, from South America, Astrud Gilberto—a style that has had an unanticipated second life here in the 21st century. Guryan began her musical career in jazz in the late '50s, and did not start paying attention to pop music until a friend of hers forced her to listen to "God Only Knows." She eventually recorded one album, 1968's Take a Picture, a light-sounding but deceptively complex collection of songs which was well-received critically but found no audience. (Guryan did not want to tour, so her record label didn't promote the release.) She thereafter abandoned her recording career, and spent most of the ensuing decades as a music teacher. She is still alive, and is active on Twitter.
Younghusband, meanwhile, is a quartet from London that released its debut album, Dromes, in September, in the UK only. Their "I Don't Intend to Spend Christmas Without You" cover was made available via their record label, Sonic Cathedral . Thanks to Lauren Laverne at BBC6 for the head's up.
For the excessively curious, the original Margo Guryan version can be heard on Spotify, here (available only to Spotify subscribers):
Author jeremyfingertipsPosted on December 19, 2013 Categories MP3sTags Christmas, cover song, UK
One thought on "Free and legal MP3: Younghusband (deft re-intepretation of lost classic)"
Sean H. Campbell says:
Color me excessively curious! This is completely great. Its greatness is complete.
Previous Previous post: Free and legal MP3: Matt Longo
Next Next post: Favorite free & legal MP3s of 2013

redpajama_set_name: RedPajamaCommonCrawl


text:
Lake Jordan, Alabama
 Lake Jordan (Montana)
 Jordan Lake, North Carolina

redpajama_set_name: RedPajamaWikipedia


text:
package tom.spark.utils.csv

import org.apache.spark.rdd.RDD
import java.io.PrintWriter
import java.io.File

object CsvWriter {
  def write(path: String, data: RDD[String], header: String = "") {
    val printWriter = new PrintWriter(new File(path))
    if (!header.isEmpty()) printWriter.write(header + "\n")
    data.foreach { line => printWriter.write(line + "\n") }
    printWriter.close()
  }
}


Steve Snape will be working from his home in Dorset and helping to provide our products and services to clients in his area. He will be known to many of you and we are sure he will be a great asset to our team.
To contact Steve please call his mobile on 07827 290322 or the office on 01480 890686.


text:
"YOU KNOW WHERE YOU ARRREE!!?? Guns N' Roses To Rock Fenway Park
Andy Austin
Andy Austin Published: February 3, 2020
Frazer Harrison, Getty Images
Fenway Park's concert lineup might have more hits than the Red Sox this summer.
Boston is going to feel very 1988 this summer. First, Def Leppard, Motley Crue, Poison, and Joan Jett announced two shows at Fenway Park. Just a few weeks ago, Bon Jovi announced they were headlining the TD Garden with Bryan Adams.
It's widely believed the success of Guns N' Roses 'Not in This Lifetime' tour of a few years ago paved the way for this summer's Def Lep/Motley/Poison/Jett stadium trek. Monday morning, it was announced Axl, Slash, Duff, and crew will invade Fenway Park July 21st. Tickets go on sale Feb. 7, according to Live Nation.
While other bands like The Black Crowes are celebrating a 30 year milestone this summer by playing a classic album front to back, Guns were focuses on recording what would become the Use Your Illusion albums in 1990. Also, they fired original drummer Steven Adler for taking too many drugs. Adler has since mended fences with the band, and has joined them on occasion. However, he is not a regular member and isn't expected to participate at Fenway Park. Classic era guitarist/songwriter Izzy Stradlin has also been MIA since the reformation of the classic era lineup.
Filed Under: concert, fenway park, Guns N' Roses, live music, Live Nation, Music, Rock, summer


EAW034923 ENGLAND (1951). The Festival of Britain South Bank Site under construction, Lambeth, 1951. This image has been produced from a print.
Title [EAW034923] The Festival of Britain South Bank Site under construction, Lambeth, 1951. This image has been produced from a print.


Atlas Inkjet System Control Software – a powerful platform for system control. Features include nozzle-out compensation, printhead linearisation, rotation, skew and distortion correction capabilities, and direct-to-complex-shape software.
Ink / Fluid Delivery Systems – a successful production-proven range of components – comprising software, electronics, and all key system components for different flow rates, with optional independent pressure control per fluid, and high-flow, high-laydown capability. All parts are extensible, enabling GIS to offer tailored solutions for industrial inkjet systems of any size.
To find out more, visit Stand Q18 at IDTechEx Show 2019.


Ng is a very light weight Emacs clone editor, written in C.
changing small file a bit.
japanese port. Ng supports EUC, JIS and SJIS code.
Ng also have (rather simple) C-mode.
It is also very useful even if you don't need Japanese support.
Add socket libraries on SunOS.  Fix from Sebastian Wiedenroth.
Add termios.h formerly included by unistd.h.
Update to 1.4.4+official patch, from ISIHARA Takanori in PR 47134.
While here, do some pkglint cleanup.
a) "mark" was changed like GNU Emacs from Ng 1.5alpha3.
b) fix canna bug for UNIX.
c) fix compile problem when libc was used for Human68K.
1) Add missing mk/termcap buildlink3.
3) Enable "USE_CANNA" on Linux and SunOS.
(1) specify PKG_OPTIONS.ng= -canna in /etc/mk.conf.
always, but the current Makefile does not consider it.
(2) compile ng on system-V like platforms e.g. *-linux, Solaris.
pkgsrc Makefile is only suitable for BSD platforms.


If you have generated an address on faucethub on Deposit page, that address cant be linked on Wallet Addresses page because is not from a real wallet. The error returned is same as you described.
Thanks for update and for fixing the problem. I did few claims and i can confirm that now everything is ok with the new website. I do claims when i can but dont forget to test the claims because from time to time bugs related to shortlinks can occure, or some shortlinks may send infected popups, so you can fix the problems (recommended is to rotate shortlinks) so people wont believe that bugs are simulated. You can start advertise the faucet to get more users and i would ask a Faucethub moderator to delete this topic or flag it as resolved.
The minimum withdraw amount for PPC coin is 5 PPC which means $ 2.70 (almost 3$) , while average amounts for other coins in USD is $ 0.5. Maybe PPC withdraw amounts and fees has not been adjusted since some time ago when the coin was worthing less $$ ? Can you lower the minimum withdraw amount for PPC for users ? (unless the official desktop PPC wallet does not accept incoming amounts lower than 5 PPC just as it was for blockchain.info not accepting lower than 20000 satoshi incoming ) Thank you.
Posted in General Talk Faucet Discussion Updated Dutchy AutoFaucets to Earn or Level Up very Fast !
RE: Updated Dutchy AutoFaucets to Earn or Level Up very Fast !
dutchybeatz fix your dutchycorp 4 minute autofaucet counter or i will consider youre scamming people because your counter jumps from 10 to 6 and then to 2 credits available. The counter should decrease by 1 credit not by 4. People be careful with the counters on his autofaucets.
Thank you for your time and for reply. I have tried again and still nothing : https://imgur.com/kAP5H6G (tried to link a screenshot but isnt working here) i keep my opinion as either this is a simulated bug, either the owner is a amateur who doesnt even test his website.
http://takehomemonero.faucethero.com/ first time when you visit the faucet you have to input the monero address. So far so good but after finishing the captchas from shortlinks you get redirected on the homepage with the error: "Shortlink verification failed. Please try again." and bellow there is a button: "VERIFY SHORTLINK" Even if you come back later there is the same message displayed. Which makes you visit over and over the shortlinks without getting paid. Other notices : -the website is loading slow and sometimes returns just a blank page instead of content on the homepage. -on the top right corner the balance of the faucet is : Balance: 0.04694048 -it seems to be one of the faucets of the faucethero : Powered by: FaucetHero.com Can someone check this faucet if the bug is simulated or real. What makes suspicious is that the message keeps displaying and there is no way to add again the address . Thank you.
thank you for your time and reply. So its either those colorful rains are flagged as "rainmaster" in the history list , or im not eligible by chance to get rain when (autofaucet.org) rains , either there is something wrong or a bug . Because the real rainmaster make rare rains but when i see those colorful mesages about rain i dont get any altcoin at all (and history list entries too) and this is not by chance because i keep monitoring very closely since yesterday and no amounts are added at all to my altcoins between the real rainmaster rains. Can't make a youtube video proof because of space on hdd or my free time, anyways thanks for your time and replies again. I'll move this mistery to X-files and keep claiming and hoping those colorful rains are for real :).
Thank you very much i didn't knew about color meaning , i thought it has something to do with mining on FH or being a veteran. Speaking about colors: I wonder why i dont get anything as rain from those colorful messages , i get rain only from the rainmaster. Are those messages fakes by bots to advertise their faucets ? (autofaucet.org, bitco.world, etc) . My umbrella is green ( i have even 50 payouts daily and 17 faucets visited and talk in chat) and i did refreshed to check the amounts on my altcoins , so no rain amount entries from such mesage in the chat. The chat mentions notify me only when i get rain from rainmaster . Can you tell me what's the catch ? Are those colorful rains country targeted or the user has to claim especially on those websites? I see people saying "thank you autofaucet.org for the rain" and thats funny for me :). Tha chat is spammed with such colorful rains and makes me think those are not real at all even because are so many rains and who will give such amounts every few seconds without getting bankrupt.
Nice ! i'm the one who answered you on the bitcointalk forum . I like it because there are no annoying popups and when i told you about that infected short link, you have removed it immediately ! Highly recommended.
Posted in General Talk Faucet Discussion Free Bitcoin Auto Payouts!
RE: Free Bitcoin Auto Payouts!
once you go to home page always a login and register button displays. Long time registering procedure, confirmation comes to email after 1 or 2 minutes. After clicking on registering email i got redirected and receive a registration code which is useless . Back to home page the buttons Login (and Register) keeps displaying even if you are logged in. There is no account displaying button or name display to see your settings if any, no logged in confirmation at all . The roulette is just a dead image ,is not working. The scratch cards redirects to a error 404 page. You claim on faucet but there is no display that you are logged in . "Payouts made automatically, every 20 minutes, to your faucethub.io account" .....so payments are not instant. Free bits - "A minimum of 30,000 Bits is Needed to Withdraw into Bitcoin" ...ok I have the feeling that i know the bitcoin and i'm user/tester of faucets before you even heard of bitcoin. Got payed at least here is the proof (i dont know why the payment is flagged as referral because i didnt advertised yet) : https://i.imgur.com/f2mW2Zp.jpg Amateurs in rush, you should test the faucet before releasing ,specially the login feature.


Another day, another non-vegan item I can't live without! Creme eggs are one of the universe's greatest creations, but alas - they are full of animal products and that simply won't do. I've been waiting for Easter to try out this simple recipe for homemade creme eggs, and the best thing about them is they can be made with any vegan chocolate you like! Next I'm going to try chocolate orange flavour eggs using Tesco own-brand dark chocolate with orange, and a drop of orange essence in the fondant.
If you've been vegan for any length of time, no doubt you'll have hunted down your favourite vegan chocolate varieties available in the supermarket. There are some super luxurious ones that mimic milk chocolate, like Ombar in Waitrose, but I've found I'm pretty happy saying farewell to milkier chocolates and switching to darker (slightly healthier) varieties. You can grab super cheap bars of dark/plain chocolate in most supermarkets, although these are at risk of containing sustainable palm oil, so if you have a few pennies to spare I recommend Divine or Montezuma. You can find a list of the best and worst ranking ethical chocolate makers at Ethical Consumer here.
For this recipe, you will need a silicone Easter egg mould like this one. You can use any size, but I've gone for little eggs because you can eat more. Logic.
1. Create a bain-marie by heating a pan of water over the hob until it is simmering.
2. Chop the chocolate into smallish pieces and place them in a heat-proof jug or glass bowl over the simmering water. Stir gently until the chocolate is fully melted.
3. Pour the melted chocolate into each egg mould until the shape is full up, then place in the fridge for 5-10 minutes to allow the chocolate to start cooling.
4. After a few minutes, take the mould and scoop out a small amount of chocolate from each semi-solid egg, leaving a small hollow in the eggs. Pop the mould back in the fridge and allow the eggs to completely cool. You can use the leftover chocolate to make more eggs later (or just eat it).
5. Meanwhile, make the fondant centre by combining a few spoonfuls of icing sugar with a little water. Adjust the quantities of each until you have formed a thick fondant mixture that holds its own shape.
6. Remove a quarter of this mixture and add to a separate bowl with 2-3 drops of yellow food colouring (add more for a richer colour). Stir well to form the yellow part of the fondant centre.
7. When the chocolates are cool and solid, remove from the fridge and pop out of their moulds. Carefully scoop a blob of white fondant into each side of the egg halves, then add a small scoop of yellow before pressing the egg halves together to create a whole egg. Remove any excess fondant that might squidge out of the sides, then seal the eggs with a tiny bit of melted chocolate.
8. Don't worry if they look a bit messy - they taste delicious! For an extra flourish you could wrap them in foil, but they're best served in an oozing pile, drizzled with melted chocolate. Enjoy!


Meander down the Niger River, traverse the slopes of Mount Bintumani, feel the sand beneath your toes on Bojo Beach or float in the pink water of Lake Retba. An atmospheric and evocative musical journey through West Africa!
Tell us a little bit about yourself: where were you born, where did you grow up and what career did you dream of having?
Well I was born in the north-west province, in a small town called Saulspoort. From there I grew up in Mahikeng. In high school I was not really sure what I wanted to do once done with matric. When I got a varsity I did a bridging course which highlighted the aspects of marketing as a career and from there I pursued my marketing degree.
What do you do from Monday to Friday, 8 to 5pm (or thereabouts)?
I'd have to say it's mostly music. If I'm not researching sound manipulation techniques as well as the effects of frequency on the body in its auric field then I'm probably looking into new production techniques that I can I add to my arsenal. I also produce music for other artists as well as my own production library.
What takes up the rest of your time?
I'd have to say looking into new ways of staying afloat in the music industry is what preoccupies most of my time.
When did the desire to make music first grab you?
The desire to 1st make music came in high school where I first learnt to DJ. It was great to play other people's music but I always wondered what it would be like to actually make a song myself.
What gear do you use to produce music?
Currently I use Reason to build concepts as well as the basic mixing all my projects and then Cubase to do all the final mixing and mastering. I have a Rhode mic, a UAD-2 satellite mastering unit, Korg MIDI keyboard, a Lexicon Omega soundcard, KRK rocket 8 monitors and a Yamaha MG166cx mixing console. That makes up the core of my production gear.
Which artists or composers have influenced you over the years?
I'd have to say Charles Webster in terms of the house genre and J Dilla in terms of the hip-hop genre have greatly influenced the way I approach my production process as a whole. Rather than trying to create a specific sound according to the norm I incorporate a fusion of the different aspects of multiple genres in order to achieve a feeling and mood that's unique to just me.
What are some of the challenges for local composers, artists and musicians and in South Africa?
I'd have to say the biggest challenge is that the industry's heavily fragmented. Meaning that a composer or artist cannot rely on the conventional avenues of old like CD sales with the advent of digital sales and streaming that have cut earnings greatly for the up-and-coming artist. Even radio play is not guaranteed with a great song as trends dictate what makes it to play listing or not. Now one has to find other ways of adding value to their catalogue by incorporating music into ad and brand campaigns through sync deals and corporate partnerships. Well that's just one way as you will still need to figure out a couple more.
How did you find out about the production/library music industry?
I initially started composing music on a fellow producer's record label. He was doing his publishing through another company. The publishing company that was doing his admin inquired as to whether I'd be keen on doing production music and not just commercial. I was unfamiliar with the term production music so I began to do some research and I realized that it was actually a great stream to get into. I've been at it since 2013 and haven't looked back since.
What would you do if you had to stop working in the sound/music industry?
If I had to stop working in the music industry I'd probably be working in advertising or a marketing department for a company I believe in. Well only if I had to.
The STARS are shining on Mama Dance !
The music industry is changing fast, and as artists have seen their CD sales slashed and are still waiting for streaming and download income to catch up, other business models have stepped up to provide much needed income to composers and musicians worldwide.
Due to the explosion of media, especially online content, but also TV, radio, apps, podcasts and games, a huge demand for "ready to go" music has been created. And because the aim is to maximise eye balls or ears on the content, the creators are reluctant to infringe copyright legislation by using unlicensed music. The swathe of digital monitoring technologies that constantly reports all music broadcast and streamed online also helps copyright owners identify illegal music usage.
Numerous high-quality music libraries are now supplying a wide variety of production ready music to content producers, final mix engineers, ad agencies, corporate communications companies, podcasters and thousands of amateur YouTubers!
One such library is The Mama Dance Music Library. Started in 2002, 16 years and 170 albums later, the library is booming in South Africa, Africa and Internationally.
Much of the library's success is due to its niche as an African production music library, which covers genres from Boeremusiek to Kwaito to Bongo Flava and Maskandi. Its focus is both on traditional sounds as well as the latest urban and EDM flavours from Gqom to Hip Hop, Trap and House.
With a reputation for releasing high quality albums, the library has attracted renowned composers such as Dizu Plaatjies, long-time Johnny Clegg collaborators Andy Innes and Barry Van Zyl, Freshly Ground's Josh Hawks, Bright Blue's Tom Fox, Themba Mkhize and Steve Newman.
What made you decide to compose for production music libraries?
Andy: Production music is a last bastion in many respects. The composer has more freedom to create than they do in other spaces in the industry. Production music is also a space that is still profitable in the long term if you can find enough avenues to keep pushing out product, providing the quality of your output is top notch.
Josh: The decision to compose for libraries is a natural progression of a composer's life. We're content providers and the libraries are becoming more and more prevalent and relevant. If you are a composer and have a catalogue of ideas knocking around it's a great avenue to pursue!
How has your experience been working with Mama Dance?
Andy: Mama Dance is a professional and hard-working outfit who look after their writers. I'm really glad we've managed to build a good relationship.
Josh: Experience with Mama Dance was easy going and collaborative. We'd throw some ideas their way and with their experience and knowledge of the landscape, they would advise as to what was working and how to shape the material. Everything took shape quite quickly; a painless collaboration.
These great artists music can be easily auditioned and downloaded at www.mamadance.com using simple music search functions.
And if clients prefer searches to be done for them, this is where the friendly Mama Dance team is on top of their game – they know and love music! Their free, personalised music searches are fast and on point. After receiving a music brief, the team will send the client a playlist of track selections within an hour.
This type of service, together with compelling music from big name composers, keeps clients coming back for more and ensures that Mama Dance remains South Africa's favourite music library.
The simplified 2018 music rate card can be downloaded from their website and new clients will be pleasantly surprised at how little it costs to license fresh and innovative music produced by big stars!
Mama Dance is a CAPASSO affiliated library and can be used under the blanket license agreements with SABC, ETV and many Multichoice (DSTV) channels.
Mama Dance ! Music Library track used in latest Samsung ads!
A fun-filled Funk-themed album. Some tracks are straight happy, high energy funk and others blend with African styles like Gospel and Maskandi to create a very unique fusion that you won't find on any other library! Either way it is sure to make you FEEL GOOD!
The album that originally made James Brown feel good! Okay not really, but it is still a great selection of upbeat folk tracks to follow on from the extremely popular first album. Some Ukes, Banjos, Marimbas and Guitars to make you feel like a room without a roof!
Jam-packed with happy catchy folk rock tunes that will make even the grumpiest grinch feel good!!! Prolific Mama Dance composer and melodic genius, Matt Gair, is back with his best album yet! An ad agency and positive Lifestyle TV producer's dream album.
Another superb album from popular composer Matthew Gair! It's filled to the brim with foot-tapping, head-bobbing, smile-on-your-dial, acoustic African tracks played on guitar, marimba and ukulele. These catchy tunes will definitely bring some light-hearted fun to your production.
For fans of the very successful Easy Folk Pickings series. Extraordinarily beautiful acoustic melodies played on Guitar, Ukulele, Mbira and Marimba covering moods from light-hearted and quirky to peaceful and heart-warming. A 'Must-Listen' album!
A beautiful selection of lush African vocal orientated tracks with positive, uplifting, warm and inspiring moods. Energy levels are gentle right through to fast tempo and high energy.
Compelling West African Afro Pop for Corporate, Reality and TV programming.
Your soundtrack to the African summer! These feel good, warm and easy-going electro-folk tracks are the ideal accompaniment for a truly magical summer. Tailor-made for lifestyle programming, trendy productions, wildlife shows and anything else that needs a shot of vitamin D.
This album is truly beautiful, often seductive and often not shy to put on its dancing shoes! Styles vary from 70's style melancholic Cape Verdean, to pacey Angolan Semba and romantic Kizomba. A very memorable album that you'll probably download to play at home!
New Library Music Release – Feel Good Africa – Folkin' Fantastic!
Happy Go Lucky, Cute but Tender, Warm and Contented, Chirpy and Fun are all adjectives that spring to mind with this crossover album that combines western acoustic pop and folk with African elements. Road trip to the Wild Coast anyone?


text:
Q: swift-firebase create user does not work Why does this code does not create a new account? I connected it with my Firebase console but there is always an error if I run it and click on the button. Can anyone help me?
FIRAuth.auth()?.createUser(withEmail: "user1@gmail.com", password: "123451", completion: { (user, error) in
    if error != nil {
        print("error")}
    })
}

Here is the the console with the error:


Irish company Kastus has come a long way. Since beginning life as a spin out from the Centre for Research in Engineering Surface Technology at Dublin Institute of Technology (CREST DIT), the company has gone on on to win the overall prize at the prestigious Irish Times Innovation Awards in 2017.
But neither is Kastus an overnight success story. Its innovative solutions have been ten years in the making, involving collaboration with scientists at Caltech and Trinity College Dublin.
It is two years since the company secured a worldwide patent for its photocatalytic antimicrobial coatings and additives, which are +99.99% effective against even the most difficult 'superbugs', including Clostridium difficile, Campylobacter and MRSA. Securing those patents has enabled Kastus to commercialise the antimicrobial coating for an incredibly broad range of applications including ceramics and glass.
"The investment we put into our patenting process is significant. Our Intellectual Property is key to the business," explains John Browne, Kastus founder and CEO.
Kastus is currently in the midst of a multi-million euro investment round raising additional capital to ramp up commercial expansion. By the end of this year, Browne sees the company doubling the number of its employees to a staff count of 30. He is especially interested in recruiting personnel with the language skills to sell into Europe. "Initially, they will be employed in Dublin," he says. "But as we grow we will be looking to have personnel based overseas.
With innovation at the heart of the company, it is no surprise that Kastus continues to push the boundary of the potential applications for its coatings. Browne explains, "We have a range of products in development and have recently launched a solution that can be used on metals. This coating has many applications including the aviation, architectural hardware and consumer electronics sectors. As the solution is both antimicrobial and anticorrosive, there are applications both large and small. We see the product being used on sinks, worktops and on door handles, in hospitals and cleanrooms in the food industry, but also in offices and in the home. We also have a patented zeolite product that is a great fit for the paint industry.


Comcast Corporation has bowed out of continued negotations with 21st Century Fox for its entertainment and sports assets. In a statement to Variety, the conglomerate said they "never got the level of engagement needed to make a definitive offer."
Talks between Fox and the Walt Disney Company are reportedly still ongoing.


text:
cook_islands_logo_white
LovaALittleRaro-143x115px
/rarotonga
/en-AU/islands/aitutaki
Atiu
/en-AU/islands/atiu
/en-AU/page/mauke
Mangaia
/en-AU/islands/mangaia
Mitiaro
/en-AU/islands/mitiaro
Our History & People
Explore by Land
Explore by Water
Choose from a range of accommodation options. Luxury villas, resorts, hotels and holiday homes. We are sure to have something to suit you.
Lagoon cruises, fishing, guided mountain hikes, buggies, cultural island nights. Do as much or as little as you like in our little paradise.
JETZT Suchen!
Flight Centre Sale - $499 Return Flights
AusTravel
Trailfinders
Turquoise Holidays
Tour Pacific
SÖDERHAVSRESOR
All Exclusive Offers
MYPLANET
PlaneFlights
Information on how to get to the Cook Islands, travel between islands, or combining travel with New Zealand and/or Australia.
AccommodationAccommodation
Getting AroundGetting Around
TalkTalk with a specialist
Need help with your travel planning? Talk with someone who's been to the Cook Islands.
Local ServicesLocal Services
The Cook Islands lies halfway between New Zealand and Hawaii, boasting an idyllic climate, endless adventure, romance and pure relaxation. And getting here is easy with flights on Air New Zealand, Virgin Australia, Jetstar and Air Tahiti as well as domestic flights between the islands with our national carrier Air Rarotonga.
Walk the beaches less travelled.
It's the accessibility and ease of everything that makes Rarotonga so different from other South Pacific island destinations.
Just 32 km in circumference, you can drive around the island in 40 minutes. With a wide range of scenery, activities, accommodation, restaurants and cafes, no matter where you are or what you want to do, the whole island is your playground.
Often called 'Heaven on Earth', Aitutaki is a place to enjoy pure paradise.
Only a 50-minute flight north of Rarotonga, it's spectacularly beautiful, with a triangular-shaped reef surrounding a bright turquoise lagoon containing 15 small motus (islets). The crystal-clear water is home to an array of tropical fish and its pristine white-sand beaches are private and secluded. Tony Wheeler, founder of Lonely Planet, has said Aitutaki boasts, "the world's most beautiful lagoon."
For the truly adventurous in spirit, the undeveloped outer islands have a remote, unspoiled appeal for the explorer, author and artist in all of us. Seven sister islands are in the rest of the southern group and six more lie to the north. Some are accessible by local flights, all are accessible by boat occasionally. Off the beaten track, and spread over 700,000 square miles of the South Pacific Ocean, their uniqueness and timelessness are their own reward.
There are a few places left in the world like Atiu, an island over 8 million years old - ancient, remote, and lush with dense rainforests and coastal bush. Known as the land of birds, Atiu is about half the size of Rarotonga. Villages are in the central plateau where soil is rich, and some of the best coffee in the Pacific Rim is organically grown.
Mangaia is traditionally known as Auau enua. Geologists have estimated the island at over 18 million years old, making it the oldest island in the entire Pacific. Mangaia is the second largest and southernmost island of the Cooks. This island is made up of raised limestone coral, peppered with numerous caves that stretch into giant underground caverns.
The traditional name for Mauke is Akatokamanava which translates to "where my heart rests." It's a fitting name for this little garden of Eden, as many visitors find the island takes hold of their heart on arrival. Often described as the garden island of the Cook Islands, it is hugged by a close reef where everyday locals can be seen catching their evening dinner.
Does sleeping under a kikau thatched roof with the sound of the waves rolling in seem like the ultimate island escape? Also known as Nukuroa, Mitiaro is one of the most beautiful, yet remote islands in the Pacific. Mitiaro has a distinctive history, plus the unique appeal of some of the most stunning subterranean limestone pools and caves in Polynesia.
Our Other Islands
Described as "the stuff that dreams are made of", their remote appeal pulls at the hearts of explorers, adventurers, authors and artists.
Manihiki
Pukapuka
Rakahanga
Takutea
Suwarrow
Manuae
SIGN UP AND WE'LL KEEP YOU IN THE LOOP WITH OUR BEST DEALS AND UPDATES.
The official site of Cook Islands Tourism Corporation
Privacy | Site Map | Back To Top
We've got your details and we'll be in touch soon.