<commit_before>define([
    'dojo/query'

], function(
    query
    ) {
    return {
        getSelectedRadioValue: function(btnGroupName) {
            // summary:
            //      Gets the value of the selected radio button in the group.
            // btnGroupName: String
            //      The name of the radio button group
            // returns: String
            //      Returns ' if no button is selected
            console.log('agrc/modules/HelperFunctions:getSelectedRadioValue', arguments);

            function getSelectedRadio(buttonGroup) {
                // returns the array number of the selected radio button or -1 if no button is selected
                if (buttonGroup[0]) { // if the button group is an array (one button is not an array)
                    for (var i = 0; i < buttonGroup.length; i++) {
                        if (buttonGroup[i].checked) {
                            return i;
                        }
                    }
                } else {
                    if (buttonGroup.checked) {
                        return 0;
                    } // if the one button is checked, return zero
                }
                // if we get to this point, no radio button is selected
                return -1;
            }

            var buttonGroup = query('input[name=' + btnGroupName + ']');

            // returns the value of the selected radio button or ' if no button is selected
            var i = getSelectedRadio(buttonGroup);
            if (i === -1) {
                return undefined;
            } else {
                if (buttonGroup[i]) { // Make sure the button group is an array (not just one button)
                    return buttonGroup[i].value;
                } else { // The button group is just the one button, and it is checked
                    return buttonGroup.value;
                }
            }
        },

        loadCss: function(href) {
            // summary:
            //      Loads a css file into the current document's head.
            // href: String
            //      The url to the css file that you want to load
            console.log('agrc/modules/HelperFunctions:loadCss', arguments);

            var head = document.getElementsByTagName('head').item(0);

            var link = document.createElement('link');
            link.rel = 'stylesheet';
            link.type = 'text/css';
            link.href = href;
            head.appendChild(link);
        },

        loadJavaScript: function(src) {
            // summary:
            //      Loads a JavaScript file into the current document's head.
            // src: String
            //      The url to the JavaScript file that you want to load
            console.log('agrc/modules/HelperFunctions:loadJavaScript', arguments);

            var head = document.getElementsByTagName('head').item(0);

            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = src;
            head.appendChild(script);
        }
    };
});<commit_msg>Fixed docs<commit_after>define([
    'dojo/query'

], function(
    query
    ) {
    return {
        getSelectedRadioValue: function(btnGroupName) {
            // summary:
            //      Gets the value of the selected radio button in the group.
            // btnGroupName: String
            //      The name of the radio button group
            // returns: String
            //      Returns '' if no button is selected
            console.log('agrc/modules/HelperFunctions:getSelectedRadioValue', arguments);

            function getSelectedRadio(buttonGroup) {
                // returns the array number of the selected radio button or -1 if no button is selected
                if (buttonGroup[0]) { // if the button group is an array (one button is not an array)
                    for (var i = 0; i < buttonGroup.length; i++) {
                        if (buttonGroup[i].checked) {
                            return i;
                        }
                    }
                } else {
                    if (buttonGroup.checked) {
                        return 0;
                    } // if the one button is checked, return zero
                }
                // if we get to this point, no radio button is selected
                return -1;
            }

            var buttonGroup = query('input[name=' + btnGroupName + ']');

            // returns the value of the selected radio button or ' if no button is selected
            var i = getSelectedRadio(buttonGroup);
            if (i === -1) {
                return undefined;
            } else {
                if (buttonGroup[i]) { // Make sure the button group is an array (not just one button)
                    return buttonGroup[i].value;
                } else { // The button group is just the one button, and it is checked
                    return buttonGroup.value;
                }
            }
        },

        loadCss: function(href) {
            // summary:
            //      Loads a css file into the current document's head.
            // href: String
            //      The url to the css file that you want to load
            console.log('agrc/modules/HelperFunctions:loadCss', arguments);

            var head = document.getElementsByTagName('head').item(0);

            var link = document.createElement('link');
            link.rel = 'stylesheet';
            link.type = 'text/css';
            link.href = href;
            head.appendChild(link);
        },

        loadJavaScript: function(src) {
            // summary:
            //      Loads a JavaScript file into the current document's head.
            // src: String
            //      The url to the JavaScript file that you want to load
            console.log('agrc/modules/HelperFunctions:loadJavaScript', arguments);

            var head = document.getElementsByTagName('head').item(0);

            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = src;
            head.appendChild(script);
        }
    };
});<|endoftext|>


<commit_before><commit_msg>Added checks for bankrupcy<commit_after><|endoftext|>


<commit_before>var path = require('path');
var currentPath = null;

module.exports = {
    mapPath: function (paths) {
        if(currentPath !== null)
        return path.join(currentPath, paths);

        var dir = __dirname;
        if (dir.indexOf('node_modules') !== -1)
            dir = dir.substring(0, dir.indexOf('node_modules'));

        currentPath = dir;

        return path.join(dir, paths);
    }
};<commit_msg>no message<commit_after>var path = require('path');
var currentPath = null;

module.exports = {
    mapPath: function (paths) {
        if(currentPath !== null)
            return path.join(currentPath, paths);

        var dir = __dirname;
        if (dir.indexOf('node_modules') !== -1)
            dir = dir.substring(0, dir.indexOf('node_modules'));

        currentPath = dir;

        return path.join(dir, paths);
    }
};<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const path = require('path')

if (!process.argv[2]) {
  console.error('Usage: ead2calisphere input.xml [output.tsv]')
  process.exit(1)
}

const eadRaw = fs.readFileSync(path.resolve(process.cwd(), process.argv[2]), 'utf-8')

const outputFile = process.argv[3] ? path.resolve(process.cwd(), process.argv[3]) : ''
if (outputFile) {
  try {
    fs.unlinkSync(outputFile)
  } catch (e) {
    // file probably didn't exist
  }
}

const htmlparser2 = require('htmlparser2')

let tagStack = []
let fileLevelTagStack = []
let dataMapStack = []
let dataMap = new Map()
let collectionNumber = ''
let creator = ''
let creatorType = ''
let creatorSource = 'local'
let language = {}
let languageStack = []
let collectionTitle = ''
let containerDisplay = ''

const subjectName = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
let subjectNameIndex = 0

const subjectTopic = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
let subjectTopicIndex = 0

let emptyOutput = true

const displayData = (data) => {
  emptyOutput = false
  if (data.get('DONOTDISPLAY')) { return }

  if (!collectionNumber) {
    throw new Error('no collection number found')
  }

  const container = data.get('container')
  if (!container) { return }

  const output = []
  // File path: leave blank
  output.push('')

  // Title
  const unittitlePrefix = dataMapStack.reduce(
    (rv, value) => {
      if (value.get('unittitle')) {
        return rv + `${value.get('unittitle')}: `
      }
      return rv
    },
    ''
  )

  const localUnittitle = data.get('unittitle') || data.get('unitdate')
  if (!localUnittitle) {
    throw new Error('unittitle or unitdate required')
  }
  output.push(`${unittitlePrefix}${localUnittitle}`)

  // Alternative title: leave blank
  output.push('')

  // Identifier: leave blank
  output.push('')

  // Local identifier
  const containers = container.split(/[ :]+/)
  const containersPadded = containers.map((val) => val.padStart(3, '0'))
  output.push(`${collectionNumber.trim().replace(/\s+/g, '')}_${containersPadded.join('_')}_0000`.toLowerCase())

  // Type: leave blank
  output.push('')

  // Campus/unit: leave blank
  output.push('')

  // Date
  output.push(data.get('unitdate') || 'undated')

  // Date type: always "created"
  output.push('created')

  // Single: leave blank
  output.push('')

  // Inclusive Start: leave blank
  output.push('')

  // Inclusive End: leave blank
  output.push('')

  // Publication/origin: leave blank
  output.push('')

  // Creator 1 Name
  // Our finding aids only seem to have one creator.
  output.push(creator)

  // Creator 1 Name Type
  output.push(creatorType)

  // Creator 1 Role: leave blank
  output.push('')

  // Creator 1 Source
  output.push(creatorSource)

  // Creator 1 Authority ID: leave blank (for now at least)
  output.push('')

  // Leave Creator 2 * blank
  output.push('') // name
  output.push('') // name type
  output.push('') // role
  output.push('') // source
  output.push('') // authority id

  // Leave Contributor * blank
  output.push('') // name
  output.push('') // name type
  output.push('') // role
  output.push('') // source
  output.push('') // authority id

  // Leave format/physical description blank; needs to be filled out manually
  output.push('')

  // Leave description notes and types blank
  output.push('') // Description 1 Note
  output.push('') // Description 1 Type
  output.push('') // Description 2 Note
  output.push('') // Description 2 Type
  output.push('') // Description 3 Note
  output.push('') // Description 3 Type

  // Extent
  output.push(data.get('extent') || '')

  // Language
  output.push(language.text)

  // Language code
  output.push(language.attribs.langcode)

  // Temporal coverage: leave blank
  output.push('')

  // Transcription: leave blank
  output.push('')

  // Access restriction: leave blank
  output.push('')

  // Copyright Status: leave blank
  output.push('')

  // Copyright Statement: leave blank
  output.push('')
  // Copyright Holder Name Type: leave blank
  output.push('')
  // Copyright Holder Name: leave blank
  output.push('')
  // Copyright Holder Source: leave blank
  output.push('')
  // Copyright Holder Authority ID: leave blank
  output.push('')
  // Copyright Contact: leave blank
  output.push('')
  // Copyright Notice: leave blank
  output.push('')
  // Copyright Determination Date: leave blank
  output.push('')
  // Copyright Start Date: leave blank
  output.push('')
  // Copyright End Date: leave blank
  output.push('')
  // Copyright Jurisdiction: leave blank
  output.push('')
  // Copyright Note: leave blank
  output.push('')

  // Collection 1: leave blank
  output.push('')

  // Collection 2: leave blank
  output.push('')

  // Related Resource: leave blank
  output.push('')

  // Source
  output.push(`${collectionTitle}, ${collectionNumber}, ${containerDisplay}`)

  subjectName.forEach((val) => {
    output.push(val.name || '')
    output.push(val.type || '')
    output.push(val.role || '')
    output.push(val.source || '')
    output.push(val.authorityId || '')
  })

  // We think places are all blank
  for (let i = 0; i < 12; i++) {
    output.push('')
  }

  subjectTopic.forEach((val) => {
    output.push(val.heading || '')
    output.push(val.headingType || '')
    output.push(val.source || '')
    output.push(val.authorityId || '')
  })

  // We think form/genre are all blank
  for (let i = 0; i < 9; i++) {
    output.push('')
  }

  // Provenance: leave blank
  output.push('')

  // Physical location: leave blank
  output.push('')

  const badTypes = output.filter((val) => typeof val !== 'string')
  if (badTypes.length) {
    console.error(`Non-string found in ${output.join('\t')}`)
    throw new TypeError(`${typeof badTypes[0]} found at index ${output.indexOf(badTypes[0])}, string expected`)
  }

  const detabbedOutput = output.map((val) => val.replace('\t', ' '))
  const tsvOutput = detabbedOutput.join('\t')

  if (outputFile) {
    fs.writeFileSync(outputFile, `${tsvOutput}\n`, {flag: 'a'})
  } else {
    console.log(tsvOutput)
  }
}

const handlers = {
  /*
    See possible events at:
      https://github.com/fb55/htmlparser2/wiki/Parser-options#events
    See fields we need at:
      https://docs.google.com/spreadsheets/d/1zmJVEZtdJ_6cwmdyWYR7dXMGYFKp_TGiyRV9zQgGbXE/edit
    See desired output format at:
      https://docs.google.com/spreadsheets/d/1zmJVEZtdJ_6cwmdyWYR7dXMGYFKp_TGiyRV9zQgGbXE/edit?usp=sharing
   */
  onopentag: function (name, attribs) {
    tagStack.push({name, attribs})
    if (/^language$/i.test(name)) {
      language = {name, attribs, text: ''}
      languageStack.push(language)
    }
    // Use both `level="file"` and `level="item"` because some finding aids don't include `level="file"`.
    if (/^(?:file|item)$/i.test(attribs.level)) {
      if (dataMap.size > 0) {
        // This map encloses another map, so do not display on line by itself.
        dataMap.set('DONOTDISPLAY', true)
        dataMapStack.push(dataMap)
        dataMap = new Map()
      }
      fileLevelTagStack.push(name.toLowerCase())
      containerDisplay = ''
    }
  },
  ontext: function (text) {
    const thisTag = tagStack[tagStack.length - 1]
    if (thisTag) {
      const prevTag = tagStack[tagStack.length - 2]
      const prevPrevTag = tagStack[tagStack.length - 3]
      if (/^unittitle$/i.test(thisTag.name) && /^did$/i.test(prevTag.name) && /^archdesc$/i.test(prevPrevTag.name)) {
        collectionTitle += text
      }
      if (/^unitid$/i.test(thisTag.name) && /^did$/i.test(prevTag.name) && /^archdesc$/i.test(prevPrevTag.name) && /^collection$/i.test(prevPrevTag.attribs.level)) {
        collectionNumber += text
      }
      if (/^language$/i.test(thisTag.name)) {
        language.text += text
      }
      if (/^container$/i.test(thisTag.name)) {
        const types = thisTag.attribs.type.split(/[: -]+/).map((val) => val.charAt(0).toUpperCase() + val.slice(1))
        const texts = text.split(/[: ]+/)
        const pieces = types.map((type, idx) => `${type} ${texts[idx]}`)
        if (containerDisplay) {
          containerDisplay += ' ' + pieces.join(', ')
        } else {
          containerDisplay = pieces.join(', ')
        }
      }
    }
    if (tagStack.filter((tag) => { return /^origination$/i.test(tag.name) && /^creator$/i.test(tag.attribs.label) }).length > 0) {
      creator += text.trim()
      if (['corpname', 'famname', 'persname'].includes(thisTag.name)) {
        creatorType = thisTag.name
        if (/^lcnaf$/i.test(thisTag.attribs.source)) {
          creatorSource = 'naf'
        }
      }
    }
    if (tagStack.filter((tag) => /^controlaccess$/i.test(tag.name)).length > 0) {
      if (['corpname', 'famname', 'persname'].includes(thisTag.name)) {
        if (subjectNameIndex === subjectName.length) {
          throw new Error(`Too many Names! Max: ${subjectName.length}`)
        }
        const mine = subjectName[subjectNameIndex]
        subjectNameIndex++
        mine.name = text.trim() // This assumes no nested tags in the names
        mine.type = thisTag.name
        mine.role = ''
        mine.source = /^lcnaf$/i.test(thisTag.attribs.source) ? 'naf' : 'local'
        mine.authrityId = ''
      }
      if (['subject'].includes(thisTag.name)) {
        if (subjectTopicIndex === subjectTopic.length) {
          throw new Error(`Too many Topics! Max: ${subjectTopic.length}`)
        }
        const mine = subjectTopic[subjectTopicIndex]
        subjectTopicIndex++
        mine.heading = text.trim() // This assumes no nested tags in topics
        mine.headingType = 'topic'
        mine.source = /^lcsh$/i.test(thisTag.attribs.source) ? 'lcsh' : 'local'
        mine.authorityId = ''
      }
    }
    if (fileLevelTagStack.length === 0) { return }
    const trimmedText = text.trim().replace(/\s+/g, ' ')
    if (trimmedText.length > 0) {
      if (tagStack.length === 0) {
        throw new Error(`found text outside of tags: ${trimmedText}`)
      }

      tagStack.forEach((tag, index) => {
        const soFar = dataMap.get(tagStack[index].name)
        if (soFar === undefined) {
          return dataMap.set(tag.name, trimmedText)
        }
        if (/[A-Za-z0-9]$/.test(soFar)) {
          return dataMap.set(tag.name, `${soFar} ${trimmedText}`)
        }
        return dataMap.set(tag.name, `${soFar}${trimmedText}`)
      })
    }
  },
  onclosetag: function (tagname) {
    const expectedTag = tagStack.pop()
    if (expectedTag.name !== tagname) { throw new Error(`Invalid XML: Expected closing tag ${expectedTag.name} but saw ${tagname}`) }
    if (tagname.toLowerCase() === fileLevelTagStack[fileLevelTagStack.length - 1]) {
      fileLevelTagStack.pop()

      displayData(dataMap)
      dataMap = dataMapStack.pop() || new Map()
    }
    if (/^language$/i.test(tagname)) {
      language = languageStack.pop()
    }
  }
}

const options = {
  decodeEntities: true,
  xmlMode: true
}

const parser = new htmlparser2.Parser(handlers, options)
parser.write(eadRaw) // passed through handlers
parser.end()

if (emptyOutput) {
  console.warn('No output! Check the XML input for problems.')
}
<commit_msg>fix tab replacement<commit_after>'use strict'

const fs = require('fs')
const path = require('path')

if (!process.argv[2]) {
  console.error('Usage: ead2calisphere input.xml [output.tsv]')
  process.exit(1)
}

const eadRaw = fs.readFileSync(path.resolve(process.cwd(), process.argv[2]), 'utf-8')

const outputFile = process.argv[3] ? path.resolve(process.cwd(), process.argv[3]) : ''
if (outputFile) {
  try {
    fs.unlinkSync(outputFile)
  } catch (e) {
    // file probably didn't exist
  }
}

const htmlparser2 = require('htmlparser2')

let tagStack = []
let fileLevelTagStack = []
let dataMapStack = []
let dataMap = new Map()
let collectionNumber = ''
let creator = ''
let creatorType = ''
let creatorSource = 'local'
let language = {}
let languageStack = []
let collectionTitle = ''
let containerDisplay = ''

const subjectName = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
let subjectNameIndex = 0

const subjectTopic = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
let subjectTopicIndex = 0

let emptyOutput = true

const displayData = (data) => {
  emptyOutput = false
  if (data.get('DONOTDISPLAY')) { return }

  if (!collectionNumber) {
    throw new Error('no collection number found')
  }

  const container = data.get('container')
  if (!container) { return }

  const output = []
  // File path: leave blank
  output.push('')

  // Title
  const unittitlePrefix = dataMapStack.reduce(
    (rv, value) => {
      if (value.get('unittitle')) {
        return rv + `${value.get('unittitle')}: `
      }
      return rv
    },
    ''
  )

  const localUnittitle = data.get('unittitle') || data.get('unitdate')
  if (!localUnittitle) {
    throw new Error('unittitle or unitdate required')
  }
  output.push(`${unittitlePrefix}${localUnittitle}`)

  // Alternative title: leave blank
  output.push('')

  // Identifier: leave blank
  output.push('')

  // Local identifier
  const containers = container.split(/[ :]+/)
  const containersPadded = containers.map((val) => val.padStart(3, '0'))
  output.push(`${collectionNumber.trim().replace(/\s+/g, '')}_${containersPadded.join('_')}_0000`.toLowerCase())

  // Type: leave blank
  output.push('')

  // Campus/unit: leave blank
  output.push('')

  // Date
  output.push(data.get('unitdate') || 'undated')

  // Date type: always "created"
  output.push('created')

  // Single: leave blank
  output.push('')

  // Inclusive Start: leave blank
  output.push('')

  // Inclusive End: leave blank
  output.push('')

  // Publication/origin: leave blank
  output.push('')

  // Creator 1 Name
  // Our finding aids only seem to have one creator.
  output.push(creator)

  // Creator 1 Name Type
  output.push(creatorType)

  // Creator 1 Role: leave blank
  output.push('')

  // Creator 1 Source
  output.push(creatorSource)

  // Creator 1 Authority ID: leave blank (for now at least)
  output.push('')

  // Leave Creator 2 * blank
  output.push('') // name
  output.push('') // name type
  output.push('') // role
  output.push('') // source
  output.push('') // authority id

  // Leave Contributor * blank
  output.push('') // name
  output.push('') // name type
  output.push('') // role
  output.push('') // source
  output.push('') // authority id

  // Leave format/physical description blank; needs to be filled out manually
  output.push('')

  // Leave description notes and types blank
  output.push('') // Description 1 Note
  output.push('') // Description 1 Type
  output.push('') // Description 2 Note
  output.push('') // Description 2 Type
  output.push('') // Description 3 Note
  output.push('') // Description 3 Type

  // Extent
  output.push(data.get('extent') || '')

  // Language
  output.push(language.text)

  // Language code
  output.push(language.attribs.langcode)

  // Temporal coverage: leave blank
  output.push('')

  // Transcription: leave blank
  output.push('')

  // Access restriction: leave blank
  output.push('')

  // Copyright Status: leave blank
  output.push('')

  // Copyright Statement: leave blank
  output.push('')
  // Copyright Holder Name Type: leave blank
  output.push('')
  // Copyright Holder Name: leave blank
  output.push('')
  // Copyright Holder Source: leave blank
  output.push('')
  // Copyright Holder Authority ID: leave blank
  output.push('')
  // Copyright Contact: leave blank
  output.push('')
  // Copyright Notice: leave blank
  output.push('')
  // Copyright Determination Date: leave blank
  output.push('')
  // Copyright Start Date: leave blank
  output.push('')
  // Copyright End Date: leave blank
  output.push('')
  // Copyright Jurisdiction: leave blank
  output.push('')
  // Copyright Note: leave blank
  output.push('')

  // Collection 1: leave blank
  output.push('')

  // Collection 2: leave blank
  output.push('')

  // Related Resource: leave blank
  output.push('')

  // Source
  output.push(`${collectionTitle}, ${collectionNumber}, ${containerDisplay}`)

  subjectName.forEach((val) => {
    output.push(val.name || '')
    output.push(val.type || '')
    output.push(val.role || '')
    output.push(val.source || '')
    output.push(val.authorityId || '')
  })

  // We think places are all blank
  for (let i = 0; i < 12; i++) {
    output.push('')
  }

  subjectTopic.forEach((val) => {
    output.push(val.heading || '')
    output.push(val.headingType || '')
    output.push(val.source || '')
    output.push(val.authorityId || '')
  })

  // We think form/genre are all blank
  for (let i = 0; i < 9; i++) {
    output.push('')
  }

  // Provenance: leave blank
  output.push('')

  // Physical location: leave blank
  output.push('')

  const badTypes = output.filter((val) => typeof val !== 'string')
  if (badTypes.length) {
    console.error(`Non-string found in ${output.join('\t')}`)
    throw new TypeError(`${typeof badTypes[0]} found at index ${output.indexOf(badTypes[0])}, string expected`)
  }

  const detabbedOutput = output.map((val) => val.replace(/\t/g, ' '))
  const tsvOutput = detabbedOutput.join('\t')

  if (outputFile) {
    fs.writeFileSync(outputFile, `${tsvOutput}\n`, {flag: 'a'})
  } else {
    console.log(tsvOutput)
  }
}

const handlers = {
  /*
    See possible events at:
      https://github.com/fb55/htmlparser2/wiki/Parser-options#events
    See fields we need at:
      https://docs.google.com/spreadsheets/d/1zmJVEZtdJ_6cwmdyWYR7dXMGYFKp_TGiyRV9zQgGbXE/edit
    See desired output format at:
      https://docs.google.com/spreadsheets/d/1zmJVEZtdJ_6cwmdyWYR7dXMGYFKp_TGiyRV9zQgGbXE/edit?usp=sharing
   */
  onopentag: function (name, attribs) {
    tagStack.push({name, attribs})
    if (/^language$/i.test(name)) {
      language = {name, attribs, text: ''}
      languageStack.push(language)
    }
    // Use both `level="file"` and `level="item"` because some finding aids don't include `level="file"`.
    if (/^(?:file|item)$/i.test(attribs.level)) {
      if (dataMap.size > 0) {
        // This map encloses another map, so do not display on line by itself.
        dataMap.set('DONOTDISPLAY', true)
        dataMapStack.push(dataMap)
        dataMap = new Map()
      }
      fileLevelTagStack.push(name.toLowerCase())
      containerDisplay = ''
    }
  },
  ontext: function (text) {
    const thisTag = tagStack[tagStack.length - 1]
    if (thisTag) {
      const prevTag = tagStack[tagStack.length - 2]
      const prevPrevTag = tagStack[tagStack.length - 3]
      if (/^unittitle$/i.test(thisTag.name) && /^did$/i.test(prevTag.name) && /^archdesc$/i.test(prevPrevTag.name)) {
        collectionTitle += text
      }
      if (/^unitid$/i.test(thisTag.name) && /^did$/i.test(prevTag.name) && /^archdesc$/i.test(prevPrevTag.name) && /^collection$/i.test(prevPrevTag.attribs.level)) {
        collectionNumber += text
      }
      if (/^language$/i.test(thisTag.name)) {
        language.text += text
      }
      if (/^container$/i.test(thisTag.name)) {
        const types = thisTag.attribs.type.split(/[: -]+/).map((val) => val.charAt(0).toUpperCase() + val.slice(1))
        const texts = text.split(/[: ]+/)
        const pieces = types.map((type, idx) => `${type} ${texts[idx]}`)
        if (containerDisplay) {
          containerDisplay += ' ' + pieces.join(', ')
        } else {
          containerDisplay = pieces.join(', ')
        }
      }
    }
    if (tagStack.filter((tag) => { return /^origination$/i.test(tag.name) && /^creator$/i.test(tag.attribs.label) }).length > 0) {
      creator += text.trim()
      if (['corpname', 'famname', 'persname'].includes(thisTag.name)) {
        creatorType = thisTag.name
        if (/^lcnaf$/i.test(thisTag.attribs.source)) {
          creatorSource = 'naf'
        }
      }
    }
    if (tagStack.filter((tag) => /^controlaccess$/i.test(tag.name)).length > 0) {
      if (['corpname', 'famname', 'persname'].includes(thisTag.name)) {
        if (subjectNameIndex === subjectName.length) {
          throw new Error(`Too many Names! Max: ${subjectName.length}`)
        }
        const mine = subjectName[subjectNameIndex]
        subjectNameIndex++
        mine.name = text.trim() // This assumes no nested tags in the names
        mine.type = thisTag.name
        mine.role = ''
        mine.source = /^lcnaf$/i.test(thisTag.attribs.source) ? 'naf' : 'local'
        mine.authrityId = ''
      }
      if (['subject'].includes(thisTag.name)) {
        if (subjectTopicIndex === subjectTopic.length) {
          throw new Error(`Too many Topics! Max: ${subjectTopic.length}`)
        }
        const mine = subjectTopic[subjectTopicIndex]
        subjectTopicIndex++
        mine.heading = text.trim() // This assumes no nested tags in topics
        mine.headingType = 'topic'
        mine.source = /^lcsh$/i.test(thisTag.attribs.source) ? 'lcsh' : 'local'
        mine.authorityId = ''
      }
    }
    if (fileLevelTagStack.length === 0) { return }
    const trimmedText = text.trim().replace(/\s+/g, ' ')
    if (trimmedText.length > 0) {
      if (tagStack.length === 0) {
        throw new Error(`found text outside of tags: ${trimmedText}`)
      }

      tagStack.forEach((tag, index) => {
        const soFar = dataMap.get(tagStack[index].name)
        if (soFar === undefined) {
          return dataMap.set(tag.name, trimmedText)
        }
        if (/[A-Za-z0-9]$/.test(soFar)) {
          return dataMap.set(tag.name, `${soFar} ${trimmedText}`)
        }
        return dataMap.set(tag.name, `${soFar}${trimmedText}`)
      })
    }
  },
  onclosetag: function (tagname) {
    const expectedTag = tagStack.pop()
    if (expectedTag.name !== tagname) { throw new Error(`Invalid XML: Expected closing tag ${expectedTag.name} but saw ${tagname}`) }
    if (tagname.toLowerCase() === fileLevelTagStack[fileLevelTagStack.length - 1]) {
      fileLevelTagStack.pop()

      displayData(dataMap)
      dataMap = dataMapStack.pop() || new Map()
    }
    if (/^language$/i.test(tagname)) {
      language = languageStack.pop()
    }
  }
}

const options = {
  decodeEntities: true,
  xmlMode: true
}

const parser = new htmlparser2.Parser(handlers, options)
parser.write(eadRaw) // passed through handlers
parser.end()

if (emptyOutput) {
  console.warn('No output! Check the XML input for problems.')
}
<|endoftext|>


<commit_before>// Missing Tests:
// Amazon
// Pandora
// Seesu
// Spotify
// VK

var base = require("./_base_test.js"),
    driver = base.getDriver(),
    secrets = require("./secrets.json"),
    By = require("selenium-webdriver").By;

const TIMEOUT_ERROR = /Wait timed out after ([0-9]* ?)ms/;
const WAIT_TIMEOUT = 30000;

var baseSites = [
  {name: "7digital", url: "http://www.7digital.com"},
  {name: "bandcamp", url: "http://www.bandcamp.com"},
  {name: "bop.fm", url: "http://www.bop.fm"},
  {name: "di.fm", url: "http://www.di.fm/ambient"},
  {name: "edge player", url: "http://player.edge.ca"},
  {name: "grooveshark", url: "http://www.grooveshark.com"},
  {name: "hypemachine", url: "http://www.hypem.com"},
  {name: "last.fm", url: "http://www.last.fm/listen"},
  {name: "myspace", url: "http://music.myspace.com"},
  {name: "mixcloud", url: "http://www.mixcloud.com"},
  {name: "pleer", url: "http://www.pleer.com"},
  {name: "radio paradise", url: "http://www.radioparadise.com"},
  {name: "slacker", url: "http://www.slacker.com"},
  {name: "tunein", url: "http://www.tunein.com"},
  {name: "youarelisteningto", url: "http://www.youarelistening.to"}
];

describe("Streamkeys suite", function() {

  before(function(done) {
    // Wait for ABP to load
    driver.sleep(1000).then(function() {
      done();
    });
  });

  after(function() {
    driver.quit();
  });

  baseSites.forEach(function(site) {
    describe(site.name, function() {
      shared.shouldBehaveLikeAMusicSite(driver, site.url);
    });
  });

  // @depends: a.guest-login
  describe("stitcher", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://app.stitcher.com/");
      helpers.waitAndClick(driver, {css: "a.guest-login"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: img.concierge-situation-image, div.concierge-filter-play-icon
  describe("songza", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://songza.com/");
      helpers.waitAndClick(driver, {css: "img.concierge-situation-image"});
      helpers.waitAndClick(driver, {css: "div.concierge-filter-play-icon"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .playControls_wrapper
  describe("soundcloud", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://soundcloud.com/explore");
      helpers.waitForSelector(driver, {className: "playControls__wrapper"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #ready_link
  describe("thesixtyone", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.thesixtyone.com");
      helpers.waitAndClick(driver, {id: "ready_link"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: a.yt-uix-tile-link
  describe("youtube", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://www.youtube.com");
      helpers.waitAndClick(driver, {css: "a.yt-uix-tile-link"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .station_anchor
  describe("jango", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.jango.com");
      helpers.waitAndClick(driver, {className: "station_anchor"});
      done();
    });

    // Ad popup might mess up driver
    after(function(done) {
      driver.sleep(5000).then(function() {
        done();
      });
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  describe("NPR one", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://one.npr.org");
      done();
    });

    // Ad popup might mess up driver
    after(function(done) {
      driver.sleep(5000).then(function() {
        done();
      });
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: td.logo_on, /search/
  describe("songstr", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://songstr.com/#!/search/The-Smiths");
      helpers.waitAndClick(driver, {css: "td.logo_on > img"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: body.dragdrop-dropTarget
  describe("sony music unlimited", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://music.sonyentertainmentnetwork.com/");
      // Wait for body to contain class that is added when webapp has loaded
      helpers.waitForSelector(driver, {css: "body.dragdrop-dropTarget"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .top-channel, .audio-buttons
  describe("earbits", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.earbits.com");
      helpers.waitAndClick(driver, {className: "top-channel"});
      helpers.waitForSelector(driver, {className: "audio-buttons"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .login_btn, .login_mail, .login_password, .login_form_submit, .player-controls
  describe("deezer", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.deezer.com");
      helpers.waitAndClick(driver, {id: "login_btn"});
      driver.wait(function() {
        return (driver.isElementPresent({id: "login_mail"}) &&
                driver.isElementPresent({id: "login_password"}) &&
                driver.isElementPresent({id: "login_form_submit"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "login_mail"}).sendKeys(secrets.deezer.username);
      driver.findElement({id: "login_password"}).sendKeys(secrets.deezer.password);
      driver.findElement({id: "login_form_submit"}).click();
      driver.wait(function() {
        return (driver.isElementPresent({className: "player-controls"}));
      }, WAIT_TIMEOUT);

      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .genre-btn, .btn-primary, .player-controls, [@data-station-id]
  describe("iHeartRadio", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.iheart.com");
      helpers.waitAndClick(driver, {className: "genre-btn"});
      helpers.waitAndClick(driver, {className: "btn-primary"});
      helpers.waitForSelector(driver, {className: "player-controls"})
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #username, #password, [name=submit], .player_bottom, /account/signin/
  describe("rdio", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://www.rdio.com/account/signin/");
      driver.wait(function() {
        return (driver.isElementPresent({id: "username"}) &&
                driver.isElementPresent({id: "password"}) &&
                driver.isElementPresent({name: "submit"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "username"}).sendKeys(secrets.rdio.username);
      driver.findElement({id: "password"}).sendKeys(secrets.rdio.password);
      driver.findElement({name: "submit"}).click();
      helpers.waitForSelector(driver, {className: "player_bottom"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: a.mix_name, a#play_overlay
  describe("8tracks", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.8tracks.com");
      helpers.waitAndClick(driver, {css: "a.mix_name"});
      helpers.waitAndClick(driver, {css: "a#play_overlay"});
      done();
    })

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #Email, #Passwd, #signIn, #player
  describe("googlemusic", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://music.google.com");
      driver.wait(function() {
        return (driver.isElementPresent({id: "Email"}) &&
                driver.isElementPresent({id: "Passwd"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "Email"}).sendKeys(secrets.googlemusic.username);
      driver.findElement({id: "Passwd"}).sendKeys(secrets.googlemusic.password);
      helpers.waitAndClick(driver, {id: "signIn"});
      helpers.waitForSelector(driver, {id: "player"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // // Strange bug here with webdriver messing up reading the console output
  // //@depends: #username, #password, [name=submit], .player_bottom, /account/signin/
  // describe("vk", function() {
  //   before(function(done) {
  //     helpers.getAndWait(driver, "http://www.vk.com").then(function() {
  //       driver.wait(function() {
  //         return (driver.isElementPresent({id: "quick_email"}) &&
  //                 driver.isElementPresent({id: "quick_pass"}) &&
  //                 driver.isElementPresent({id: "quick_login_button"}));
  //       }, WAIT_TIMEOUT);
  //       driver.findElement({id: "quick_email"}).sendKeys(secrets.vk.username);
  //       driver.findElement({id: "quick_pass"}).sendKeys(secrets.vk.password);
  //       driver.findElement({id: "quick_login_button"}).click();
  //       helpers.waitForSelector(driver, {id: "head_music"});
  //       done();
  //     });
  //   });

  //   shared.shouldBehaveLikeAMusicSite(driver, false);
  // });

  // // Iframes are too anoying
  // describe("spotify", function() {
  //   before(function(done) {
  //     helpers.getAndWait(driver, "https://play.spotify.com/");
  //     driver.findElement({id: "has-account"}).click();
  //     driver.wait(function() {
  //       return (driver.isElementPresent({id: "login-usr"}) &&
  //               driver.isElementPresent({id: "login-pass"}) &&
  //               driver.isElementPresent({css: "button[type=submit]"}));
  //     }, WAIT_TIMEOUT);
  //     driver.findElement({id: "login-usr"}).sendKeys(secrets.spotify.username);
  //     driver.findElement({id: "login-pass"}).sendKeys(secrets.spotify.password);
  //     driver.findElement({css: "button[type=submit]"}).click();
  //     driver.wait(function() {
  //       return (driver.isElementPresent({css: ".root > iframe"}));
  //     }, WAIT_TIMEOUT);
  //     driver.switchTo().frame(driver.findElement({css: ".root > iframe"})).then(function() {
  //       driver.wait(function() {
  //         console.log("wait for playback");
  //         return (driver.isElementPresent({className: "media-object-playlist"}));
  //       }, WAIT_TIMEOUT)
  //       .then(function() {
  //         driver.sleep(1000).then(function() {
  //           driver.findElement({className: "media-object-playlist"}).click().then(function() {
  //             console.log("clicked it");
  //             driver.wait(function() {
  //               return (driver.isElementPresent({className: "btn-play-text"}));
  //             });
  //             driver.findElement({className: "btn-play-text"}).click().then(function() {
  //               driver.switchTo().defaultContent().then(function() {
  //                 driver.sleep(2000).then(function(){done();});
  //               });
  //             })
  //           });
  //         });
  //       });
  //     });
  //   });

  //   shared.shouldBehaveLikeAMusicSite(driver, false);
  // });
});
<commit_msg>Remove mixcloud test.<commit_after>// Missing Tests:
// Amazon
// Pandora
// Seesu
// Spotify
// VK

var base = require("./_base_test.js"),
    driver = base.getDriver(),
    secrets = require("./secrets.json"),
    By = require("selenium-webdriver").By;

const TIMEOUT_ERROR = /Wait timed out after ([0-9]* ?)ms/;
const WAIT_TIMEOUT = 30000;

var baseSites = [
  {name: "7digital", url: "http://www.7digital.com"},
  {name: "bandcamp", url: "http://www.bandcamp.com"},
  {name: "bop.fm", url: "http://www.bop.fm"},
  {name: "di.fm", url: "http://www.di.fm/ambient"},
  {name: "edge player", url: "http://player.edge.ca"},
  {name: "grooveshark", url: "http://www.grooveshark.com"},
  {name: "hypemachine", url: "http://www.hypem.com"},
  {name: "last.fm", url: "http://www.last.fm/listen"},
  {name: "myspace", url: "http://music.myspace.com"},
  // {name: "mixcloud", url: "http://www.mixcloud.com"},
  {name: "pleer", url: "http://www.pleer.com"},
  {name: "radio paradise", url: "http://www.radioparadise.com"},
  {name: "slacker", url: "http://www.slacker.com"},
  {name: "tunein", url: "http://www.tunein.com"},
  {name: "youarelisteningto", url: "http://www.youarelistening.to"}
];

describe("Streamkeys suite", function() {

  before(function(done) {
    // Wait for ABP to load
    driver.sleep(1000).then(function() {
      done();
    });
  });

  after(function() {
    driver.quit();
  });

  baseSites.forEach(function(site) {
    describe(site.name, function() {
      shared.shouldBehaveLikeAMusicSite(driver, site.url);
    });
  });

  // @depends: a.guest-login
  describe("stitcher", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://app.stitcher.com/");
      helpers.waitAndClick(driver, {css: "a.guest-login"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: img.concierge-situation-image, div.concierge-filter-play-icon
  describe("songza", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://songza.com/");
      helpers.waitAndClick(driver, {css: "img.concierge-situation-image"});
      helpers.waitAndClick(driver, {css: "div.concierge-filter-play-icon"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .playControls_wrapper
  describe("soundcloud", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://soundcloud.com/explore");
      helpers.waitForSelector(driver, {className: "playControls__wrapper"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #ready_link
  describe("thesixtyone", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.thesixtyone.com");
      helpers.waitAndClick(driver, {id: "ready_link"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: a.yt-uix-tile-link
  describe("youtube", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://www.youtube.com");
      helpers.waitAndClick(driver, {css: "a.yt-uix-tile-link"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .station_anchor
  describe("jango", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.jango.com");
      helpers.waitAndClick(driver, {className: "station_anchor"});
      done();
    });

    // Ad popup might mess up driver
    after(function(done) {
      driver.sleep(5000).then(function() {
        done();
      });
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  describe("NPR one", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://one.npr.org");
      done();
    });

    // Ad popup might mess up driver
    after(function(done) {
      driver.sleep(5000).then(function() {
        done();
      });
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: td.logo_on, /search/
  describe("songstr", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://songstr.com/#!/search/The-Smiths");
      helpers.waitAndClick(driver, {css: "td.logo_on > img"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: body.dragdrop-dropTarget
  describe("sony music unlimited", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://music.sonyentertainmentnetwork.com/");
      // Wait for body to contain class that is added when webapp has loaded
      helpers.waitForSelector(driver, {css: "body.dragdrop-dropTarget"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .top-channel, .audio-buttons
  describe("earbits", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.earbits.com");
      helpers.waitAndClick(driver, {className: "top-channel"});
      helpers.waitForSelector(driver, {className: "audio-buttons"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .login_btn, .login_mail, .login_password, .login_form_submit, .player-controls
  describe("deezer", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.deezer.com");
      helpers.waitAndClick(driver, {id: "login_btn"});
      driver.wait(function() {
        return (driver.isElementPresent({id: "login_mail"}) &&
                driver.isElementPresent({id: "login_password"}) &&
                driver.isElementPresent({id: "login_form_submit"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "login_mail"}).sendKeys(secrets.deezer.username);
      driver.findElement({id: "login_password"}).sendKeys(secrets.deezer.password);
      driver.findElement({id: "login_form_submit"}).click();
      driver.wait(function() {
        return (driver.isElementPresent({className: "player-controls"}));
      }, WAIT_TIMEOUT);

      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: .genre-btn, .btn-primary, .player-controls, [@data-station-id]
  describe("iHeartRadio", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.iheart.com");
      helpers.waitAndClick(driver, {className: "genre-btn"});
      helpers.waitAndClick(driver, {className: "btn-primary"});
      helpers.waitForSelector(driver, {className: "player-controls"})
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #username, #password, [name=submit], .player_bottom, /account/signin/
  describe("rdio", function() {
    before(function(done) {
      helpers.getAndWait(driver, "https://www.rdio.com/account/signin/");
      driver.wait(function() {
        return (driver.isElementPresent({id: "username"}) &&
                driver.isElementPresent({id: "password"}) &&
                driver.isElementPresent({name: "submit"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "username"}).sendKeys(secrets.rdio.username);
      driver.findElement({id: "password"}).sendKeys(secrets.rdio.password);
      driver.findElement({name: "submit"}).click();
      helpers.waitForSelector(driver, {className: "player_bottom"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: a.mix_name, a#play_overlay
  describe("8tracks", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://www.8tracks.com");
      helpers.waitAndClick(driver, {css: "a.mix_name"});
      helpers.waitAndClick(driver, {css: "a#play_overlay"});
      done();
    })

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // @depends: #Email, #Passwd, #signIn, #player
  describe("googlemusic", function() {
    before(function(done) {
      helpers.getAndWait(driver, "http://music.google.com");
      driver.wait(function() {
        return (driver.isElementPresent({id: "Email"}) &&
                driver.isElementPresent({id: "Passwd"}));
      }, WAIT_TIMEOUT);
      driver.findElement({id: "Email"}).sendKeys(secrets.googlemusic.username);
      driver.findElement({id: "Passwd"}).sendKeys(secrets.googlemusic.password);
      helpers.waitAndClick(driver, {id: "signIn"});
      helpers.waitForSelector(driver, {id: "player"});
      done();
    });

    shared.shouldBehaveLikeAMusicSite(driver, false);
  });

  // // Strange bug here with webdriver messing up reading the console output
  // //@depends: #username, #password, [name=submit], .player_bottom, /account/signin/
  // describe("vk", function() {
  //   before(function(done) {
  //     helpers.getAndWait(driver, "http://www.vk.com").then(function() {
  //       driver.wait(function() {
  //         return (driver.isElementPresent({id: "quick_email"}) &&
  //                 driver.isElementPresent({id: "quick_pass"}) &&
  //                 driver.isElementPresent({id: "quick_login_button"}));
  //       }, WAIT_TIMEOUT);
  //       driver.findElement({id: "quick_email"}).sendKeys(secrets.vk.username);
  //       driver.findElement({id: "quick_pass"}).sendKeys(secrets.vk.password);
  //       driver.findElement({id: "quick_login_button"}).click();
  //       helpers.waitForSelector(driver, {id: "head_music"});
  //       done();
  //     });
  //   });

  //   shared.shouldBehaveLikeAMusicSite(driver, false);
  // });

  // // Iframes are too anoying
  // describe("spotify", function() {
  //   before(function(done) {
  //     helpers.getAndWait(driver, "https://play.spotify.com/");
  //     driver.findElement({id: "has-account"}).click();
  //     driver.wait(function() {
  //       return (driver.isElementPresent({id: "login-usr"}) &&
  //               driver.isElementPresent({id: "login-pass"}) &&
  //               driver.isElementPresent({css: "button[type=submit]"}));
  //     }, WAIT_TIMEOUT);
  //     driver.findElement({id: "login-usr"}).sendKeys(secrets.spotify.username);
  //     driver.findElement({id: "login-pass"}).sendKeys(secrets.spotify.password);
  //     driver.findElement({css: "button[type=submit]"}).click();
  //     driver.wait(function() {
  //       return (driver.isElementPresent({css: ".root > iframe"}));
  //     }, WAIT_TIMEOUT);
  //     driver.switchTo().frame(driver.findElement({css: ".root > iframe"})).then(function() {
  //       driver.wait(function() {
  //         console.log("wait for playback");
  //         return (driver.isElementPresent({className: "media-object-playlist"}));
  //       }, WAIT_TIMEOUT)
  //       .then(function() {
  //         driver.sleep(1000).then(function() {
  //           driver.findElement({className: "media-object-playlist"}).click().then(function() {
  //             console.log("clicked it");
  //             driver.wait(function() {
  //               return (driver.isElementPresent({className: "btn-play-text"}));
  //             });
  //             driver.findElement({className: "btn-play-text"}).click().then(function() {
  //               driver.switchTo().defaultContent().then(function() {
  //                 driver.sleep(2000).then(function(){done();});
  //               });
  //             })
  //           });
  //         });
  //       });
  //     });
  //   });

  //   shared.shouldBehaveLikeAMusicSite(driver, false);
  // });
});
<|endoftext|>


<commit_before>var http = require('http');
var ServerResponse = http.ServerResponse;
var parsers = http.parsers;
var insertHeaders = require('./lib/insert_headers');

var net = require('net');

var bouncy = module.exports = function (cb) {
    return net.createServer(handler.bind(null, cb));
};

var handler = bouncy.handler = function (cb, c) {
    var parser = parsers.alloc();
    parser.reinitialize('request');
    parser.socket = c;
    parser.incoming = null;

    var request = null;
    parser.onIncoming = function (req, shouldKeepAlive) {
        request = req;
    };

    var buffers = [];
    var bufSize = 0;

    function respond (req, bytesInHeader) {
        var bufs = buffers;
        buffers = [];
        bufSize = 0;
        var headers = null;

        if (req.upgrade) {
            req.pause();
        }
        else {
            req.socket.pause();
        }

        var bounce = function (stream, y) {
            if (!stream || !stream.write) {
                stream = parseArgs(stream, y);
            }

            if (headers) {
                bytesInHeader += insertHeaders(bufs, headers);
            }

            var written = 0;

            for (var i = 0; i < bufs.length; i++) {
                var buf = bufs[i];

                if (written + buf.length > bytesInHeader) {
                    stream.write(buf.slice(0, bytesInHeader - written));
                    break;
                }
                else {
                    stream.write(buf);
                    written += buf.length;
                }
            }

            if (req.upgrade) {
                req.socket.pipe(stream);
                stream.pipe(c);
                req.socket.resume();
            }
            else {
                req.pipe(stream);
                stream.pipe(c);
                req.resume();
            }
        };

        bounce.respond = function () {
            var res = new ServerResponse(req);
            res.assignSocket(req.socket);
            return res;
        };

        bounce.addHeader = function (key, value) {
            if (!headers) headers = {};
            headers[key] = value;
        };

        cb(req, bounce);
    };

    c.on('data', function onData (buf) {
        buffers.push(buf);
        bufSize += buf.length;

        var ret = parser.execute(buf, 0, buf.length);
        if (ret instanceof Error) {
            c.destroy();
        }
        else if (parser.incoming && parser.incoming.upgrade) {
            c.removeListener('data', onData);
            respond(parser.incoming, bufSize);
            buffers = [];
            bufSize = 0;
        }
        else if (request) {
            respond(request, ret);
            request = null;
        }
    });

    c.on('close', function () {
        parsers.free(parser);
    });

    c.on('end', function () {
        parser.finish();
        c.destroy();
    });
};

function parseArgs (x, y) {
    if (typeof x === 'string' && typeof y === 'number') {
        // flip host and port
        return net.createConnection(y, x);
    }
    else if (typeof x === 'string' && typeof y === 'string'
    && /^\d+$/.test(y)) {
        // convert string port to number
        return net.createConnection(parseInt(y,10), x);
    }
    else if (typeof x === 'string' && typeof y === 'string'
    && /^\d+$/.test(x)) {
        // convert string port to number, flipped
        return net.createConnection(parseInt(x,10), y);
    }
    else if (y) {
        return net.createConnection(x, y);
    }
    else {
        return net.createConnection(x);
    }
}
<commit_msg>implemented the new headers interface, all tests pass<commit_after>var http = require('http');
var ServerResponse = http.ServerResponse;
var parsers = http.parsers;
var insertHeaders = require('./lib/insert_headers');

var net = require('net');

var bouncy = module.exports = function (cb) {
    return net.createServer(handler.bind(null, cb));
};

var handler = bouncy.handler = function (cb, c) {
    var parser = parsers.alloc();
    parser.reinitialize('request');
    parser.socket = c;
    parser.incoming = null;

    var request = null;
    parser.onIncoming = function (req, shouldKeepAlive) {
        request = req;
    };

    var buffers = [];
    var bufSize = 0;

    function respond (req, bytesInHeader) {
        var bufs = buffers;
        buffers = [];
        bufSize = 0;

        if (req.upgrade) {
            req.pause();
        }
        else {
            req.socket.pause();
        }

        var bounce = function (stream, opts) {
            if (!stream || !stream.write) {
                opts = parseArgs(arguments);
                stream = opts.stream;
            }
            if (!opts) opts = {};

            if (opts.headers) {
                bytesInHeader += insertHeaders(bufs, opts.headers);
            }

            var written = 0;

            for (var i = 0; i < bufs.length; i++) {
                var buf = bufs[i];

                if (written + buf.length > bytesInHeader) {
                    stream.write(buf.slice(0, bytesInHeader - written));
                    break;
                }
                else {
                    stream.write(buf);
                    written += buf.length;
                }
            }

            if (req.upgrade) {
                req.socket.pipe(stream);
                stream.pipe(c);
                req.socket.resume();
            }
            else {
                req.pipe(stream);
                stream.pipe(c);
                req.resume();
            }
        };

        bounce.respond = function () {
            var res = new ServerResponse(req);
            res.assignSocket(req.socket);
            return res;
        };

        cb(req, bounce);
    };

    c.on('data', function onData (buf) {
        buffers.push(buf);
        bufSize += buf.length;

        var ret = parser.execute(buf, 0, buf.length);
        if (ret instanceof Error) {
            c.destroy();
        }
        else if (parser.incoming && parser.incoming.upgrade) {
            c.removeListener('data', onData);
            respond(parser.incoming, bufSize);
            buffers = [];
            bufSize = 0;
        }
        else if (request) {
            respond(request, ret);
            request = null;
        }
    });

    c.on('close', function () {
        parsers.free(parser);
    });

    c.on('end', function () {
        parser.finish();
        c.destroy();
    });
};

function parseArgs (args) {
    var opts = {};

    for (var i = 0; i < args.length; i++) {
        var arg = args[i];

        if (typeof arg === 'number') {
            opts.port = arg;
        }
        else if (typeof arg === 'string') {
            if (/^\d+$/.test(arg)) opts.port = parseInt(arg, 10)
            else if (/\//.test(arg)) opts.unix = arg
            else opts.host = arg;
        }
        else if (typeof arg === 'object') {
            if (arg.write) opts.stream = arg;
            else {
                for (var key in arg) {
                    opts[key] = arg[key]
                }
            }
        }
    }

    if (!opts.stream) {
        if (opts.unix) {
            opts.stream = net.createConnection(opts.unix);
        }
        else if (opts.host && opts.port) {
            opts.stream = net.createConnection(opts.port, opts.host);
        }
        else if (opts.port) {
            opts.stream = net.createConnection(opts.port);
        }
    }

    return opts;
}
<|endoftext|>


<commit_before>// Description:
//   Have Hubot remind you to do standups.
//   hh:mm must be in the same timezone as the server Hubot is on. Probably UTC.
//
//   This is configured to work for Hipchat. You may need to change the 'create standup' command
//   to match the adapter you're using.

//
// Commands:
//   hubot standup help - See a help document explaining how to use.
//   hubot create standup hh:mm - Creates a standup at hh:mm every weekday for this room
//   hubot list standups - See all standups for this room
//   hubot list standups in every room - See all standups in every room
//   hubot delete hh:mm standup - If you have a standup at hh:mm, deletes it
//   hubot delete all standups - Deletes all standups for this room.
//
// Dependencies:
//   underscore
//   cron

var cronJob = require('cron').CronJob;
var _ = require('underscore');

module.exports = function(robot) {

    // Constants.
    var STANDUP_MESSAGES = [
        "Standup time!",
        "Time for standup, y'all.",
        "It's standup time once again!",
        "Get up, stand up (it's time for our standup)",
        "Standup time. Get up, humans",
        "Standup time! Now! Go go go!"
    ];

    // Check for standups that need to be fired, once a minute
    // Monday to Friday.
    var standupClock = new cronJob('1 * * * * 1-5', function() {
        checkStandups();
    }, null, true);

    // Compares current time to the time of the standup
    // to see if it should be fired.
    function standupShouldFire(standupTime) {
        var now = new Date();
        var currentHours = now.getHours();
        var currentMinutes = now.getMinutes();

        var standupHours = standupTime.split(':')[0];
        var standupMinutes = standupTime.split(':')[1];

        try {
            standupHours = parseInt(standupHours);
            standupMinutes = parseInt(standupMinutes);
        }
        catch (_error) {
            return false;
        }

        if (standupHours == currentHours && standupMinutes == currentMinutes) {
            return true;
        }
        return false;
    }

    // Returns all standups.
    function getStandups() {
        return robot.brain.get('standups') || [];
    }

    // Returns just standups for a given room.
    function getStandupsForRoom(room) {
        var allStandups = getStandups();
        var standupsForRoom = [];
        _.each(allStandups, function(standup) {
            if (standup.room == room) {
                standupsForRoom.push(standup);
            }
        });
        return standupsForRoom;
    }

    // Gets all standups, fires ones that should be.
    function checkStandups() {
        var standups = getStandups();

        _.each(standups, function(standup) {
            if (standupShouldFire(standup.time)) {
                doStandup(standup.room);
            }
        });
    }

    // Fires the standup message.
    function doStandup(room) {
        var message = _.sample(STANDUP_MESSAGES);
        robot.messageRoom(room, message);
    }

    // Stores a standup in the brain.
    function saveStandup(room, time) {
        var standups = getStandups();
        var newStandup = {
            time: time,
            room: room
        };
        standups.push(newStandup);
        updateBrain(standups);
    }

    // Updates the brain's standup knowledge.
    function updateBrain(standups) {
        robot.brain.set('standups', standups);
    }

    function clearAllStandupsForRoom(room) {
        var standups = getStandups();
        var standupsToKeep = [];
        var standupsRemoved = 0;
        _.each(standups, function(standup) {
           if (standup.room != room) {
               standupsToKeep.push(standup);
           }
           else {
               standupsRemoved++;
           }
        });
        updateBrain(standupsToKeep);
        return standupsRemoved;
    }

    function clearSpecificStandupForRoom(room, time) {
        var standups = getStandups();
        var standupsToKeep = [];
        var standupsRemoved = 0;
        _.each(standups, function(standup) {
            if (standup.room == room && standup.time == time) {
                standupsRemoved++;
            }
            else {
                standupsToKeep.push(standup);
            }
        });
        updateBrain(standupsToKeep);
        return standupsRemoved;
    }

    robot.respond(/delete all standups/i, function(msg) {
        var standupsCleared = clearAllStandupsForRoom(msg.envelope.user.room);
        msg.send('Deleted ' + standupsCleared + ' standup' + (standupsCleared === 1 ? '' : 's') + '. No more standups for you.');
    });

    robot.respond(/delete ([0-5]?[0-9]:[0-5]?[0-9]) standup/i, function(msg) {
        var time = msg.match[1]
        var standupsCleared = clearSpecificStandupForRoom(msg.envelope.user.room, time);
        if (standupsCleared === 0) {
            msg.send("Nice try. You don't even have a standup at " + time);
        }
        else {
            msg.send("Deleted your " + time + " standup.");
        }
    });

    robot.respond(/create standup ([0-5]?[0-9]:[0-5]?[0-9])$/i, function(msg) {
        var time = msg.match[1];

        // NOTE: This works for Hipchat. You may need to change this line to
        // match your adapter. 'room' must be saved in a format that will
        // work with the robot.messageRoom function.
        var room = msg.envelope.user.room;

        saveStandup(room, time);
        msg.send("Ok, from now on I'll remind this room to do a standup every weekday at " + time);
    });

    robot.respond(/list standups$/i, function(msg) {
        console.log(robot.adapter);
        var standups = getStandupsForRoom(msg.envelope.user.room);

        if (standups.length === 0) {
            msg.send("Well this is awkward. You haven't got any standups set :-/");
        }
        else {
            var standupsText = [];
            standupsText.push("Here's your standups:");
            _.each(standups, function (standup) {
                standupsText.push(standup.time);
            });
            msg.send(standupsText.join('\n'));
        }
    });

    robot.respond(/list standups in every room/i, function(msg) {
        var standups = getStandups();
        if (standups.length === 0) {
            msg.send("No, because there aren't any.");
        }
        else {
            var standupsText = [];
            standupsText.push("Here's the standups for every room:");
            _.each(standups, function (standup) {
                standupsText.push('Room: ' + standup.room + ', Time: ' + standup.time);
            });
            msg.send(standupsText.join('\n'));
        }
    });

    robot.respond(/standup help/i, function(msg) {
        var message = [];
        message.push("I can remind you to do your daily standup!");
        message.push("Use me to create a standup, and then I'll post in this room every weekday at the time you specify. Here's how:");
        message.push("");
        message.push(robot.name + " create standup hh:mm - I'll remind you to standup in this room at hh:mm every weekday.");
        message.push(robot.name + " list standups - See all standups for this room.");
        message.push(robot.name + " list standups in every room - Be nosey and see when other rooms have their standup.");
        message.push(robot.name + " delete hh:mm standup - If you have a standup at hh:mm, I'll delete it.");
        message.push(robot.name + " delete all standups - Deletes all standups for this room.");
        msg.send(message.join('\n'));
    });
};
<commit_msg>more debugging on room name<commit_after>// Description:
//   Have Hubot remind you to do standups.
//   hh:mm must be in the same timezone as the server Hubot is on. Probably UTC.
//
//   This is configured to work for Hipchat. You may need to change the 'create standup' command
//   to match the adapter you're using.

//
// Commands:
//   hubot standup help - See a help document explaining how to use.
//   hubot create standup hh:mm - Creates a standup at hh:mm every weekday for this room
//   hubot list standups - See all standups for this room
//   hubot list standups in every room - See all standups in every room
//   hubot delete hh:mm standup - If you have a standup at hh:mm, deletes it
//   hubot delete all standups - Deletes all standups for this room.
//
// Dependencies:
//   underscore
//   cron

var cronJob = require('cron').CronJob;
var _ = require('underscore');

module.exports = function(robot) {

    // Constants.
    var STANDUP_MESSAGES = [
        "Standup time!",
        "Time for standup, y'all.",
        "It's standup time once again!",
        "Get up, stand up (it's time for our standup)",
        "Standup time. Get up, humans",
        "Standup time! Now! Go go go!"
    ];

    // Check for standups that need to be fired, once a minute
    // Monday to Friday.
    var standupClock = new cronJob('1 * * * * 1-5', function() {
        checkStandups();
    }, null, true);

    // Compares current time to the time of the standup
    // to see if it should be fired.
    function standupShouldFire(standupTime) {
        var now = new Date();
        var currentHours = now.getHours();
        var currentMinutes = now.getMinutes();

        var standupHours = standupTime.split(':')[0];
        var standupMinutes = standupTime.split(':')[1];

        try {
            standupHours = parseInt(standupHours);
            standupMinutes = parseInt(standupMinutes);
        }
        catch (_error) {
            return false;
        }

        if (standupHours == currentHours && standupMinutes == currentMinutes) {
            return true;
        }
        return false;
    }

    // Returns all standups.
    function getStandups() {
        return robot.brain.get('standups') || [];
    }

    // Returns just standups for a given room.
    function getStandupsForRoom(room) {
        var allStandups = getStandups();
        var standupsForRoom = [];
        _.each(allStandups, function(standup) {
            if (standup.room == room) {
                standupsForRoom.push(standup);
            }
        });
        return standupsForRoom;
    }

    // Gets all standups, fires ones that should be.
    function checkStandups() {
        var standups = getStandups();

        _.each(standups, function(standup) {
            if (standupShouldFire(standup.time)) {
                doStandup(standup.room);
            }
        });
    }

    // Fires the standup message.
    function doStandup(room) {
        var message = _.sample(STANDUP_MESSAGES);
        robot.messageRoom(room, message);
    }

    // Stores a standup in the brain.
    function saveStandup(room, time) {
        var standups = getStandups();
        var newStandup = {
            time: time,
            room: room
        };
        standups.push(newStandup);
        updateBrain(standups);
    }

    // Updates the brain's standup knowledge.
    function updateBrain(standups) {
        robot.brain.set('standups', standups);
    }

    function clearAllStandupsForRoom(room) {
        var standups = getStandups();
        var standupsToKeep = [];
        var standupsRemoved = 0;
        _.each(standups, function(standup) {
           if (standup.room != room) {
               standupsToKeep.push(standup);
           }
           else {
               standupsRemoved++;
           }
        });
        updateBrain(standupsToKeep);
        return standupsRemoved;
    }

    function clearSpecificStandupForRoom(room, time) {
        var standups = getStandups();
        var standupsToKeep = [];
        var standupsRemoved = 0;
        _.each(standups, function(standup) {
            if (standup.room == room && standup.time == time) {
                standupsRemoved++;
            }
            else {
                standupsToKeep.push(standup);
            }
        });
        updateBrain(standupsToKeep);
        return standupsRemoved;
    }

    robot.respond(/delete all standups/i, function(msg) {
        var standupsCleared = clearAllStandupsForRoom(msg.envelope.user.room);
        msg.send('Deleted ' + standupsCleared + ' standup' + (standupsCleared === 1 ? '' : 's') + '. No more standups for you.');
    });

    robot.respond(/delete ([0-5]?[0-9]:[0-5]?[0-9]) standup/i, function(msg) {
        var time = msg.match[1]
        var standupsCleared = clearSpecificStandupForRoom(msg.envelope.user.room, time);
        if (standupsCleared === 0) {
            msg.send("Nice try. You don't even have a standup at " + time);
        }
        else {
            msg.send("Deleted your " + time + " standup.");
        }
    });

    robot.respond(/create standup ([0-5]?[0-9]:[0-5]?[0-9])$/i, function(msg) {
        var time = msg.match[1];

        // NOTE: This works for Hipchat. You may need to change this line to
        // match your adapter. 'room' must be saved in a format that will
        // work with the robot.messageRoom function.
        var room = msg.envelope.user.room;

        saveStandup(room, time);
        msg.send("Ok, from now on I'll remind this room to do a standup every weekday at " + time);
    });

    robot.respond(/list standups$/i, function(msg) {
        room = msg.envelope.user.room;
        console.log("HAI");
        console.log(robot.adapter);
        console.log(room);
        var standups = getStandupsForRoom(room);

        if (standups.length === 0) {
            msg.send("Well this is awkward. You haven't got any standups set for" + room + " :-/");
        }
        else {
            var standupsText = [];
            standupsText.push("Here's your standups:");
            _.each(standups, function (standup) {
                standupsText.push(standup.time);
            });
            msg.send(standupsText.join('\n'));
        }
    });

    robot.respond(/list standups in every room/i, function(msg) {
        var standups = getStandups();
        if (standups.length === 0) {
            msg.send("No, because there aren't any.");
        }
        else {
            var standupsText = [];
            standupsText.push("Here's the standups for every room:");
            _.each(standups, function (standup) {
                standupsText.push('Room: ' + standup.room + ', Time: ' + standup.time);
            });
            msg.send(standupsText.join('\n'));
        }
    });

    robot.respond(/standup help/i, function(msg) {
        var message = [];
        message.push("I can remind you to do your daily standup!");
        message.push("Use me to create a standup, and then I'll post in this room every weekday at the time you specify. Here's how:");
        message.push("");
        message.push(robot.name + " create standup hh:mm - I'll remind you to standup in this room at hh:mm every weekday.");
        message.push(robot.name + " list standups - See all standups for this room.");
        message.push(robot.name + " list standups in every room - Be nosey and see when other rooms have their standup.");
        message.push(robot.name + " delete hh:mm standup - If you have a standup at hh:mm, I'll delete it.");
        message.push(robot.name + " delete all standups - Deletes all standups for this room.");
        msg.send(message.join('\n'));
    });
};
<|endoftext|>