text:
ResultSelection2021
SelectionFinals 2021
WINNER biopartner LEIDEN JAZZ AWARD 2021
Processing personal data
This document (file in the sense of the NGPR) sets out how the Leiden Jazz History Foundation, acting under the name Leiden Jazz Award (hereinafter referred to as the Foundation), handles the (personal) data entrusted to it, with which bodies the data is shared and why, and how the consent of the data subjects is regulated.
The privacy statement of the foundation is also included in this file, and it describes how the privacy statement is brought to the attention of all those who are involved with the foundation.
1. Whose data is kept
2. What data is stored
3. How are these data stored
4. The files
5. With whom are the data shared
6. What are the data used for
7. Control decisions regarding the AGV
1. Whose data is stored
The secretariat and treasurer of the Foundation store and edit data from all participants in the annual competition, the Dutch conservatoires, sponsors, donors and other legal entities that contribute to the realization and realization of the annual competition that the Foundation issues and provides.
Finally, the foundation stores data from and about regional press agencies and subsidizing institutions.
Secretary and treasurer each keep an overview of participants, conservatories, subsidisers, sponsors and such legal entities who are registered with the Foundation. As well as officials acting on behalf of these legal entities, such as board members, webmasters, financial contacts.
The settings are saved:
Web address (url), Web address (url) of the periodic publications of these institutions (newsletters, magazines, magazines, etc.), Contact address (e-mail address), Contacts and their e-mail address: - Name and function, - Functional e-mail addresses such as: info @, treasurer @ , chairman @ and so on or, if these are not available, - the private mail addresses of the relevant officials. If applicable: the physical correspondence address
In addition, the participants of the competition are kept:
Name, date of birth and place, Conservatory where it is registered, Email address, Eventual web address, A photo, A curriculum vitae, Bank details (account number)
The data is stored in Microsoft Excel spreadsheets 'Contacts 20xx.xlsx' for the annual subsidies or contributions for the competition organized by the Foundation.
In the spreadsheet 'and' Participant 20xx.xlsx 'for all the information mentioned above under 2 with respect to the aforementioned participants and their representatives, insofar as these are relevant to the competition website and the dissemination of information far this competition. In addition, in the spreadsheet 'Relationfile.xlsx' information is kept for internal use with regard to subsidizing institutions, press contacts, venues and volunteers who support the activities of the Foundation. The Sheets are stored in Google Docs / Google Drive and on the personal computers of the secretary and the treasurer. Of these files, a back-up is periodically produced and is also stored in 'the cloud'.
To the extent that the Foundation has been able to establish all servers in Europe / Netherlands.
The spreadsheets are protected with a password. The treasurer's computer is secured with professional Avast software against burglary, hacking and the like.
Used abbreviations: N = name / No (organization name), A = address, W = place of residence (including the postcode), E = email, T = phone
Spreadsheet 'Contacts':
Name (organization), Place (organization), Invoice Date, Date Reminder, Date Paid, Amount, Email financial contact, Name financial contact
The information was collected by the treasurer of the Foundation and checked for correctness by those involved. This check is also intended to obtain explicit permission for the use of said data for the collection of the participant's contribution.
Spreadsheet 'Relationship file'
Divided over several tabs, the information gathered centrally, for the benefit of the secretariat, is necessary or useful for the realization of the objectives of the Foundation.
1. Affiliated organizations: NoAWTE - This information is derived from public sources: generally the website of the relevant organization.
2. Webmasters: NoNWE - This information is derived from public sources: in general the website of the relevant organization.
3. Sheets: Naan organization; NE - This information is derived from public sources: in general the website of the relevant organization.
4. Board: NAWTE of the directors of the Foundation, the committee of recommendation, members of the working groups and the editors of the website - this information was made available by the persons concerned to the board
5. Regional media: NE - This information is derived from public sources: generally the website of the organization in question.
6. Funds: NAWE - This information is derived from public sources: generally the website of the organization in question
7. Sponsors: NAWE - This information is derived from public sources: in general the website of the organization in question
Spreadsheet 'participants'
Name and surname of the participant, Date of birth, Place of birth, Name of the conservatory, Instrument, Street and house number of place of residence, ZIP code and place of residence, Telephone / e-mail / site, Preferred day of round, Names of supervisor (s), Date of birth of supervisors, If the candidate is admitted the bank number is added to the competition.
The Foundation will retain the aforementioned information exclusively for the benefit of the Foundation and the tasks entrusted to its management, such as the management of the website and the collection of the contributions for the maintenance of this website. The data is not shared with any external party.
The data made available to the Foundation are used for the following activities:
1. Invoicing for the contribution to the creation of the competition (or the donation) is done once a year via email. On this occasion, a reminder will be sent no more than twice, also by email;
2. Announcements of periodic meetings or meetings.
3. Press releases about the competition, participants and winners.
7. Governance decisions regarding the NGPR
If the board of the Foundation is of the opinion that a formal issue from the law constitutes an unreasonably heavy burden for the Foundation as a small organization, the board will make a reasoned decision about it. If this is the case, then the relevant decision will be recorded in the NGPR file as a board decision on the NGPR.
The Foundation will not appoint, or need to appoint, any Data Protection Officer due to its size and the nature of the stored information. This task is fulfilled by a designated board member: the Treasurer in consultation with the Secretary.
The Leiden Jazz History / Leiden Jazz Award Foundation registers participants, volunteers and drivers such as name, address, place of residence, e-mail address and other information to the extent that these are necessary for the annual competition or the implementation of the sponsorship (membership) or the processing a one-off gift. We provide your data - if applicable - exclusively to parties that perform services for our foundation. All information entrusted to us is treated confidentially by us and our suppliers.
Your email address will only be used to send information that concerns our foundation.
Your data will only be used for the purposes for which it was obtained.
You can unsubscribe as a donor at any time. Send an e-mail to This email address is being protected from spambots. You need JavaScript enabled to view it.
You can also give address changes and other changes to our secretariat.
The Leiden Jazz History / Leiden Jazz Award Foundation ensures proper and appropriate protection (both technically and physically) of the (personal) files entrusted to it.
Competition rules and privacy policy
To download the rules for this year's competition you may click here. You will find the competition rules as a pdf with verso information about the way we handle your personal data in accordance with EU rules.
New name!
The Stichting Leidse Jazz Geschiedenis (Leiden Jazz History Foundation) was founded in 2006 with the single goal to write the history of jazz music in Leiden. That aim was realized with the publication of a bulky book in 2008. Ready! one should think.
But in 2009 a new initiative was started: a annual competition for young -professional – musicians. Students from one of the Dutch conservatories. In 2018 the 10th edition of the competition was held. The Foundation will, as of now, be operating under the name Leiden Jazz Award.
Intro Result 2021 Selection 2021 Rules Privacy policy Organisation Contact


Membership in the Canadian Tax Foundation is open to all. Membership is for a 12-month period that begins on the date that we receive your application and payment.
An individual who has been working in tax (for a firm or a corporation, in sole practice, or in another capacity) for more than 10 years—that is, more than 10 years have passed since the individual's tax practice start date.
An individual who has been working in tax (for a firm or a corporation, in sole practice, or in another capacity) for 10 years or less—that is, no more than 10 years have passed since the individual's tax practice start date.
An individual who is actively employed in an agency or department of a provincial or federal government.
An individual who is on the full-time teaching staff of a recognized college, university, or other educational institution.
An individual who attends full-time a recognized educational institution.
A Foundation member who is 65 years of age or older and is no longer practising tax.
NOTE: For memberships of individuals living outside Canada, $55.00 is added to cover additional mailing costs.


text:
kubota mini excavators
UK's best selling mini excavator range from KUBOTA Construction Machinery. With over 17 models to choose from including traditional tail swing, reduced tail swing, and zero tail swing.
KUBOTA UK were formed in 1979 and based at Thame, Oxfordshire. Kubota (U.K.) Limited is a subsidiary of the Kubota Corporation, which was established in 1890 as a manufacturer of cast-iron water pipes in Osaka, Japan. In the early 1900s, the Kubota Corporation turned its attention towards powered equipment. The tremendous expertise and experience gained over the past century has led to many important product developments, helping reinforce Kubota's position as the number one world-wide within the various market sectors it serves.
Dedicated support for KUBOTA equipment starts at KUBOTA (U.K.)'s Oxfordshire headquarters, which house the company's sales and marketing teams, distribution, service and parts support, training and product development for the UK and Irish markets. The efficiency of the Thame operation was recognised in 1996 when KUBOTA (U.K.) Limited was awarded ISO 9002 accreditation for its quality systems. Today, KUBOTA remains the best selling mini excavator in the UK, and this is down to the highest of manufacturing standards in its Japanese and German factories, product reliability, durability and low running costs as
well as excellent resale values.
http://www.kubota.co.uk/
Since the development of its first mini excavator in 1974, Kubota has been extending the limits of design and technology in the production of equipment incorporating optimum economy, environmental awareness, ease of operation and functionality.
Utilising the same technology as Kubota's world renowned tractors, the rugged, versatile RTV900 all terrain utility vehicle delivers outstanding performance for an exceptional drive, whether work or pleasure.
Continued model development and growth has seen the KX Series expand into a formidable line-up of machines capable of handling the toughest of tasks on the most difficult of terrains.

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Groovy - Get shortname of the month in German I try to get the short name of the month in groovy, but in German... (Jan, Feb, Mrz, Apr...)
I can get it in English with the simple statement:
mydate='2012-11-23 02:26:55.983'
origDate=new Date().parse('yyyy-MM-dd H:mm:ss.S',mydate).format('MMM')

but in german ?
thanks in advance!

A: Use SimpleDateFormat:
import java.text.SimpleDateFormat

String mydate = '2012-03-23 02:26:55.983'

SimpleDateFormat sdf = new SimpleDateFormat( 'MMM', Locale.GERMANY )

assert sdf.format( Date.parse( 'yyyy-MM-dd H:mm:ss.S', mydate ) ) == 'Mrz'

Longer example:
def months = new SimpleDateFormat( 'MMM', Locale.GERMANY ).with { sdf ->
  (1..12).collect { month ->
    sdf.format( Date.parse( 'MM', "$month" ) )
  }
}
println months

prints:
[Jan, Feb, Mrz, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]

redpajama_set_name: RedPajamaStackExchange


Around the year 2000 were any of the people involved aware of any drastic physical changes in conditions on Mars? If so what were they?
ANY THOUGHTS ON JADE HELM 15?
ALL TELLING LIES.. and they Know it.
It is so VERY VERY DISGUSTING.


text:
"Silicon Valley" & "Veep" Return For Near-Perfect Comedy Hour
by Brian Tallerico
When the second season of "True Detective" was met with skepticism last season, there was some theorizing that HBO viewers had become accustomed to arguably the network's three best shows from April to June, in a block that included "Game of Thrones," "Silicon Valley" and "Veep." Not that the following should be the barometer of greatness, but that's the Emmy winner for Best Drama and Best Comedy in one two-hour block on one network (and I wonder if that's ever happened before). It's quite a bar to set for whatever comes after it. And most critics agreed that season two of Mike Judge's comedy improved on the freshman year and that "Veep" had never been funnier. Where do the two shows stand a year later? The same place, basically.
If anything, "Silicon Valley" feels more confident, less uncertain of its identity or place in the TV landscape, and more willing to utilize its excellent supporting cast, especially Kumail Nanjiani and Martin Starr. The lack of notable female characters continues to be a bit alarming, but it's hard not to agree with Judge's assertion that this is reflective of the industry he's capturing more than anything else. At the start of season two, Richard (Thomas Middleditch) has been fired from his own company, back with the boys and ready to join another tech start-up. The season premiere finds the group torn apart as Richard seeks new work and assumes that people like Dinesh (Nanjiani) and Gilfoyle (Starr) will just go with him. Meanwhile, Gavin Belson (Matt Ross) continues his scorched earth campaign at Hooli and Erlich (T.J. Miller), well, mostly just gets high.
"Silicon Valley," much like "Beavis & Butthead" and Judge's other work, perfectly balances the stupid with the brilliant. There are tech elements of the show that go over my head and the character work is much better than people give it credit for, but it's also a show that features a scene of horses having graphic sex. It can be both puerile and brilliantly clever. It's one of the reasons I love it so much—its funny bone seems just a bit out of place.
While "Veep" may be a more traditional comedy, it's also smarter and arguably the best on TV. The big drama in the off-season was the departure of Armando Iannucci, creator and showrunner for the first four seasons. Don't panic, HBO didn't bring in a new crew to run the show, turning the keys over instead to David Mandel, who worked on the show since the beginning and was a major writer on "Seinfeld." Consequently, "Veep" hasn't lost much in the way of wit and energy. I have to say there are a few jokes that fall flat in the first four episodes of the new season, and I wondered if that was because of the new regime, but I may be looking too hard for problems.
Last season ended with Selina Meyer (Julia Louis-Dreyfus) in an Electoral College tie, and the first arc of the fifth season focuses on the recount effort, particularly in Nevada, where Amy (Anna Chlumsky) is sent to lead the way. The energy this season feels a little unfocused at times, but when "Veep" is smart, it's very smart. Any comedy in its fifth season or greater is going to start to get compared to previous seasons. Based on the first four episodes, I'm not willing to say that "Veep" is as "funny as it's ever been" but it's still much funnier than most things on TV.
Next Article: The Society of the Real: How An Intrepid Group of Newsreel Cameramen Changed Documentary Film Previous Article: Home Entertainment Consumer Guide: April 21, 2016
Demanders RSS
Demanders Archives
Year 2019 2018 2017 2016 2015 2014 2013 2012 2011 Month January (0) February (0) March (0) April (0) May (0) June (0) July (0) August (0) September (0) October (0) November (0) December (0)


text:
#include "src/impl.h"

namespace mp4v2 { namespace impl {

///////////////////////////////////////////////////////////////////////////////

#define AMR_UNINITIALIZED -1
#define AMR_TRUE 0
#define AMR_FALSE 1

MP4Track::MP4Track(MP4File& file, MP4Atom& trakAtom)
    : m_File(file)
    , m_trakAtom(trakAtom)
{
    m_lastStsdIndex = 0;
    m_lastSampleFile = NULL;

    m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID;
    m_pCachedReadSample = NULL;
    m_cachedReadSampleSize = 0;

    m_writeSampleId = 1;
    m_fixedSampleDuration = 0;
    m_pChunkBuffer = NULL;
    m_chunkBufferSize = 0;
    m_sizeOfDataInChunkBuffer = 0;
    m_chunkSamples = 0;
    m_chunkDuration = 0;

    // m_bytesPerSample should be set to 1, except for the
    // quicktime audio constant bit rate samples, which have non-1 values
    m_bytesPerSample = 1;
    m_samplesPerChunk = 0;
    m_durationPerChunk = 0;
    m_isAmr = AMR_UNINITIALIZED;
    m_curMode = 0;

    m_cachedSttsSid = MP4_INVALID_SAMPLE_ID;
    m_cachedCttsSid = MP4_INVALID_SAMPLE_ID;

    bool success = true;

    MP4Integer32Property* pTrackIdProperty;
    success &= m_trakAtom.FindProperty(
                   "trak.tkhd.trackId",
                   (MP4Property**)&pTrackIdProperty);
    if (success) {
        m_trackId = pTrackIdProperty->GetValue();
    }

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.mdhd.timeScale",
                   (MP4Property**)&m_pTimeScaleProperty);
    if (success) {
        // default chunking is 1 second of samples
        m_durationPerChunk = m_pTimeScaleProperty->GetValue();
    }

    success &= m_trakAtom.FindProperty(
                   "trak.tkhd.duration",
                   (MP4Property**)&m_pTrackDurationProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.mdhd.duration",
                   (MP4Property**)&m_pMediaDurationProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.tkhd.modificationTime",
                   (MP4Property**)&m_pTrackModificationProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.mdhd.modificationTime",
                   (MP4Property**)&m_pMediaModificationProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.hdlr.handlerType",
                   (MP4Property**)&m_pTypeProperty);

    // get handles on sample size information

    m_pStszFixedSampleSizeProperty = NULL;
    bool have_stsz =
        m_trakAtom.FindProperty("trak.mdia.minf.stbl.stsz.sampleSize",
                                  (MP4Property**)&m_pStszFixedSampleSizeProperty);

    if (have_stsz) {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stsz.sampleCount",
                       (MP4Property**)&m_pStszSampleCountProperty);

        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stsz.entries.entrySize",
                       (MP4Property**)&m_pStszSampleSizeProperty);
        m_stsz_sample_bits = 32;
    } else {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stz2.sampleCount",
                       (MP4Property**)&m_pStszSampleCountProperty);
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stz2.entries.entrySize",
                       (MP4Property**)&m_pStszSampleSizeProperty);
        MP4Integer8Property *stz2_field_size;
        if (m_trakAtom.FindProperty(
                    "trak.mdia.minf.stbl.stz2.fieldSize",
                    (MP4Property **)&stz2_field_size)) {
            m_stsz_sample_bits = stz2_field_size->GetValue();
            m_have_stz2_4bit_sample = false;
        } else success = false;
    }

    // get handles on information needed to map sample id's to file offsets

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stsc.entryCount",
                   (MP4Property**)&m_pStscCountProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stsc.entries.firstChunk",
                   (MP4Property**)&m_pStscFirstChunkProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stsc.entries.samplesPerChunk",
                   (MP4Property**)&m_pStscSamplesPerChunkProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stsc.entries.sampleDescriptionIndex",
                   (MP4Property**)&m_pStscSampleDescrIndexProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stsc.entries.firstSample",
                   (MP4Property**)&m_pStscFirstSampleProperty);

    bool haveStco = m_trakAtom.FindProperty(
                        "trak.mdia.minf.stbl.stco.entryCount",
                        (MP4Property**)&m_pChunkCountProperty);

    if (haveStco) {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stco.entries.chunkOffset",
                       (MP4Property**)&m_pChunkOffsetProperty);
    } else {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.co64.entryCount",
                       (MP4Property**)&m_pChunkCountProperty);

        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.co64.entries.chunkOffset",
                       (MP4Property**)&m_pChunkOffsetProperty);
    }

    // get handles on sample timing info

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stts.entryCount",
                   (MP4Property**)&m_pSttsCountProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stts.entries.sampleCount",
                   (MP4Property**)&m_pSttsSampleCountProperty);

    success &= m_trakAtom.FindProperty(
                   "trak.mdia.minf.stbl.stts.entries.sampleDelta",
                   (MP4Property**)&m_pSttsSampleDeltaProperty);

    // get handles on rendering offset info if it exists

    m_pCttsCountProperty = NULL;
    m_pCttsSampleCountProperty = NULL;
    m_pCttsSampleOffsetProperty = NULL;

    bool haveCtts = m_trakAtom.FindProperty(
                        "trak.mdia.minf.stbl.ctts.entryCount",
                        (MP4Property**)&m_pCttsCountProperty);

    if (haveCtts) {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.ctts.entries.sampleCount",
                       (MP4Property**)&m_pCttsSampleCountProperty);

        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.ctts.entries.sampleOffset",
                       (MP4Property**)&m_pCttsSampleOffsetProperty);
    }

    // get handles on sync sample info if it exists

    m_pStssCountProperty = NULL;
    m_pStssSampleProperty = NULL;

    bool haveStss = m_trakAtom.FindProperty(
                        "trak.mdia.minf.stbl.stss.entryCount",
                        (MP4Property**)&m_pStssCountProperty);

    if (haveStss) {
        success &= m_trakAtom.FindProperty(
                       "trak.mdia.minf.stbl.stss.entries.sampleNumber",
                       (MP4Property**)&m_pStssSampleProperty);
    }

    // edit list
    (void)InitEditListProperties();

    // was everything found?
    if (!success) {
        throw new Exception("invalid track", __FILE__, __LINE__, __FUNCTION__ );
    }
    CalculateBytesPerSample();

    // update sdtp log from sdtp atom
    MP4SdtpAtom* sdtp = (MP4SdtpAtom*)m_trakAtom.FindAtom( "trak.mdia.minf.stbl.sdtp" );
    if( sdtp ) {
        uint8_t* buffer;
        uint32_t bufsize;
        sdtp->data.GetValue( &buffer, &bufsize );
        m_sdtpLog.assign( (char*)buffer, bufsize );
        free( buffer );
    }
}

MP4Track::~MP4Track()
{
    MP4Free(m_pCachedReadSample);
    m_pCachedReadSample = NULL;
    MP4Free(m_pChunkBuffer);
    m_pChunkBuffer = NULL;
}

const char* MP4Track::GetType()
{
    return m_pTypeProperty->GetValue();
}

void MP4Track::SetType(const char* type)
{
    m_pTypeProperty->SetValue(MP4NormalizeTrackType(type));
}

void MP4Track::ReadSample(
    MP4SampleId   sampleId,
    uint8_t**     ppBytes,
    uint32_t*     pNumBytes,
    MP4Timestamp* pStartTime,
    MP4Duration*  pDuration,
    MP4Duration*  pRenderingOffset,
    bool*         pIsSyncSample,
    bool*         hasDependencyFlags,
    uint32_t*     dependencyFlags )
{
    if( sampleId == MP4_INVALID_SAMPLE_ID )
        throw new Exception( "sample id can't be zero", __FILE__, __LINE__, __FUNCTION__ );

    if( hasDependencyFlags )
        *hasDependencyFlags = !m_sdtpLog.empty();

    if( dependencyFlags ) {
        if( m_sdtpLog.empty() ) {
            *dependencyFlags = 0;
        }
        else {
            if( sampleId > m_sdtpLog.size() )
                throw new Exception( "sample id > sdtp logsize", __FILE__, __LINE__, __FUNCTION__ );
            *dependencyFlags = m_sdtpLog[sampleId-1]; // sampleId is 1-based
        }
    }

    // handle unusual case of wanting to read a sample
    // that is still sitting in the write chunk buffer
    if (m_pChunkBuffer && sampleId >= m_writeSampleId - m_chunkSamples) {
        WriteChunkBuffer();
    }

    File* fin = GetSampleFile( sampleId );
    if( fin == (File*)-1 )
        throw new Exception( "sample is located in an inaccessible file", __FILE__, __LINE__, __FUNCTION__ );

    uint64_t fileOffset = GetSampleFileOffset(sampleId);

    uint32_t sampleSize = GetSampleSize(sampleId);
    if (*ppBytes != NULL && *pNumBytes < sampleSize) {
        throw new Exception("sample buffer is too small",
                            __FILE__, __LINE__, __FUNCTION__ );
    }
    *pNumBytes = sampleSize;

    log.verbose3f("\"%s\": ReadSample: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)",
                  GetFile().GetFilename().c_str(), m_trackId, sampleId, fileOffset, *pNumBytes, *pNumBytes);

    bool bufferMalloc = false;
    if (*ppBytes == NULL) {
        *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes);
        bufferMalloc = true;
    }

    uint64_t oldPos = m_File.GetPosition( fin ); // only used in mode == 'w'
    try {
        m_File.SetPosition( fileOffset, fin );
        m_File.ReadBytes( *ppBytes, *pNumBytes, fin );

        if (pStartTime || pDuration) {
            GetSampleTimes(sampleId, pStartTime, pDuration);

            log.verbose3f("\"%s\": ReadSample:  start %" PRIu64 " duration %" PRId64,
                          GetFile().GetFilename().c_str(), (pStartTime ? *pStartTime : 0),
                          (pDuration ? *pDuration : 0));
        }
        if (pRenderingOffset) {
            *pRenderingOffset = GetSampleRenderingOffset(sampleId);

            log.verbose3f("\"%s\": ReadSample:  renderingOffset %" PRId64,
                          GetFile().GetFilename().c_str(), *pRenderingOffset);
        }
        if (pIsSyncSample) {
            *pIsSyncSample = IsSyncSample(sampleId);

            log.verbose3f("\"%s\": ReadSample:  isSyncSample %u",
                          GetFile().GetFilename().c_str(), *pIsSyncSample);
        }
    }

    catch (Exception* x) {
        if( bufferMalloc ) {
            MP4Free( *ppBytes );
            *ppBytes = NULL;
        }

        if( m_File.IsWriteMode() )
            m_File.SetPosition( oldPos, fin );

        throw x;
    }

    if( m_File.IsWriteMode() )
        m_File.SetPosition( oldPos, fin );
}

void MP4Track::ReadSampleFragment(
    MP4SampleId sampleId,
    uint32_t sampleOffset,
    uint16_t sampleLength,
    uint8_t* pDest)
{
    if (sampleId == MP4_INVALID_SAMPLE_ID) {
        throw new Exception("invalid sample id",
                            __FILE__, __LINE__, __FUNCTION__ );
    }

    if (sampleId != m_cachedReadSampleId) {
        MP4Free(m_pCachedReadSample);
        m_pCachedReadSample = NULL;
        m_cachedReadSampleSize = 0;
        m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID;

        ReadSample(
            sampleId,
            &m_pCachedReadSample,
            &m_cachedReadSampleSize);

        m_cachedReadSampleId = sampleId;
    }

    if (sampleOffset + sampleLength > m_cachedReadSampleSize) {
        throw new Exception("offset and/or length are too large",
                            __FILE__, __LINE__, __FUNCTION__ );
    }

    memcpy(pDest, &m_pCachedReadSample[sampleOffset], sampleLength);
}

void MP4Track::WriteSample(
    const uint8_t* pBytes,
    uint32_t       numBytes,
    MP4Duration    duration,
    MP4Duration    renderingOffset,
    bool           isSyncSample )
{
    uint8_t curMode = 0;

    log.verbose3f("\"%s\": WriteSample: track %u id %u size %u (0x%x) ",
                  GetFile().GetFilename().c_str(),
                  m_trackId, m_writeSampleId, numBytes, numBytes);

    if (pBytes == NULL && numBytes > 0) {
        throw new Exception("no sample data", __FILE__, __LINE__, __FUNCTION__ );
    }

    if (m_isAmr == AMR_UNINITIALIZED ) {
        // figure out if this is an AMR audio track
        if (m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd.samr") ||
                m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd.sawb")) {
            m_isAmr = AMR_TRUE;
            m_curMode = (pBytes[0] >> 3) & 0x000F;
        } else {
            m_isAmr = AMR_FALSE;
        }
    }

    if (m_isAmr == AMR_TRUE) {
        curMode = (pBytes[0] >> 3) &0x000F; // The mode is in the first byte
    }

    if (duration == MP4_INVALID_DURATION) {
        duration = GetFixedSampleDuration();
    }

    log.verbose3f("\"%s\": duration %" PRIu64, GetFile().GetFilename().c_str(),
                  duration);

    if ((m_isAmr == AMR_TRUE) &&
            (m_curMode != curMode)) {
        WriteChunkBuffer();
        m_curMode = curMode;
    }

    // append sample bytes to chunk buffer
    if( m_sizeOfDataInChunkBuffer + numBytes > m_chunkBufferSize ) {
        m_pChunkBuffer = (uint8_t*)MP4Realloc(m_pChunkBuffer, m_chunkBufferSize + numBytes);
        if (m_pChunkBuffer == NULL)
            return;

        m_chunkBufferSize += numBytes;
    }

    memcpy(&m_pChunkBuffer[m_sizeOfDataInChunkBuffer], pBytes, numBytes);
    m_sizeOfDataInChunkBuffer += numBytes;
    m_chunkSamples++;
    m_chunkDuration += duration;

    UpdateSampleSizes(m_writeSampleId, numBytes);

    UpdateSampleTimes(duration);

    UpdateRenderingOffsets(m_writeSampleId, renderingOffset);

    UpdateSyncSamples(m_writeSampleId, isSyncSample);

    if (IsChunkFull(m_writeSampleId)) {
        WriteChunkBuffer();
        m_curMode = curMode;
    }

    UpdateDurations(duration);

    UpdateModificationTimes();

    m_writeSampleId++;
}

void MP4Track::WriteSampleDependency(
    const uint8_t* pBytes,
    uint32_t       numBytes,
    MP4Duration    duration,
    MP4Duration    renderingOffset,
    bool           isSyncSample,
    uint32_t       dependencyFlags )
{
    m_sdtpLog.push_back( dependencyFlags ); // record dependency flags for processing at finish
    WriteSample( pBytes, numBytes, duration, renderingOffset, isSyncSample );
}

void MP4Track::WriteChunkBuffer()
{
    if (m_sizeOfDataInChunkBuffer == 0) {
        return;
    }

    uint64_t chunkOffset = m_File.GetPosition();

    // write chunk buffer
    m_File.WriteBytes(m_pChunkBuffer, m_sizeOfDataInChunkBuffer);

    log.verbose3f("\"%s\": WriteChunk: track %u offset 0x%" PRIx64 " size %u (0x%x) numSamples %u",
                  GetFile().GetFilename().c_str(),
                  m_trackId, chunkOffset, m_sizeOfDataInChunkBuffer,
                  m_sizeOfDataInChunkBuffer, m_chunkSamples);

    UpdateSampleToChunk(m_writeSampleId,
                        m_pChunkCountProperty->GetValue() + 1,
                        m_chunkSamples);

    UpdateChunkOffsets(chunkOffset);

    // note: we do not free our chunk buffer; we reuse it, expanding as needed.
    // It gets zapped when this class goes out of scope
    m_sizeOfDataInChunkBuffer = 0;
    m_chunkSamples = 0;
    m_chunkDuration = 0;
}

void MP4Track::FinishWrite(uint32_t options)
{
    FinishSdtp();

    // write out any remaining samples in chunk buffer
    WriteChunkBuffer();

    if (m_pStszFixedSampleSizeProperty == NULL &&
            m_stsz_sample_bits == 4) {
        if (m_have_stz2_4bit_sample) {
            ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(m_stz2_4bit_sample_value);
            m_pStszSampleSizeProperty->IncrementValue();
        }
    }

    // record buffer size and bitrates
    MP4BitfieldProperty* pBufferSizeProperty;

    if (m_trakAtom.FindProperty(
                "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.bufferSizeDB",
                (MP4Property**)&pBufferSizeProperty)) {
        pBufferSizeProperty->SetValue(GetMaxSampleSize());
    }

	// don't overwrite bitrate if it was requested in the Close call
    if( !(options & MP4_CLOSE_DO_NOT_COMPUTE_BITRATE)) {
        MP4Integer32Property* pBitrateProperty;

        if (m_trakAtom.FindProperty(
                    "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.maxBitrate",
                    (MP4Property**)&pBitrateProperty)) {
            pBitrateProperty->SetValue(GetMaxBitrate());
        }

        if (m_trakAtom.FindProperty(
                    "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate",
                    (MP4Property**)&pBitrateProperty)) {
            pBitrateProperty->SetValue(GetAvgBitrate());
        }
    }

    // cleaup trak.udta
    MP4BytesProperty* nameProperty = NULL;
    m_trakAtom.FindProperty("trak.udta.name.value", (MP4Property**) &nameProperty);
    if( nameProperty != NULL && nameProperty->GetValueSize() == 0 ){
        // Zero length name value--delete name, and then udta if no child atoms
        MP4Atom* name = m_trakAtom.FindChildAtom("udta.name");
        if( name ) {
            MP4Atom* udta = name->GetParentAtom();
            udta->DeleteChildAtom( name );
            delete name;

            if( udta->GetNumberOfChildAtoms() == 0 ) {
                udta->GetParentAtom()->DeleteChildAtom( udta );
                delete udta;
            }
        }
    }
}

// Process sdtp log and add sdtp atom.
//
// Testing (subjective) showed a marked improvement with QuickTime
// player on Mac OS X when scrubbing. Best results were obtained
// from encodings using low number of bframes. It's expected sdtp may help
// other QT-based players.
//
void MP4Track::FinishSdtp()
{
    // bail if log is empty -- indicates dependency information was not written
    if( m_sdtpLog.empty() )
        return;

    MP4SdtpAtom* sdtp = (MP4SdtpAtom*)m_trakAtom.FindAtom( "trak.mdia.minf.stbl.sdtp" );
    if( !sdtp )
        sdtp = (MP4SdtpAtom*)AddAtom( "trak.mdia.minf.stbl", "sdtp" );
    sdtp->data.SetValue( (const uint8_t*)m_sdtpLog.data(), (uint32_t)m_sdtpLog.size() );

    // add avc1 compatibility indicator if not present
    MP4FtypAtom* ftyp = (MP4FtypAtom*)m_File.FindAtom( "ftyp" );
    if( ftyp ) {
        bool found = false;
        const uint32_t max = ftyp->compatibleBrands.GetCount();
        for( uint32_t i = 0; i < max; i++ ) {
            if( !strcmp( ftyp->compatibleBrands.GetValue( i ), "avc1" )) {
                found = true;
                break;
            }
        }

        if( !found )
            ftyp->compatibleBrands.AddValue( "avc1" );
    }
}

bool MP4Track::IsChunkFull(MP4SampleId sampleId)
{
    if (m_samplesPerChunk) {
        return m_chunkSamples >= m_samplesPerChunk;
    }

    ASSERT(m_durationPerChunk);
    return m_chunkDuration >= m_durationPerChunk;
}

uint32_t MP4Track::GetNumberOfSamples()
{
    return m_pStszSampleCountProperty->GetValue();
}

uint32_t MP4Track::GetSampleSize(MP4SampleId sampleId)
{
    if (m_pStszFixedSampleSizeProperty != NULL) {
        uint32_t fixedSampleSize =
            m_pStszFixedSampleSizeProperty->GetValue();

        if (fixedSampleSize != 0) {
            return fixedSampleSize * m_bytesPerSample;
        }
    }
    // will have to check for 4 bit sample size here
    if (m_stsz_sample_bits == 4) {
        uint8_t value = m_pStszSampleSizeProperty->GetValue((sampleId - 1) / 2);
        if ((sampleId - 1) / 2 == 0) {
            value >>= 4;
        } else value &= 0xf;
        return m_bytesPerSample * value;
    }
    return m_bytesPerSample *
           m_pStszSampleSizeProperty->GetValue(sampleId - 1);
}

uint32_t MP4Track::GetMaxSampleSize()
{
    if (m_pStszFixedSampleSizeProperty != NULL) {
        uint32_t fixedSampleSize =
            m_pStszFixedSampleSizeProperty->GetValue();

        if (fixedSampleSize != 0) {
            return fixedSampleSize * m_bytesPerSample;
        }
    }

    uint32_t maxSampleSize = 0;
    uint32_t numSamples = m_pStszSampleSizeProperty->GetCount();
    for (MP4SampleId sid = 1; sid <= numSamples; sid++) {
        uint32_t sampleSize =
            m_pStszSampleSizeProperty->GetValue(sid - 1);
        if (sampleSize > maxSampleSize) {
            maxSampleSize = sampleSize;
        }
    }
    return maxSampleSize * m_bytesPerSample;
}

uint64_t MP4Track::GetTotalOfSampleSizes()
{
    uint64_t retval;
    if (m_pStszFixedSampleSizeProperty != NULL) {
        uint32_t fixedSampleSize =
            m_pStszFixedSampleSizeProperty->GetValue();

        // if fixed sample size, just need to multiply by number of samples
        if (fixedSampleSize != 0) {
            retval = m_bytesPerSample;
            retval *= fixedSampleSize;
            retval *= GetNumberOfSamples();
            return retval;
        }
    }

    // else non-fixed sample size, sum them
    uint64_t totalSampleSizes = 0;
    uint32_t numSamples = m_pStszSampleSizeProperty->GetCount();
    for (MP4SampleId sid = 1; sid <= numSamples; sid++) {
        uint32_t sampleSize =
            m_pStszSampleSizeProperty->GetValue(sid - 1);
        totalSampleSizes += sampleSize;
    }
    return totalSampleSizes * m_bytesPerSample;
}

void MP4Track::SampleSizePropertyAddValue (uint32_t size)
{
    // this has to deal with different sample size values
    switch (m_pStszSampleSizeProperty->GetType()) {
    case Integer32Property:
        ((MP4Integer32Property *)m_pStszSampleSizeProperty)->AddValue(size);
        break;
    case Integer16Property:
        ((MP4Integer16Property *)m_pStszSampleSizeProperty)->AddValue(size);
        break;
    case Integer8Property:
        if (m_stsz_sample_bits == 4) {
            if (m_have_stz2_4bit_sample == false) {
                m_have_stz2_4bit_sample = true;
                m_stz2_4bit_sample_value = size << 4;
                return;
            } else {
                m_have_stz2_4bit_sample = false;
                size &= 0xf;
                size |= m_stz2_4bit_sample_value;
            }
        }
        ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(size);
        break;
    default:
        break;
    }

    //  m_pStszSampleSizeProperty->IncrementValue();
}

void MP4Track::UpdateSampleSizes(MP4SampleId sampleId, uint32_t numBytes)
{
    if (m_bytesPerSample > 1) {
        if ((numBytes % m_bytesPerSample) != 0) {
            // error
            log.errorf("%s: \"%s\": numBytes %u not divisible by bytesPerSample %u sampleId %u",
                       __FUNCTION__, GetFile().GetFilename().c_str(),
                       numBytes, m_bytesPerSample, sampleId);
        }
        numBytes /= m_bytesPerSample;
    }
    // for first sample
    // wmay - if we are adding, we want to make sure that
    // we don't inadvertently set up the fixed size again.
    // so, we check the number of samples
    if (sampleId == 1 && GetNumberOfSamples() == 0) {
        if (m_pStszFixedSampleSizeProperty == NULL ||
                numBytes == 0) {
            // special case of first sample is zero bytes in length
            // leave m_pStszFixedSampleSizeProperty at 0
            // start recording variable sample sizes
            if (m_pStszFixedSampleSizeProperty != NULL)
                m_pStszFixedSampleSizeProperty->SetValue(0);
            SampleSizePropertyAddValue(0);
        } else {
            // presume sample size is fixed
            m_pStszFixedSampleSizeProperty->SetValue(numBytes);
        }
    } else { // sampleId > 1

        uint32_t fixedSampleSize = 0;
        if (m_pStszFixedSampleSizeProperty != NULL) {
            fixedSampleSize = m_pStszFixedSampleSizeProperty->GetValue();
        }

        // if we don't have a fixed size, or the current sample size
        // doesn't match our sample size, we need to write the current
        // sample size into the table
        if (fixedSampleSize == 0 || numBytes != fixedSampleSize) {
            if (fixedSampleSize != 0) {
                // fixed size was set; we need to clear fixed sample size
                m_pStszFixedSampleSizeProperty->SetValue(0);

                // and create sizes for all previous samples
                // use GetNumberOfSamples due to needing the total number
                // not just the appended part of the file
                uint32_t samples = GetNumberOfSamples();
                for (MP4SampleId sid = 1; sid <= samples; sid++) {
                    SampleSizePropertyAddValue(fixedSampleSize);
                }
            }
            // add size value for this sample
            SampleSizePropertyAddValue(numBytes);
        }
    }
    // either way, we increment the number of samples.
    m_pStszSampleCountProperty->IncrementValue();
}

uint32_t MP4Track::GetAvgBitrate()
{
    if (GetDuration() == 0) {
        return 0;
    }

    double calc = double(GetTotalOfSampleSizes());
    // this is a bit better - we use the whole duration
    calc *= 8.0;
    calc *= GetTimeScale();
    calc /= double(GetDuration());
    // we might want to think about rounding to the next 100 or 1000
    return (uint32_t) ceil(calc);
}

uint32_t MP4Track::GetMaxBitrate()
{
    uint32_t timeScale = GetTimeScale();
    MP4SampleId numSamples = GetNumberOfSamples();
    uint32_t maxBytesPerSec = 0;
    uint32_t bytesThisSec = 0;
    MP4Timestamp thisSecStart = 0;
    MP4Timestamp lastSampleTime = 0;
    uint32_t lastSampleSize = 0;

    MP4SampleId thisSecStartSid = 1;
    for (MP4SampleId sid = 1; sid <= numSamples; sid++) {
        uint32_t sampleSize;
        MP4Timestamp sampleTime;

        sampleSize = GetSampleSize(sid);
        GetSampleTimes(sid, &sampleTime, NULL);

        if (sampleTime < thisSecStart + timeScale) {
            bytesThisSec += sampleSize;
            lastSampleSize = sampleSize;
            lastSampleTime = sampleTime;
        } else {
            // we've already written the last sample and sampleSize.
            // this means that we've probably overflowed the last second
            // calculate the time we've overflowed
            MP4Duration overflow_dur =
                (thisSecStart + timeScale) - lastSampleTime;
            // calculate the duration of the last sample
            MP4Duration lastSampleDur = sampleTime - lastSampleTime;
            // now, calculate the number of bytes we overflowed.  Round up.
            if( lastSampleDur > 0 ) {
                uint32_t overflow_bytes = 0;
                overflow_bytes = ((lastSampleSize * overflow_dur) + (lastSampleDur - 1)) / lastSampleDur;

                if (bytesThisSec - overflow_bytes > maxBytesPerSec) {
                    maxBytesPerSec = bytesThisSec - overflow_bytes;
                }
            }

            // now adjust the values for this sample.  Remove the bytes
            // from the first sample in this time frame
            lastSampleTime = sampleTime;
            lastSampleSize = sampleSize;
            bytesThisSec += sampleSize;
            bytesThisSec -= GetSampleSize(thisSecStartSid);
            thisSecStartSid++;
            GetSampleTimes(thisSecStartSid, &thisSecStart, NULL);
        }
    }

    return maxBytesPerSec * 8;
}

uint32_t MP4Track::GetSampleStscIndex(MP4SampleId sampleId)
{
    uint32_t stscIndex;
    uint32_t numStscs = m_pStscCountProperty->GetValue();

    if (numStscs == 0) {
        throw new Exception("No data chunks exist", __FILE__, __LINE__, __FUNCTION__ );
    }

    for (stscIndex = 0; stscIndex < numStscs; stscIndex++) {
        if (sampleId < m_pStscFirstSampleProperty->GetValue(stscIndex)) {
            ASSERT(stscIndex != 0);
            stscIndex -= 1;
            break;
        }
    }
    if (stscIndex == numStscs) {
        ASSERT(stscIndex != 0);
        stscIndex -= 1;
    }

    return stscIndex;
}

File* MP4Track::GetSampleFile( MP4SampleId sampleId )
{
    uint32_t stscIndex = GetSampleStscIndex( sampleId );
    uint32_t stsdIndex = m_pStscSampleDescrIndexProperty->GetValue( stscIndex );

    // check if the answer will be the same as last time
    if( m_lastStsdIndex && stsdIndex == m_lastStsdIndex )
        return m_lastSampleFile;

    MP4Atom* pStsdAtom = m_trakAtom.FindAtom( "trak.mdia.minf.stbl.stsd" );
    ASSERT( pStsdAtom );

    MP4Atom* pStsdEntryAtom = pStsdAtom->GetChildAtom( stsdIndex - 1 );
    ASSERT( pStsdEntryAtom );

    MP4Integer16Property* pDrefIndexProperty = NULL;
    if( !pStsdEntryAtom->FindProperty( "*.dataReferenceIndex", (MP4Property**)&pDrefIndexProperty ) ||
        pDrefIndexProperty == NULL )
    {
        throw new Exception( "invalid stsd entry", __FILE__, __LINE__, __FUNCTION__ );
    }

    uint32_t drefIndex = pDrefIndexProperty->GetValue();

    MP4Atom* pDrefAtom = m_trakAtom.FindAtom( "trak.mdia.minf.dinf.dref" );
    ASSERT(pDrefAtom);

    MP4Atom* pUrlAtom = pDrefAtom->GetChildAtom( drefIndex - 1 );
    ASSERT( pUrlAtom );

    File* file;

    // make sure this is actually a url atom (somtimes it's "cios", like in iTunes videos)
    if( strcmp(pUrlAtom->GetType(), "url ") ||
        pUrlAtom->GetFlags() & 1 ) {
        file = NULL; // self-contained
    }
    else {
        MP4StringProperty* pLocationProperty = NULL;
        ASSERT( pUrlAtom->FindProperty( "*.location", (MP4Property**)&pLocationProperty) );
        ASSERT( pLocationProperty );

        const char* url = pLocationProperty->GetValue();

        log.verbose3f("\"%s\": dref url = %s", GetFile().GetFilename().c_str(),
                      url);

        file = (File*)-1;

        // attempt to open url if it's a file url
        // currently this is the only thing we understand
        if( !strncmp( url, "file:", 5 )) {
            const char* fileName = url + 5;

            if( !strncmp(fileName, "//", 2 ))
                fileName = strchr( fileName + 2, '/' );

            if( fileName ) {
                file = new File( fileName, File::MODE_READ );
                if( !file->open() ) {
                    delete file;
                    file = (File*)-1;
                }
            }
        }
    }

    if( m_lastSampleFile )
        m_lastSampleFile->close();

    // cache the answer
    m_lastStsdIndex = stsdIndex;
    m_lastSampleFile = file;

    return file;
}

uint64_t MP4Track::GetSampleFileOffset(MP4SampleId sampleId)
{
    uint32_t stscIndex =
        GetSampleStscIndex(sampleId);

    // firstChunk is the chunk index of the first chunk with
    // samplesPerChunk samples in the chunk.  There may be multiples -
    // ie: several chunks with the same number of samples per chunk.
    uint32_t firstChunk =
        m_pStscFirstChunkProperty->GetValue(stscIndex);

    MP4SampleId firstSample =
        m_pStscFirstSampleProperty->GetValue(stscIndex);

    uint32_t samplesPerChunk =
        m_pStscSamplesPerChunkProperty->GetValue(stscIndex);

    // chunkId tells which is the absolute chunk number that this sample
    // is stored in.
    MP4ChunkId chunkId = firstChunk +
                         ((sampleId - firstSample) / samplesPerChunk);

    // chunkOffset is the file offset (absolute) for the start of the chunk
    uint64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1);

    MP4SampleId firstSampleInChunk =
        sampleId - ((sampleId - firstSample) % samplesPerChunk);

    // need cumulative samples sizes from firstSample to sampleId - 1
    uint32_t sampleOffset = 0;
    for (MP4SampleId i = firstSampleInChunk; i < sampleId; i++) {
        sampleOffset += GetSampleSize(i);
    }

    return chunkOffset + sampleOffset;
}

void MP4Track::UpdateSampleToChunk(MP4SampleId sampleId,
                                   MP4ChunkId chunkId, uint32_t samplesPerChunk)
{
    uint32_t numStsc = m_pStscCountProperty->GetValue();

    // if samplesPerChunk == samplesPerChunk of last entry
    if (numStsc && samplesPerChunk ==
            m_pStscSamplesPerChunkProperty->GetValue(numStsc-1)) {

        // nothing to do

    } else {
        // add stsc entry
        m_pStscFirstChunkProperty->AddValue(chunkId);
        m_pStscSamplesPerChunkProperty->AddValue(samplesPerChunk);
        m_pStscSampleDescrIndexProperty->AddValue(1);
        m_pStscFirstSampleProperty->AddValue(sampleId - samplesPerChunk + 1);

        m_pStscCountProperty->IncrementValue();
    }
}

void MP4Track::UpdateChunkOffsets(uint64_t chunkOffset)
{
    if (m_pChunkOffsetProperty->GetType() == Integer32Property) {
        ((MP4Integer32Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset);
    } else {
        ((MP4Integer64Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset);
    }
    m_pChunkCountProperty->IncrementValue();
}

MP4Duration MP4Track::GetFixedSampleDuration()
{
    uint32_t numStts = m_pSttsCountProperty->GetValue();

    if (numStts == 0) {
        return m_fixedSampleDuration;
    }
    if (numStts != 1) {
        return MP4_INVALID_DURATION;    // sample duration is not fixed
    }
    return m_pSttsSampleDeltaProperty->GetValue(0);
}

void MP4Track::SetFixedSampleDuration(MP4Duration duration)
{
    uint32_t numStts = m_pSttsCountProperty->GetValue();

    // setting this is only allowed before samples have been written
    if (numStts != 0) {
        return;
    }
    m_fixedSampleDuration = duration;
    return;
}

void MP4Track::GetSampleTimes(MP4SampleId sampleId,
                              MP4Timestamp* pStartTime, MP4Duration* pDuration)
{
    uint32_t numStts = m_pSttsCountProperty->GetValue();
    MP4SampleId sid;
    MP4Duration elapsed;

    if (m_cachedSttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedSttsSid) {
        sid   = m_cachedSttsSid;
        elapsed   = m_cachedSttsElapsed;
    } else {
        m_cachedSttsIndex = 0;
        sid   = 1;
        elapsed   = 0;
    }

    for (uint32_t sttsIndex = m_cachedSttsIndex; sttsIndex < numStts; sttsIndex++) {
        uint32_t sampleCount =
            m_pSttsSampleCountProperty->GetValue(sttsIndex);
        uint32_t sampleDelta =
            m_pSttsSampleDeltaProperty->GetValue(sttsIndex);

        if (sampleId <= sid + sampleCount - 1) {
            if (pStartTime) {
                *pStartTime = (sampleId - sid);
                *pStartTime *= sampleDelta;
                *pStartTime += elapsed;
            }
            if (pDuration) {
                *pDuration = sampleDelta;
            }

            m_cachedSttsIndex = sttsIndex;
            m_cachedSttsSid = sid;
            m_cachedSttsElapsed = elapsed;

            return;
        }
        sid += sampleCount;
        elapsed += sampleCount * sampleDelta;
    }

    throw new Exception("sample id out of range",
                        __FILE__, __LINE__, __FUNCTION__ );
}

MP4SampleId MP4Track::GetSampleIdFromTime(
    MP4Timestamp when,
    bool wantSyncSample)
{
    uint32_t numStts = m_pSttsCountProperty->GetValue();
    MP4SampleId sid = 1;
    MP4Duration elapsed = 0;

    for (uint32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) {
        uint32_t sampleCount =
            m_pSttsSampleCountProperty->GetValue(sttsIndex);
        uint32_t sampleDelta =
            m_pSttsSampleDeltaProperty->GetValue(sttsIndex);

        if (sampleDelta == 0 && sttsIndex < numStts - 1) {
            log.warningf("%s: \"%s\": Zero sample duration, stts entry %u",
                         __FUNCTION__, GetFile().GetFilename().c_str(), sttsIndex);
        }

        MP4Duration d = when - elapsed;

        if (d <= sampleCount * sampleDelta) {
            MP4SampleId sampleId = sid;
            if (sampleDelta) {
                sampleId += (d / sampleDelta);
            }

            if (wantSyncSample) {
                return GetNextSyncSample(sampleId);
            }
            return sampleId;
        }

        sid += sampleCount;
        elapsed += sampleCount * sampleDelta;
    }

    throw new Exception("time out of range",
                        __FILE__, __LINE__, __FUNCTION__);

    return 0; // satisfy MS compiler
}

void MP4Track::UpdateSampleTimes(MP4Duration duration)
{
    uint32_t numStts = m_pSttsCountProperty->GetValue();

    // if duration == duration of last entry
    if (numStts
            && duration == m_pSttsSampleDeltaProperty->GetValue(numStts-1)) {
        // increment last entry sampleCount
        m_pSttsSampleCountProperty->IncrementValue(1, numStts-1);

    } else {
        // add stts entry, sampleCount = 1, sampleDuration = duration
        m_pSttsSampleCountProperty->AddValue(1);
        m_pSttsSampleDeltaProperty->AddValue(duration);
        m_pSttsCountProperty->IncrementValue();;
    }
}

uint32_t MP4Track::GetSampleCttsIndex(MP4SampleId sampleId,
                                      MP4SampleId* pFirstSampleId)
{
    uint32_t numCtts = m_pCttsCountProperty->GetValue();
    MP4SampleId sid;

    if (m_cachedCttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedCttsSid) {
        sid   = m_cachedCttsSid;
    } else {
        m_cachedCttsIndex = 0;
        sid = 1;
    }

    for (uint32_t cttsIndex = m_cachedCttsIndex; cttsIndex < numCtts; cttsIndex++) {
        uint32_t sampleCount =
            m_pCttsSampleCountProperty->GetValue(cttsIndex);

        if (sampleId <= sid + sampleCount - 1) {
            if (pFirstSampleId) {
                *pFirstSampleId = sid;
            }

            m_cachedCttsIndex = cttsIndex;
            m_cachedCttsSid = sid;

            return cttsIndex;
        }
        sid += sampleCount;
    }

    throw new Exception("sample id out of range",
                        __FILE__, __LINE__, __FUNCTION__ );
    return 0; // satisfy MS compiler
}

MP4Duration MP4Track::GetSampleRenderingOffset(MP4SampleId sampleId)
{
    if (m_pCttsCountProperty == NULL) {
        return 0;
    }
    if (m_pCttsCountProperty->GetValue() == 0) {
        return 0;
    }

    uint32_t cttsIndex = GetSampleCttsIndex(sampleId);

    return m_pCttsSampleOffsetProperty->GetValue(cttsIndex);
}

void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId,
                                      MP4Duration renderingOffset)
{
    // if ctts atom doesn't exist
    if (m_pCttsCountProperty == NULL) {

        // no rendering offset, so nothing to do
        if (renderingOffset == 0) {
            return;
        }

        // else create a ctts atom
        MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts");

        // and get handles on the properties
        ASSERT(pCttsAtom->FindProperty(
                   "ctts.entryCount",
                   (MP4Property**)&m_pCttsCountProperty));

        ASSERT(pCttsAtom->FindProperty(
                   "ctts.entries.sampleCount",
                   (MP4Property**)&m_pCttsSampleCountProperty));

        ASSERT(pCttsAtom->FindProperty(
                   "ctts.entries.sampleOffset",
                   (MP4Property**)&m_pCttsSampleOffsetProperty));

        // if this is not the first sample
        if (sampleId > 1) {
            // add a ctts entry for all previous samples
            // with rendering offset equal to zero
            m_pCttsSampleCountProperty->AddValue(sampleId - 1);
            m_pCttsSampleOffsetProperty->AddValue(0);
            m_pCttsCountProperty->IncrementValue();;
        }
    }

    // ctts atom exists (now)

    uint32_t numCtts = m_pCttsCountProperty->GetValue();

    // if renderingOffset == renderingOffset of last entry
    if (numCtts && renderingOffset
            == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) {

        // increment last entry sampleCount
        m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1);

    } else {
        // add ctts entry, sampleCount = 1, sampleOffset = renderingOffset
        m_pCttsSampleCountProperty->AddValue(1);
        m_pCttsSampleOffsetProperty->AddValue(renderingOffset);
        m_pCttsCountProperty->IncrementValue();
    }
}

void MP4Track::SetSampleRenderingOffset(MP4SampleId sampleId,
                                        MP4Duration renderingOffset)
{
    // check if any ctts entries exist
    if (m_pCttsCountProperty == NULL
            || m_pCttsCountProperty->GetValue() == 0) {
        // if not then Update routine can be used
        // to create a ctts entry for samples before this one
        // and a ctts entry for this sample
        UpdateRenderingOffsets(sampleId, renderingOffset);

        // but we also need a ctts entry
        // for all samples after this one
        uint32_t afterSamples = GetNumberOfSamples() - sampleId;

        if (afterSamples) {
            m_pCttsSampleCountProperty->AddValue(afterSamples);
            m_pCttsSampleOffsetProperty->AddValue(0);
            m_pCttsCountProperty->IncrementValue();;
        }

        return;
    }

    MP4SampleId firstSampleId;
    uint32_t cttsIndex = GetSampleCttsIndex(sampleId, &firstSampleId);

    // do nothing in the degenerate case
    if (renderingOffset ==
            m_pCttsSampleOffsetProperty->GetValue(cttsIndex)) {
        return;
    }

    uint32_t sampleCount =
        m_pCttsSampleCountProperty->GetValue(cttsIndex);

    // if this sample has it's own ctts entry
    if (sampleCount == 1) {
        // then just set the value,
        // note we don't attempt to collapse entries
        m_pCttsSampleOffsetProperty->SetValue(renderingOffset, cttsIndex);
        return;
    }

    MP4SampleId lastSampleId = firstSampleId + sampleCount - 1;

    // else we share this entry with other samples
    // we need to insert our own entry
    if (sampleId == firstSampleId) {
        // our sample is the first one
        m_pCttsSampleCountProperty->
        InsertValue(1, cttsIndex);
        m_pCttsSampleOffsetProperty->
        InsertValue(renderingOffset, cttsIndex);

        m_pCttsSampleCountProperty->
        SetValue(sampleCount - 1, cttsIndex + 1);

        m_pCttsCountProperty->IncrementValue();

    } else if (sampleId == lastSampleId) {
        // our sample is the last one
        m_pCttsSampleCountProperty->
        InsertValue(1, cttsIndex + 1);
        m_pCttsSampleOffsetProperty->
        InsertValue(renderingOffset, cttsIndex + 1);

        m_pCttsSampleCountProperty->
        SetValue(sampleCount - 1, cttsIndex);

        m_pCttsCountProperty->IncrementValue();

    } else {
        // our sample is in the middle, UGH!

        // insert our new entry
        m_pCttsSampleCountProperty->
        InsertValue(1, cttsIndex + 1);
        m_pCttsSampleOffsetProperty->
        InsertValue(renderingOffset, cttsIndex + 1);

        // adjust count of previous entry
        m_pCttsSampleCountProperty->
        SetValue(sampleId - firstSampleId, cttsIndex);

        // insert new entry for those samples beyond our sample
        m_pCttsSampleCountProperty->
        InsertValue(lastSampleId - sampleId, cttsIndex + 2);
        uint32_t oldRenderingOffset =
            m_pCttsSampleOffsetProperty->GetValue(cttsIndex);
        m_pCttsSampleOffsetProperty->
        InsertValue(oldRenderingOffset, cttsIndex + 2);

        m_pCttsCountProperty->IncrementValue(2);
    }
}

bool MP4Track::IsSyncSample(MP4SampleId sampleId)
{
    if (m_pStssCountProperty == NULL) {
        return true;
    }

    uint32_t numStss = m_pStssCountProperty->GetValue();
    uint32_t stssLIndex = 0;
    uint32_t stssRIndex = numStss - 1;

    while (stssRIndex >= stssLIndex) {
        uint32_t stssIndex = (stssRIndex + stssLIndex) >> 1;
        MP4SampleId syncSampleId =
            m_pStssSampleProperty->GetValue(stssIndex);

        if (sampleId == syncSampleId) {
            return true;
        }

        if (sampleId > syncSampleId) {
            stssLIndex = stssIndex + 1;
        } else {
            stssRIndex = stssIndex - 1;
        }
    }

    return false;
}

// N.B. "next" is inclusive of this sample id
MP4SampleId MP4Track::GetNextSyncSample(MP4SampleId sampleId)
{
    if (m_pStssCountProperty == NULL) {
        return sampleId;
    }

    uint32_t numStss = m_pStssCountProperty->GetValue();

    for (uint32_t stssIndex = 0; stssIndex < numStss; stssIndex++) {
        MP4SampleId syncSampleId =
            m_pStssSampleProperty->GetValue(stssIndex);

        if (sampleId > syncSampleId) {
            continue;
        }
        return syncSampleId;
    }

    // LATER check stsh for alternate sample

    return MP4_INVALID_SAMPLE_ID;
}

void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample)
{
    if (isSyncSample) {
        // if stss atom exists, add entry
        if (m_pStssCountProperty) {
            m_pStssSampleProperty->AddValue(sampleId);
            m_pStssCountProperty->IncrementValue();
        } // else nothing to do (yet)

    } else { // !isSyncSample
        // if stss atom doesn't exist, create one
        if (m_pStssCountProperty == NULL) {

            MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss");

            ASSERT(pStssAtom->FindProperty(
                       "stss.entryCount",
                       (MP4Property**)&m_pStssCountProperty));

            ASSERT(pStssAtom->FindProperty(
                       "stss.entries.sampleNumber",
                       (MP4Property**)&m_pStssSampleProperty));

            // set values for all samples that came before this one
            uint32_t samples = GetNumberOfSamples();
            for (MP4SampleId sid = 1; sid < samples; sid++) {
                m_pStssSampleProperty->AddValue(sid);
                m_pStssCountProperty->IncrementValue();
            }
        } // else nothing to do
    }
}

MP4Atom* MP4Track::AddAtom(const char* parentName, const char* childName)
{
    MP4Atom* pParentAtom = m_trakAtom.FindAtom(parentName);
    ASSERT(pParentAtom);

    MP4Atom* pChildAtom = MP4Atom::CreateAtom(m_File, pParentAtom, childName);

    pParentAtom->AddChildAtom(pChildAtom);

    pChildAtom->Generate();

    return pChildAtom;
}

uint64_t MP4Track::GetDuration()
{
    return m_pMediaDurationProperty->GetValue();
}

uint32_t MP4Track::GetTimeScale()
{
    return m_pTimeScaleProperty->GetValue();
}

void MP4Track::UpdateDurations(MP4Duration duration)
{
    // update media, track, and movie durations
    m_pMediaDurationProperty->SetValue(
        m_pMediaDurationProperty->GetValue() + duration);

    MP4Duration movieDuration = ToMovieDuration(
        m_pMediaDurationProperty->GetValue());
    m_pTrackDurationProperty->SetValue(movieDuration);

    m_File.UpdateDuration(m_pTrackDurationProperty->GetValue());
}

MP4Duration MP4Track::ToMovieDuration(MP4Duration trackDuration)
{
    return (trackDuration * m_File.GetTimeScale())
           / m_pTimeScaleProperty->GetValue();
}

void MP4Track::UpdateModificationTimes()
{
    // update media and track modification times
    MP4Timestamp now = MP4GetAbsTimestamp();
    m_pMediaModificationProperty->SetValue(now);
    m_pTrackModificationProperty->SetValue(now);
}

uint32_t MP4Track::GetNumberOfChunks()
{
    return m_pChunkOffsetProperty->GetCount();
}

uint32_t MP4Track::GetChunkStscIndex(MP4ChunkId chunkId)
{
    uint32_t stscIndex;
    uint32_t numStscs = m_pStscCountProperty->GetValue();

    ASSERT(chunkId);
    ASSERT(numStscs > 0);

    for (stscIndex = 0; stscIndex < numStscs; stscIndex++) {
        if (chunkId < m_pStscFirstChunkProperty->GetValue(stscIndex)) {
            ASSERT(stscIndex != 0);
            break;
        }
    }
    return stscIndex - 1;
}

MP4Timestamp MP4Track::GetChunkTime(MP4ChunkId chunkId)
{
    uint32_t stscIndex = GetChunkStscIndex(chunkId);

    MP4ChunkId firstChunkId =
        m_pStscFirstChunkProperty->GetValue(stscIndex);

    MP4SampleId firstSample =
        m_pStscFirstSampleProperty->GetValue(stscIndex);

    uint32_t samplesPerChunk =
        m_pStscSamplesPerChunkProperty->GetValue(stscIndex);

    MP4SampleId firstSampleInChunk =
        firstSample + ((chunkId - firstChunkId) * samplesPerChunk);

    MP4Timestamp chunkTime;

    GetSampleTimes(firstSampleInChunk, &chunkTime, NULL);

    return chunkTime;
}

uint32_t MP4Track::GetChunkSize(MP4ChunkId chunkId)
{
    uint32_t stscIndex = GetChunkStscIndex(chunkId);

    MP4ChunkId firstChunkId =
        m_pStscFirstChunkProperty->GetValue(stscIndex);

    MP4SampleId firstSample =
        m_pStscFirstSampleProperty->GetValue(stscIndex);

    uint32_t samplesPerChunk =
        m_pStscSamplesPerChunkProperty->GetValue(stscIndex);

    MP4SampleId firstSampleInChunk =
        firstSample + ((chunkId - firstChunkId) * samplesPerChunk);

    // need cumulative sizes of samples in chunk
    uint32_t chunkSize = 0;
    for (uint32_t i = 0; i < samplesPerChunk; i++) {
        chunkSize += GetSampleSize(firstSampleInChunk + i);
    }

    return chunkSize;
}

void MP4Track::ReadChunk(MP4ChunkId chunkId,
                         uint8_t** ppChunk, uint32_t* pChunkSize)
{
    ASSERT(chunkId);
    ASSERT(ppChunk);
    ASSERT(pChunkSize);

    uint64_t chunkOffset =
        m_pChunkOffsetProperty->GetValue(chunkId - 1);

    *pChunkSize = GetChunkSize(chunkId);
    *ppChunk = (uint8_t*)MP4Malloc(*pChunkSize);

    log.verbose3f("\"%s\": ReadChunk: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)",
                  GetFile().GetFilename().c_str(),
                  m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize);

    uint64_t oldPos = m_File.GetPosition(); // only used in mode == 'w'
    try {
        m_File.SetPosition( chunkOffset );
        m_File.ReadBytes( *ppChunk, *pChunkSize );
    }
    catch( Exception* x ) {
        MP4Free( *ppChunk );
        *ppChunk = NULL;

        if( m_File.IsWriteMode() )
            m_File.SetPosition( oldPos );

        throw x;
    }

    if( m_File.IsWriteMode() )
        m_File.SetPosition( oldPos );
}

void MP4Track::RewriteChunk(MP4ChunkId chunkId,
                            uint8_t* pChunk, uint32_t chunkSize)
{
    uint64_t chunkOffset = m_File.GetPosition();

    m_File.WriteBytes(pChunk, chunkSize);

    m_pChunkOffsetProperty->SetValue(chunkOffset, chunkId - 1);

    log.verbose3f("\"%s\": RewriteChunk: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)",
                  GetFile().GetFilename().c_str(),
                  m_trackId, chunkId, chunkOffset, chunkSize, chunkSize);
}

// map track type name aliases to official names

bool MP4Track::InitEditListProperties()
{
    m_pElstCountProperty = NULL;
    m_pElstMediaTimeProperty = NULL;
    m_pElstDurationProperty = NULL;
    m_pElstRateProperty = NULL;
    m_pElstReservedProperty = NULL;

    MP4Atom* pElstAtom =
        m_trakAtom.FindAtom("trak.edts.elst");

    if (!pElstAtom) {
        return false;
    }

    (void)pElstAtom->FindProperty(
        "elst.entryCount",
        (MP4Property**)&m_pElstCountProperty);
    (void)pElstAtom->FindProperty(
        "elst.entries.mediaTime",
        (MP4Property**)&m_pElstMediaTimeProperty);
    (void)pElstAtom->FindProperty(
        "elst.entries.segmentDuration",
        (MP4Property**)&m_pElstDurationProperty);
    (void)pElstAtom->FindProperty(
        "elst.entries.mediaRate",
        (MP4Property**)&m_pElstRateProperty);

    (void)pElstAtom->FindProperty(
        "elst.entries.reserved",
        (MP4Property**)&m_pElstReservedProperty);

    return m_pElstCountProperty
           && m_pElstMediaTimeProperty
           && m_pElstDurationProperty
           && m_pElstRateProperty
           && m_pElstReservedProperty;
}

MP4EditId MP4Track::AddEdit(MP4EditId editId)
{
    if (!m_pElstCountProperty) {
        (void)m_File.AddDescendantAtoms(&m_trakAtom, "edts.elst");
        if (InitEditListProperties() == false) return MP4_INVALID_EDIT_ID;
    }

    if (editId == MP4_INVALID_EDIT_ID) {
        editId = m_pElstCountProperty->GetValue() + 1;
    }

    m_pElstMediaTimeProperty->InsertValue(0, editId - 1);
    m_pElstDurationProperty->InsertValue(0, editId - 1);
    m_pElstRateProperty->InsertValue(1, editId - 1);
    m_pElstReservedProperty->InsertValue(0, editId - 1);

    m_pElstCountProperty->IncrementValue();

    return editId;
}

void MP4Track::DeleteEdit(MP4EditId editId)
{
    if (editId == MP4_INVALID_EDIT_ID) {
        throw new Exception("edit id can't be zero",
                            __FILE__, __LINE__, __FUNCTION__ );
    }

    if (!m_pElstCountProperty
            || m_pElstCountProperty->GetValue() == 0) {
        throw new Exception("no edits exist",
                            __FILE__, __LINE__, __FUNCTION__ );
    }

    m_pElstMediaTimeProperty->DeleteValue(editId - 1);
    m_pElstDurationProperty->DeleteValue(editId - 1);
    m_pElstRateProperty->DeleteValue(editId - 1);
    m_pElstReservedProperty->DeleteValue(editId - 1);

    m_pElstCountProperty->IncrementValue(-1);

    // clean up if last edit is deleted
    if (m_pElstCountProperty->GetValue() == 0) {
        m_pElstCountProperty = NULL;
        m_pElstMediaTimeProperty = NULL;
        m_pElstDurationProperty = NULL;
        m_pElstRateProperty = NULL;
        m_pElstReservedProperty = NULL;

        m_trakAtom.DeleteChildAtom(
            m_trakAtom.FindAtom("trak.edts"));
    }
}

MP4Timestamp MP4Track::GetEditStart(
    MP4EditId editId)
{
    if (editId == MP4_INVALID_EDIT_ID) {
        return MP4_INVALID_TIMESTAMP;
    } else if (editId == 1) {
        return 0;
    }
    return (MP4Timestamp)GetEditTotalDuration(editId - 1);
}

MP4Duration MP4Track::GetEditTotalDuration(
    MP4EditId editId)
{
    uint32_t numEdits = 0;

    if (m_pElstCountProperty) {
        numEdits = m_pElstCountProperty->GetValue();
    }

    if (editId == MP4_INVALID_EDIT_ID) {
        editId = numEdits;
    }

    if (numEdits == 0 || editId > numEdits) {
        return MP4_INVALID_DURATION;
    }

    MP4Duration totalDuration = 0;

    for (MP4EditId eid = 1; eid <= editId; eid++) {
        totalDuration +=
            m_pElstDurationProperty->GetValue(eid - 1);
    }

    return totalDuration;
}

MP4SampleId MP4Track::GetSampleIdFromEditTime(
    MP4Timestamp editWhen,
    MP4Timestamp* pStartTime,
    MP4Duration* pDuration)
{
    MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID;
    uint32_t numEdits = 0;

    if (m_pElstCountProperty) {
        numEdits = m_pElstCountProperty->GetValue();
    }

    if (numEdits) {
        MP4Duration editElapsedDuration = 0;

        for (MP4EditId editId = 1; editId <= numEdits; editId++) {
            // remember edit segment's start time (in edit timeline)
            MP4Timestamp editStartTime =
                (MP4Timestamp)editElapsedDuration;

            // accumulate edit segment's duration
            editElapsedDuration +=
                m_pElstDurationProperty->GetValue(editId - 1);

            // calculate difference between the specified edit time
            // and the end of this edit segment
            if (editElapsedDuration - editWhen <= 0) {
                // the specified time has not yet been reached
                continue;
            }

            // 'editWhen' is within this edit segment

            // calculate the specified edit time
            // relative to just this edit segment
            MP4Duration editOffset =
                editWhen - editStartTime;

            // calculate the media (track) time that corresponds
            // to the specified edit time based on the edit list
            MP4Timestamp mediaWhen =
                m_pElstMediaTimeProperty->GetValue(editId - 1)
                + editOffset;

            // lookup the sample id for the media time
            sampleId = GetSampleIdFromTime(mediaWhen, false);

            // lookup the sample's media start time and duration
            MP4Timestamp sampleStartTime;
            MP4Duration sampleDuration;

            GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration);

            // calculate the difference if any between when the sample
            // would naturally start and when it starts in the edit timeline
            MP4Duration sampleStartOffset =
                mediaWhen - sampleStartTime;

            // calculate the start time for the sample in the edit time line
            MP4Timestamp editSampleStartTime =
                editWhen - min(editOffset, sampleStartOffset);

            MP4Duration editSampleDuration = 0;

            // calculate how long this sample lasts in the edit list timeline
            if (m_pElstRateProperty->GetValue(editId - 1) == 0) {
                // edit segment is a "dwell"
                // so sample duration is that of the edit segment
                editSampleDuration =
                    m_pElstDurationProperty->GetValue(editId - 1);

            } else {
                // begin with the natural sample duration
                editSampleDuration = sampleDuration;

                // now shorten that if the edit segment starts
                // after the sample would naturally start
                if (editOffset < sampleStartOffset) {
                    editSampleDuration -= sampleStartOffset - editOffset;
                }

                // now shorten that if the edit segment ends
                // before the sample would naturally end
                if (editElapsedDuration
                        < editSampleStartTime + sampleDuration) {
                    editSampleDuration -= (editSampleStartTime + sampleDuration)
                                          - editElapsedDuration;
                }
            }

            if (pStartTime) {
                *pStartTime = editSampleStartTime;
            }

            if (pDuration) {
                *pDuration = editSampleDuration;
            }

            log.verbose2f("\"%s\": GetSampleIdFromEditTime: when %" PRIu64 " "
                          "sampleId %u start %" PRIu64 " duration %" PRId64,
                          GetFile().GetFilename().c_str(),
                          editWhen, sampleId,
                          editSampleStartTime, editSampleDuration);

            return sampleId;
        }

        throw new Exception("time out of range",
                            __FILE__, __LINE__, __FUNCTION__ );

    } else { // no edit list
        sampleId = GetSampleIdFromTime(editWhen, false);

        if (pStartTime || pDuration) {
            GetSampleTimes(sampleId, pStartTime, pDuration);
        }
    }

    return sampleId;
}

void MP4Track::CalculateBytesPerSample ()
{
    MP4Atom *pMedia = m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd");
    MP4Atom *pMediaData;
    const char *media_data_name;
    if (pMedia == NULL) return;

    if (pMedia->GetNumberOfChildAtoms() != 1) return;

    pMediaData = pMedia->GetChildAtom(0);
    media_data_name = pMediaData->GetType();
    if ((ATOMID(media_data_name) == ATOMID("twos")) ||
            (ATOMID(media_data_name) == ATOMID("sowt"))) {
        MP4IntegerProperty *chan, *sampleSize;
        chan = (MP4IntegerProperty *)pMediaData->GetProperty(4);
        sampleSize = (MP4IntegerProperty *)pMediaData->GetProperty(5);
        m_bytesPerSample = chan->GetValue() * (sampleSize->GetValue() / 8);
    }
}

MP4Duration MP4Track::GetDurationPerChunk()
{
    return m_durationPerChunk;
}

void MP4Track::SetDurationPerChunk( MP4Duration duration )
{
    m_durationPerChunk = duration;
}

///////////////////////////////////////////////////////////////////////////////

}} // namespace mp4v2::impl

redpajama_set_name: RedPajamaGithub


text:
Alabama's legislative districts are 'racially gerrymandered,' Supreme Court rules
25 Mar, 2015 22:32
Reuters / Joshua Roberts © Reuters
The Supreme Court has ruled that Alabama's redistricting plans weaken blacks' political power by concentrating them together, thus increasing Republican power. Justices sent the case back to the same District Court that had okayed Alabama's new maps.
In 2012, Alabama's Republican-led state legislature re-drew the boundaries of the state legislature's 105 House districts and 35 Senate districts. It focused on obtaining the theoretical ideal of precisely equal population by keeping any deviation from that goal to less than one percent. Alabama also sought to avoid hampering racial minorities' ability to elect their candidates of choice ‒ as required by Section 5 of the Voting Rights Act of 1965 ‒ by maintaining roughly the same percentage of African-Americans in majority-minority districts that existed within the previous district lines.
The Alabama Legislative Black Caucus and the Alabama Democratic Conference each sued the state in August 2012 over the redistricting plans; the two cases were subsequently consolidated. The appellants claimed the new district boundaries created "racial gerrymanders" in violation of the Fourteenth Amendment's Equal Protection Clause ‒ a question the Supreme Court ignored ‒ and the Voting Rights Act.
In December 2013, a three-judge panel from the US District Court voted 2-1 to uphold the Alabama redistricting map. The District Court ruled that the claims of racial gerrymandering failed because "[r]ace was not the predominant motivating factor." The judges believed the appellants needed to prove that racial gerrymandering occurred on a statewide basis as well, which they were unable to do.
The District Court also ruled that the plaintiffs lacked standing because the record did "not clearly identify the districts in which the individual members of the [Conference] reside," and that the Conference had "not proved that it has members who have standing to pursue any district-specific claims of racial gerrymandering."
Supreme Court decision
In a 5-4 vote, the Supreme Court disagreed with that decision. Justice Stephen Breyer wrote the majority opinion, in which Justices Anthony Kennedy, Ruth Bader Ginsburg, Sonia Sotomayor and Elena Kagan joined.
Breyer applauded Alabama's attempt to create an idealistic "one-person, one-vote" situation by limiting the deviation from the goal population to one percent, but noted that a five percent deviation from the ideal is "generally permissible." However, he disliked how the state went about drawing district boundaries to obtain that goal.
"In order for Senate District 26, for example, to meet the State's no-more-than-1 [percent] population-deviation objective, the State would have to add about 16,000 individuals to the district. And, prior to redistricting, 72.75 [percent] of District 26's population was black. Accordingly, Alabama's plan added 15,785 new individuals, and only 36 of those newly added individuals were white," he wrote, adding that was "a remarkable feat given the local demographics."
The Supreme Court cited the Department of Justice Guidelines for Section 5's pre-clearance determinations, which say that districts are not based "on any predetermined or fixed demographic percentages."
The majority opinion also held that the appellants didn't claim that the Alabama legislature employed racial gerrymandering as a whole, but that individual majority-minority districts were racially gerrymandered, and that the evidence of such required looking at the state as a whole.
"And those are the districts that we believe the District Court must reconsider," Breyer noted. "That Alabama expressly adopted and applied a policy of prioritizing mechanical racial targets above all other districting criteria (save one-person, one-vote) provides evidence that race motivated the drawing of particular lines in multiple districts in the State."
When it came to standing, the Supreme Court disagreed with the District Court, writing that "the common sense inference is strong enough to lead the Conference reasonably to believe that, in the absence of a state challenge or a court request for more detailed information, it need not provide additional information such as a specific membership list."
In a scathing dissent, Justice Antonin Scalia called the majority's decision a "sweeping holding that will have profound implications for the constitutional ideal of one person, one vote, for the future of the Voting Rights Act of 1965, and for the primacy of the State in managing its own elections."
"If the Court's destination seems fantastical, just wait until you see the journey," he added.
Joined by Chief Justice John Roberts and Justices Clarence Thomas and Samuel Alito, Scalia sided with the District Court's opinion on the appellants' standing, writing that they did not prove that they sufficiently represented members in the affected Alabama districts, as counties and districts have different boundaries.
"Frankly, I do not know what to make of appellants' arguments. They are pleaded with such opacity that, squinting hard enough, one can find them to contain just about anything," Scalia concluded. "This, the Court believes, justifies demanding that the District Court go back and squint harder, so that it may divine some new means of construing the filings."
In a dissent of his own, Thomas ‒ the Supreme Court's only black justice ‒ focused on the effective racism that resulted as a consequence of Section 5 and the Supreme Court's role in creating Alabama's current redistricting problems.
"The practice of creating highly packed ‒ 'safe' ‒ majority-minority districts is the product of our erroneous jurisprudence, which created a system that forces States to segregate voters into districts based on the color of their skin" he wrote. "Nor does this Court have clean hands."
"I do not pretend that Alabama is blameless when it comes to its sordid history of racial politics. But, today the State is not the one that is culpable. Its redistricting effort was indeed tainted, but it was tainted by our voting rights jurisprudence and the uses to which the Voting Rights Act has been put," Thomas added. "Long ago, the DOJ and special-interest groups like the [American Civil Liberties Union] hijacked the Act, and they have been using it ever since to achieve their vision of maximized black electoral strength, often at the expense of the voters they purport to help."
Supreme Court to review anti-racism voting law
Supreme Court guts Civil Rights-era voting protection, siding with 'Old Confederacy'
Justice Department sues North Carolina over 'discriminatory' voting law


text:
Why Blockchain's growing pains will be worth it
Experts say blockchain has a bright future, much like the optimistic predictions the industry had for the cloud 10 years ago.
By David Needle
CIO |
HALF MOON BAY, Calif. – Experts at a recent technology conference agreed that blockchain has a bright future, but warned it may be a rocky ride until that future arrives. Blockchain is a distributed database that uses a secure digital ledger of transactions that users can share across a computer network. It's also the technology behind virtual currency bitcoin.
"When you are at the leading edge there will be mistakes. People will get a lot wrong in the next five years. I think of it kind of like running with scissors," says Constellation Research analyst Steve Wilson at the Oct. 26 Connected Enterprise conference hosted by his company.
Constellation Research Connected Enterprise conference
From left to right: Shawn Wiora, CEO of Maxxsure, Silicon Valley Product Exec Chirag Mehta, and Aron Dutta, Global Head of Blockchain at IBM
But blockchain enthusiast Richie Etwaru, chief digital officer at IMS Health, had a different take. He started by pointing to the colorful pair of sneakers he was wearing and noted he bought them using bitcoin, the controversial digital currency that's been plagued by security issues.
"I think blockchain is the biggest thing I've seen in my life," says Etwaru. "I work in healthcare and bitcoin to blockchain is like what AOL chat was to the internet, and bitcoin is only one substantiation of blockchain."
Blockchain can help the healthcare industry build trust
In the healthcare industry Etwaru says blockchain can help establish new business models that overcome what he describes as the massive absence of trust that exists today among patients, doctors, the pharmaceutical industry and the government.
"We started thinking of how we can engineer trust into the network and the distributed ledger (i.e. blockchain) is a great way to solve the trust issue because the information is owned by everyone and no one, and can be seen by everyone and no one," he says. "It's immutable, you can't reverse it, it's pretty decently encrypted and it can be permissions-based."
One example Etwaru points to is that trials for new drugs are often flawed because patients don't trust how their information is going to be used. "With blockchain you could do things like citizen research for healthcare. There could be autonomous organizations like a Wikipedia of research on cancer based on an abundance of trust enabled by blockchain," said Etwaru.
Blockchain can disrupt the cybersecurity landscape
Mike Kail,chief innovation officer at Cybric, a company that's looking to "disrupt the cybersecurity landscape" with new services, says blockchain has got people thinking differently about what's possible.
Kail says blockchain technology promises to change the status quo of having to trust a broker to complete financial transactions to a system of automated, verifiable transactions that eliminates the middleman. Speaking more broadly, he says blockchain can bring more efficiency to every company with a supply chain challenge.
For companies looking to test the blockchain waters he suggests figuring out a small use case where you can apply blockchain methodology and monitor the results.
Another speaker, Shawn Wiora, cofounder and CEO of Maxxsure, a cybersecurity and cyber insurance company, is using blockchain to offer new kinds of services. "We're able to offer things like variable premiums for a cyber insurance policy that changes as your cyber profile changes," said Wiora. "Does anyone else offer that?" he asked rhetorically.
But even with some companies already innovating, veteran Silicon Valley product executive Chirag Mehta says blockchain's best days are clearly ahead of it. "Blockchain looks like what the cloud looked like 10 or 15 years ago," says Mehta, a former executive at SAP and adjunct professor at Santa Clara University where he teaches such topics as web services and cloud computing to graduate students.
One difference he sees vs. the cloud though that's surprised him, is that companies big and small seem to be interested in exploring blockchain's potential. "Big companies weren't as interested in the cloud in the early days," says Mehta. "They weren't as ready to jump in."
What blockchain does really well, he adds, is provide the technical integrity necessary to let you trust a series of events. "But don't confuse that with security," he emphasized.
If blockchain needs a blue chip, big name advocate it has one in IBM. Aron Dutta, global head of blockchain at IBM, says he's already running blockchain technology globally across industries. He sees blockchain as giving companies a way to rethink business models and make more money.
Dutta says he has over 4,000 PhDs and 100,000 consultants he can call on to aid his work at IBM, so stay tuned. "It's not about use cases," he emphasizes. "It's about business models."
David Needle is a technology journalist based in Silicon Valley.
This story, "Why Blockchain's growing pains will be worth it" was originally published by CIO.


text:
The Fashion Footmark of Wayfarer Sunglasses
Blog The Fashion Footmark of Wayfarer Sunglasses
Wayfarer, the plastic, trapezoidal frames have gained immediate popularity and stayed in vogue for almost 20 years before sinking into fashion and then reappeared again in the 21st century, and have made yet another comeback in modern day fashion. Follow Vlook, let's learn about the fashion footmark of wayfarer sunglasses.
Wayfarers were created by optical designer Raymond Stegeman in 1952 when he procured dozens of patents for Baush and Lomb, Ray-Ban's parent company at the time. At the time of their inception, the wayfarer was seen as a radical design that rivaled the Cadillac's tail fin and design critic Stephen Bayley, the "distinctive trapezoidal frame spoke a non-verbal language that hinted at unstable dangerousness, but one nicely tempered by the sturdy arms which, according to the advertising, gave the frames a 'masculine look." They wayfarers also ushered in the trend of glasses made of plastic and not wire or metal.
In the 1960s, wayfarers grew in popularity from being worn by key figures such as John F Kennedy and Audrey Hepburn. Then in the '70s the popular frames all but disappeared, only to reemerge with a vengeance in the early '80s in a prominent appearance in "The Blues Brothers" in 1980. Though wayfarers enjoyed a great success in that year, the style verged on discontinuation after only 18,000 units were sold worldwide in 1981. However, throughout the early-mid '80s, they began to show up on many popular actors and in numerous films, reestablishing their popularity. Tom Cruise wore them in "Risky Business" (1983), they showed up in "The Breakfast Club" (1985) and then again in "Miami Vice" (1989); Jack Nicholson wore wayfarers throughout the 80's, so did fashion maven Anna Wintour.
Wayfarers even showed up in pop fiction and songs. In brief, Wayfarers were everywhere throughout the '80s, but by the '90s, they experienced a major decline and, once again, disappeared from the public eye in the early 2000s.
In 2001, the style underwent a redesign with frames that were less angular and smaller and were also made of lighter injected plastic. By the late 2000's the sunglasses made a full recovery and are now very popular again. Using smart PR, edgy advertising and grass roots marketing efforts to make the style trendy again. Every year since the wayfarer has shown signs of steady growth with no signs of stopping.
Wayfarers have reemerged in the second decade of the 21st century as a sunglasses mainstay, pervading both pop culture and main street fashion. They've also lent inspiration to designers who use modern techniques to design similar shapes and styles and use new materials & processes to craft sunglasses that have timeless appeal for all tastes.
Modern Adaptations
Modern sunglass makers have adapted the wayfarer and added major flare and twists to the design. Proof Eyewear, for example, crafts bamboo and mahogany frames with iridescent colored lenses in their Ontario Wood line for unique and truly interesting looks that, while definitely wayfarers, but totally departures from the old materials and craftwork.
Meanwhile, the traditional wayfarer stylization changed with fun, vibrant colors and reflective lenses that can be worn by anyone.
There's a wayfarer for everyone from more conservative, classic wayfarer-style glasses to brighter, flashier, and more modern versions. Some people say style itself is the only thing that never goes out of fashion, and wayfarers certainly have it spared.
Clear Non-prescription Eyeglasses Guide
Glasses VS Contacts
Polarized sunglasses vs Non-polarized Sunglasses
Tips: What is the Air Conditioning Disease of the Eye?
How to make the lenses thinner?
Why Choose Titanium Frame Glasses?
Tags:Frame, Sunglasses, History, Wayfarer,


Have you ever traveled to Kuala Lumpur before? This is a beautiful area of the world that many people visit for both business and pleasure. Some of the best activities that you can do are in the main city. You are able to see the Petronas Towers, and outside of the city are the Batu Caves. It is the perfect destination for people that have never been to Malaysia before. If you are going to go, you will need to find a rental car that you can use. Here are the steps that you need to take in order to get the best deal on a car rental KL from Big Thumb.
The main reason that you will need a car in this country is to go around to the different places were you may be visiting. This could be a vacation that you have planned for many years, but there may also be places you need to drive if this is for a business trip. You may need a larger car if you are bringing people with you, perhaps to different meetings. You will have to find many different rental companies, compare the prices, and try to get a package deal of possible when you are ordering your flight and hotel online.
These companies can be found in many different locations. Primarily, you need to search on the web. When you do your booking for your flight, you will likely be able to see special deals on these rental cars that will come as part of a package deal. If these deals are not good enough, you may want to try a different website. There are quite a few that offer travel deals. Once you have found one of these companies, you can pick and choose from the many different cars that they have available. It is recommended that you get one that is relatively small as it's difficult to park in this country.
To get the best possible deals, you are going to have to search several different websites. You may find that you actually are able to get the car for free. It just depends on the company you are going through, special offers they are making available, and how much you are paying for the flight. Usually, the car is included for free if you are paying almost regular price for the plane ticket, or if you are also combining a hotel in the package. You simply have to search around until you find something that is affordable.
The one that you finally choose is going to be not only affordable, but large enough to accommodate everything that you will need. As mentioned before, always try to get one that is smaller so that you will have no problem parking. Gas mileage is also something to consider since the cost of gas in this country is relatively high. It may take you a few hours, but once you have done the research, you will have an affordable car rental that you can drive in Kuala Lumpur, you can also contact Big Thumb to learn more.


London office TMT Partner, James Martin, is speaking at the Global IP Convention (GIPC) in Delhi on 11th January on the law and developments in the protection of trade secrets in the UK and EU.
The GIPC, now in its ninth year, is the largest, longest running and most prestigious international IP conference held in India attracting high calibre speakers and delegates from the world of intellectual property including the Heads of IP and General Counsel from major multi-national corporations. Some of the other speakers James will join at the conference include the Chief IP Counsel at Siemens, the Head of Global Patent Litigation Strategy at Novartis, the Head of IP at ThyssenKrupp and the Head of IP Portfolio Management at Philips.
The conference provides a great opportunity to showcase the expertise of DMH Stallard's TMT and IP practice in UK and multi-national IP disputes to an international audience including a promotional focus on the firm's practice in the conference brochure.


This past Sunday stars hit the red carpet to attend Hollywood's biggest night! Here's a few of my top choices for best dressed.
Start the New Year off with the perfect shoe. Here are a few options to help you bring in the New Year instyle.
Travel is hard enough so why not do it in style.
Once a year San Diego's top magazine, Riviera partners up with Neiman Marcus for their Men Of Style party. Each time it's better than the last, with a great fashion show, craft cocktails, and delectable eats. Any reason to dress up and I'm there, but make it a men's fashion event and I'm there until the end! Kudos to all the men of San Diego who were celebrated for their impeccable style!


We believe that our menu truly reflects the customs and traditions of Napoli cuisine. Our goal is to give our customers a dining experience they will never forget, with cuisine that will never disappoint. We use only the freshest and finest ingredients in our dishes, most of which are shipped from all across the world to ensure that our dishes are up to par. We hope that you come dine with us soon, so you too can experience our cuisine for yourself.


As only Modern does, we manufacture our Hi-Hi Roller Stand with 304 military grade stainless steel legs and tubes. Also know as Overhead Stands, these stands have a wide base for stability and we equip them with an adjustable rocky mountain leg which enables it to be leveled on uneven surfaces. These stands have three risers that terminates into Modern's redesigned 4-1/2" grip head. These stands are typically used in studios to support large backdrops and on location for Overheads and Butterflys.


You are spamming the forum. You are double posting under 2 different user accounts. See below image and username in the image.
I would help but I do not like spammers. Sorry. Please pick a username to use and use only that one. Double posting will not get you help any faster. Frankly speaking, it takes up more of our time reading an extra post only to find out it was the same person with the same problem, thus the term SPAM. If I was a mod I would give you a warning but since I am not, I will simply move on and wish you a good day.


text:
What is being built
From 2022 to 2023, Scott County will be reconstructing County Road 83 from Highway 169 to Valley Industrial Boulevard South. The purpose of the project is to address existing safety issues for people driving, walking, and biking by converting the 4-lane undivided highway to a 4-lane divided highway with added pedestrian facilities. This road is one of few roads providing north/south access through Shakopee into Prior Lake and provides critical access to major industrial areas and high-volume entertainment venues. This route is also an important connection for regional traffic, connecting Highway 169 to Highway 101, County Road 16, County Road 42, and County Road 82.
Be sure to sign up for weekly updates to receive the most up to date information on construction.
CONSTRUCTION TIMEFRAME
March 2022-October 2023
Send us an email at 83construction@bolton-menk.com
Call our help line at 952-392-9631
Sign up for construction updates
Wireless Number
Designed and Maintained by Bolton & Menk, LLC