<commit_before>import { editorCss } from './styles/editor'
import { injectCss } from './styles/injector'
import { defaultCssTheme } from './styles/theme-default'
import { escapeHtml } from './utils/html-escape'
import Prism from 'prismjs'

export default class CodeFlask {
  constructor (selectorOrElement, opts) {
    if (!selectorOrElement) {
      // If no selector or element is passed to CodeFlask,
      // stop execution and throw error.
      throw Error('CodeFlask expects a parameter which is Element or a String selector')
    }

    if (!opts) {
      // If no selector or element is passed to CodeFlask,
      // stop execution and throw error.
      throw Error('CodeFlask expects an object containing options as second parameter')
    }

    if (selectorOrElement.nodeType) {
      // If it is an element, assign it directly
      this.editorRoot = selectorOrElement
    } else {
      // If it is a selector, tries to find element
      const editorRoot = document.querySelector(selectorOrElement)

      // If an element is found using this selector,
      // assign this element as the root element
      if (editorRoot) {
        this.editorRoot = editorRoot
      }
    }

    this.opts = opts
    this.startEditor()
  }

  startEditor () {
    const isCSSInjected = injectCss(editorCss, null, this.opts.styleParent)

    if (!isCSSInjected) {
      throw Error('Failed to inject CodeFlask CSS.')
    }

    // The order matters (pre > code). Don't change it
    // or things are going to break.
    this.createWrapper()
    this.createTextarea()
    this.createPre()
    this.createCode()

    this.runOptions()
    this.listenTextarea()
    this.populateDefault()
    this.updateCode(this.code)
  }

  createWrapper () {
    this.code = this.editorRoot.innerHTML
    this.editorRoot.innerHTML = ''
    this.elWrapper = this.createElement('div', this.editorRoot)
    this.elWrapper.classList.add('codeflask')
  }

  createTextarea () {
    this.elTextarea = this.createElement('textarea', this.elWrapper)
    this.elTextarea.classList.add('codeflask__textarea', 'codeflask__flatten')
  }

  createPre () {
    this.elPre = this.createElement('pre', this.elWrapper)
    this.elPre.classList.add('codeflask__pre', 'codeflask__flatten')
  }

  createCode () {
    this.elCode = this.createElement('code', this.elPre)
    this.elCode.classList.add('codeflask__code', `language-${this.opts.language || 'html'}`)
  }

  createLineNumbers () {
    this.elLineNumbers = this.createElement('div', this.elWrapper)
    this.elLineNumbers.classList.add('codeflask__lines')
    this.setLineNumber()
  }

  createElement (elementTag, whereToAppend) {
    const element = document.createElement(elementTag)
    whereToAppend.appendChild(element)

    return element
  }

  runOptions () {
    this.opts.rtl = this.opts.rtl || false
    this.opts.tabSize = this.opts.tabSize || 2
    this.opts.enableAutocorrect = this.opts.enableAutocorrect || false
    this.opts.lineNumbers = this.opts.lineNumbers || false
    this.opts.defaultTheme = this.opts.defaultTheme !== false
    this.opts.areaId = this.opts.areaId || null
    this.opts.ariaLabelledby = this.opts.ariaLabelledby || null
    this.opts.readonly = this.opts.readonly || null

    // if handleTabs is not either true or false, make it true by default
    if (typeof this.opts.handleTabs !== 'boolean') {
      this.opts.handleTabs = true
    }

    if (this.opts.rtl === true) {
      this.elTextarea.setAttribute('dir', 'rtl')
      this.elPre.setAttribute('dir', 'rtl')
    }

    if (this.opts.enableAutocorrect === false) {
      this.elTextarea.setAttribute('spellcheck', 'false')
      this.elTextarea.setAttribute('autocapitalize', 'off')
      this.elTextarea.setAttribute('autocomplete', 'off')
      this.elTextarea.setAttribute('autocorrect', 'off')
    }

    if (this.opts.lineNumbers) {
      this.elWrapper.classList.add('codeflask--has-line-numbers')
      this.createLineNumbers()
    }

    if (this.opts.defaultTheme) {
      injectCss(defaultCssTheme, 'theme-default', this.opts.styleParent)
    }

    if (this.opts.areaId) {
      this.elTextarea.setAttribute('id', this.opts.areaId)
    }

    if (this.opts.ariaLabelledby) {
      this.elTextarea.setAttribute('aria-labelledby', this.opts.ariaLabelledby)
    }

    if (this.opts.readonly) {
      this.enableReadonlyMode()
    }
  }

  updateLineNumbersCount () {
    let numberList = ''

    for (let i = 1; i <= this.lineNumber; i++) {
      numberList = numberList + `<span class="codeflask__lines__line">${i}</span>`
    }

    this.elLineNumbers.innerHTML = numberList
  }

  listenTextarea () {
    this.elTextarea.addEventListener('input', (e) => {
      this.code = e.target.value
      this.elCode.innerHTML = escapeHtml(e.target.value)
      this.highlight()
      setTimeout(() => {
        this.runUpdate()
        this.setLineNumber()
      }, 1)
    })

    this.elTextarea.addEventListener('keydown', (e) => {
      this.handleTabs(e)
      this.handleSelfClosingCharacters(e)
      this.handleNewLineIndentation(e)
    })

    this.elTextarea.addEventListener('scroll', (e) => {
      this.elPre.style.transform = `translate3d(-${e.target.scrollLeft}px, -${e.target.scrollTop}px, 0)`
      if (this.elLineNumbers) {
        this.elLineNumbers.style.transform = `translate3d(0, -${e.target.scrollTop}px, 0)`
      }
    })
  }

  handleTabs (e) {
    if (this.opts.handleTabs) {
      if (e.keyCode !== 9) {
        return
      }
      e.preventDefault()

      var input = this.elTextarea
      var selectionDir = input.selectionDirection
      var selStartPos = input.selectionStart
      var selEndPos = input.selectionEnd
      var inputVal = input.value

      var beforeSelection = inputVal.substr(0, selStartPos)
      var selectionVal = inputVal.substring(selStartPos, selEndPos)
      var afterSelection = inputVal.substring(selEndPos)
      const indent = ' '.repeat(this.opts.tabSize)

      if (selStartPos !== selEndPos && selectionVal.length >= indent.length) {
        var currentLineStart = selStartPos - beforeSelection.split('\n').pop().length
        var startIndentLen = indent.length
        var endIndentLen = indent.length

        // Unindent
        if (e.shiftKey) {
          var currentLineStartStr = inputVal.substr(currentLineStart, indent.length)
          // Line start whit indent
          if (currentLineStartStr === indent) {
            startIndentLen = -startIndentLen

            if (currentLineStart > selStartPos) {
              // Indent is in selection
              selectionVal = selectionVal.substring(0, currentLineStart) + selectionVal.substring(currentLineStart + indent.length)
              endIndentLen = 0
            } else if (currentLineStart === selStartPos) {
              // Indent is in start of selection
              startIndentLen = 0
              endIndentLen = 0
              selectionVal = selectionVal.substring(indent.length)
            } else {
              // Indent is before selection
              endIndentLen = -endIndentLen
              beforeSelection = beforeSelection.substring(0, currentLineStart) + beforeSelection.substring(currentLineStart + indent.length)
            }
          } else {
            startIndentLen = 0
            endIndentLen = 0
          }

          selectionVal = selectionVal.replace(new RegExp('\n' + indent.split('').join('\\'), 'g'), '\n')
        } else {
          // Indent
          beforeSelection = beforeSelection.substr(0, currentLineStart) + indent + beforeSelection.substring(currentLineStart, selStartPos)
          selectionVal = selectionVal.replace(/\n/g, '\n' + indent)
        }

        // Set new indented value
        input.value = beforeSelection + selectionVal + afterSelection

        input.selectionStart = selStartPos + startIndentLen
        input.selectionEnd = selStartPos + selectionVal.length + endIndentLen
        input.selectionDirection = selectionDir
      } else {
        input.value = beforeSelection + indent + afterSelection
        input.selectionStart = selStartPos + indent.length
        input.selectionEnd = selStartPos + indent.length
      }

      var newCode = input.value
      this.updateCode(newCode)
      this.elTextarea.selectionEnd = selEndPos + this.opts.tabSize
    }
  }

  handleSelfClosingCharacters (e) {
    const openChars = ['(', '[', '{', '<']
    const key = e.key

    if (!openChars.includes(key)) {
      return
    }

    switch (key) {
      case '(':
        this.closeCharacter(')')
        break

      case '[':
        this.closeCharacter(']')
        break

      case '{':
        this.closeCharacter('}')
        break

      case '<':
        this.closeCharacter('>')
        break
    }
  }

  setLineNumber () {
    this.lineNumber = this.code.split('\n').length

    if (this.opts.lineNumbers) {
      this.updateLineNumbersCount()
    }
  }

  handleNewLineIndentation (e) {
    if (e.keyCode !== 13) {
      return
    }

    e.preventDefault()
    var input = this.elTextarea
    var selStartPos = input.selectionStart
    var selEndPos = input.selectionEnd
    var inputVal = input.value

    var beforeSelection = inputVal.substr(0, selStartPos)
    var afterSelection = inputVal.substring(selEndPos)

    var lineStart = inputVal.lastIndexOf('\n', selStartPos - 1)
    var spaceLast = lineStart + inputVal.slice(lineStart + 1).search(/[^ ]|$/)
    var indent = (spaceLast > lineStart) ? (spaceLast - lineStart) : 0
    var newCode = beforeSelection + '\n' + ' '.repeat(indent) + afterSelection

    input.value = newCode
    input.selectionStart = selStartPos + indent + 1
    input.selectionEnd = selStartPos + indent + 1

    this.updateCode(input.value)
  }

  closeCharacter (closeChar) {
    const selectionStart = this.elTextarea.selectionStart
    const selectionEnd = this.elTextarea.selectionEnd
    const newCode = `${this.code.substring(0, selectionStart)}${closeChar}${this.code.substring(selectionEnd)}`

    this.updateCode(newCode)
    this.elTextarea.selectionEnd = selectionEnd
  }

  updateCode (newCode) {
    this.code = newCode
    this.elTextarea.value = newCode
    this.elCode.innerHTML = escapeHtml(newCode)
    this.highlight()
    this.setLineNumber()
    setTimeout(this.runUpdate.bind(this), 1)
  }

  updateLanguage (newLanguage) {
    const oldLanguage = this.opts.language
    this.elCode.classList.remove(`language-${oldLanguage}`)
    this.elCode.classList.add(`language-${newLanguage}`)
    this.opts.language = newLanguage
    this.highlight()
  }

  addLanguage (name, options) {
    Prism.languages[name] = options
  }

  populateDefault () {
    this.updateCode(this.code)
  }

  highlight () {
    Prism.highlightElement(this.elCode, false)
  }

  onUpdate (callback) {
    if (callback && {}.toString.call(callback) !== '[object Function]') {
      throw Error('CodeFlask expects callback of type Function')
    }

    this.updateCallBack = callback
  }

  getCode () {
    return this.code
  }

  runUpdate () {
    if (this.updateCallBack) {
      this.updateCallBack(this.code)
    }
  }

  enableReadonlyMode () {
    this.elTextarea.setAttribute('readonly', true)
  }

  disableReadonlyMode () {
    this.elTextarea.removeAttribute('readonly')
  }
}
<commit_msg>wrap selected text on self closing chars<commit_after>import { editorCss } from './styles/editor'
import { injectCss } from './styles/injector'
import { defaultCssTheme } from './styles/theme-default'
import { escapeHtml } from './utils/html-escape'
import Prism from 'prismjs'

export default class CodeFlask {
  constructor (selectorOrElement, opts) {
    if (!selectorOrElement) {
      // If no selector or element is passed to CodeFlask,
      // stop execution and throw error.
      throw Error('CodeFlask expects a parameter which is Element or a String selector')
    }

    if (!opts) {
      // If no selector or element is passed to CodeFlask,
      // stop execution and throw error.
      throw Error('CodeFlask expects an object containing options as second parameter')
    }

    if (selectorOrElement.nodeType) {
      // If it is an element, assign it directly
      this.editorRoot = selectorOrElement
    } else {
      // If it is a selector, tries to find element
      const editorRoot = document.querySelector(selectorOrElement)

      // If an element is found using this selector,
      // assign this element as the root element
      if (editorRoot) {
        this.editorRoot = editorRoot
      }
    }

    this.opts = opts
    this.startEditor()
  }

  startEditor () {
    const isCSSInjected = injectCss(editorCss, null, this.opts.styleParent)

    if (!isCSSInjected) {
      throw Error('Failed to inject CodeFlask CSS.')
    }

    // The order matters (pre > code). Don't change it
    // or things are going to break.
    this.createWrapper()
    this.createTextarea()
    this.createPre()
    this.createCode()

    this.runOptions()
    this.listenTextarea()
    this.populateDefault()
    this.updateCode(this.code)
  }

  createWrapper () {
    this.code = this.editorRoot.innerHTML
    this.editorRoot.innerHTML = ''
    this.elWrapper = this.createElement('div', this.editorRoot)
    this.elWrapper.classList.add('codeflask')
  }

  createTextarea () {
    this.elTextarea = this.createElement('textarea', this.elWrapper)
    this.elTextarea.classList.add('codeflask__textarea', 'codeflask__flatten')
  }

  createPre () {
    this.elPre = this.createElement('pre', this.elWrapper)
    this.elPre.classList.add('codeflask__pre', 'codeflask__flatten')
  }

  createCode () {
    this.elCode = this.createElement('code', this.elPre)
    this.elCode.classList.add('codeflask__code', `language-${this.opts.language || 'html'}`)
  }

  createLineNumbers () {
    this.elLineNumbers = this.createElement('div', this.elWrapper)
    this.elLineNumbers.classList.add('codeflask__lines')
    this.setLineNumber()
  }

  createElement (elementTag, whereToAppend) {
    const element = document.createElement(elementTag)
    whereToAppend.appendChild(element)

    return element
  }

  runOptions () {
    this.opts.rtl = this.opts.rtl || false
    this.opts.tabSize = this.opts.tabSize || 2
    this.opts.enableAutocorrect = this.opts.enableAutocorrect || false
    this.opts.lineNumbers = this.opts.lineNumbers || false
    this.opts.defaultTheme = this.opts.defaultTheme !== false
    this.opts.areaId = this.opts.areaId || null
    this.opts.ariaLabelledby = this.opts.ariaLabelledby || null
    this.opts.readonly = this.opts.readonly || null

    // if handleTabs is not either true or false, make it true by default
    if (typeof this.opts.handleTabs !== 'boolean') {
      this.opts.handleTabs = true
    }

    if (this.opts.rtl === true) {
      this.elTextarea.setAttribute('dir', 'rtl')
      this.elPre.setAttribute('dir', 'rtl')
    }

    if (this.opts.enableAutocorrect === false) {
      this.elTextarea.setAttribute('spellcheck', 'false')
      this.elTextarea.setAttribute('autocapitalize', 'off')
      this.elTextarea.setAttribute('autocomplete', 'off')
      this.elTextarea.setAttribute('autocorrect', 'off')
    }

    if (this.opts.lineNumbers) {
      this.elWrapper.classList.add('codeflask--has-line-numbers')
      this.createLineNumbers()
    }

    if (this.opts.defaultTheme) {
      injectCss(defaultCssTheme, 'theme-default', this.opts.styleParent)
    }

    if (this.opts.areaId) {
      this.elTextarea.setAttribute('id', this.opts.areaId)
    }

    if (this.opts.ariaLabelledby) {
      this.elTextarea.setAttribute('aria-labelledby', this.opts.ariaLabelledby)
    }

    if (this.opts.readonly) {
      this.enableReadonlyMode()
    }
  }

  updateLineNumbersCount () {
    let numberList = ''

    for (let i = 1; i <= this.lineNumber; i++) {
      numberList = numberList + `<span class="codeflask__lines__line">${i}</span>`
    }

    this.elLineNumbers.innerHTML = numberList
  }

  listenTextarea () {
    this.elTextarea.addEventListener('input', (e) => {
      this.code = e.target.value
      this.elCode.innerHTML = escapeHtml(e.target.value)
      this.highlight()
      setTimeout(() => {
        this.runUpdate()
        this.setLineNumber()
      }, 1)
    })

    this.elTextarea.addEventListener('keydown', (e) => {
      this.handleTabs(e)
      this.handleSelfClosingCharacters(e)
      this.handleNewLineIndentation(e)
    })

    this.elTextarea.addEventListener('scroll', (e) => {
      this.elPre.style.transform = `translate3d(-${e.target.scrollLeft}px, -${e.target.scrollTop}px, 0)`
      if (this.elLineNumbers) {
        this.elLineNumbers.style.transform = `translate3d(0, -${e.target.scrollTop}px, 0)`
      }
    })
  }

  handleTabs (e) {
    if (this.opts.handleTabs) {
      if (e.keyCode !== 9) {
        return
      }
      e.preventDefault()

      var input = this.elTextarea
      var selectionDir = input.selectionDirection
      var selStartPos = input.selectionStart
      var selEndPos = input.selectionEnd
      var inputVal = input.value

      var beforeSelection = inputVal.substr(0, selStartPos)
      var selectionVal = inputVal.substring(selStartPos, selEndPos)
      var afterSelection = inputVal.substring(selEndPos)
      const indent = ' '.repeat(this.opts.tabSize)

      if (selStartPos !== selEndPos && selectionVal.length >= indent.length) {
        var currentLineStart = selStartPos - beforeSelection.split('\n').pop().length
        var startIndentLen = indent.length
        var endIndentLen = indent.length

        // Unindent
        if (e.shiftKey) {
          var currentLineStartStr = inputVal.substr(currentLineStart, indent.length)
          // Line start whit indent
          if (currentLineStartStr === indent) {
            startIndentLen = -startIndentLen

            if (currentLineStart > selStartPos) {
              // Indent is in selection
              selectionVal = selectionVal.substring(0, currentLineStart) + selectionVal.substring(currentLineStart + indent.length)
              endIndentLen = 0
            } else if (currentLineStart === selStartPos) {
              // Indent is in start of selection
              startIndentLen = 0
              endIndentLen = 0
              selectionVal = selectionVal.substring(indent.length)
            } else {
              // Indent is before selection
              endIndentLen = -endIndentLen
              beforeSelection = beforeSelection.substring(0, currentLineStart) + beforeSelection.substring(currentLineStart + indent.length)
            }
          } else {
            startIndentLen = 0
            endIndentLen = 0
          }

          selectionVal = selectionVal.replace(new RegExp('\n' + indent.split('').join('\\'), 'g'), '\n')
        } else {
          // Indent
          beforeSelection = beforeSelection.substr(0, currentLineStart) + indent + beforeSelection.substring(currentLineStart, selStartPos)
          selectionVal = selectionVal.replace(/\n/g, '\n' + indent)
        }

        // Set new indented value
        input.value = beforeSelection + selectionVal + afterSelection

        input.selectionStart = selStartPos + startIndentLen
        input.selectionEnd = selStartPos + selectionVal.length + endIndentLen
        input.selectionDirection = selectionDir
      } else {
        input.value = beforeSelection + indent + afterSelection
        input.selectionStart = selStartPos + indent.length
        input.selectionEnd = selStartPos + indent.length
      }

      var newCode = input.value
      this.updateCode(newCode)
      this.elTextarea.selectionEnd = selEndPos + this.opts.tabSize
    }
  }

  handleSelfClosingCharacters (e) {
    const openChars = ['(', '[', '{', '<', '\'', '"']
    const key = e.key

    if (!openChars.includes(key)) {
      return
    }

    switch (key) {
      case '(':
        this.closeCharacter(')')
        break

      case '[':
        this.closeCharacter(']')
        break

      case '{':
        this.closeCharacter('}')
        break

      case '<':
        this.closeCharacter('>')
        break

      case '\'':
        this.closeCharacter('\'')
        break

      case '"':
        this.closeCharacter('"')
        break
    }
  }

  setLineNumber () {
    this.lineNumber = this.code.split('\n').length

    if (this.opts.lineNumbers) {
      this.updateLineNumbersCount()
    }
  }

  handleNewLineIndentation (e) {
    if (e.keyCode !== 13) {
      return
    }

    e.preventDefault()
    var input = this.elTextarea
    var selStartPos = input.selectionStart
    var selEndPos = input.selectionEnd
    var inputVal = input.value

    var beforeSelection = inputVal.substr(0, selStartPos)
    var afterSelection = inputVal.substring(selEndPos)

    var lineStart = inputVal.lastIndexOf('\n', selStartPos - 1)
    var spaceLast = lineStart + inputVal.slice(lineStart + 1).search(/[^ ]|$/)
    var indent = (spaceLast > lineStart) ? (spaceLast - lineStart) : 0
    var newCode = beforeSelection + '\n' + ' '.repeat(indent) + afterSelection

    input.value = newCode
    input.selectionStart = selStartPos + indent + 1
    input.selectionEnd = selStartPos + indent + 1

    this.updateCode(input.value)
  }

  closeCharacter (closeChar) {
    const selectionStart = this.elTextarea.selectionStart
    const selectionEnd = this.elTextarea.selectionEnd
    const selectionText = this.code.substring(selectionStart, selectionEnd)
    const newCode = `${this.code.substring(0, selectionStart)}${selectionText}${closeChar}${this.code.substring(selectionEnd)}`

    this.updateCode(newCode)
    this.elTextarea.selectionEnd = selectionStart
  }

  updateCode (newCode) {
    this.code = newCode
    this.elTextarea.value = newCode
    this.elCode.innerHTML = escapeHtml(newCode)
    this.highlight()
    this.setLineNumber()
    setTimeout(this.runUpdate.bind(this), 1)
  }

  updateLanguage (newLanguage) {
    const oldLanguage = this.opts.language
    this.elCode.classList.remove(`language-${oldLanguage}`)
    this.elCode.classList.add(`language-${newLanguage}`)
    this.opts.language = newLanguage
    this.highlight()
  }

  addLanguage (name, options) {
    Prism.languages[name] = options
  }

  populateDefault () {
    this.updateCode(this.code)
  }

  highlight () {
    Prism.highlightElement(this.elCode, false)
  }

  onUpdate (callback) {
    if (callback && {}.toString.call(callback) !== '[object Function]') {
      throw Error('CodeFlask expects callback of type Function')
    }

    this.updateCallBack = callback
  }

  getCode () {
    return this.code
  }

  runUpdate () {
    if (this.updateCallBack) {
      this.updateCallBack(this.code)
    }
  }

  enableReadonlyMode () {
    this.elTextarea.setAttribute('readonly', true)
  }

  disableReadonlyMode () {
    this.elTextarea.removeAttribute('readonly')
  }
}
<|endoftext|>


<commit_before>define('table2chart', function () {

    function tableDomAdapter(table) {
        return {
            getCaption: function () {
                return table.children[0].textContent;
            },
            __getHead: function () {
                return table.children[1];
            },
            __getBody: function () {
                return table.children[2];
            },
            __getHeaderLine: function () {
                return this.__getHead().children[0];
            },
            __getLine: function (index) {
                return this.__getBody().children[index];
            },
            getColumnCount: function () {
                return this.__getHeaderLine().childElementCount;
            },
            getLineCount: function () {
                return this.__getBody().childElementCount;
            },
            getHeaderCell: function (index) {
                var cell = {};

                var domCell = this.__getHeaderLine().children[index];

                cell.label = domCell.textContent;

                cell.dataType = domCell.getAttribute('data-t2c-type');

                if (cell.dataType === 'number') {
                    cell.converter = parseFloat;
                } else if (cell.dataType === 'string') {
                    cell.converter = null;
                } else {
                    //default
                    cell.converter = null;
                }

                return cell;
            },
            getDataCell: function (lineIndex, columnIndex) {
                var header = this.getHeaderCell(columnIndex);
                var line = this.__getLine(lineIndex);
                var td = line.children[columnIndex];
                var retval = td.textContent;
                if (header.converter) {
                    retval = header.converter(retval);
                }
                return retval;
            },

            toGoogleDataTable: function () {
                var googleDataTable = new google.visualization.DataTable();

                var converters = [];

                var columnIndex;

                for (columnIndex = 0; columnIndex < this.getColumnCount(); columnIndex++) {

                    var cell = this.getHeaderCell(columnIndex);
                    googleDataTable.addColumn(cell.dataType, cell.label);
                }

                for (var lineIndex = 0; lineIndex < this.getLineCount(); lineIndex++) {

                    var googleDataLine = [];

                    for (columnIndex = 0; columnIndex < this.getColumnCount(); columnIndex++) {
                        var cellData = this.getDataCell(lineIndex, columnIndex);
                        googleDataLine.push(cellData);
                    }

                    googleDataTable.addRows([googleDataLine]);
                }

                return googleDataTable;
            }
        };
    }

    function applySize(on) {
        var sizeAsString = on.getAttribute('data-t2c-size');
        if (sizeAsString) {
            var dim = sizeAsString.split('x');
            if (dim && dim.length === 2) {
                var currentStyle = on.style;
                if (!currentStyle) currentStyle = '';
                on.style = 'width:' + dim[0] + ';height:' + dim[1] + ';' + currentStyle;
            }
        }
    }

    function getGoogleOptions(on) {
        var optAsString = on.getAttribute('data-t2c-options');
        //console.log(optAsString);
        if (optAsString) {
            try {
                return JSON.parse(optAsString);
            } catch (err) {
                throw Error('Invalid JSON options: ' + optAsString);
            }
        }
        return undefined;
    }

    return {
        apply: function (placeholder, table) {

            if (!table) table = placeholder;

            var tableId = placeholder.getAttribute('data-t2c-source');

            if (tableId) table = document.getElementById(tableId);

            var kindId = placeholder.getAttribute('data-t2c');

            if (!google.visualization[kindId]) {
                throw Error('Unknown Chart kind: ' + kindId);
            }

            var tableAdapter = tableDomAdapter(table);

            var data = tableAdapter.toGoogleDataTable();

            applySize(placeholder);

            var options = getGoogleOptions(placeholder) || {};

            if (!options.title) {
                options.title = tableAdapter.getCaption();
            }

            var chart = new google.visualization[kindId](placeholder);
            chart.draw(data, options);
        }
    };
});
<commit_msg>Give precedence to data-t2c-size option<commit_after>define('table2chart', function () {

    function tableDomAdapter(table) {
        return {
            getCaption: function () {
                return table.children[0].textContent;
            },
            __getHead: function () {
                return table.children[1];
            },
            __getBody: function () {
                return table.children[2];
            },
            __getHeaderLine: function () {
                return this.__getHead().children[0];
            },
            __getLine: function (index) {
                return this.__getBody().children[index];
            },
            getColumnCount: function () {
                return this.__getHeaderLine().childElementCount;
            },
            getLineCount: function () {
                return this.__getBody().childElementCount;
            },
            getHeaderCell: function (index) {
                var cell = {};

                var domCell = this.__getHeaderLine().children[index];

                cell.label = domCell.textContent;

                cell.dataType = domCell.getAttribute('data-t2c-type');

                if (cell.dataType === 'number') {
                    cell.converter = parseFloat;
                } else if (cell.dataType === 'string') {
                    cell.converter = null;
                } else {
                    //default
                    cell.converter = null;
                }

                return cell;
            },
            getDataCell: function (lineIndex, columnIndex) {
                var header = this.getHeaderCell(columnIndex);
                var line = this.__getLine(lineIndex);
                var td = line.children[columnIndex];
                var retval = td.textContent;
                if (header.converter) {
                    retval = header.converter(retval);
                }
                return retval;
            },

            toGoogleDataTable: function () {
                var googleDataTable = new google.visualization.DataTable();

                var converters = [];

                var columnIndex;

                for (columnIndex = 0; columnIndex < this.getColumnCount(); columnIndex++) {

                    var cell = this.getHeaderCell(columnIndex);
                    googleDataTable.addColumn(cell.dataType, cell.label);
                }

                for (var lineIndex = 0; lineIndex < this.getLineCount(); lineIndex++) {

                    var googleDataLine = [];

                    for (columnIndex = 0; columnIndex < this.getColumnCount(); columnIndex++) {
                        var cellData = this.getDataCell(lineIndex, columnIndex);
                        googleDataLine.push(cellData);
                    }

                    googleDataTable.addRows([googleDataLine]);
                }

                return googleDataTable;
            }
        };
    }

    function applySize(on) {
        var sizeAsString = on.getAttribute('data-t2c-size');
        if (sizeAsString) {
            var dim = sizeAsString.split('x');
            if (dim && dim.length === 2) {
                var currentStyle = on.style;
                if (!currentStyle) currentStyle = '';
                on.style = currentStyle + 'width:' + dim[0] + ';height:' + dim[1] + ';';
            }
        }
    }

    function getGoogleOptions(on) {
        var optAsString = on.getAttribute('data-t2c-options');
        //console.log(optAsString);
        if (optAsString) {
            try {
                return JSON.parse(optAsString);
            } catch (err) {
                throw Error('Invalid JSON options: ' + optAsString);
            }
        }
        return undefined;
    }

    return {
        apply: function (placeholder, table) {

            if (!table) table = placeholder;

            var tableId = placeholder.getAttribute('data-t2c-source');

            if (tableId) table = document.getElementById(tableId);

            var kindId = placeholder.getAttribute('data-t2c');

            if (!google.visualization[kindId]) {
                throw Error('Unknown Chart kind: ' + kindId);
            }

            var tableAdapter = tableDomAdapter(table);

            var data = tableAdapter.toGoogleDataTable();

            applySize(placeholder);

            var options = getGoogleOptions(placeholder) || {};

            if (!options.title) {
                options.title = tableAdapter.getCaption();
            }

            var chart = new google.visualization[kindId](placeholder);
            chart.draw(data, options);
        }
    };
});
<|endoftext|>


<commit_before>Package.describe({
  summary: 'Style with attitude. Sass and SCSS support for Meteor.js.',
  version: "3.10.0",
  git: "https://github.com/fourseven/meteor-scss.git",
  name: "fourseven:scss"
});

Package.registerBuildPlugin({
  name: "compileScssBatch",
  use: ['caching-compiler@1.1.7', 'ecmascript@0.5.8', 'underscore@1.0.9'],
  sources: [
    'plugin/compile-scss.js'
  ],
  npmDependencies: {
    'node-sass': '3.10.0'
  }
});

Package.onUse(function (api) {
  api.versionsFrom("1.4.1");
  api.use('isobuild:compiler-plugin@1.0.0');
});

Package.on_test(function (api) {
  api.use(['test-helpers',
           'tinytest']);

  api.use(['fourseven:scss']);

  // Tests for .scss
  api.addFiles([
    'test/scss/_emptyimport.scss',
    'test/scss/_not-included.scss',
    'test/scss/_top.scss',
    'test/scss/_top3.scss',
    'test/scss/empty.scss',
    'test/scss/dir/_in-dir.scss',
    'test/scss/dir/_in-dir2.scss',
    'test/scss/dir/root.scss',
    'test/scss/dir/subdir/_in-subdir.scss']);
  api.addFiles('test/scss/top2.scss', 'client', {isImport: true});

  // Tests for .sass
  //api.addFiles([
  //  'test/sass/_emptyimport.sass',
  //  'test/sass/_not-included.sass',
  //  'test/sass/_top.sass',
  //  'test/sass/_top3.sass',
  //  'test/sass/empty.sass',
  //  'test/sass/dir/_in-dir.sass',
  //  'test/sass/dir/_in-dir2.sass',
  //  'test/sass/dir/root.sass',
  //  'test/sass/dir/subdir/_in-subdir.sass']);
  //api.addFiles('test/sass/top2.sass', 'client', {isImport: true});

  api.addFiles('tests.js', 'client');

});
<commit_msg>Update to node-sass 3.10.1<commit_after>Package.describe({
  summary: 'Style with attitude. Sass and SCSS support for Meteor.js.',
  version: "3.10.1",
  git: "https://github.com/fourseven/meteor-scss.git",
  name: "fourseven:scss"
});

Package.registerBuildPlugin({
  name: "compileScssBatch",
  use: ['caching-compiler@1.1.7', 'ecmascript@0.5.8', 'underscore@1.0.9'],
  sources: [
    'plugin/compile-scss.js'
  ],
  npmDependencies: {
    'node-sass': '3.10.1'
  }
});

Package.onUse(function (api) {
  api.versionsFrom("1.4.1");
  api.use('isobuild:compiler-plugin@1.0.0');
});

Package.on_test(function (api) {
  api.use(['test-helpers',
           'tinytest']);

  api.use(['fourseven:scss']);

  // Tests for .scss
  api.addFiles([
    'test/scss/_emptyimport.scss',
    'test/scss/_not-included.scss',
    'test/scss/_top.scss',
    'test/scss/_top3.scss',
    'test/scss/empty.scss',
    'test/scss/dir/_in-dir.scss',
    'test/scss/dir/_in-dir2.scss',
    'test/scss/dir/root.scss',
    'test/scss/dir/subdir/_in-subdir.scss']);
  api.addFiles('test/scss/top2.scss', 'client', {isImport: true});

  // Tests for .sass
  //api.addFiles([
  //  'test/sass/_emptyimport.sass',
  //  'test/sass/_not-included.sass',
  //  'test/sass/_top.sass',
  //  'test/sass/_top3.sass',
  //  'test/sass/empty.sass',
  //  'test/sass/dir/_in-dir.sass',
  //  'test/sass/dir/_in-dir2.sass',
  //  'test/sass/dir/root.sass',
  //  'test/sass/dir/subdir/_in-subdir.sass']);
  //api.addFiles('test/sass/top2.sass', 'client', {isImport: true});

  api.addFiles('tests.js', 'client');

});
<|endoftext|>


<commit_before>/*!
 * nodeGame
 */

(function (exports) {

	var node = exports;

	node.version = '0.7.5';

	node.verbosity = 0;

	node.verbosity_levels = {
			ALWAYS: -(Number.MIN_VALUE+1), // Actually, it is not really always...
			ERR: -1,
			WARN: 0,
			INFO: 1,
			DEBUG: 3
	};

	node.log = function (txt, level) {
		var level = level || 0;
		if ('string' === typeof level) {
			var level = node.verbosity_levels[level];
		}
		if (node.verbosity > level) {
			console.log(txt);
		}
	};

	// Memory related operations
	// Will be initialized later
	node.memory = {};

	// It will be overwritten later
	node.game = {};

	// Load the auxiliary library if available in the browser
	if ('undefined' !== typeof JSUS) node.JSUS = JSUS;
	if ('undefined' !== typeof NDDB) node.NDDB = NDDB;

	// if node
	if ('object' === typeof module && 'function' === typeof require) {

	    /**
	     * Expose JSU
	     *
	     * @api public
	     */

	    node.JSUS = require('JSUS').JSUS;

		/**
	     * Expose NDDB
	     *
	     * @api public
	     */

	    node.NDDB = require('NDDB').NDDB;

		/**
	     * Expose Socket.io-client
	     *
	     * @api public
	     */

	    node.io = require('socket.io-client');

		/**
	     * Expose EventEmitter
	     *
	     * @api public
	     */

	    node.EventEmitter = require('./EventEmitter').EventEmitter;

	    /**
	     * Expose Utils
	     *
	     * @api public
	     */

	    node.utils = node.Utils = require('./Utils').Utils;

	    /**
	     * Expose GameState.
	     *
	     * @api public
	     */

	    node.GameState = require('./GameState').GameState;

	    /**
	     * Expose PlayerList.
	     *
	     * @api public
	     */

	    node.PlayerList = require('./PlayerList').PlayerList;

	    /**
	     * Expose Player.
	     *
	     * @api public
	     */

	    node.Player = require('./PlayerList').Player;

	    /**
	     * Expose GameMsg
	     *
	     * @api public
	     */

	     node.GameMsg = require('./GameMsg').GameMsg;

	    /**
	     * Expose GameLoop
	     *
	     * @api public
	     */

	    node.GameLoop = require('./GameLoop').GameLoop;

	    /**
	     * Expose GameMsgGenerator
	     *
	     * @api public
	     */

	    node.GameMsgGenerator = require('./GameMsgGenerator').GameMsgGenerator;

	    /**
	     * Expose GameSocketClient
	     *
	     * @api public
	     */

	    node.GameSocketClient = require('./GameSocketClient').GameSocketClient;

	    /**
	     * Expose GameStorage
	     *
	     * @api public
	     */

	    node.GameDB = require('./GameDB').GameDB;

	    /**
	     * Expose Game
	     *
	     * @api public
	     */

	    node.Game = require('./Game').Game;

	    // TODO: add a method to scan the addons directory. Based on configuration
	    node.GameTimer = require('./addons/GameTimer').GameTimer;

	  }
	  // end node

	var EventEmitter = node.EventEmitter;
	var GameSocketClient = node.GameSocketClient;
	var GameState = node.GameState;
	var GameMsg = node.GameMsg;
	var Game = node.Game;

	/**
	 * Expose constructor
	 *
	 */
	exports.nodeGame = nodeGame;

	/**
	 *  Exposing constants
	 */
	exports.actions = GameMsg.actions;
	exports.IN = GameMsg.IN;
	exports.OUT = GameMsg.OUT;
	exports.targets = GameMsg.targets;
	exports.states = GameState.iss;

	// Constructor
	nodeGame.prototype.__proto__ = EventEmitter.prototype;
	nodeGame.prototype.constructor = nodeGame;

	function nodeGame() {
		EventEmitter.call(this);
		this.gsc = null;
		this.game = null;
	};

	/**
	 * Creating an object
	 */
	var that = node.node = new nodeGame();

	// TODO: Check: is this the best place do it?
    node.node._listeners.set('state', GameState.compare);

	node.state = function() {
		return (that.game) ? node.node.game.gameState : false;
	};

	node.on = function (event, listener) {
		var state = this.state();
		//node.log(state);

		// It is in the init function;
		if (!state || (GameState.compare(state, new GameState(), true) === 0 )) {
			that.addListener(event, listener);
			//node.log('global');
		}
		else {
			that.addLocalListener(event, listener);
			//node.log('local');
		}
	};

	node.once = function (event, listener) {
		node.on(event, listener);
		node.on(event, function(event, listener) {
			that.removeListener(event, listener);
		});
	};

	node.removeListener = function (event, func) {
		return that.removeListener(event, func);
	};

	// TODO: create conf objects
	node.play = function (conf, game) {
		node._analyzeConf(conf);

		node.gsc = that.gsc = new GameSocketClient(conf);

		node.game = that.game = new Game(game, that.gsc);
		node.emit('NODEGAME_GAME_CREATED');

		//node.memory = that.game.memory;
		// INIT the game
		that.game.init.call(that.game);
		that.gsc.setGame(that.game);

		node.log('nodeGame: game loaded...');
		node.log('nodeGame: ready.');
	};

	node.observe = function (conf, game) {
		node._analyzeConf(conf);

		var game = game || {loops: {1: {state: function(){}}}};
		node.gsc = that.gsc = new GameSocketClient(conf);

		node.game = that.game = new Game(game, that.gsc);
		node.gsc.setGame(that.game);

		node.on('NODEGAME_READY', function(){

			// Retrieve the game and set is as observer
			node.get('LOOP', function(game) {

				//alert(game);
				console.log('ONLY ONE');
				console.log(game);
	//			var game = game.observer = true;
	//			node.game = that.game = game;
	//
	//			that.game.init();
	//
	//			that.gsc.setGame(that.game);
	//
	//			node.log('nodeGame: game loaded...');
	//			node.log('nodeGame: ready.');
			});
		});

//		node.onDATA('GAME', function(data){
//			alert(data);
//			console.log(data);
//		});

//		node.on('DATA', function(msg){
//			console.log('--------->Eh!')
//			console.log(msg);
//		});
	};

	node.fire = node.emit = function (event, p1, p2, p3) {
		that.emit(event, p1, p2, p3);
	};

	node.say = function (data, what, whom) {
		that.emit('out.say.DATA', data, whom, what);
	};

	/**
	 * Set the pair (key,value) into the server
	 * @value can be an object literal.
	 *
	 *
	 */
	node.set = function (key, value) {
		// TODO: parameter to say who will get the msg
		that.emit('out.set.DATA', value, null, key);
	};

	node.get = function (key, func) {
		that.emit('out.get.DATA', key);

		var listener = function(msg) {
			if (msg.text === key) {
				func.call(node.game, msg.data);
				that.removeListener('in.say.DATA',listener);
			}
			//that.printAllListeners();
		};

		node.on('in.say.DATA', listener);
	};

	// *Aliases*
	//
	// Conventions:
	//
	// - Direction:
	// 		'in' for all
	//
	// - Target:
	// 		DATA and TXT are 'say' as default
	// 		STATE and PLIST are 'set' as default

	// Sending

//	this.setSTATE = function(action,state,to){
//		var stateEvent = GameMsg.OUT + action + '.STATE';
//		fire(stateEvent,action,state,to);
//	};

	// Receiving

	// Say

	node.onTXT = function(func) {
		node.on("in.say.TXT", function(msg) {
			func.call(that.game,msg);
		});
	};

	node.onDATA = function(text, func) {
		node.on('in.say.DATA', function(msg) {
			if (text && msg.text === text) {
				func.call(that.game,msg);
			}
		});

		node.on('in.set.DATA', function(msg) {
			func.call(that.game,msg);
		});
	};

	// Set

	node.onSTATE = function(func) {
		node.on("in.set.STATE", function(msg) {
			func.call(that.game, msg);
		});
	};

	node.onPLIST = function(func) {
		node.on("in.set.PLIST", function(msg) {
			func.call(that.game, msg);
		});

		node.on("in.say.PLIST", function(msg) {
			func.call(that.game, msg);
		});
	};

	node.DONE = function (text) {
		node.emit("DONE",text);
	};

	node.TXT = function (text, to) {
		node.emit('out.say.TXT', text, to);
	};

	node.random = {};

	// Generates event at RANDOM timing in milliseconds
	// if timing is missing, default is 6000
	node.random.emit = function (event, timing){
		var timing = timing || 6000;
		setTimeout(function(event) {
			node.emit(event);
		}, Math.random()*timing, event);
	};

	node.random.exec = function (func, timing) {
		var timing = timing || 6000;
		setTimeout(function(func) {
			func.call();
		}, Math.random()*timing, func);
	}

	node.replay = function (reset) {
		if (reset) node.game.memory.clear(true);
		node.goto(new GameState({state: 1, step: 1, round: 1}));
	}

	node.goto = function (state) {
		node.game.updateState(state);
	};

	/**
	 * Parses the a node configuration object and add
	 * default and missing values.
	 *
	 */
	node._analyzeConf = function (conf) {
		if (!conf) {
			node.log('Invalid configuration object found.', 'ERR');
			return false;
		}

		// URL
		if (!conf.host && conf.url) {
			// Try to determine the server url
			var serverUrlArray = conf.url.split('/');
			if (JSUS.in_array(serverUrlArray[0], ['http:', 'https:'])) {
				conf.host = serverUrlArray[0] + '//' + serverUrlArray[2];
			}
			else {
				conf.host = serverUrlArray[0];
			}
		}

		// VERBOSITY
		if ('undefined' !== typeof conf.verbosity) {
			node.verbosity = conf.verbosity;
		}

		this.conf = conf;
		return conf;
	};

	// if node
	if ('object' === typeof module && 'function' === typeof require) {

		 /**
	     * Enable file system operations
	     */

	    node.csv = {};
	    node.fs = {};

	    var fs = require('fs');
	    var path = require('path');
	    var csv = require('ya-csv');

	    /**
	     * Takes an obj and write it down to a csv file;
	     */
	    node.fs.writeCsv = function (path, obj) {
	    	var writer = csv.createCsvStreamWriter(fs.createWriteStream( path, {'flags': 'a'}));
	    	var i;
	        for (i=0;i<obj.length;i++) {
	    		writer.writeRecord(obj[i]);
	    	}
	    };

	    node.memory.dump = function (path) {
			node.fs.writeCsv(path, node.game.memory.split().fetchValues());
	    }

	}
	// end node

	node.log('nodeGame ' + node.version + ' loaded', 'ALWAYS');

})('undefined' != typeof node ? node : module.exports);
<commit_msg>exposed GameBit in nodeGame<commit_after>/*!
 * nodeGame
 */

(function (exports) {

	var node = exports;

	node.version = '0.7.5';

	node.verbosity = 0;

	node.verbosity_levels = {
			ALWAYS: -(Number.MIN_VALUE+1), // Actually, it is not really always...
			ERR: -1,
			WARN: 0,
			INFO: 1,
			DEBUG: 3
	};

	node.log = function (txt, level) {
		var level = level || 0;
		if ('string' === typeof level) {
			var level = node.verbosity_levels[level];
		}
		if (node.verbosity > level) {
			console.log(txt);
		}
	};

	// Memory related operations
	// Will be initialized later
	node.memory = {};

	// It will be overwritten later
	node.game = {};

	// Load the auxiliary library if available in the browser
	if ('undefined' !== typeof JSUS) node.JSUS = JSUS;
	if ('undefined' !== typeof NDDB) node.NDDB = NDDB;

	// if node
	if ('object' === typeof module && 'function' === typeof require) {

	    /**
	     * Expose JSU
	     *
	     * @api public
	     */

	    node.JSUS = require('JSUS').JSUS;

		/**
	     * Expose NDDB
	     *
	     * @api public
	     */

	    node.NDDB = require('NDDB').NDDB;

		/**
	     * Expose Socket.io-client
	     *
	     * @api public
	     */

	    node.io = require('socket.io-client');

		/**
	     * Expose EventEmitter
	     *
	     * @api public
	     */

	    node.EventEmitter = require('./EventEmitter').EventEmitter;

	    /**
	     * Expose Utils
	     *
	     * @api public
	     */

	    node.utils = node.Utils = require('./Utils').Utils;

	    /**
	     * Expose GameState.
	     *
	     * @api public
	     */

	    node.GameState = require('./GameState').GameState;

	    /**
	     * Expose PlayerList.
	     *
	     * @api public
	     */

	    node.PlayerList = require('./PlayerList').PlayerList;

	    /**
	     * Expose Player.
	     *
	     * @api public
	     */

	    node.Player = require('./PlayerList').Player;

	    /**
	     * Expose GameMsg
	     *
	     * @api public
	     */

	     node.GameMsg = require('./GameMsg').GameMsg;

	    /**
	     * Expose GameLoop
	     *
	     * @api public
	     */

	    node.GameLoop = require('./GameLoop').GameLoop;

	    /**
	     * Expose GameMsgGenerator
	     *
	     * @api public
	     */

	    node.GameMsgGenerator = require('./GameMsgGenerator').GameMsgGenerator;

	    /**
	     * Expose GameSocketClient
	     *
	     * @api public
	     */

	    node.GameSocketClient = require('./GameSocketClient').GameSocketClient;

	    /**
	     * Expose GameDB
	     *
	     * @api public
	     */

	    node.GameDB = require('./GameDB').GameDB;

	    /**
	     * Expose GameBit
	     *
	     * @api public
	     */

	    node.GameBit = require('./GameDB').GameBit;

	    /**
	     * Expose Game
	     *
	     * @api public
	     */

	    node.Game = require('./Game').Game;

	    // TODO: add a method to scan the addons directory. Based on configuration
	    node.GameTimer = require('./addons/GameTimer').GameTimer;

	  }
	  // end node

	var EventEmitter = node.EventEmitter;
	var GameSocketClient = node.GameSocketClient;
	var GameState = node.GameState;
	var GameMsg = node.GameMsg;
	var Game = node.Game;

	/**
	 * Expose constructor
	 *
	 */
	exports.nodeGame = nodeGame;

	/**
	 *  Exposing constants
	 */
	exports.actions = GameMsg.actions;
	exports.IN = GameMsg.IN;
	exports.OUT = GameMsg.OUT;
	exports.targets = GameMsg.targets;
	exports.states = GameState.iss;

	// Constructor
	nodeGame.prototype.__proto__ = EventEmitter.prototype;
	nodeGame.prototype.constructor = nodeGame;

	function nodeGame() {
		EventEmitter.call(this);
		this.gsc = null;
		this.game = null;
	};

	/**
	 * Creating an object
	 */
	var that = node.node = new nodeGame();

	// TODO: Check: is this the best place do it?
    node.node._listeners.set('state', GameState.compare);

	node.state = function() {
		return (that.game) ? node.node.game.gameState : false;
	};

	node.on = function (event, listener) {
		var state = this.state();
		//node.log(state);

		// It is in the init function;
		if (!state || (GameState.compare(state, new GameState(), true) === 0 )) {
			that.addListener(event, listener);
			//node.log('global');
		}
		else {
			that.addLocalListener(event, listener);
			//node.log('local');
		}
	};

	node.once = function (event, listener) {
		node.on(event, listener);
		node.on(event, function(event, listener) {
			that.removeListener(event, listener);
		});
	};

	node.removeListener = function (event, func) {
		return that.removeListener(event, func);
	};

	// TODO: create conf objects
	node.play = function (conf, game) {
		node._analyzeConf(conf);

		node.gsc = that.gsc = new GameSocketClient(conf);

		node.game = that.game = new Game(game, that.gsc);
		node.emit('NODEGAME_GAME_CREATED');

		//node.memory = that.game.memory;
		// INIT the game
		that.game.init.call(that.game);
		that.gsc.setGame(that.game);

		node.log('nodeGame: game loaded...');
		node.log('nodeGame: ready.');
	};

	node.observe = function (conf, game) {
		node._analyzeConf(conf);

		var game = game || {loops: {1: {state: function(){}}}};
		node.gsc = that.gsc = new GameSocketClient(conf);

		node.game = that.game = new Game(game, that.gsc);
		node.gsc.setGame(that.game);

		node.on('NODEGAME_READY', function(){

			// Retrieve the game and set is as observer
			node.get('LOOP', function(game) {

				//alert(game);
				console.log('ONLY ONE');
				console.log(game);
	//			var game = game.observer = true;
	//			node.game = that.game = game;
	//
	//			that.game.init();
	//
	//			that.gsc.setGame(that.game);
	//
	//			node.log('nodeGame: game loaded...');
	//			node.log('nodeGame: ready.');
			});
		});

//		node.onDATA('GAME', function(data){
//			alert(data);
//			console.log(data);
//		});

//		node.on('DATA', function(msg){
//			console.log('--------->Eh!')
//			console.log(msg);
//		});
	};

	node.fire = node.emit = function (event, p1, p2, p3) {
		that.emit(event, p1, p2, p3);
	};

	node.say = function (data, what, whom) {
		that.emit('out.say.DATA', data, whom, what);
	};

	/**
	 * Set the pair (key,value) into the server
	 * @value can be an object literal.
	 *
	 *
	 */
	node.set = function (key, value) {
		// TODO: parameter to say who will get the msg
		that.emit('out.set.DATA', value, null, key);
	};

	node.get = function (key, func) {
		that.emit('out.get.DATA', key);

		var listener = function(msg) {
			if (msg.text === key) {
				func.call(node.game, msg.data);
				that.removeListener('in.say.DATA',listener);
			}
			//that.printAllListeners();
		};

		node.on('in.say.DATA', listener);
	};

	// *Aliases*
	//
	// Conventions:
	//
	// - Direction:
	// 		'in' for all
	//
	// - Target:
	// 		DATA and TXT are 'say' as default
	// 		STATE and PLIST are 'set' as default

	// Sending

//	this.setSTATE = function(action,state,to){
//		var stateEvent = GameMsg.OUT + action + '.STATE';
//		fire(stateEvent,action,state,to);
//	};

	// Receiving

	// Say

	node.onTXT = function(func) {
		node.on("in.say.TXT", function(msg) {
			func.call(that.game,msg);
		});
	};

	node.onDATA = function(text, func) {
		node.on('in.say.DATA', function(msg) {
			if (text && msg.text === text) {
				func.call(that.game,msg);
			}
		});

		node.on('in.set.DATA', function(msg) {
			func.call(that.game,msg);
		});
	};

	// Set

	node.onSTATE = function(func) {
		node.on("in.set.STATE", function(msg) {
			func.call(that.game, msg);
		});
	};

	node.onPLIST = function(func) {
		node.on("in.set.PLIST", function(msg) {
			func.call(that.game, msg);
		});

		node.on("in.say.PLIST", function(msg) {
			func.call(that.game, msg);
		});
	};

	node.DONE = function (text) {
		node.emit("DONE",text);
	};

	node.TXT = function (text, to) {
		node.emit('out.say.TXT', text, to);
	};

	node.random = {};

	// Generates event at RANDOM timing in milliseconds
	// if timing is missing, default is 6000
	node.random.emit = function (event, timing){
		var timing = timing || 6000;
		setTimeout(function(event) {
			node.emit(event);
		}, Math.random()*timing, event);
	};

	node.random.exec = function (func, timing) {
		var timing = timing || 6000;
		setTimeout(function(func) {
			func.call();
		}, Math.random()*timing, func);
	}

	node.replay = function (reset) {
		if (reset) node.game.memory.clear(true);
		node.goto(new GameState({state: 1, step: 1, round: 1}));
	}

	node.goto = function (state) {
		node.game.updateState(state);
	};

	/**
	 * Parses the a node configuration object and add
	 * default and missing values.
	 *
	 */
	node._analyzeConf = function (conf) {
		if (!conf) {
			node.log('Invalid configuration object found.', 'ERR');
			return false;
		}

		// URL
		if (!conf.host && conf.url) {
			// Try to determine the server url
			var serverUrlArray = conf.url.split('/');
			if (JSUS.in_array(serverUrlArray[0], ['http:', 'https:'])) {
				conf.host = serverUrlArray[0] + '//' + serverUrlArray[2];
			}
			else {
				conf.host = serverUrlArray[0];
			}
		}

		// VERBOSITY
		if ('undefined' !== typeof conf.verbosity) {
			node.verbosity = conf.verbosity;
		}

		this.conf = conf;
		return conf;
	};

	// if node
	if ('object' === typeof module && 'function' === typeof require) {

		 /**
	     * Enable file system operations
	     */

	    node.csv = {};
	    node.fs = {};

	    var fs = require('fs');
	    var path = require('path');
	    var csv = require('ya-csv');

	    /**
	     * Takes an obj and write it down to a csv file;
	     */
	    node.fs.writeCsv = function (path, obj) {
	    	var writer = csv.createCsvStreamWriter(fs.createWriteStream( path, {'flags': 'a'}));
	    	var i;
	        for (i=0;i<obj.length;i++) {
	    		writer.writeRecord(obj[i]);
	    	}
	    };

	    node.memory.dump = function (path) {
			node.fs.writeCsv(path, node.game.memory.split().fetchValues());
	    }

	}
	// end node

	node.log('nodeGame ' + node.version + ' loaded', 'ALWAYS');

})('undefined' != typeof node ? node : module.exports);
<|endoftext|>


<commit_before>function CodeFlask(indent) {
  this.indent = indent || "    ";
}

CodeFlask.prototype.run = function(selector, opts) {
    var target = document.querySelectorAll(selector);

    if(target.length > 1) {
        throw 'CodeFlask.js ERROR: run() expects only one element, ' +
        target.length + ' given. Use .runAll() instead.';
    } else {
        this.scaffold(target[0], false, opts);
    }
}

CodeFlask.prototype.runAll = function(selector, opts) {
    // Remove update API for bulk rendering
    this.update = null;
    this.onUpdate = null;

    var target = document.querySelectorAll(selector);

    var i;
    for(i=0; i < target.length; i++) {
        this.scaffold(target[i], true, opts);
    }
}

CodeFlask.prototype.scaffold = function(target, isMultiple, opts) {
    var textarea = document.createElement('TEXTAREA'),
        highlightPre = document.createElement('PRE'),
        highlightCode = document.createElement('CODE'),
        initialCode = target.textContent,
        lang;

    if(!opts.enableAutocorrect == true)
    {
        // disable autocorrect and spellcheck features
        textarea.setAttribute('spellcheck', 'false');
        textarea.setAttribute('autocapitalize', 'off');
        textarea.setAttribute('autocomplete', 'off');
        textarea.setAttribute('autocorrect', 'off');
    }

    opts.language = this.handleLanguage(opts.language);

    this.defaultLanguage = target.dataset.language || opts.language || 'markup';

    // Prevent these vars from being refreshed when rendering multiple
    // instances
    if(!isMultiple) {
        this.textarea = textarea;
        this.highlightCode = highlightCode;
    }

    target.classList.add('CodeFlask');
    textarea.classList.add('CodeFlask__textarea');
    highlightPre.classList.add('CodeFlask__pre');
    highlightCode.classList.add('CodeFlask__code');
    highlightCode.classList.add('language-' + this.defaultLanguage);

    // Fixing iOS "drunk-text" issue
    if(/iPad|iPhone|iPod/.test(navigator.platform)) {
        highlightCode.style.paddingLeft = '3px';
    }

    // Appending editor elements to DOM
    target.innerHTML = '';
    target.appendChild(textarea);
    target.appendChild(highlightPre);
    highlightPre.appendChild(highlightCode);

    // Render initial code inside tag
    textarea.value = initialCode;
    this.renderOutput(highlightCode, textarea);

    Prism.highlightAll();

    this.handleInput(textarea, highlightCode, highlightPre);
    this.handleScroll(textarea, highlightPre);

}

CodeFlask.prototype.renderOutput = function(highlightCode, input) {
    highlightCode.innerHTML = input.value.replace(/&/g, "&")
        .replace(/</g, "<")
        .replace(/>/g, ">") + "\n";
}

CodeFlask.prototype.handleInput = function(textarea, highlightCode, highlightPre) {
    var self = this,
        input,
        selStartPos,
        inputVal,
        roundedScroll,
        currentLineStart,
        indentLength;

    textarea.addEventListener('input', function(e) {
        input = this;

        self.renderOutput(highlightCode, input);

        Prism.highlightAll();
    });

    textarea.addEventListener('keydown', function(e) {
        input = this,
        selStartPos = input.selectionStart,
        inputVal = input.value;
        currentLineStart = selStartPos - input.value.substr(0, selStartPos).split("\n").pop().length;

        // If tab pressed, indent
        if (e.keyCode === 9) {
          e.preventDefault();

          // Allow shift-tab
          if (e.shiftKey) {
            indentLength = self.indent.length;

            // If the current line begins with the indent, unindent
            if (inputVal.substring(currentLineStart, currentLineStart + indentLength) == self.indent) {
              input.value = inputVal.substring(0, currentLineStart) +
                            inputVal.substring(currentLineStart + indentLength, input.value.length);
              input.selectionStart = selStartPos - self.indent.length;
              input.selectionEnd = selStartPos - self.indent.length;
            }
          } else {
            input.value = inputVal.substring(0, selStartPos) + self.indent +
                          inputVal.substring(selStartPos, input.value.length);
            input.selectionStart = selStartPos + self.indent.length;
            input.selectionEnd = selStartPos + self.indent.length;
          }

            highlightCode.innerHTML = input.value.replace(/&/g, "&")
                .replace(/</g, "<")
                .replace(/>/g, ">") + "\n";
            Prism.highlightAll();
        }
    });
}

CodeFlask.prototype.handleScroll = function(textarea, highlightPre) {
    textarea.addEventListener('scroll', function(){

        roundedScroll = Math.floor(this.scrollTop);

        // Fixes issue of desync text on mouse wheel, fuck Firefox.
        if(navigator.userAgent.toLowerCase().indexOf('firefox') < 0) {
            this.scrollTop = roundedScroll;
        }

        highlightPre.style.top = "-" + roundedScroll + "px";
    });
}

CodeFlask.prototype.handleLanguage = function(lang) {
    if(lang.match(/html|xml|xhtml|svg/)) {
        return 'markup';
    } else  if(lang.match(/js/)) {
        return 'javascript';
    } else {
        return lang;
    }
}

CodeFlask.prototype.onUpdate = function(cb) {
    if(typeof(cb) == "function") {
        this.textarea.addEventListener('input', function(e) {
            cb(this.value);
        });
    }else{
        throw 'CodeFlask.js ERROR: onUpdate() expects function, ' +
        typeof(cb) + ' given instead.';
    }
}

CodeFlask.prototype.update = function(string) {
    var evt = document.createEvent("HTMLEvents");

    this.textarea.value = string;
    this.renderOutput(this.highlightCode, this.textarea);
    Prism.highlightAll();

    evt.initEvent("input", false, true);
    this.textarea.dispatchEvent(evt);
}
<commit_msg>Fix errors when options are null<commit_after>function CodeFlask(indent) {
  this.indent = indent || "    ";
}

CodeFlask.prototype.run = function(selector, opts) {
    var target = document.querySelectorAll(selector);

    if(target.length > 1) {
        throw 'CodeFlask.js ERROR: run() expects only one element, ' +
        target.length + ' given. Use .runAll() instead.';
    } else {
        this.scaffold(target[0], false, opts);
    }
}

CodeFlask.prototype.runAll = function(selector, opts) {
    // Remove update API for bulk rendering
    this.update = null;
    this.onUpdate = null;

    var target = document.querySelectorAll(selector);

    var i;
    for(i=0; i < target.length; i++) {
        this.scaffold(target[i], true, opts);
    }
}

CodeFlask.prototype.scaffold = function(target, isMultiple, opts) {
    var textarea = document.createElement('TEXTAREA'),
        highlightPre = document.createElement('PRE'),
        highlightCode = document.createElement('CODE'),
        initialCode = target.textContent,
        lang;

    if(opts && !opts.enableAutocorrect)
    {
        // disable autocorrect and spellcheck features
        textarea.setAttribute('spellcheck', 'false');
        textarea.setAttribute('autocapitalize', 'off');
        textarea.setAttribute('autocomplete', 'off');
        textarea.setAttribute('autocorrect', 'off');
    }

    if(opts)
    {
      lang = this.handleLanguage(opts.language);
    }

    this.defaultLanguage = target.dataset.language || lang || 'markup';

    // Prevent these vars from being refreshed when rendering multiple
    // instances
    if(!isMultiple) {
        this.textarea = textarea;
        this.highlightCode = highlightCode;
    }

    target.classList.add('CodeFlask');
    textarea.classList.add('CodeFlask__textarea');
    highlightPre.classList.add('CodeFlask__pre');
    highlightCode.classList.add('CodeFlask__code');
    highlightCode.classList.add('language-' + this.defaultLanguage);

    // Fixing iOS "drunk-text" issue
    if(/iPad|iPhone|iPod/.test(navigator.platform)) {
        highlightCode.style.paddingLeft = '3px';
    }

    // Appending editor elements to DOM
    target.innerHTML = '';
    target.appendChild(textarea);
    target.appendChild(highlightPre);
    highlightPre.appendChild(highlightCode);

    // Render initial code inside tag
    textarea.value = initialCode;
    this.renderOutput(highlightCode, textarea);

    Prism.highlightAll();

    this.handleInput(textarea, highlightCode, highlightPre);
    this.handleScroll(textarea, highlightPre);

}

CodeFlask.prototype.renderOutput = function(highlightCode, input) {
    highlightCode.innerHTML = input.value.replace(/&/g, "&")
        .replace(/</g, "<")
        .replace(/>/g, ">") + "\n";
}

CodeFlask.prototype.handleInput = function(textarea, highlightCode, highlightPre) {
    var self = this,
        input,
        selStartPos,
        inputVal,
        roundedScroll,
        currentLineStart,
        indentLength;

    textarea.addEventListener('input', function(e) {
        input = this;

        self.renderOutput(highlightCode, input);

        Prism.highlightAll();
    });

    textarea.addEventListener('keydown', function(e) {
        input = this,
        selStartPos = input.selectionStart,
        inputVal = input.value;
        currentLineStart = selStartPos - input.value.substr(0, selStartPos).split("\n").pop().length;

        // If tab pressed, indent
        if (e.keyCode === 9) {
          e.preventDefault();

          // Allow shift-tab
          if (e.shiftKey) {
            indentLength = self.indent.length;

            // If the current line begins with the indent, unindent
            if (inputVal.substring(currentLineStart, currentLineStart + indentLength) == self.indent) {
              input.value = inputVal.substring(0, currentLineStart) +
                            inputVal.substring(currentLineStart + indentLength, input.value.length);
              input.selectionStart = selStartPos - self.indent.length;
              input.selectionEnd = selStartPos - self.indent.length;
            }
          } else {
            input.value = inputVal.substring(0, selStartPos) + self.indent +
                          inputVal.substring(selStartPos, input.value.length);
            input.selectionStart = selStartPos + self.indent.length;
            input.selectionEnd = selStartPos + self.indent.length;
          }

            highlightCode.innerHTML = input.value.replace(/&/g, "&")
                .replace(/</g, "<")
                .replace(/>/g, ">") + "\n";
            Prism.highlightAll();
        }
    });
}

CodeFlask.prototype.handleScroll = function(textarea, highlightPre) {
    textarea.addEventListener('scroll', function(){

        roundedScroll = Math.floor(this.scrollTop);

        // Fixes issue of desync text on mouse wheel, fuck Firefox.
        if(navigator.userAgent.toLowerCase().indexOf('firefox') < 0) {
            this.scrollTop = roundedScroll;
        }

        highlightPre.style.top = "-" + roundedScroll + "px";
    });
}

CodeFlask.prototype.handleLanguage = function(lang) {
    if(lang.match(/html|xml|xhtml|svg/)) {
        return 'markup';
    } else  if(lang.match(/js/)) {
        return 'javascript';
    } else {
        return lang;
    }
}

CodeFlask.prototype.onUpdate = function(cb) {
    if(typeof(cb) == "function") {
        this.textarea.addEventListener('input', function(e) {
            cb(this.value);
        });
    }else{
        throw 'CodeFlask.js ERROR: onUpdate() expects function, ' +
        typeof(cb) + ' given instead.';
    }
}

CodeFlask.prototype.update = function(string) {
    var evt = document.createEvent("HTMLEvents");

    this.textarea.value = string;
    this.renderOutput(this.highlightCode, this.textarea);
    Prism.highlightAll();

    evt.initEvent("input", false, true);
    this.textarea.dispatchEvent(evt);
}
<|endoftext|>


<commit_before>// The `cmap` table stores the mappings from characters to glyphs.
// https://www.microsoft.com/typography/OTSPEC/cmap.htm

'use strict';

var check = require('../check');
var parse = require('../parse');
var table = require('../table');

// Parse the `cmap` table. This table stores the mappings from characters to glyphs.
// There are many available formats, but we only support the Windows format 4.
// This function returns a `CmapEncoding` object or null if no supported format could be found.
function parseCmapTable(data, start) {
    var version, numTables, offset, platformId, encodingId, format, segCount,
        ranges, i, j, parserOffset, idRangeOffset, p, offsetBound;
    var cmap = {};
    cmap.version = version = parse.getUShort(data, start);
    check.argument(version === 0, 'cmap table version should be 0.');

    // The cmap table can contain many sub-tables, each with their own format.
    // We're only interested in a "platform 3" table. This is a Windows format.
    cmap.numtables = numTables = parse.getUShort(data, start + 2);
    offset = -1;
    for (i = 0; i < numTables; i += 1) {
        platformId = parse.getUShort(data, start + 4 + (i * 8));
        encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2);
        if (platformId === 3 && (encodingId === 1 || encodingId === 0)) {
            offset = parse.getULong(data, start + 4 + (i * 8) + 4);
            break;
        }
    }
    if (offset === -1) {
        // There is no cmap table in the font that we support, so return null.
        // This font will be marked as unsupported.
        return null;
    }

    p = new parse.Parser(data, start + offset);
    cmap.format = format = p.parseUShort();
    check.argument(format === 4, 'Only format 4 cmap tables are supported.');
    // Length in bytes of the sub-tables.
    cmap.length = p.parseUShort();
    cmap.language = p.parseUShort();
    // segCount is stored x 2.
    cmap.segCount = segCount = p.parseUShort() >> 1;
    // Skip searchRange, entrySelector, rangeShift.
    p.skip('uShort', 3);
    ranges = [];
    for (i = 0; i < segCount; i += 1) {
        ranges[i] = { end: p.parseUShort() };
    }
    // Skip a padding value.
    p.skip('uShort');
    for (i = 0; i < segCount; i += 1) {
        ranges[i].start = p.parseUShort();
        ranges[i].length = ranges[i].end - ranges[i].start + 1;
    }
    for (i = 0; i < segCount; i += 1) {
        ranges[i].idDelta = p.parseShort();
    }
    offsetBound = p.offset + cmap.length;
    for (i = 0; i < segCount; i += 1) {
        parserOffset = p.offset + p.relativeOffset;
        idRangeOffset = p.parseUShort();
        parserOffset += idRangeOffset;
        if (idRangeOffset > 0) {
            ranges[i].ids = [];
            if (parserOffset >= offsetBound) break;
            for (j = 0; j < ranges[i].length; j += 1) {
                ranges[i].ids[j] = parse.getUShort(data, parserOffset);
                parserOffset += 2;
            }
        }
    }
    cmap.segments = ranges;
    return cmap;
}

function addSegment(t, code) {
    var index = t.segments.length;
    t.segments.push({
        end: code,
        start: code,
        delta: -(code - index),
        offset: 0,
        glyphId: index
    });
}

function addTerminatorSegment(t) {
    t.segments.push({
        end: 0xFFFF,
        start: 0xFFFF,
        delta: 1,
        offset: 0
    });
}

function makeCmapTable(glyphs) {
    var i, j, glyph;
    var t = new table.Table('cmap', [
        {name: 'version', type: 'USHORT', value: 0},
        {name: 'numTables', type: 'USHORT', value: 1},
        {name: 'platformID', type: 'USHORT', value: 3},
        {name: 'encodingID', type: 'USHORT', value: 1},
        {name: 'offset', type: 'ULONG', value: 12},
        {name: 'format', type: 'USHORT', value: 4},
        {name: 'length', type: 'USHORT', value: 0},
        {name: 'language', type: 'USHORT', value: 0},
        {name: 'segCountX2', type: 'USHORT', value: 0},
        {name: 'searchRange', type: 'USHORT', value: 0},
        {name: 'entrySelector', type: 'USHORT', value: 0},
        {name: 'rangeShift', type: 'USHORT', value: 0}
    ]);

    t.segments = [];
    addSegment(t, 0);
    for (i = 1; i < glyphs.length; i += 1) {
        glyph = glyphs[i];
        for (j = 0; j < glyph.unicodes.length; j += 1) {
            addSegment(t, glyph.unicodes[j]);
        }
    }
    addTerminatorSegment(t);

    var segCount;
    segCount = t.segments.length;
    t.segCountX2 = segCount * 2;
    t.searchRange = Math.pow(Math.floor(Math.log(segCount) / Math.log(2)), 2) * 2;
    t.entrySelector = Math.log(t.searchRange / 2) / Math.log(2);
    t.rangeShift = t.segCountX2 - t.searchRange;

     // Set up parallel segment arrays.
    var endCounts = [],
        startCounts = [],
        idDeltas = [],
        idRangeOffsets = [],
        glyphIds = [];

    for (i = 0; i < segCount; i += 1) {
        var segment = t.segments[i];
        endCounts = endCounts.concat({name: 'end_' + i, type: 'USHORT', value: segment.end});
        startCounts = startCounts.concat({name: 'start_' + i, type: 'USHORT', value: segment.start});
        idDeltas = idDeltas.concat({name: 'idDelta_' + i, type: 'SHORT', value: segment.delta});
        idRangeOffsets = idRangeOffsets.concat({name: 'idRangeOffset_' + i, type: 'USHORT', value: segment.offset});
        if (segment.glyphId !== undefined) {
            glyphIds = glyphIds.concat({name: 'glyph_' + i, type: 'USHORT', value: segment.glyphId});
        }
    }
    t.fields = t.fields.concat(endCounts);
    t.fields.push({name: 'reservedPad', type: 'USHORT', value: 0});
    t.fields = t.fields.concat(startCounts);
    t.fields = t.fields.concat(idDeltas);
    t.fields = t.fields.concat(idRangeOffsets);
    t.fields = t.fields.concat(glyphIds);
    return t;
}

exports.parse = parseCmapTable;
exports.make = makeCmapTable;
<commit_msg>Correct length calculation for cmap format 4 subtable.<commit_after>// The `cmap` table stores the mappings from characters to glyphs.
// https://www.microsoft.com/typography/OTSPEC/cmap.htm

'use strict';

var check = require('../check');
var parse = require('../parse');
var table = require('../table');

// Parse the `cmap` table. This table stores the mappings from characters to glyphs.
// There are many available formats, but we only support the Windows format 4.
// This function returns a `CmapEncoding` object or null if no supported format could be found.
function parseCmapTable(data, start) {
    var version, numTables, offset, platformId, encodingId, format, segCount,
        ranges, i, j, parserOffset, idRangeOffset, p, offsetBound;
    var cmap = {};
    cmap.version = version = parse.getUShort(data, start);
    check.argument(version === 0, 'cmap table version should be 0.');

    // The cmap table can contain many sub-tables, each with their own format.
    // We're only interested in a "platform 3" table. This is a Windows format.
    cmap.numtables = numTables = parse.getUShort(data, start + 2);
    offset = -1;
    for (i = 0; i < numTables; i += 1) {
        platformId = parse.getUShort(data, start + 4 + (i * 8));
        encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2);
        if (platformId === 3 && (encodingId === 1 || encodingId === 0)) {
            offset = parse.getULong(data, start + 4 + (i * 8) + 4);
            break;
        }
    }
    if (offset === -1) {
        // There is no cmap table in the font that we support, so return null.
        // This font will be marked as unsupported.
        return null;
    }

    p = new parse.Parser(data, start + offset);
    cmap.format = format = p.parseUShort();
    check.argument(format === 4, 'Only format 4 cmap tables are supported.');
    // Length in bytes of the sub-tables.
    cmap.length = p.parseUShort();
    cmap.language = p.parseUShort();
    // segCount is stored x 2.
    cmap.segCount = segCount = p.parseUShort() >> 1;
    // Skip searchRange, entrySelector, rangeShift.
    p.skip('uShort', 3);
    ranges = [];
    for (i = 0; i < segCount; i += 1) {
        ranges[i] = { end: p.parseUShort() };
    }
    // Skip a padding value.
    p.skip('uShort');
    for (i = 0; i < segCount; i += 1) {
        ranges[i].start = p.parseUShort();
        ranges[i].length = ranges[i].end - ranges[i].start + 1;
    }
    for (i = 0; i < segCount; i += 1) {
        ranges[i].idDelta = p.parseShort();
    }
    offsetBound = p.offset + cmap.length;
    for (i = 0; i < segCount; i += 1) {
        parserOffset = p.offset + p.relativeOffset;
        idRangeOffset = p.parseUShort();
        parserOffset += idRangeOffset;
        if (idRangeOffset > 0) {
            ranges[i].ids = [];
            if (parserOffset >= offsetBound) break;
            for (j = 0; j < ranges[i].length; j += 1) {
                ranges[i].ids[j] = parse.getUShort(data, parserOffset);
                parserOffset += 2;
            }
        }
    }
    cmap.segments = ranges;
    return cmap;
}

function addSegment(t, code) {
    var index = t.segments.length;
    t.segments.push({
        end: code,
        start: code,
        delta: -(code - index),
        offset: 0,
        glyphId: index
    });
}

function addTerminatorSegment(t) {
    t.segments.push({
        end: 0xFFFF,
        start: 0xFFFF,
        delta: 1,
        offset: 0
    });
}

function makeCmapTable(glyphs) {
    var i, j, glyph;
    var t = new table.Table('cmap', [
        {name: 'version', type: 'USHORT', value: 0},
        {name: 'numTables', type: 'USHORT', value: 1},
        {name: 'platformID', type: 'USHORT', value: 3},
        {name: 'encodingID', type: 'USHORT', value: 1},
        {name: 'offset', type: 'ULONG', value: 12},
        {name: 'format', type: 'USHORT', value: 4},
        {name: 'length', type: 'USHORT', value: 0},
        {name: 'language', type: 'USHORT', value: 0},
        {name: 'segCountX2', type: 'USHORT', value: 0},
        {name: 'searchRange', type: 'USHORT', value: 0},
        {name: 'entrySelector', type: 'USHORT', value: 0},
        {name: 'rangeShift', type: 'USHORT', value: 0}
    ]);

    t.segments = [];
    for (i = 0; i < glyphs.length; i += 1) {
        glyph = glyphs[i];
        for (j = 0; j < glyph.unicodes.length; j += 1) {
            addSegment(t, glyph.unicodes[j]);
        }
    }
    addTerminatorSegment(t);

    var segCount;
    segCount = t.segments.length;
    t.segCountX2 = segCount * 2;
    t.searchRange = Math.pow(Math.floor(Math.log(segCount) / Math.log(2)), 2) * 2;
    t.entrySelector = Math.log(t.searchRange / 2) / Math.log(2);
    t.rangeShift = t.segCountX2 - t.searchRange;

     // Set up parallel segment arrays.
    var endCounts = [],
        startCounts = [],
        idDeltas = [],
        idRangeOffsets = [],
        glyphIds = [];

    for (i = 0; i < segCount; i += 1) {
        var segment = t.segments[i];
        endCounts = endCounts.concat({name: 'end_' + i, type: 'USHORT', value: segment.end});
        startCounts = startCounts.concat({name: 'start_' + i, type: 'USHORT', value: segment.start});
        idDeltas = idDeltas.concat({name: 'idDelta_' + i, type: 'SHORT', value: segment.delta});
        idRangeOffsets = idRangeOffsets.concat({name: 'idRangeOffset_' + i, type: 'USHORT', value: segment.offset});
        if (segment.glyphId !== undefined) {
            glyphIds = glyphIds.concat({name: 'glyph_' + i, type: 'USHORT', value: segment.glyphId});
        }
    }
    t.fields = t.fields.concat(endCounts);
    t.fields.push({name: 'reservedPad', type: 'USHORT', value: 0});
    t.fields = t.fields.concat(startCounts);
    t.fields = t.fields.concat(idDeltas);
    t.fields = t.fields.concat(idRangeOffsets);
    t.fields = t.fields.concat(glyphIds);

    t.length = 14 + // Subtable header
        endCounts.length * 2 +
        2 + // reservedPad
        startCounts.length * 2 +
        idDeltas.length * 2 +
        idRangeOffsets.length * 2 +
        glyphIds.length * 2;
    return t;
}

exports.parse = parseCmapTable;
exports.make = makeCmapTable;
<|endoftext|>


<commit_before>Package.describe({
  name: 'jagi:astronomy',
  version: '2.0.1',
  summary: 'Model layer for Meteor',
  git: 'https://github.com/jagi/meteor-astronomy.git'
});

Npm.depends({
  lodash: '4.11.1'
});

Package.onUse(function(api) {
  api.versionsFrom('1.3');

  api.use([
    'ecmascript',
    'es5-shim',
    'ddp',
    'mongo',
    'check',
    'minimongo',
    'ejson',
    'mdg:validation-error@0.5.1'
  ], ['client', 'server']);

  api.mainModule('lib/main.js', ['client', 'server']);

  // For backward compatibility.
  api.export('Astro', ['client', 'server']);
});

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

Package.onTest(function(api) {
  api.use([
    'tinytest',
    'ecmascript',
    'es5-shim',
    'insecure',
    'mongo',
    'ejson',
    'jagi:astronomy@2.0.1'
  ], ['client', 'server']);

  api.addFiles('test/utils.js', ['client', 'server']);
  // Core.
  api.addFiles([
    'test/core/inherit.js',
    'test/core/extend.js',
    'test/core/state.js',
    'test/core/ejson.js'
  ], ['client', 'server']);
  // Modules.
  // Modules - Behaviors.
  api.addFiles([
    'test/modules/behaviors/create.js',
    'test/modules/behaviors/apply.js'
  ], ['client', 'server']);
  // Modules - Validators.
  api.addFiles([
    'test/modules/validators/create.js',
    'test/modules/validators/apply.js',
    'test/modules/validators/validate.js',
    'test/modules/validators/validate_callback.js'
  ], ['client', 'server']);
  // Modules - Storage.
  api.addFiles([
    'test/modules/storage/init.js',
    'test/modules/storage/type_field.js',
    'test/modules/storage/transform.js',
    'test/modules/storage/document_insert.js',
    'test/modules/storage/document_update.js',
    'test/modules/storage/document_remove.js',
    'test/modules/storage/class_insert.js',
    'test/modules/storage/class_update.js',
    'test/modules/storage/class_remove.js',
    'test/modules/storage/reload.js',
    'test/modules/storage/copy.js',
  ], ['client', 'server']);
  // Modules - Events.
  api.addFiles([
    'test/modules/events/order.js',
    'test/modules/events/propagation.js',
    'test/modules/events/cancelable.js'
  ], ['client', 'server']);
  // Modules - Fields.
  api.addFiles([
    'test/modules/fields/definition.js',
    'test/modules/fields/default.js',
    'test/modules/fields/set.js',
    'test/modules/fields/get.js',
    'test/modules/fields/raw.js',
    'test/modules/fields/optional.js'
  ], ['client', 'server']);
  // Modules - Indexes.
  api.addFiles([
    // 'test/indexes/indexes_definition.js'
  ], 'server');
  // Modules - Methods.
  api.addFiles([
    // 'test/methods/methods_definition.js'
  ], ['client', 'server']);
});<commit_msg>Bump version to 2.1<commit_after>Package.describe({
  name: 'jagi:astronomy',
  version: '2.1.0',
  summary: 'Model layer for Meteor',
  git: 'https://github.com/jagi/meteor-astronomy.git'
});

Npm.depends({
  lodash: '4.11.1'
});

Package.onUse(function(api) {
  api.versionsFrom('1.3');

  api.use([
    'ecmascript',
    'es5-shim',
    'ddp',
    'mongo',
    'check',
    'minimongo',
    'ejson',
    'mdg:validation-error@0.5.1'
  ], ['client', 'server']);

  api.mainModule('lib/main.js', ['client', 'server']);

  // For backward compatibility.
  api.export('Astro', ['client', 'server']);
});

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

Package.onTest(function(api) {
  api.use([
    'tinytest',
    'ecmascript',
    'es5-shim',
    'insecure',
    'mongo',
    'ejson',
    'jagi:astronomy@2.0.1'
  ], ['client', 'server']);

  api.addFiles('test/utils.js', ['client', 'server']);
  // Core.
  api.addFiles([
    'test/core/inherit.js',
    'test/core/extend.js',
    'test/core/state.js',
    'test/core/ejson.js'
  ], ['client', 'server']);
  // Modules.
  // Modules - Behaviors.
  api.addFiles([
    'test/modules/behaviors/create.js',
    'test/modules/behaviors/apply.js'
  ], ['client', 'server']);
  // Modules - Validators.
  api.addFiles([
    'test/modules/validators/create.js',
    'test/modules/validators/apply.js',
    'test/modules/validators/validate.js',
    'test/modules/validators/validate_callback.js'
  ], ['client', 'server']);
  // Modules - Storage.
  api.addFiles([
    'test/modules/storage/init.js',
    'test/modules/storage/type_field.js',
    'test/modules/storage/transform.js',
    'test/modules/storage/document_insert.js',
    'test/modules/storage/document_update.js',
    'test/modules/storage/document_remove.js',
    'test/modules/storage/class_insert.js',
    'test/modules/storage/class_update.js',
    'test/modules/storage/class_remove.js',
    'test/modules/storage/reload.js',
    'test/modules/storage/copy.js',
  ], ['client', 'server']);
  // Modules - Events.
  api.addFiles([
    'test/modules/events/order.js',
    'test/modules/events/propagation.js',
    'test/modules/events/cancelable.js'
  ], ['client', 'server']);
  // Modules - Fields.
  api.addFiles([
    'test/modules/fields/definition.js',
    'test/modules/fields/default.js',
    'test/modules/fields/set.js',
    'test/modules/fields/get.js',
    'test/modules/fields/raw.js',
    'test/modules/fields/optional.js'
  ], ['client', 'server']);
  // Modules - Indexes.
  api.addFiles([
    // 'test/indexes/indexes_definition.js'
  ], 'server');
  // Modules - Methods.
  api.addFiles([
    // 'test/methods/methods_definition.js'
  ], ['client', 'server']);
});<|endoftext|>


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

var config = require('./config/config.js');
var unreadNotifications = [];
var readNotifications = [];

// find index for new notification based on its timestamp
// assumes 'array' is sorted in ascending order according to .date fields
var findId = function(date, array) {
	for (var i = 0; i < array.length; i++) {
		if(array[i].date >= date)
			return i;
	}

	return array.length;
};

// store notification in (un)readNotifications array at a date sorted index
var storeNotification = function(data_json, read) {
	data_json.text = data_json.text.replace('\t',' '); // tabs to single spaces
	data_json.text = data_json.text.replace(/^\s*/, ""); // get rid of leading ws
	data_json.text = data_json.text.replace(/\s*$/, ""); // get rid of trailing ws

	// plugin did not provide timestamp, create one from current time
	if(!data_json.date)
		data_json.date = new Date().valueOf();

	var primaryArray = unreadNotifications; var secondaryArray = readNotifications;
	if(read) {
		primaryArray = readNotifications; secondaryArray = unreadNotifications;
	}

	if(data_json.uid) {
		// notification has a set UID:
		// look for notification with duplicate UID in both arrays. if found, remove
		var i;
		for(i = primaryArray.length - 1; i >= 0; i--) {
			if(primaryArray[i].uid === data_json.uid) {
				primaryArray.splice(i, 1);
			}
		}
		// look in unread array too, if duplicate UID found there, remove it
		for(i = secondaryArray.length - 1; i >= 0; i--) {
			if(secondaryArray[i].uid === data_json.uid) {
				secondaryArray.splice(i, 1);
			}
		}
	} else {
		// notification lacks UID: generate a pseudo random hash and set it as the UID
		var shasum = crypto.createHash('md5');
		shasum.update(String(Math.random()));
		data_json.uid = shasum.digest('base64');
	}

	if (read) {
		// insert notification at end of readNotifications array
		readNotifications.push(data_json);

		// if readNotifications is full, pop from beginning
		if(readNotifications.length >= config.numReadToKeep) {
			readNotifications.splice(0, 1);
		}

		return readNotifications.length - 1;
	} else {
		// insert notification to unreadNotifications array
		var id = findId(data_json.date, unreadNotifications);
		unreadNotifications.splice(id, 0, data_json);

		return id;
	}
};

// return notifications with matching id, uid, source, context
// if id is given only it will be used. if id is undefined search using other
// fields. undefined fields not included in search.
var range_re = /(\d*)\.\.(\d*)/;
var searchNotifications = function(id, uid, source, context, read) {
	var array = read ? readNotifications : unreadNotifications;

	if(id) {
		var range = id.match(range_re);
		if(range) {
			var min = range[1] || 0;
			var max = range[2] || 9999999999999;
			min = parseInt(min);
			max = parseInt(max);

			if (min > max) {
				var temp = min;
				min = max;
				max = temp;
			}
			return array.filter(function (notification, i) {
				return (i >= min && i <= max);
			});
		} else {
			return array.filter(function (notification, i) {
				return i == id;
			});
		}
	} else {
		return array.filter(function (notification) {
			return (!uid || (notification.uid == uid)) && (!source || (notification.source.toUpperCase() == source.toUpperCase())) && (!context || (notification.context.toUpperCase() == context.toUpperCase()));
		});
	}
};

// update .(un)readID and .read properties of all notifications
var updateIDRead = function() {
	var i;
	for (i = 0; i < unreadNotifications.length; i++) {
		unreadNotifications[i].unreadID = i;
		unreadNotifications[i].read = false;
	}
	for (i = 0; i < readNotifications.length; i++) {
		readNotifications[i].readID = i;
		readNotifications[i].read = true;
	}
};

// mark notifications as (un)read
// move notifications between (un)readNotifications arrays accordingly
// NOTE: all given notifications must already be in (un)readNotifications
var markAs = function(notifications, read) {
	var msg = "";

	// check if arg is object, then make it into an array
	if(Object.prototype.toString.call(notifications) === '[object Object]') {
		notifications = [notifications];
	}

	var i;
	var notification;

	// update read boolean field of every given notification
	for (i = 0; i < notifications.length; i++) {
		notifications[i].read = read;
	}

	// loop through (un)readNotifications. see if we can find any that were
	// marked as (un)read and thus belong to the other array, move these
	if(read) {
		for(i = unreadNotifications.length - 1; i >= 0; i--) {
			if(unreadNotifications[i].read) {
				notification = unreadNotifications[i];
				unreadNotifications.splice(i, 1);
				storeNotification(notification, true);
			}
		}
	} else {
		for(i = readNotifications.length - 1; i >= 0; i--) {
			if(!readNotifications[i].read) {
				notification = readNotifications[i];
				readNotifications.splice(i, 1);
				storeNotification(notification, false);
			}
		}
	}
};

// networking
var tls = require('tls')
var fs = require('fs');
var options = {
	key: fs.readFileSync('config/nodifier-key.pem'),
	cert: fs.readFileSync('config/nodifier-cert.pem'),
	ca: fs.readFileSync('config/nodifier-cert.pem'),
	requestCert: true,
	rejectUnauthorized: true
};
var sockets = [];
var server = tls.createServer(options, function(socket) {
	sockets.push(socket);
	var notifications;

	var recvBuffer = "";
	var incomingLength = 0;

	socket.on('data', function(data) {
		if(!incomingLength) {
			// first message is always the length
			incomingLength = data.toString();
		} else {
			recvBuffer += data.toString();

			// recv'd entire message
			if(recvBuffer.length >= incomingLength) {
				data = JSON.parse(recvBuffer);
				recvBuffer = "";
				incomingLength = 0;
				if(data[0] !== 'data')
					socket.emit(data[0], data[1]);
			}
		}
	});
	socket.send = function(evt, data) {
		data = JSON.stringify([evt, data]);
		socket.write(data.length.toString());
		socket.write(data);
	};
	socket.broadcast = function(evt, data, ignoreSelf) {
		for(var i = 0; i < sockets.length; i++) {
			if(!ignoreSelf || sockets[i] !== socket) {
				sockets[i].send(evt, data);
			}
		}
	};
	socket.on('end', function() {
		if(sockets.indexOf(socket) !== -1)
			sockets.splice(sockets.indexOf(socket), 1);
	});

	socket.on('newNotification', function(notification) {
		// add new notification
		var id = storeNotification(notification, false);
		updateIDRead(); // indices may have changed, fix them

		// broadcast new notification to all connected clients
		socket.broadcast('newNotification', unreadNotifications[id]);
	});
	socket.on('markAs', function(search) {
		// search for notifications and mark results as (un)read according to s.read
		notifications = searchNotifications(search.id, search.uid, search.source, search.context, !search.read);
		if(notifications)
			markAs(notifications, search.read);
		updateIDRead(); // indices/read states may have changed, fix them

		socket.send('notifications', notifications);

		// broadcast updated notifications to all other connected clients
		socket.broadcast('markAs', notifications, true);
	});
	socket.on('getRead', function() {
		socket.send('notifications', readNotifications);
	});
	socket.on('getUnread', function(search) {
		// get unread notifications by id, or all notifications if no search terms
		if(!search) {
			notifications = unreadNotifications;
		} else {
			notifications = searchNotifications(search.id, search.uid, search.source, search.context, false);
		}

		socket.send('notifications', notifications);
	});
});

server.listen(config.port);
console.log('nodifier tls server listening on port ' + config.port);

process.on('uncaughtException', function (err) {
	console.error(err.stack);
	console.log("ERROR! Node not exiting.");
});
<commit_msg>include crypto lib or this won't work<commit_after>#!/usr/bin/env node

var config = require('./config/config.js');
var crypto = require('crypto');
var unreadNotifications = [];
var readNotifications = [];

// find index for new notification based on its timestamp
// assumes 'array' is sorted in ascending order according to .date fields
var findId = function(date, array) {
	for (var i = 0; i < array.length; i++) {
		if(array[i].date >= date)
			return i;
	}

	return array.length;
};

// store notification in (un)readNotifications array at a date sorted index
var storeNotification = function(data_json, read) {
	data_json.text = data_json.text.replace('\t',' '); // tabs to single spaces
	data_json.text = data_json.text.replace(/^\s*/, ""); // get rid of leading ws
	data_json.text = data_json.text.replace(/\s*$/, ""); // get rid of trailing ws

	// plugin did not provide timestamp, create one from current time
	if(!data_json.date)
		data_json.date = new Date().valueOf();

	var primaryArray = unreadNotifications; var secondaryArray = readNotifications;
	if(read) {
		primaryArray = readNotifications; secondaryArray = unreadNotifications;
	}

	if(data_json.uid) {
		// notification has a set UID:
		// look for notification with duplicate UID in both arrays. if found, remove
		var i;
		for(i = primaryArray.length - 1; i >= 0; i--) {
			if(primaryArray[i].uid === data_json.uid) {
				primaryArray.splice(i, 1);
			}
		}
		// look in unread array too, if duplicate UID found there, remove it
		for(i = secondaryArray.length - 1; i >= 0; i--) {
			if(secondaryArray[i].uid === data_json.uid) {
				secondaryArray.splice(i, 1);
			}
		}
	} else {
		// notification lacks UID: generate a pseudo random hash and set it as the UID
		var shasum = crypto.createHash('md5');
		shasum.update(String(Math.random()));
		data_json.uid = shasum.digest('base64');
	}

	if (read) {
		// insert notification at end of readNotifications array
		readNotifications.push(data_json);

		// if readNotifications is full, pop from beginning
		if(readNotifications.length >= config.numReadToKeep) {
			readNotifications.splice(0, 1);
		}

		return readNotifications.length - 1;
	} else {
		// insert notification to unreadNotifications array
		var id = findId(data_json.date, unreadNotifications);
		unreadNotifications.splice(id, 0, data_json);

		return id;
	}
};

// return notifications with matching id, uid, source, context
// if id is given only it will be used. if id is undefined search using other
// fields. undefined fields not included in search.
var range_re = /(\d*)\.\.(\d*)/;
var searchNotifications = function(id, uid, source, context, read) {
	var array = read ? readNotifications : unreadNotifications;

	if(id) {
		var range = id.match(range_re);
		if(range) {
			var min = range[1] || 0;
			var max = range[2] || 9999999999999;
			min = parseInt(min);
			max = parseInt(max);

			if (min > max) {
				var temp = min;
				min = max;
				max = temp;
			}
			return array.filter(function (notification, i) {
				return (i >= min && i <= max);
			});
		} else {
			return array.filter(function (notification, i) {
				return i == id;
			});
		}
	} else {
		return array.filter(function (notification) {
			return (!uid || (notification.uid == uid)) && (!source || (notification.source.toUpperCase() == source.toUpperCase())) && (!context || (notification.context.toUpperCase() == context.toUpperCase()));
		});
	}
};

// update .(un)readID and .read properties of all notifications
var updateIDRead = function() {
	var i;
	for (i = 0; i < unreadNotifications.length; i++) {
		unreadNotifications[i].unreadID = i;
		unreadNotifications[i].read = false;
	}
	for (i = 0; i < readNotifications.length; i++) {
		readNotifications[i].readID = i;
		readNotifications[i].read = true;
	}
};

// mark notifications as (un)read
// move notifications between (un)readNotifications arrays accordingly
// NOTE: all given notifications must already be in (un)readNotifications
var markAs = function(notifications, read) {
	var msg = "";

	// check if arg is object, then make it into an array
	if(Object.prototype.toString.call(notifications) === '[object Object]') {
		notifications = [notifications];
	}

	var i;
	var notification;

	// update read boolean field of every given notification
	for (i = 0; i < notifications.length; i++) {
		notifications[i].read = read;
	}

	// loop through (un)readNotifications. see if we can find any that were
	// marked as (un)read and thus belong to the other array, move these
	if(read) {
		for(i = unreadNotifications.length - 1; i >= 0; i--) {
			if(unreadNotifications[i].read) {
				notification = unreadNotifications[i];
				unreadNotifications.splice(i, 1);
				storeNotification(notification, true);
			}
		}
	} else {
		for(i = readNotifications.length - 1; i >= 0; i--) {
			if(!readNotifications[i].read) {
				notification = readNotifications[i];
				readNotifications.splice(i, 1);
				storeNotification(notification, false);
			}
		}
	}
};

// networking
var tls = require('tls')
var fs = require('fs');
var options = {
	key: fs.readFileSync('config/nodifier-key.pem'),
	cert: fs.readFileSync('config/nodifier-cert.pem'),
	ca: fs.readFileSync('config/nodifier-cert.pem'),
	requestCert: true,
	rejectUnauthorized: true
};
var sockets = [];
var server = tls.createServer(options, function(socket) {
	sockets.push(socket);
	var notifications;

	var recvBuffer = "";
	var incomingLength = 0;

	socket.on('data', function(data) {
		if(!incomingLength) {
			// first message is always the length
			incomingLength = data.toString();
		} else {
			recvBuffer += data.toString();

			// recv'd entire message
			if(recvBuffer.length >= incomingLength) {
				data = JSON.parse(recvBuffer);
				recvBuffer = "";
				incomingLength = 0;
				if(data[0] !== 'data')
					socket.emit(data[0], data[1]);
			}
		}
	});
	socket.send = function(evt, data) {
		data = JSON.stringify([evt, data]);
		socket.write(data.length.toString());
		socket.write(data);
	};
	socket.broadcast = function(evt, data, ignoreSelf) {
		for(var i = 0; i < sockets.length; i++) {
			if(!ignoreSelf || sockets[i] !== socket) {
				sockets[i].send(evt, data);
			}
		}
	};
	socket.on('end', function() {
		if(sockets.indexOf(socket) !== -1)
			sockets.splice(sockets.indexOf(socket), 1);
	});

	socket.on('newNotification', function(notification) {
		// add new notification
		var id = storeNotification(notification, false);
		updateIDRead(); // indices may have changed, fix them

		// broadcast new notification to all connected clients
		socket.broadcast('newNotification', unreadNotifications[id]);
	});
	socket.on('markAs', function(search) {
		// search for notifications and mark results as (un)read according to s.read
		notifications = searchNotifications(search.id, search.uid, search.source, search.context, !search.read);
		if(notifications)
			markAs(notifications, search.read);
		updateIDRead(); // indices/read states may have changed, fix them

		socket.send('notifications', notifications);

		// broadcast updated notifications to all other connected clients
		socket.broadcast('markAs', notifications, true);
	});
	socket.on('getRead', function() {
		socket.send('notifications', readNotifications);
	});
	socket.on('getUnread', function(search) {
		// get unread notifications by id, or all notifications if no search terms
		if(!search) {
			notifications = unreadNotifications;
		} else {
			notifications = searchNotifications(search.id, search.uid, search.source, search.context, false);
		}

		socket.send('notifications', notifications);
	});
});

server.listen(config.port);
console.log('nodifier tls server listening on port ' + config.port);

process.on('uncaughtException', function (err) {
	console.error(err.stack);
	console.log("ERROR! Node not exiting.");
});
<|endoftext|>