<commit_before>import React, { PropTypes } from 'react'
import s from './Location.css'
import icons from '../../icons/css/icons.css'

import { relevantTaxonomies, getIcon } from '../../lib/taxonomies'
import { capitalize } from '../../lib/stringHelpers'

import Link from '../Link'
import GoogleMap from '../GoogleMap'

const getGender = (abbr) => {
  if (abbr === '' || abbr === 'MF' || abbr === 'FM') return 'Everyone'
  return abbr === 'F' ? 'Women' : 'Men'
}

const getGenderAdj = (abbr) => {
  if (abbr === '' || abbr === 'MF' || abbr === 'FM') {
    return 'All'
  }
  return abbr === 'F' ? 'Female' : 'Male'
}

const getAge = (abbr) => {
  switch (abbr) {
    case 'C':
      return 'children'
    case 'Y':
      return 'teens'
    case 'A':
      return 'adults'
    case 'S':
      return 'seniors'
    default:
      return ''
  }
}

const getAllGendersAndAges = (services) => {
  const allGendersAndAges = Object.values(services)
    .map(service => service.eligibility)
    .reduce((acc, eligibility) => {
      const { gender, age } = acc
      const moreGender = [...gender, eligibility.gender]
      const moreAge = eligibility.age ? [...age, ...eligibility.age] : age // ['C', 'Y']
      return { gender: moreGender, age: moreAge }
    }, { gender: [], age: [] })
  return {
    gender: Array.from(new Set(allGendersAndAges.gender)).join(''),
    age: Array.from(new Set(allGendersAndAges.age)),
  }
}

const getEligibility = ({ gender, age = [] }) => {
  if (gender === '' && age.length === 0) {
    return getGender(gender)
  }

  const ages = age.map(getAge).join(', ')

  return `${getGenderAdj(gender)} ${ages}`
}

const getMapsUrl = (location) => {
  const { latitude, longitude } = location
  return `https://maps.google.com/maps?q=loc:${latitude},${longitude}`
}

const DAYS = {
  0: 'sunday',
  1: 'monday',
  2: 'tuesday',
  3: 'wednesday',
  4: 'thursday',
  5: 'friday',
  6: 'saturday',
}

const DAY = {
  Sunday: 'sunday',
  Monday: 'monday',
  Tuesday: 'tuesday',
  Wednesday: 'wednesday',
  Thursday: 'thursday',
  Friday: 'friday',
  Saturday: 'saturday',
}

const DAY_ABBREVIATIONS = {
  sunday: 'Sun',
  monday: 'Mon',
  tuesday: 'Tue',
  wednesday: 'Wed',
  thursday: 'Thu',
  friday: 'Fri',
  saturday: 'Sat',
}

const convertMilitaryTime = (time) => {
  const hours = Math.floor(time / 100)
  const mins = time % 100
  let output = ''
  if (hours < 12) {
    if (hours == 0) {
      output += 12
    } else {
      output += hours
    }
    if (mins > 0) {
      output += `:${mins}`
    }
    output += 'am'
  } else {
    if (hours == 12) {
      output += hours
    } else {
      output += hours - 12
    }
    if (mins > 0) {
      output += `:${mins}`
    }
    output += 'pm'
  }
  return output
}

const getDailySchedules = (schedules) => {
  const daySchedules = Object.assign({}, DAY_ABBREVIATIONS)
  Object.keys(daySchedules).forEach(day => {
    daySchedules[day] = []
  })
  schedules
    .forEach(schedule => {
      const day = schedule.weekday.toLowerCase()
      const daySchedule = daySchedules[day]
      daySchedule.push({
        opensAt: schedule.opensAt,
        closesAt: schedule.closesAt,
      })
    })
  return daySchedules
}

const getTimeRange = hours => (
  `${convertMilitaryTime(hours.opensAt)} - ${convertMilitaryTime(hours.closesAt)}`
)

const Schedule = (props) => {
  const daySchedules = getDailySchedules(props.schedules)
  const indexToDaySchedule = index => daySchedules[DAYS[index]]
  const dayHasSchedules = daySchedule => indexToDaySchedule(daySchedule).length > 0
  const scheduleRows = Object.keys(DAYS).sort()
    .filter(dayHasSchedules)
    .map(index => (
      <tr key={`day-${index}`}>

          {DAY_ABBREVIATIONS[DAYS[index]]}

          {indexToDaySchedule(index)
              .sort((a, b) => a.opensAt  {
  const { location, organization } = props
  const { services = [] } = location
  return (

{location.name}

        Welcome:
          {getEligibility(getAllGendersAndAges(services))}

Services

          {relevantTaxonomies(services).map((taxonomy, index) => (
            <span key={`category-${index}`}>
              <i className={`category-icon ${getIcon(taxonomy)}`}>
              {capitalize(taxonomy)}

          ))}

      {location.physicalAddress &&

            <GoogleMap lat={location.latitude} long={location.longitude} />

            {location.physicalAddress.address1}

      }
      {organization.phones &&

          <label className={`${s.contactLabel} ${icons.iconPhone} icon-phone`}>Call

               {organization.phones.map((phone, index) => (
                <div key={`phone-${index}`}>
                  {phone.number}
                  {phone.department}

              ))}

      }
      {organization.url &&

          <label className={`${s.contactLabel} ${icons.iconLink} icon-website`}>Website

              {organization.url}

      }

          <button>
            <label className={`${s.directionsLabel} ${icons.iconCompass} icon-compass`}>Directions
          </button>

        {services && Object.values(services).map((service, index) => (
          <li key={`service-${index}`} className={s.insetServices}>

{service.name}

{service.description}

              <Schedule schedules={service.schedules} />

              Notes

{service.applicationProcess}

        ))}

  )
}

export default Location
<commit_msg>Only add days that are open to hours list<commit_after>import React, { PropTypes } from 'react'
import s from './Location.css'
import icons from '../../icons/css/icons.css'

import { relevantTaxonomies, getIcon } from '../../lib/taxonomies'
import { capitalize } from '../../lib/stringHelpers'

import Link from '../Link'
import GoogleMap from '../GoogleMap'

const getGender = (abbr) => {
  if (abbr === '' || abbr === 'MF' || abbr === 'FM') return 'Everyone'
  return abbr === 'F' ? 'Women' : 'Men'
}

const getGenderAdj = (abbr) => {
  if (abbr === '' || abbr === 'MF' || abbr === 'FM') {
    return 'All'
  }
  return abbr === 'F' ? 'Female' : 'Male'
}

const getAge = (abbr) => {
  switch (abbr) {
    case 'C':
      return 'children'
    case 'Y':
      return 'teens'
    case 'A':
      return 'adults'
    case 'S':
      return 'seniors'
    default:
      return ''
  }
}

const getAllGendersAndAges = (services) => {
  const allGendersAndAges = Object.values(services)
    .map(service => service.eligibility)
    .reduce((acc, eligibility) => {
      const { gender, age } = acc
      const moreGender = [...gender, eligibility.gender]
      const moreAge = eligibility.age ? [...age, ...eligibility.age] : age // ['C', 'Y']
      return { gender: moreGender, age: moreAge }
    }, { gender: [], age: [] })
  return {
    gender: Array.from(new Set(allGendersAndAges.gender)).join(''),
    age: Array.from(new Set(allGendersAndAges.age)),
  }
}

const getEligibility = ({ gender, age = [] }) => {
  if (gender === '' && age.length === 0) {
    return getGender(gender)
  }

  const ages = age.map(getAge).join(', ')

  return `${getGenderAdj(gender)} ${ages}`
}

const getMapsUrl = (location) => {
  const { latitude, longitude } = location
  return `https://maps.google.com/maps?q=loc:${latitude},${longitude}`
}

const DAYS = {
  0: 'sunday',
  1: 'monday',
  2: 'tuesday',
  3: 'wednesday',
  4: 'thursday',
  5: 'friday',
  6: 'saturday',
}

const DAY = {
  Sunday: 'sunday',
  Monday: 'monday',
  Tuesday: 'tuesday',
  Wednesday: 'wednesday',
  Thursday: 'thursday',
  Friday: 'friday',
  Saturday: 'saturday',
}

const DAY_ABBREVIATIONS = {
  sunday: 'Sun',
  monday: 'Mon',
  tuesday: 'Tue',
  wednesday: 'Wed',
  thursday: 'Thu',
  friday: 'Fri',
  saturday: 'Sat',
}

const convertMilitaryTime = (time) => {
  const hours = Math.floor(time / 100)
  const mins = time % 100
  let output = ''
  if (hours < 12) {
    if (hours == 0) {
      output += 12
    } else {
      output += hours
    }
    if (mins > 0) {
      output += `:${mins}`
    }
    output += 'am'
  } else {
    if (hours == 12) {
      output += hours
    } else {
      output += hours - 12
    }
    if (mins > 0) {
      output += `:${mins}`
    }
    output += 'pm'
  }
  return output
}

const getDailySchedules = (schedules) => {
  const daySchedules = Object.assign({}, DAY_ABBREVIATIONS)
  Object.keys(daySchedules).forEach(day => {
    daySchedules[day] = []
  })
  schedules
    .forEach(schedule => {
      if(schedule.opensAt != schedule.closesAt) { // Check if location is open
        const day = schedule.weekday.toLowerCase()
        const daySchedule = daySchedules[day]
        daySchedule.push({
          opensAt: schedule.opensAt,
          closesAt: schedule.closesAt,
        })
      }
    })
  return daySchedules
}

const getTimeRange = hours => (
  `${convertMilitaryTime(hours.opensAt)} - ${convertMilitaryTime(hours.closesAt)}`
)

const Schedule = (props) => {
  const daySchedules = getDailySchedules(props.schedules)
  const indexToDaySchedule = index => daySchedules[DAYS[index]]
  const dayHasSchedules = daySchedule => indexToDaySchedule(daySchedule).length > 0
  const scheduleRows = Object.keys(DAYS).sort()
    .filter(dayHasSchedules)
    .map(index => (
      <tr key={`day-${index}`}>

          {DAY_ABBREVIATIONS[DAYS[index]]}

          {indexToDaySchedule(index)
              .sort((a, b) => a.opensAt  {
  const { location, organization } = props
  const { services = [] } = location
  return (

{location.name}

        Welcome:
          {getEligibility(getAllGendersAndAges(services))}

Services

          {relevantTaxonomies(services).map((taxonomy, index) => (
            <span key={`category-${index}`}>
              <i className={`category-icon ${getIcon(taxonomy)}`}>
              {capitalize(taxonomy)}

          ))}

      {location.physicalAddress &&

            <GoogleMap lat={location.latitude} long={location.longitude} />

            {location.physicalAddress.address1}

      }
      {organization.phones &&

          <label className={`${s.contactLabel} ${icons.iconPhone} icon-phone`}>Call

               {organization.phones.map((phone, index) => (
                <div key={`phone-${index}`}>
                  {phone.number}
                  {phone.department}

              ))}

      }
      {organization.url &&

          <label className={`${s.contactLabel} ${icons.iconLink} icon-website`}>Website

              {organization.url}

      }

          <button>
            <label className={`${s.directionsLabel} ${icons.iconCompass} icon-compass`}>Directions
          </button>

        {services && Object.values(services).map((service, index) => (
          <li key={`service-${index}`} className={s.insetServices}>

{service.name}

{service.description}

              <Schedule schedules={service.schedules} />

              Notes

{service.applicationProcess}

        ))}

  )
}

export default Location
<|endoftext|>


<commit_before>var ghostdriver = ghostdriver || {};

ghostdriver.WebElementReqHand = function(id, session) {
    // private:
    var
    _id = id + '',      //< ensure this is always a string
    _session = session,
    _protoParent = ghostdriver.WebElementReqHand.prototype,
    _const = {
        VALUE               : "value"
    },

    _handle = function(req, res) {
        _protoParent.handle.call(this, req, res);

        // TODO lots to do...

        if (req.urlParsed.file === _const.VALUE && req.method === "POST") {
            _valueCommand(req, res);
            return;
        } // else ...

        // TODO lots to do...

        throw new ghostdriver.InvalidCommandMethod(req);
    },

    _valueCommand = function(req, res) {
        var i, ilen,
            postObj = JSON.parse(req.post);

        // Ensure all required parameters are available
        if (typeof(postObj) === "object" && typeof(postObj.value) === "object") {
            if (!_isAttachedToDOM())
                throw new ghostdriver.StaleElementReference(JSON.stringify(req));

            if (!_isVisible())
                throw new ghostdriver.ElementNotVisible(JSON.stringify(req));

            // For every String in the "value" array...
            for (i = 0, ilen = postObj.value.length; i < ilen; ++i) {
                _getSession().getPage().evaluateWithParams(function(elementId, valueToAppend) {
                    document.querySelector("#"+elementId).value += valueToAppend;
                }, _getId(), postObj.value[i]);
            }

            res.statusCode = 200;
            res.closeGracefully();
            return;
        }

        throw new ghostdriver.MissingCommandParameters(req);
    },

    _isAttachedToDOM = function() {
        return _getSession().getPage().evaluateWithParams(function(elementId) {
            if (document.querySelector("#"+elementId))
                return true;
            return false;
        }, _getId());
    },

    _isVisible = function() {
        if (!_isAttachedToDOM())
            return false;

        return _getSession().getPage().evaluateWithParams(function(elementId) {
            var el = document.querySelector("#"+elementId);
            if (el && el.style.visibility !== "hidden" && el.style.width >= 0 && el.style.height >= 0)
                return true;
            return false;
        }, _getId());
    },

    _getJSON = function() {
        return {
            "ELEMENT" : _getId()
        };
    },

    _getId = function() { return _id; },
    _getSession = function() { return _session; };

    // public:
    return {
        handle : _handle,
        getId : _getId,
        getJSON : _getJSON,
        getSession : _getSession,
        isAttachedToDOM : _isAttachedToDOM,
        isVisible : _isVisible
    };
};
// prototype inheritance:
ghostdriver.WebElementReqHand.prototype = new ghostdriver.RequestHandler();<commit_msg>Initial implementation of the "/session/:id/element/:id/submit" command.<commit_after>var ghostdriver = ghostdriver || {};

ghostdriver.WebElementReqHand = function(id, session) {
    // private:
    var
    _id = id + '',      //< ensure this is always a string
    _session = session,
    _protoParent = ghostdriver.WebElementReqHand.prototype,
    _const = {
        VALUE           : "value",
        SUBMIT          : "submit"
    },

    _handle = function(req, res) {
        _protoParent.handle.call(this, req, res);

        // TODO lots to do...

        if (req.urlParsed.file === _const.VALUE && req.method === "POST") {
            _valueCommand(req, res);
            return;
        } else if (req.urlParsed.file === _const.SUBMIT && req.method === "POST") {
            _submitCommand(req, res);
            return;
        } // else ...

        // TODO lots to do...

        throw new ghostdriver.InvalidCommandMethod(req);
    },

    _valueCommand = function(req, res) {
        var i, ilen,
            postObj = JSON.parse(req.post);

        // Ensure all required parameters are available
        if (typeof(postObj) === "object" && typeof(postObj.value) === "object") {
            if (!_isAttachedToDOM())
                throw new ghostdriver.StaleElementReference(JSON.stringify(req));

            if (!_isVisible())
                throw new ghostdriver.ElementNotVisible(JSON.stringify(req));

            // For every String in the "value" array...
            for (i = 0, ilen = postObj.value.length; i < ilen; ++i) {
                _getSession().getPage().evaluateWithParams(function(elementId, valueToAppend) {
                    document.querySelector("#"+elementId).value += valueToAppend;
                }, _getId(), postObj.value[i]);
            }

            res.statusCode = 200;
            res.closeGracefully();
            return;
        }

        throw new ghostdriver.MissingCommandParameters(req);
    },

    _submitCommand = function(req, res) {
        if (!_isAttachedToDOM())
            throw new ghostdriver.StaleElementReference(JSON.stringify(req));

        _getSession().getPage().onLoadFinished = function(status) {
            if (status === "success") {
                res.statusCode = 200;
                res.closeGracefully();
            }

            // TODO - what do we do if this fails?
        };

        // Submit element: either it's a form or an element in a form
        _getSession().getPage().evaluateWithParams(function(elementId) {
            var el = document.getElementById(elementId);
            if (el.tagName === "FORM") {
                el.submit();
            } else if (el.form) {
                el.form.submit();
            }
        }, _getId());
    },

    _isAttachedToDOM = function() {
        return _getSession().getPage().evaluateWithParams(function(elementId) {
            if (document.querySelector("#"+elementId))
                return true;
            return false;
        }, _getId());
    },

    _isVisible = function() {
        if (!_isAttachedToDOM())
            return false;

        return _getSession().getPage().evaluateWithParams(function(elementId) {
            var el = document.querySelector("#"+elementId);
            if (el && el.style.visibility !== "hidden" && el.style.width >= 0 && el.style.height >= 0)
                return true;
            return false;
        }, _getId());
    },

    _getJSON = function() {
        return {
            "ELEMENT" : _getId()
        };
    },

    _getId = function() { return _id; },
    _getSession = function() { return _session; };

    // public:
    return {
        handle : _handle,
        getId : _getId,
        getJSON : _getJSON,
        getSession : _getSession,
        isAttachedToDOM : _isAttachedToDOM,
        isVisible : _isVisible
    };
};
// prototype inheritance:
ghostdriver.WebElementReqHand.prototype = new ghostdriver.RequestHandler();<|endoftext|>


<commit_before>import React from 'react';
import SprkFooter from './SprkFooter';
import SprkLink from '../../base/links/SprkLink';
import { markdownDocumentationLinkBuilder } from '../../../../storybook-utilities/markdownDocumentationLinkBuilder';
import SprkFooterAwards from './components/SprkFooterAwards/SprkFooterAwards';
import SprkFooterConnectIcons from './components/SprkFooterConnectIcons/SprkFooterConnectIcons';
import SprkFooterGlobalSection from './components/SprkFooterGlobalSection/SprkFooterGlobalSection';

export default {
  title: 'Components/Footer',
  decorators: [(story) =>
{story()}
],
  component: SprkFooter,
  parameters: {
    subcomponents: {
      SprkFooterAwards,
      SprkFooterConnectIcons,
      SprkFooterGlobalSection,
    },
    jest: ['SprkFooter'],
    info: `
${markdownDocumentationLinkBuilder('footer')}
- The Footer is a navigation landmark for
accessibility tools. The attribute \`role=”contentinfo”\`
must be present.
    `,
  },
};

export const defaultStory = () => (
  <SprkFooter
    globalItems={{
      heading: 'Our Sister Companies',
      items: [
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-by-ql-white.svg',
          altText: 'Rocket Mortgage by Quicken Loans Logo',
          description:
            "Buy a home, refinance, or manage your mortgage online with America's largest mortgage lender",
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-loans-white.svg',
          altText: 'Rocket Loans Logo',
          description:
            'Get a personal loan to consolidate debt, renovate your home and more',
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-homes-white.svg',
          altText: 'Rocket Homes Logo',
          description:
            'Get a real estate agent handpicked for you and search the latest home listings',
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-hq-white.svg',
          altText: 'Rocket HQ Logo',
          description:
            'Access tools and articles that can help you reach your financial goals',
          element: 'a',
          mediaHref: '#nogo',
        },
      ],
    }}
    linkColumns={[
      {
        heading: 'Site Links',
        links: [
          {
            href: '#nogo',
            text: 'About This.',
            analyticsString: 'about-this-link',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About This Other Thing',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About That',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Link Item',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'This Link Item',
            element: 'a',
          },
        ],
      },
      {
        heading: 'Learn More',
        links: [
          {
            href: '#nogo',
            text: 'About This Other Thing',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About This',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About That',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Link Item',
            element: 'a',
          },
        ],
      },
      {
        heading: 'Support',
        links: [
          {
            href: '#nogo',
            text: 'Share Your Screen',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Opt Out',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Disclosures and Other Things',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'We Want Your Feedback',
            element: 'a',
          },
        ],
      },
    ]}
    connectIcons={{
      heading: 'Connect With Us',
      icons: [
        {
          href: '#nogo',
          name: 'facebook',
          screenReaderText: 'Facebook',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'instagram',
          screenReaderText: 'Instagram',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'twitter',
          screenReaderText: 'Twitter',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'youtube',
          screenReaderText: 'YouTube',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
      ],
    }}
    awards={{
      heading: 'Awards Heading Title',
      images: [
        {
          href: '#nogo',
          src: 'https://spark-assets.netlify.app/spark-logo-mark.svg',
          altText: 'Spark Logo',
          element: 'a',
        },
        {
          href: '#nogo',
          src: 'https://spark-assets.netlify.app/spark-logo-mark.svg',
          altText: 'Spark Logo',
          element: 'a',
        },
      ],
      disclaimerTitle: 'My Award Disclaimer',
      disclaimerAnalytics: 'test',
      disclaimerText:
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in laoreet ante, non feugiat neque. Suspendisse et ipsum leo. Quisque non consectetur justo.',
    }}
    additionalIcons={[
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
    ]}
    paragraphs={[
      {
        text:
          '*Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam',
      },
      {
        text:
          'Incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur.',
      },
      {
        text:
          '**Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.',
      },
      {
        text: 'Lorem ipsum dolor sit amet, consectetur.',
      },
    ]}
    additionalDisclaimer={

        Sed ut perspiciatis unde omnis iste natus error sit{' '}
        <SprkLink href="noGo" additionalClasses="sprk-b-Link--footer">
          inline link
        </SprkLink>{' '}
        accusantium doloremque laudantiu

    }
  />
);

defaultStory.story = {
  name: 'Default',
};
<commit_msg>Added # on nogo link<commit_after>import React from 'react';
import SprkFooter from './SprkFooter';
import SprkLink from '../../base/links/SprkLink';
import { markdownDocumentationLinkBuilder } from '../../../../storybook-utilities/markdownDocumentationLinkBuilder';
import SprkFooterAwards from './components/SprkFooterAwards/SprkFooterAwards';
import SprkFooterConnectIcons from './components/SprkFooterConnectIcons/SprkFooterConnectIcons';
import SprkFooterGlobalSection from './components/SprkFooterGlobalSection/SprkFooterGlobalSection';

export default {
  title: 'Components/Footer',
  decorators: [(story) =>
{story()}
],
  component: SprkFooter,
  parameters: {
    subcomponents: {
      SprkFooterAwards,
      SprkFooterConnectIcons,
      SprkFooterGlobalSection,
    },
    jest: ['SprkFooter'],
    info: `
${markdownDocumentationLinkBuilder('footer')}
- The Footer is a navigation landmark for
accessibility tools. The attribute \`role=”contentinfo”\`
must be present.
    `,
  },
};

export const defaultStory = () => (
  <SprkFooter
    globalItems={{
      heading: 'Our Sister Companies',
      items: [
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-by-ql-white.svg',
          altText: 'Rocket Mortgage by Quicken Loans Logo',
          description:
            "Buy a home, refinance, or manage your mortgage online with America's largest mortgage lender",
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-loans-white.svg',
          altText: 'Rocket Loans Logo',
          description:
            'Get a personal loan to consolidate debt, renovate your home and more',
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-homes-white.svg',
          altText: 'Rocket Homes Logo',
          description:
            'Get a real estate agent handpicked for you and search the latest home listings',
          element: 'a',
          mediaHref: '#nogo',
        },
        {
          mediaType: 'image',
          src: 'https://spark-assets.netlify.app/rocket-hq-white.svg',
          altText: 'Rocket HQ Logo',
          description:
            'Access tools and articles that can help you reach your financial goals',
          element: 'a',
          mediaHref: '#nogo',
        },
      ],
    }}
    linkColumns={[
      {
        heading: 'Site Links',
        links: [
          {
            href: '#nogo',
            text: 'About This.',
            analyticsString: 'about-this-link',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About This Other Thing',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About That',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Link Item',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'This Link Item',
            element: 'a',
          },
        ],
      },
      {
        heading: 'Learn More',
        links: [
          {
            href: '#nogo',
            text: 'About This Other Thing',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About This',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'About That',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Link Item',
            element: 'a',
          },
        ],
      },
      {
        heading: 'Support',
        links: [
          {
            href: '#nogo',
            text: 'Share Your Screen',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Opt Out',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'Disclosures and Other Things',
            element: 'a',
          },
          {
            href: '#nogo',
            text: 'We Want Your Feedback',
            element: 'a',
          },
        ],
      },
    ]}
    connectIcons={{
      heading: 'Connect With Us',
      icons: [
        {
          href: '#nogo',
          name: 'facebook',
          screenReaderText: 'Facebook',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'instagram',
          screenReaderText: 'Instagram',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'twitter',
          screenReaderText: 'Twitter',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
        {
          href: '#nogo',
          name: 'youtube',
          screenReaderText: 'YouTube',
          element: 'a',
          addClasses:
            'sprk-c-Icon--filled-current-color sprk-c-Icon--stroke-current-color',
        },
      ],
    }}
    awards={{
      heading: 'Awards Heading Title',
      images: [
        {
          href: '#nogo',
          src: 'https://spark-assets.netlify.app/spark-logo-mark.svg',
          altText: 'Spark Logo',
          element: 'a',
        },
        {
          href: '#nogo',
          src: 'https://spark-assets.netlify.app/spark-logo-mark.svg',
          altText: 'Spark Logo',
          element: 'a',
        },
      ],
      disclaimerTitle: 'My Award Disclaimer',
      disclaimerAnalytics: 'test',
      disclaimerText:
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in laoreet ante, non feugiat neque. Suspendisse et ipsum leo. Quisque non consectetur justo.',
    }}
    additionalIcons={[
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
      {
        name: 'home',
        href: '#nogo',
        screenReaderText: 'House',
        element: 'a',
      },
    ]}
    paragraphs={[
      {
        text:
          '*Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam',
      },
      {
        text:
          'Incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur.',
      },
      {
        text:
          '**Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.',
      },
      {
        text: 'Lorem ipsum dolor sit amet, consectetur.',
      },
    ]}
    additionalDisclaimer={

        Sed ut perspiciatis unde omnis iste natus error sit{' '}
        <SprkLink href="#noGo" additionalClasses="sprk-b-Link--footer">
          inline link
        </SprkLink>{' '}
        accusantium doloremque laudantiu

    }
  />
);

defaultStory.story = {
  name: 'Default',
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

'use strict';

var fs            = require("fs"),
    path          = require("path"),
    shelljs,
    optimist;

// Check that we can load dependencies
try {
    shelljs = require("shelljs");
    optimist = require("optimist");
} catch (e) {
    console.error('Missing module. Please run "npm install" from this directory:\n\t' +
                   path.dirname(__dirname));
    process.exit(2);
}

// Vars, folders and libraries. To ensure compatibility cross platform, absolute paths are used instead of relative paths.
var top_dir =             process.cwd() + path.sep,
    cli_local_bin =       path.join(top_dir, "cordova-cli", "bin", "cordova"),
    mobile_spec_git_dir = path.join(top_dir, "cordova-mobile-spec"),
    cordova_js_git_dir =  path.join(top_dir, "cordova-js"),
    cli_project_dir =     path.join(top_dir, "mobilespec"),
    platforms =           [],
    // where to find the /bin/create command and www dir in a non-CLI project
    platform_layout =     { "android":      { "bin": "cordova-android",
                                              "www": "assets" + path.sep + "www" },
                            "blackberry10": { "bin": "cordova-blackberry" + path.sep + "blackberry10",
                                              "www": "www" },
                            "ios":          { "bin": "cordova-ios",
                                              "www": "www" },
                            "windows8":     { "bin": "cordova-windows" + path.sep + "windows8",
                                              "www": "www" },
                            "wp8":          { "bin": "cordova-wp8" + path.sep + "wp8",
                                              "www": "www" } },
    platform_dirs =       {"android": "cordova-android",
                           "blackberry10": "cordova-blackberry" + path.sep + "blackberry10",
                           "ios": "cordova-ios",
                           "windows8": "cordova-windows" + path.sep + "windows8",
                           "wp8": "cordova-wp8" + path.sep + "wp8"},
    // where to put the cordova.js file in a non-CLI project
    platform_www_dirs =   {"android": "assets" + path.sep + "www",
                          "blackberry10": "www",
                          "ios": "www",
                          "windows8": "www",
                          "wp8": "www"},
    argv = optimist.usage("\nUsage: $0 [--android] [--blackberry10] [--ios] [--windows8] [--wp8] [-h|--help] [--plugman] [--global] [--skipjs]\n" +
                          "A project will be created with the mobile-spec app and all the core plugins.\n" +
                          "At least one platform must be specified. See the included README.md.")
                   .describe("help", "Shows usage.")
                   .describe("android", "Add Android platform when creating the mobile-spec project.")
                   .describe("blackberry10", "Add Blackberry 10 platform when creating the mobile-spec project.")
                   .describe("ios", "Add iOS platform when creating the mobile-spec project.")
                   .describe("windows8", "Add Windows 8 (desktop) platform when creating the mobile-spec project.")
                   .describe("wp8", "Add Windows Phone 8 when creating the mobile-spec project.")
                   .describe("plugman", "Use /bin/create and plugman directly instead of the CLI.")
                   .describe("global", "Use the globally-installed cordova and the downloaded platforms/plugins from the registry instead of the local git repo. Will use the local git repo of mobile-spec. Generally used only to test RC or production releases. Cannot be used with --plugman.")
                   .describe("skipjs", "Do not update the platform's cordova.js from the js git repo, use the one already present in the platform. Rarely used, generally to test RC releases. Cannot be used with --global because it is implied when --global is used.")
                   .boolean("plugman")
                   .boolean("global")
                   .boolean("skipjs")
                   .alias("h", "help")
                   .argv;

if (!fs.existsSync(mobile_spec_git_dir)) {
    console.log("Please run this script from the directory that contains cordova-mobile-spec");
    shelljs.exit(1);
}

// technically not needed for --global, but we're developers.
if (!fs.existsSync(cordova_js_git_dir)) {
    console.log("Please run this script from the directory that contains cordova-js");
    shelljs.exit(1);
}

if (argv.help) { optimist.showHelp(); return; }
if (argv.android) { platforms.push("android"); }
if (argv.ios) { platforms.push("ios"); }
if (argv.blackberry10) { platforms.push("blackberry10"); }
if (argv.wp8) { platforms.push("wp8"); }
if (argv.windows8) { platforms.push("windows8"); }
if (argv.plugman && argv.global) {
    console.log("The --global option can not be used with the --plugman option.");
    optimist.showHelp();
    return;
}
if (argv.skipjs && argv.global) {
    console.log("The --skipjs option can not be used with the --global option.");
    optimist.showHelp();
    return;
}

// If no platforms, then stop and show help
if (platforms.length === 0){
    console.log("\nNo platforms were selected. Please choose at least one of the supported platforms.");
    optimist.showHelp();
    process.exit(2);
}

// select between the globally-installed one on your path or your local git repo
var cli = argv.global ? "cordova" : cli_local_bin;

// Print relevant information
if (argv.global) {
    console.log("Creating project. Using globally installed cordova and plugman, downloadable platforms and plugins, and local mobile-spec.");
    console.log("To clone needed repositories:");
    console.log("  ./cordova-coho/coho repo-clone -r mobile-spec");
    console.log("To update all repositories:");
    console.log("  ./cordova-coho/coho repo-update -r mobile-spec");
} else {
    console.log("Creating project. If you have any errors, it may be from missing repositories.");
    console.log("To clone needed repositories (android as an example):");
    console.log("  ./cordova-coho/coho repo-clone -r plugins -r mobile-spec -r android -r cli");
    console.log("To update all repositories:");
    console.log("  ./cordova-coho/coho repo-update");
}

// Setting up config.fatal as true, if something goes wrong the program will terminate
shelljs.config.fatal = true;

////////////////////// preparations before project creation

if (argv.global) {
    // clean out cached platforms and plugins and app-hello-world
    var home_dir = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
    shelljs.rm("-rf", path.join(home_dir, ".cordova"));
    shelljs.rm("-rf", path.join(home_dir, ".plugman"));
}

////////////////////// create the project for each platform

function myDelete(myDir) {
    // Custom function to delete project folder, in case a process has it locked on Windows
    try {
        shelljs.rm("-rf", myDir);
    } catch (e) {
        // The project directory after an Android build and emulation is locked by ADB.EXE (Android Debug Bridge).
        // Kill the process & restart folder deletion
        if (/^win/.test(process.platform)) {
            console.log("Not all files were deleted, killing ADB.EXE process to unlock folder...");
            shelljs.exec("TASKKILL /F /IM ADB.exe /T");
            shelljs.rm("-rf", myDir);
        } else
            throw new Error("Error during folder deletion, try to remove " + myDir + " manually.");
    }
}

function getProjName(platform) {
    return "mobilespec-" + platform;
}

if (argv.plugman) {
    // run the /bin/create script
    platforms.forEach(function (platform) {
        var projName = getProjName(platform);
        myDelete(projName);
        console.log("Creating project " + projName + "...");
        shelljs.exec(platform_layout[platform].bin + path.sep + "bin" + path.sep + "create " + projName + " org.apache.cordova.mobilespecplugman " + projName);
        shelljs.rm("-r", path.join(top_dir, projName, platform_layout[platform].www));
        shelljs.cp("-r", path.join(mobile_spec_git_dir, "*"), path.join(top_dir, projName, platform_layout[platform].www));
    });
} else {
    // Create the project using "cordova create"
    myDelete(cli_project_dir);
    console.log("Creating project mobilespec...");
    shelljs.exec(cli + " create mobilespec org.apache.cordova.mobilespec MobileSpec_Tests --link-to cordova-mobile-spec");

    // Config.json file ---> linked to local libraries
    shelljs.pushd(cli_project_dir);
    var localPlatforms = {
        "android" : top_dir + "cordova-android" ,
        "ios" : top_dir + "cordova-ios" ,
        "blackberry10" : top_dir + "cordova-blackberry" ,
        "wp8" : top_dir + "cordova-wp8" ,
        "windows8" : top_dir + "cordova-windows"
    };

    // Executing platform Add
    console.log("Adding platforms...");
    platforms.forEach(function (platform) {
        console.log("Adding Platform: " + platform);
        var platformArg = argv.global ? platform : localPlatforms[platform];
        shelljs.exec(cli + ' platform add "' + platformArg + '" --verbose');
    });
    shelljs.popd();
}

////////////////////// install plugins for each platform

if (argv.plugman) {
    console.log("Adding plugins using plugman...");
    platforms.forEach(function (platform) {
        var projName = getProjName(platform),
            nodeCommand = /^win/.test(process.platform) ? process.argv[0] +" " : "";
        shelljs.pushd(projName);
        // plugin path must be relative and not absolute (sigh)
        shelljs.exec(nodeCommand + path.join(top_dir, "cordova-plugman", "main.js") +
                     " install --platform " + platform +
                     " --project . --plugin " + path.join("..", "cordova-mobile-spec", "dependencies-plugin") +
                     " --searchpath " + top_dir);
        shelljs.popd();
    });
} else {
    // don't use local git repos for plugins when using --global
    var searchpath = argv.global ? "" : " --searchpath " + top_dir;
    shelljs.pushd(cli_project_dir);
    console.log("Adding plugins using CLI...");
    shelljs.exec(cli + " plugin add " + path.join(mobile_spec_git_dir, "dependencies-plugin") +
                 searchpath);
    shelljs.popd();
}

////////////////////// update js files for each platform from cordova-js

if (argv.skipjs) {
    console.log("Skipping the js update.");
} else if (!argv.global) {
    console.log("Updating js for platforms...");

    shelljs.pushd(cordova_js_git_dir);
    var code = shelljs.exec("grunt").code;
    if (code) {
        console.log("Failed to build js.");
        process.exit(1);
    }
    shelljs.popd();

    platforms.forEach(function (platform) {
        var src = path.join(cordova_js_git_dir, "pkg", "cordova." + (platform === "wp8" ? "windowsphone" : platform) + ".js");
        var dest = argv.plugman ? path.join(top_dir, getProjName(platform), platform_layout[platform].www, "cordova.js") :
                                  path.join(cli_project_dir, "platforms", platform, "platform_www", "cordova.js");
        shelljs.cp("-f", src, dest);
        console.log("Javascript file updated for " + platform);
    });
}

////////////////////// wrap-up

if (argv.plugman) {
    platforms.forEach(function (platform) {
        var projName = getProjName(platform);
        console.log("Done. " + platform + " project created at " + path.join(top_dir, projName));
    });
} else {
    shelljs.pushd(cli_project_dir);

    // Executing cordova prepare
    console.log("Preparing project...");
    shelljs.exec(cli + " prepare");

    if (!argv.global) {
        console.log("Linking CLI...");
        // Writing link files to use Local CLI
        if (/^win/.test(process.platform)) {
            var winBatchFile = "node  " + cli_local_bin + " %*";
            fs.writeFileSync(path.join(cli_project_dir, "cordova.bat"), winBatchFile);
        } else {
            fs.symlinkSync(cli_local_bin, path.join(cli_project_dir, "cordova"));
        }
        console.log("Symlink to CLI created as " + cli_project_dir + path.sep + "cordova");
    }

    shelljs.popd();

    console.log("Done. Project created at " + cli_project_dir);
}

<commit_msg>Add option to specify output directory for createmobilespec.js<commit_after>#!/usr/bin/env node

/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

'use strict';

var fs            = require("fs"),
    path          = require("path"),
    shelljs,
    optimist;

// Check that we can load dependencies
try {
    shelljs = require("shelljs");
    optimist = require("optimist");
} catch (e) {
    console.error('Missing module. Please run "npm install" from this directory:\n\t' +
                   path.dirname(__dirname));
    process.exit(2);
}

// Vars, folders and libraries. To ensure compatibility cross platform, absolute paths are used instead of relative paths.
var top_dir =             process.cwd() + path.sep,
    cli_local_bin =       path.join(top_dir, "cordova-cli", "bin", "cordova"),
    mobile_spec_git_dir = path.join(top_dir, "cordova-mobile-spec"),
    cordova_js_git_dir =  path.join(top_dir, "cordova-js"),
    platforms =           [],
    // where to find the /bin/create command and www dir in a non-CLI project
    platform_layout =     { "android":      { "bin": "cordova-android",
                                              "www": "assets" + path.sep + "www" },
                            "blackberry10": { "bin": "cordova-blackberry" + path.sep + "blackberry10",
                                              "www": "www" },
                            "ios":          { "bin": "cordova-ios",
                                              "www": "www" },
                            "windows8":     { "bin": "cordova-windows" + path.sep + "windows8",
                                              "www": "www" },
                            "wp8":          { "bin": "cordova-wp8" + path.sep + "wp8",
                                              "www": "www" } },
    platform_dirs =       {"android": "cordova-android",
                           "blackberry10": "cordova-blackberry" + path.sep + "blackberry10",
                           "ios": "cordova-ios",
                           "windows8": "cordova-windows" + path.sep + "windows8",
                           "wp8": "cordova-wp8" + path.sep + "wp8"},
    // where to put the cordova.js file in a non-CLI project
    platform_www_dirs =   {"android": "assets" + path.sep + "www",
                          "blackberry10": "www",
                          "ios": "www",
                          "windows8": "www",
                          "wp8": "www"},
    argv = optimist.usage("\nUsage: $0 [--android] [--blackberry10] [--ios] [--windows8] [--wp8] [-h|--help] [--plugman] [--global] [--skipjs] [directoryName]\n" +
                          "A project will be created with the mobile-spec app and all the core plugins.\n" +
                          "At least one platform must be specified. See the included README.md.")
                   .boolean("help").describe("help", "Shows usage.")
                   .boolean("android").describe("android", "Add Android platform when creating the mobile-spec project.")
                   .boolean("blackberry10").describe("blackberry10", "Add Blackberry 10 platform when creating the mobile-spec project.")
                   .boolean("ios").describe("ios", "Add iOS platform when creating the mobile-spec project.")
                   .boolean("windows8").describe("windows8", "Add Windows 8 (desktop) platform when creating the mobile-spec project.")
                   .boolean("wp8").describe("wp8", "Add Windows Phone 8 when creating the mobile-spec project.")
                   .boolean("plugman").describe("plugman", "Use /bin/create and plugman directly instead of the CLI.")
                   .boolean("global").describe("global", "Use the globally-installed cordova and the downloaded platforms/plugins from the registry instead of the local git repo. Will use the local git repo of mobile-spec. Generally used only to test RC or production releases. Cannot be used with --plugman.")
                   .boolean("skipjs").describe("skipjs", "Do not update the platform's cordova.js from the js git repo, use the one already present in the platform. Rarely used, generally to test RC releases. Cannot be used with --global because it is implied when --global is used.")
                   .alias("h", "help")
                   .argv;

if (!fs.existsSync(mobile_spec_git_dir)) {
    console.log("Please run this script from the directory that contains cordova-mobile-spec");
    shelljs.exit(1);
}

// technically not needed for --global, but we're developers.
if (!fs.existsSync(cordova_js_git_dir)) {
    console.log("Please run this script from the directory that contains cordova-js");
    shelljs.exit(1);
}

if (argv.help) { optimist.showHelp(); return; }
if (argv.android) { platforms.push("android"); }
if (argv.ios) { platforms.push("ios"); }
if (argv.blackberry10) { platforms.push("blackberry10"); }
if (argv.wp8) { platforms.push("wp8"); }
if (argv.windows8) { platforms.push("windows8"); }
if (argv.plugman && argv.global) {
    console.log("The --global option can not be used with the --plugman option.");
    optimist.showHelp();
    return;
}
if (argv.skipjs && argv.global) {
    console.log("The --skipjs option can not be used with the --global option.");
    optimist.showHelp();
    return;
}

// If no platforms, then stop and show help
if (platforms.length === 0){
    console.log("\nNo platforms were selected. Please choose at least one of the supported platforms.");
    optimist.showHelp();
    process.exit(2);
}

// select between the globally-installed one on your path or your local git repo
var cli = argv.global ? "cordova" : cli_local_bin;

var projectDirName = argv._[0] || "mobilespec";
var cli_project_dir = path.join(top_dir, projectDirName);

// Print relevant information
if (argv.global) {
    console.log("Creating project. Using globally installed cordova and plugman, downloadable platforms and plugins, and local mobile-spec.");
    console.log("To clone needed repositories:");
    console.log("  ./cordova-coho/coho repo-clone -r mobile-spec");
    console.log("To update all repositories:");
    console.log("  ./cordova-coho/coho repo-update -r mobile-spec");
} else {
    console.log("Creating project. If you have any errors, it may be from missing repositories.");
    console.log("To clone needed repositories (android as an example):");
    console.log("  ./cordova-coho/coho repo-clone -r plugins -r mobile-spec -r android -r cli");
    console.log("To update all repositories:");
    console.log("  ./cordova-coho/coho repo-update");
}

// Setting up config.fatal as true, if something goes wrong the program will terminate
shelljs.config.fatal = true;

////////////////////// preparations before project creation

if (argv.global) {
    // clean out cached platforms and plugins and app-hello-world
    var home_dir = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
    shelljs.rm("-rf", path.join(home_dir, ".cordova"));
    shelljs.rm("-rf", path.join(home_dir, ".plugman"));
}

////////////////////// create the project for each platform

function myDelete(myDir) {
    // Custom function to delete project folder, in case a process has it locked on Windows
    try {
        shelljs.rm("-rf", myDir);
    } catch (e) {
        // The project directory after an Android build and emulation is locked by ADB.EXE (Android Debug Bridge).
        // Kill the process & restart folder deletion
        if (/^win/.test(process.platform)) {
            console.log("Not all files were deleted, killing ADB.EXE process to unlock folder...");
            shelljs.exec("TASKKILL /F /IM ADB.exe /T");
            shelljs.rm("-rf", myDir);
        } else
            throw new Error("Error during folder deletion, try to remove " + myDir + " manually.");
    }
}

function getProjName(platform) {
    return "mobilespec-" + platform;
}

if (argv.plugman) {
    // run the /bin/create script
    platforms.forEach(function (platform) {
        var projName = getProjName(platform);
        myDelete(projName);
        console.log("Creating project " + projName + "...");
        shelljs.exec(platform_layout[platform].bin + path.sep + "bin" + path.sep + "create " + projName + " org.apache.cordova.mobilespecplugman " + projName);
        shelljs.rm("-r", path.join(top_dir, projName, platform_layout[platform].www));
        shelljs.cp("-r", path.join(mobile_spec_git_dir, "*"), path.join(top_dir, projName, platform_layout[platform].www));
    });
} else {
    // Create the project using "cordova create"
    myDelete(cli_project_dir);
    console.log("Creating project mobilespec...");
    shelljs.exec(cli + " create " + projectDirName + " org.apache.cordova.mobilespec MobileSpec_Tests --link-to cordova-mobile-spec");

    // Config.json file ---> linked to local libraries
    shelljs.pushd(cli_project_dir);
    var localPlatforms = {
        "android" : top_dir + "cordova-android" ,
        "ios" : top_dir + "cordova-ios" ,
        "blackberry10" : top_dir + "cordova-blackberry" ,
        "wp8" : top_dir + "cordova-wp8" ,
        "windows8" : top_dir + "cordova-windows"
    };

    // Executing platform Add
    console.log("Adding platforms...");
    platforms.forEach(function (platform) {
        console.log("Adding Platform: " + platform);
        var platformArg = argv.global ? platform : localPlatforms[platform];
        shelljs.exec(cli + ' platform add "' + platformArg + '" --verbose');
    });
    shelljs.popd();
}

////////////////////// install plugins for each platform

if (argv.plugman) {
    console.log("Adding plugins using plugman...");
    platforms.forEach(function (platform) {
        var projName = getProjName(platform),
            nodeCommand = /^win/.test(process.platform) ? process.argv[0] +" " : "";
        shelljs.pushd(projName);
        // plugin path must be relative and not absolute (sigh)
        shelljs.exec(nodeCommand + path.join(top_dir, "cordova-plugman", "main.js") +
                     " install --platform " + platform +
                     " --project . --plugin " + path.join("..", "cordova-mobile-spec", "dependencies-plugin") +
                     " --searchpath " + top_dir);
        shelljs.popd();
    });
} else {
    // don't use local git repos for plugins when using --global
    var searchpath = argv.global ? "" : " --searchpath " + top_dir;
    shelljs.pushd(cli_project_dir);
    console.log("Adding plugins using CLI...");
    shelljs.exec(cli + " plugin add " + path.join(mobile_spec_git_dir, "dependencies-plugin") +
                 searchpath);
    shelljs.popd();
}

////////////////////// update js files for each platform from cordova-js

if (argv.skipjs) {
    console.log("Skipping the js update.");
} else if (!argv.global) {
    console.log("Updating js for platforms...");

    shelljs.pushd(cordova_js_git_dir);
    var code = shelljs.exec("grunt").code;
    if (code) {
        console.log("Failed to build js.");
        process.exit(1);
    }
    shelljs.popd();

    platforms.forEach(function (platform) {
        var src = path.join(cordova_js_git_dir, "pkg", "cordova." + (platform === "wp8" ? "windowsphone" : platform) + ".js");
        var dest = argv.plugman ? path.join(top_dir, getProjName(platform), platform_layout[platform].www, "cordova.js") :
                                  path.join(cli_project_dir, "platforms", platform, "platform_www", "cordova.js");
        shelljs.cp("-f", src, dest);
        console.log("Javascript file updated for " + platform);
    });
}

////////////////////// wrap-up

if (argv.plugman) {
    platforms.forEach(function (platform) {
        var projName = getProjName(platform);
        console.log("Done. " + platform + " project created at " + path.join(top_dir, projName));
    });
} else {
    shelljs.pushd(cli_project_dir);

    // Executing cordova prepare
    console.log("Preparing project...");
    shelljs.exec(cli + " prepare");

    if (!argv.global) {
        console.log("Linking CLI...");
        // Writing link files to use Local CLI
        if (/^win/.test(process.platform)) {
            var winBatchFile = "node  " + cli_local_bin + " %*";
            fs.writeFileSync(path.join(cli_project_dir, "cordova.bat"), winBatchFile);
        } else {
            fs.symlinkSync(cli_local_bin, path.join(cli_project_dir, "cordova"));
        }
        console.log("Symlink to CLI created as " + cli_project_dir + path.sep + "cordova");
    }

    shelljs.popd();

    console.log("Done. Project created at " + cli_project_dir);
}

<|endoftext|>


<commit_before>(function(){

	var wm = util.isObject("Widget.Multimedia") ? Widget.Multimedia : {};
	var wmv = util.isObject("Widget.Multimedia.VideoPlayer") ? Widget.Multimedia.VideoPlayer : {};
	var cf = config.fileSystem;
	var videoFiles = cf.playableVideoFiles;

	// This is a mini object, to wrap video functionality and make it better useable inside the
	// tests.
	// It basically implements the Finite state machine that the spec shows on page 122, and maps
	// all state changes to the proper method call.
	// The constructor has the following signature:
	// 		new myVideo = ("url to the video file", {
	// 			autoPlay: true|false,
	// 			repeatTimes: 0..x
	// 			onOpen:function(){},
	// 			onPlay:function(){},
	// 			onStop:function(){},
	// 			onPause:function(){},
	// 			onComplete:function(){}
	// 		})
	// All options are optional.
	var myVideo = function(url, options){
		this.state = null;
		this._quit = false;
		var timeouts = []; // Store timeouts for this class in here, so we can clean up properly when cleanUp() is called.
		this.cleanUp = function(){
			wmv.stop();
			wmv.setWindow(null); // Make sure to reset the window its playing in.
			wmv.onStateChange = null;
			// Clean timeouts if there are any.
			for (var i=0, l=timeouts.length; i<l; i++){
				clearTimeout(timeouts[i]);
			}
		}
		wmv.onStateChange = doh.util.hitch(this, function(newState){
//document.getElementById("dbg").innerHTML += "
"+this.state +" => "+ newState;
			var fsm = [
				// oldState, newState, function to call
				[null, "opened", "onOpen"],
				["opened", "opened", "onOpen"],
				["opened", "stopped", "onStop"],
				["opened", "playing", "onPlay"],
				["stopped", "playing", "onPlay"],
				["playing", "stopped", "onStop"],
				["playing", "paused", "onPause"],
				["playing", "completed", "onComplete"],
				["completed", "playing", "onPlay"],
				["completed", "opened", "onOpen"],
				["paused", "playing", "onPlay"],
				["paused", "stopped", "onStop"],
				["stopped", "playing", "onPlay"],
				["stopped", "opened", "onOpen"]
			];
			// Set this.state before calling the method in t[2] that one maybe relies on the new state value.
			// Since we are not calling it asynchronously.
			var oldState = this.state;
			this.state = newState;
			for (var i=0, l=fsm.length, t; i<l; i++){
				t = fsm[i];
				if (t[0]==oldState && t[1]==newState){
					if (options[t[2]]) options[t[2]]();
					break;
				}
			}
		});
		if (options.autoPlay){
			if (!options.onOpen){
				options.onOpen = function(){
					wmv.play(options.repeatTimes ? options.repeatTimes+1 : 1);
				}
			} else {
				var b4 = options.onOpen;
				options.onOpen = function(){
					wmv.play(options.repeatTimes ? options.repeatTimes+1 : 1);
					b4();
				}
			}
		}
		// Add "stopAfter", which has to be added to onPlay and be triggered by a timeout.
		if (options.stopAfter){
			var onPlay = options.onPlay || function(){};
			options.onPlay = function(){
				onPlay();
				timeouts.push(setTimeout(function(){
					wmv.stop();
				}, options.stopAfter));
			}
		}
		wmv.open(url);
	};

	function _setUp(){
		dohx.showInfo('<object id="_videoWindow_" type="video/3gp" width="240" height="320" />');
		wmv.setWindow(util.byId("_videoWindow_"));
	};
	function _tearDown(){
		wmv.setWindow(null);
		videoObj.cleanUp();
	};

	var videoObj;

	dohx.add({name:"VideoPlayer",
		mqcExecutionOrderBaseOffset:250000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
		requiredObjects:[
			"Widget.Multimedia.VideoPlayer.open",
			"Widget.Multimedia.VideoPlayer.play",
			"Widget.Multimedia.VideoPlayer.stop"
		],
		tests:[
			//
			//	Protocols. Spec says: http, https, file, rtsp and widget context (=none of the listed prefixes) are supported.
			//

// TODO isVideoPlaying

/*			{
				id:100,
				name:"Protocol - http",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaHttp, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
			{
				id:200,
				name:"Protocol - https",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaHttps, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
			{
				id:300,
				name:"Protocol - rtsp",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaRtsp, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
*/
			//{
			//	id:400,
			//	name:"Protocol - 3GP file",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.threeGp.onDevice, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:410,
			//	name:"Protocol - H.264 file",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.h264.onDevice, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:500,
			//	name:"Protocol - 3GP widget context",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.threeGp.inWidget, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:510,
			//	name:"Protocol - H.264 widget context",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.h264.inWidget, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//
			//	play()
			//
			{
				id:600,
				name:"play 2x loop",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video twice?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						stopAfter:10*1000,
						repeatTimes:2
					});
				},
				tearDown:_tearDown
			},
			{
				id:700,
				name:"play 5x loop",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video five times?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						stopAfter:10*1000,
						repeatTimes:2
					});
				},
				tearDown:_tearDown
			},
			{
				id:800,
				name:"play, pause and play again",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did the video play, pause and play again?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						onPlay:function(){
							setTimeout(function(){
								wmv.pause();
								setTimeout(function(){
									wmv.resume();
								}, 2000);
							}, 2000);
						}
					});
				},
				tearDown:_tearDown
			},

			//
			//	setWindow()
			//
		]
	});

	// Start at ID offset 3000, just to have some place before.
	var _videoFiles = [
		{id:3000, "type":"avc", location:"inWidget"},
		{id:3010, "type":"avc", location:"onDevice"},
		{id:3020, "type":"h263", location:"inWidget"},
		{id:3030, "type":"h263", location:"onDevice"},
		{id:3040, "type":"h264", location:"inWidget"},
		{id:3050, "type":"h264", location:"onDevice"},
		{id:3060, "type":"mp4", location:"inWidget"},
		{id:3070, "type":"mp4", location:"onDevice"}
	];
	for (var i=0, l=_videoFiles.length; i<l; i++){
		(function(videoFileInfo){
			var filename = videoFiles[videoFileInfo.type][videoFileInfo.location];
			dohx.add({name:"VideoPlayer",
				mqcExecutionOrderBaseOffset:250000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
				requiredObjects:[
					"Widget.Multimedia.VideoPlayer.open",
					"Widget.Multimedia.VideoPlayer.play",
					"Widget.Multimedia.VideoPlayer.stop"
				],
				tests:[
					{
						id:videoFileInfo.id,
						name:"Protocol - Test codec '"+ videoFileInfo.type +"' from '" + filename + "'",
						instructions:"Click 'GO' to play video.",
						expectedResult:"Did you see the video?",
						setUp:_setUp,
						test:function(t){
							videoObj = new myVideo(filename, {
								autoPlay:true,
								stopAfter:10*1000
							});
						},
						tearDown:_tearDown
					}
				]
			});
		})(_videoFiles[i]);
	};

})();
<commit_msg>Use the proper files.<commit_after>(function(){

	var wm = util.isObject("Widget.Multimedia") ? Widget.Multimedia : {};
	var wmv = util.isObject("Widget.Multimedia.VideoPlayer") ? Widget.Multimedia.VideoPlayer : {};
	var cf = config.fileSystem;
	var videoFiles = cf.playableVideoFiles;

	// This is a mini object, to wrap video functionality and make it better useable inside the
	// tests.
	// It basically implements the Finite state machine that the spec shows on page 122, and maps
	// all state changes to the proper method call.
	// The constructor has the following signature:
	// 		new myVideo = ("url to the video file", {
	// 			autoPlay: true|false,
	// 			repeatTimes: 0..x
	// 			onOpen:function(){},
	// 			onPlay:function(){},
	// 			onStop:function(){},
	// 			onPause:function(){},
	// 			onComplete:function(){}
	// 		})
	// All options are optional.
	var myVideo = function(url, options){
		this.state = null;
		this._quit = false;
		var timeouts = []; // Store timeouts for this class in here, so we can clean up properly when cleanUp() is called.
		this.cleanUp = function(){
			wmv.stop();
			wmv.setWindow(null); // Make sure to reset the window its playing in.
			wmv.onStateChange = null;
			// Clean timeouts if there are any.
			for (var i=0, l=timeouts.length; i<l; i++){
				clearTimeout(timeouts[i]);
			}
		}
		wmv.onStateChange = doh.util.hitch(this, function(newState){
//document.getElementById("dbg").innerHTML += "
"+this.state +" => "+ newState;
			var fsm = [
				// oldState, newState, function to call
				[null, "opened", "onOpen"],
				["opened", "opened", "onOpen"],
				["opened", "stopped", "onStop"],
				["opened", "playing", "onPlay"],
				["stopped", "playing", "onPlay"],
				["playing", "stopped", "onStop"],
				["playing", "paused", "onPause"],
				["playing", "completed", "onComplete"],
				["completed", "playing", "onPlay"],
				["completed", "opened", "onOpen"],
				["paused", "playing", "onPlay"],
				["paused", "stopped", "onStop"],
				["stopped", "playing", "onPlay"],
				["stopped", "opened", "onOpen"]
			];
			// Set this.state before calling the method in t[2] that one maybe relies on the new state value.
			// Since we are not calling it asynchronously.
			var oldState = this.state;
			this.state = newState;
			for (var i=0, l=fsm.length, t; i<l; i++){
				t = fsm[i];
				if (t[0]==oldState && t[1]==newState){
					if (options[t[2]]) options[t[2]]();
					break;
				}
			}
		});
		if (options.autoPlay){
			if (!options.onOpen){
				options.onOpen = function(){
					wmv.play(options.repeatTimes ? options.repeatTimes+1 : 1);
				}
			} else {
				var b4 = options.onOpen;
				options.onOpen = function(){
					wmv.play(options.repeatTimes ? options.repeatTimes+1 : 1);
					b4();
				}
			}
		}
		// Add "stopAfter", which has to be added to onPlay and be triggered by a timeout.
		if (options.stopAfter){
			var onPlay = options.onPlay || function(){};
			options.onPlay = function(){
				onPlay();
				timeouts.push(setTimeout(function(){
					wmv.stop();
				}, options.stopAfter));
			}
		}
		wmv.open(url);
	};

	function _setUp(){
		dohx.showInfo('<object id="_videoWindow_" type="video/3gp" width="240" height="320" />');
		wmv.setWindow(util.byId("_videoWindow_"));
	};
	function _tearDown(){
		wmv.setWindow(null);
		videoObj.cleanUp();
	};

	var videoObj;

	dohx.add({name:"VideoPlayer",
		mqcExecutionOrderBaseOffset:250000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
		requiredObjects:[
			"Widget.Multimedia.VideoPlayer.open",
			"Widget.Multimedia.VideoPlayer.play",
			"Widget.Multimedia.VideoPlayer.stop"
		],
		tests:[
			//
			//	Protocols. Spec says: http, https, file, rtsp and widget context (=none of the listed prefixes) are supported.
			//

// TODO isVideoPlaying

/*			{
				id:100,
				name:"Protocol - http",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaHttp, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
			{
				id:200,
				name:"Protocol - https",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaHttps, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
			{
				id:300,
				name:"Protocol - rtsp",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video?",
				test:function(t){
					videoObj = new myVideo(videoFiles.viaRtsp, {
						autoPlay:true,
						stopAfter:10*1000
					});
				},
				tearDown:function(){
					videoObj.cleanUp();
				}
			},
*/
			//{
			//	id:400,
			//	name:"Protocol - 3GP file",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.threeGp.onDevice, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:410,
			//	name:"Protocol - H.264 file",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.h264.onDevice, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:500,
			//	name:"Protocol - 3GP widget context",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.threeGp.inWidget, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//{
			//	id:510,
			//	name:"Protocol - H.264 widget context",
			//	instructions:"Click 'GO' to play video.",
			//	expectedResult:"Did you see the video?",
			//	setUp:_setUp,
			//	test:function(t){
			//		videoObj = new myVideo(videoFiles.h264.inWidget, {
			//			autoPlay:true,
			//			stopAfter:10*1000
			//		});
			//	},
			//	tearDown:_tearDown
			//},
			//
			//	play()
			//
			{
				id:600,
				name:"play 2x loop",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video twice?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						stopAfter:10*1000,
						repeatTimes:2
					});
				},
				tearDown:_tearDown
			},
			{
				id:700,
				name:"play 5x loop",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did you see the video five times?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						stopAfter:10*1000,
						repeatTimes:2
					});
				},
				tearDown:_tearDown
			},
			{
				id:800,
				name:"play, pause and play again",
				instructions:"Click 'GO' to play video.",
				expectedResult:"Did the video play, pause and play again?",
				setUp:_setUp,
				test:function(t){
					videoObj = new myVideo(videoFiles.mp4.inWidget, {
						autoPlay:true,
						onPlay:function(){
							setTimeout(function(){
								wmv.pause();
								setTimeout(function(){
									wmv.resume();
								}, 2000);
							}, 2000);
						}
					});
				},
				tearDown:_tearDown
			},

			//
			//	setWindow()
			//
		]
	});

	// Start at ID offset 3000, just to have some place before.
	var _videoFiles = [
		{id:3020, "type":"h263", location:"inWidget"},
		{id:3030, "type":"h263", location:"onDevice"},
		{id:3040, "type":"h264", location:"inWidget"},
		{id:3050, "type":"h264", location:"onDevice"},
		{id:3060, "type":"mp4", location:"inWidget"},
		{id:3070, "type":"mp4", location:"onDevice"},
		{id:3080, "type":"h264", location:"inWidget1"},
		{id:3090, "type":"h264", location:"onDevice1"},
	];
	for (var i=0, l=_videoFiles.length; i<l; i++){
		(function(videoFileInfo){
			var filename = videoFiles[videoFileInfo.type][videoFileInfo.location];
			dohx.add({name:"VideoPlayer",
				mqcExecutionOrderBaseOffset:250000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
				requiredObjects:[
					"Widget.Multimedia.VideoPlayer.open",
					"Widget.Multimedia.VideoPlayer.play",
					"Widget.Multimedia.VideoPlayer.stop"
				],
				tests:[
					{
						id:videoFileInfo.id,
						name:"Protocol - Test codec '"+ videoFileInfo.type +"' from '" + filename + "'",
						instructions:"Click 'GO' to play video.",
						expectedResult:"Did you see the video?",
						setUp:_setUp,
						test:function(t){
							videoObj = new myVideo(filename, {
								autoPlay:true,
								stopAfter:10*1000
							});
						},
						tearDown:_tearDown
					}
				]
			});
		})(_videoFiles[i]);
	};

})();
<|endoftext|>


<commit_before>/*global angular, d3, get, console*/
/*jslint bitwise: true, plusplus: true, white: true, sub: true*/

var kanApp = angular.module('kanApp', ['ui.router', 'nvd3']);
var DEBUG = true;

/**
* Definition of angular views and their controllers.
*/
kanApp.config(function ($stateProvider, $urlRouterProvider) {
    "use strict";

	$urlRouterProvider.otherwise('/ld');

	$stateProvider
        .state('ld', {
            url: '/ld',
            templateUrl: 'pages/ld.html',
            controller: 'dataController'
        })

        .state('cfd', {
            url: '/cfd',
            templateUrl: 'pages/cfd.html',
            controller: 'nvd3Controller'
        })

        .state('pe', {
            url: '/pe',
            templateUrl: 'pages/pe.html'
        })

        .state('about', {
            url: '/about',
            templateUrl: 'pages/about.html'
        });
});

/**
* Base64 encoding + decoding for use in http requests.
*/
kanApp.factory('Base64', function () {
    "use strict";
    /*jslint regexp: true*/

    var keyStr = 'ABCDEFGHIJKLMNOP' +
        'QRSTUVWXYZabcdef' +
        'ghijklmnopqrstuv' +
        'wxyz0123456789+/' +
        '=';
    return {
        encode: function (input) {
            var output = "",
                chr1, chr2, chr3 = "",
                enc1, enc2, enc3, enc4 = "",
                i = 0;

            do {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                    keyStr.charAt(enc1) +
                    keyStr.charAt(enc2) +
                    keyStr.charAt(enc3) +
                    keyStr.charAt(enc4);
                chr1 = chr2 = chr3 = "";
                enc1 = enc2 = enc3 = enc4 = "";
            } while (i < input.length);

            return output;
        },

        decode: function (input) {
            var output = "",
                chr1, chr2, chr3 = "",
                enc1, enc2, enc3, enc4 = "",
                i = 0,
                base64test = /[^A-Za-z0-9\+\/\=]/g,
                alert;

            if (base64test.exec(input)) {
                alert("There were invalid base64 characters in the input text.\n" +
                    "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
                    "Expect errors in decoding.");
            }
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            do {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 !== 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 !== 64) {
                    output = output + String.fromCharCode(chr3);
                }

                chr1 = chr2 = chr3 = "";
                enc1 = enc2 = enc3 = enc4 = "";

            } while (i < input.length);
            /*jslint regexp: false*/
            return output;
        }
    };
});

/**
* Service for getting all data from a json file.
*/
kanApp.factory('dataService', function ($http) {
    "use strict";

    var dataService = {
        async: function () {
            // $http returns a promise, which has a .then function, which also returns a promise
            var promise = $http.get('../json/graphTestData.json').then(function (response) {
                // The .then function here is an opportunity to modify the response
                if(DEBUG){console.log(response);}
                // The return value gets picked up by the .then in the controller.
                return response.data;
            });
            // Return the promise to the controller
            return promise;
        }
    };
    return dataService;
});

/**
* Controller for the Load Data view.
*/
kanApp.controller('dataController', function ($scope, dataService, Base64, $http) {
    "use strict";

    /**
    * Clear json data.
    * TAGS: unused
    */
    $scope.clearData = function () {
        $scope.data = {};
    };

    /**
    * Get data from JSON file.
    */
    $scope.getData = function () {
        dataService.async().then(function (d) {
            $scope.data = d;
        });
    };

    /**
    * Dump json file content directly in app.
    * TAGS: unused
    */
    $scope.prettyString = null;
    $scope.jsonPrint = function () {
        if ($scope.prettyString === null) {
            $scope.prettyString = JSON.stringify($scope.data, null, "\t");
        } else {
            $scope.prettyString = null;
        }
    };

    /**
    * Variables for logging in.
    */
    $scope.credentials = { username: 'martin.w.greer', password: ''};
    $scope.jiraRoot = 'https://kanalyzer.atlassian.net/';
    $scope.jiraProject = 'KTD';
    $scope.jiraServer = $scope.jiraRoot + 'projects/' +  $scope.jiraProject + '/issues';

    /**
    * Login: Auth to JIRA server.
    */
    $scope.login = function (credentials) {
        //$http.defaults.headers.common = {"Access-Control-Request-Headers": "accept, origin, authorization", "Access-Control-Allow-Origin": "*"};
        //$http.defaults.headers.common = {"Access-Control-Allow-Origin": "*"};
        if(DEBUG){console.log("Attempting to authenticate to server " + $scope.jiraRoot + "...");}
        $http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode($scope.credentials.username + ':' + $scope.credentials.password);
        $http({method: 'GET', url: $scope.jiraServer})
            .success(function (data) {
                if(DEBUG){console.log("Authentication SUCCESS!");}
            })
            .error(function (data) {
                if(DEBUG){console.log("Authentication ERROR.");}
            });
    };

    $scope.logout = function (credentials) {
        if(DEBUG){console.log("Logging out from " + $scope.jiraRoot + "...");}
        $scope.credentials = { username: 'martin.w.greer', password: '' };
        $http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode(' : ');
        $http({method: 'GET', url: $scope.jiraServer})
            .success(function (data) {
                if(DEBUG){console.log("Logout ERROR.");}
            })
            .error(function (data) {
                if(DEBUG){console.log("Logout SUCCESS!");}
            });
    };

    /**
    * The max results to be returned from JIRA (-1 is unlimited results).
    */
    var maxResults = -1;

    /**
    * Get all issues for the project that was given on login.
    */
    $scope.getAllIssues = function () {
        var request = $http({
            method: "GET",
            url: $scope.jiraRoot + "rest/api/2/search?jql=project=" + $scope.jiraProject + "&expand=changelog" + "&maxResults=" + maxResults
        });
        if(DEBUG){console.log("Attempting to get all issues for project " + $scope.jiraProject + "...");}
        request.success(function (data) {
            localStorage.setItem('jiraIssues', JSON.stringify(data.issues));
            if(DEBUG){console.log("Get all issues SUCCESS!");}
        });
        request.error(function (data) {
            if(DEBUG){console.log("Get all issues ERROR. JIRA response: " + JSON.stringify(data));}
        });
    };

    /**
    * Print all issues directly in the application (for debugging).
    */
    $scope.allIssuesString = null;
    $scope.printAllIssues = function () {
        if ($scope.allIssuesString === null) {
            $scope.allIssuesString = localStorage.getItem('jiraIssues');
        } else {
            $scope.allIssuesString = null;
        }
    };
});

/**
* Controller for the CFD view.
*/
kanApp.controller('nvd3Controller', function ($scope, dataService) {
    "use strict";

    /**
    * Graph structure.
    */
    $scope.options = {
        chart: {
            type: 'stackedAreaChart',
            height: 450,
            margin: {
                top: 20,
                right: 1150,
                bottom: 60,
                left: 40
            },
            x: function (d) { return d[0]; },
            y: function (d) { return d[1]; },
            useVoronoi: false,
            clipEdge: true,
            transitionDuration: 500,
            useInteractiveGuideline: true,
            xAxis: {
                showMaxMin: false,
                tickFormat: function (d) {
                    return d3.time.format('%x')(new Date(d));
                }
            },
            yAxis: {
                tickFormat: function (d) {
                    return d3.format(',.2f')(d);
                }
            }
        }
    };

    /**
    * Get json data from file when opening CFD page. (REMOVE LATER - WE WANT GLOBAL STORAGE IN VARIABLES)
    */
    dataService.async().then(function (d) {
        $scope.data = d;
    });
});<commit_msg>pre-added function for getting board structure (columns and substatuses)<commit_after>/*global angular, d3, get, console*/
/*jslint bitwise: true, plusplus: true, white: true, sub: true*/

var kanApp = angular.module('kanApp', ['ui.router', 'nvd3']);
var DEBUG = true;

/**
* Definition of angular views and their controllers.
*/
kanApp.config(function ($stateProvider, $urlRouterProvider) {
    "use strict";

	$urlRouterProvider.otherwise('/ld');

	$stateProvider
        .state('ld', {
            url: '/ld',
            templateUrl: 'pages/ld.html',
            controller: 'dataController'
        })

        .state('cfd', {
            url: '/cfd',
            templateUrl: 'pages/cfd.html',
            controller: 'nvd3Controller'
        })

        .state('pe', {
            url: '/pe',
            templateUrl: 'pages/pe.html'
        })

        .state('about', {
            url: '/about',
            templateUrl: 'pages/about.html'
        });
});

/**
* Base64 encoding + decoding for use in http requests.
*/
kanApp.factory('Base64', function () {
    "use strict";
    /*jslint regexp: true*/

    var keyStr = 'ABCDEFGHIJKLMNOP' +
        'QRSTUVWXYZabcdef' +
        'ghijklmnopqrstuv' +
        'wxyz0123456789+/' +
        '=';
    return {
        encode: function (input) {
            var output = "",
                chr1, chr2, chr3 = "",
                enc1, enc2, enc3, enc4 = "",
                i = 0;

            do {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                    keyStr.charAt(enc1) +
                    keyStr.charAt(enc2) +
                    keyStr.charAt(enc3) +
                    keyStr.charAt(enc4);
                chr1 = chr2 = chr3 = "";
                enc1 = enc2 = enc3 = enc4 = "";
            } while (i < input.length);

            return output;
        },

        decode: function (input) {
            var output = "",
                chr1, chr2, chr3 = "",
                enc1, enc2, enc3, enc4 = "",
                i = 0,
                base64test = /[^A-Za-z0-9\+\/\=]/g,
                alert;

            if (base64test.exec(input)) {
                alert("There were invalid base64 characters in the input text.\n" +
                    "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
                    "Expect errors in decoding.");
            }
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            do {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 !== 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 !== 64) {
                    output = output + String.fromCharCode(chr3);
                }

                chr1 = chr2 = chr3 = "";
                enc1 = enc2 = enc3 = enc4 = "";

            } while (i < input.length);
            /*jslint regexp: false*/
            return output;
        }
    };
});

/**
* Service for getting all data from a json file.
*/
kanApp.factory('dataService', function ($http) {
    "use strict";

    var dataService = {
        async: function () {
            // $http returns a promise, which has a .then function, which also returns a promise
            var promise = $http.get('../json/graphTestData.json').then(function (response) {
                // The .then function here is an opportunity to modify the response
                if(DEBUG){console.log(response);}
                // The return value gets picked up by the .then in the controller.
                return response.data;
            });
            // Return the promise to the controller
            return promise;
        }
    };
    return dataService;
});

/**
* Controller for the Load Data view.
*/
kanApp.controller('dataController', function ($scope, dataService, Base64, $http) {
    "use strict";

    /**
    * Clear json data.
    * TAGS: unused
    */
    $scope.clearData = function () {
        $scope.data = {};
    };

    /**
    * Get data from JSON file.
    */
    $scope.getData = function () {
        dataService.async().then(function (d) {
            $scope.data = d;
        });
    };

    /**
    * Dump json file content directly in app.
    * TAGS: unused
    */
    $scope.prettyString = null;
    $scope.jsonPrint = function () {
        if ($scope.prettyString === null) {
            $scope.prettyString = JSON.stringify($scope.data, null, "\t");
        } else {
            $scope.prettyString = null;
        }
    };

    /**
    * Variables for logging in.
    */
    $scope.credentials = { username: 'martin.w.greer', password: ''};
    $scope.jiraRoot = 'https://kanalyzer.atlassian.net/';
    $scope.jiraProject = 'KTD';
    $scope.jiraServer = $scope.jiraRoot + 'projects/' +  $scope.jiraProject + '/issues';

    /**
    * Login: Auth to JIRA server.
    */
    $scope.login = function (credentials) {
        //$http.defaults.headers.common = {"Access-Control-Request-Headers": "accept, origin, authorization", "Access-Control-Allow-Origin": "*"};
        //$http.defaults.headers.common = {"Access-Control-Allow-Origin": "*"};
        if(DEBUG){console.log("Attempting to authenticate to server " + $scope.jiraRoot + "...");}
        $http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode($scope.credentials.username + ':' + $scope.credentials.password);
        $http({method: 'GET', url: $scope.jiraServer})
            .success(function (data) {
                if(DEBUG){console.log("Authentication SUCCESS!");}
            })
            .error(function (data) {
                if(DEBUG){console.log("Authentication ERROR.");}
            });
    };

    $scope.logout = function (credentials) {
        if(DEBUG){console.log("Logging out from " + $scope.jiraRoot + "...");}
        $scope.credentials = { username: 'martin.w.greer', password: '' };
        $http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode(' : ');
        $http({method: 'GET', url: $scope.jiraServer})
            .success(function (data) {
                if(DEBUG){console.log("Logout ERROR.");}
            })
            .error(function (data) {
                if(DEBUG){console.log("Logout SUCCESS!");}
            });
    };

    /**
    * The max results to be returned from JIRA (-1 is unlimited results).
    */
    var maxResults = -1;

    /**
    * Get all issues for the project that was given on login.
    */
    $scope.getAllIssues = function () {
        var request = $http({
            method: "GET",
            url: $scope.jiraRoot + "rest/api/2/search?jql=project=" + $scope.jiraProject + "&expand=changelog" + "&maxResults=" + maxResults
        });
        if(DEBUG){console.log("Attempting to get all issues for project " + $scope.jiraProject + "...");}
        request.success(function (data) {
            localStorage.setItem('jiraIssues', JSON.stringify(data.issues));
            if(DEBUG){console.log("Get all issues SUCCESS!");}
        });
        request.error(function (data) {
            if(DEBUG){console.log("Get all issues ERROR. JIRA response: " + JSON.stringify(data));}
        });
    };

    /**
    * Print all issues directly in the application (for debugging).
    */
    $scope.allIssuesString = null;
    $scope.printAllIssues = function () {
        if ($scope.allIssuesString === null) {
            $scope.allIssuesString = localStorage.getItem('jiraIssues');
        } else {
            $scope.allIssuesString = null;
        }
    };

    $scope.getBoardStructure = function () {
        //https://kanalyzer.atlassian.net/rest/greenhopper/1.0/xboard/work/allData.json?rapidViewId=2&selectedProjectKey=KTD
    };
});

/**
* Controller for the CFD view.
*/
kanApp.controller('nvd3Controller', function ($scope, dataService) {
    "use strict";

    /**
    * Graph structure.
    */
    $scope.options = {
        chart: {
            type: 'stackedAreaChart',
            height: 450,
            margin: {
                top: 20,
                right: 1150,
                bottom: 60,
                left: 40
            },
            x: function (d) { return d[0]; },
            y: function (d) { return d[1]; },
            useVoronoi: false,
            clipEdge: true,
            transitionDuration: 500,
            useInteractiveGuideline: true,
            xAxis: {
                showMaxMin: false,
                tickFormat: function (d) {
                    return d3.time.format('%x')(new Date(d));
                }
            },
            yAxis: {
                tickFormat: function (d) {
                    return d3.format(',.2f')(d);
                }
            }
        }
    };

    /**
    * Get json data from file when opening CFD page. (REMOVE LATER - WE WANT GLOBAL STORAGE IN VARIABLES)
    */
    dataService.async().then(function (d) {
        $scope.data = d;
    });
});<|endoftext|>