<commit_before>/*jslint es5: true, nomen: true, node: true */

/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

/**
 * The MessageQueue is a joynr internal data structure. The Message Queue caches incoming messages, which cannot be shipped
 * to the correct participant. Once a participant with the matching participantId is registered, the incoming message is forwarded to him
 */
var LoggerFactory = require("../../system/LoggerFactory");
var DiagnosticTags = require("../../system/DiagnosticTags");
var Util = require("../../util/UtilInternal");
var ParticipantQueue = require("./ParticipantQueue");

var log = LoggerFactory.getLogger("joynr/messaging/routing/MessageQueue");
var defaultSettings;
var CHECK_TTL_ON_QUEUED_MESSAGES_INTERVAL_MS = 10000; // a very loose interval because of a second check on return
/**
 * MessageQueue caches incoming messages, and cached messages can be retrieved in case the destination participant becomes visible
 *
 * @constructor
 * @name MessageQueue
 *
 * @param {Object}
 *            settings the settings object holding dependencies
 * @param {Number}
 *            settings.maxQueueSizeInKBytes the maximum buffer size that shall be allocated by the message queue
 *
 * @classdesc The MessageQueue is a joynr internal data structure. The Message Queue caches incoming messages, which cannot be shipped
 * to the correct participant. Once a participant with the matching participantId is registered, the incoming message is forwarded to him
 */
function MessageQueue(settings) {
    this._participantQueues = {};
    Util.extend(this, defaultSettings, settings);
    this.currentQueueSize = 0;

    var that = this;
    this.cleanupInterval = setInterval(function() {
        // TODO: we could call this way more lazy -> make an if and only call this if this.currentQueueSize > 100
        var newSize = 0;
        var id;
        for (id in that._participantQueues) {
            if (that._participantQueues.hasOwnProperty(id)) {
                that._participantQueues[id].filterExpiredMessages();
                var size = that._participantQueues[id].getSize();
                newSize += size;
                if (size === 0) {
                    delete that._participantQueues[id];
                }
            }
        }
        that.currentQueueSize = newSize;
    }, CHECK_TTL_ON_QUEUED_MESSAGES_INTERVAL_MS);
}

MessageQueue.DEFAULT_MAX_QUEUE_SIZE_IN_KBYTES = 10000;

defaultSettings = {
    maxQueueSizeInKBytes: MessageQueue.DEFAULT_MAX_QUEUE_SIZE_IN_KBYTES
};

/**
 * resets the queue
 *
 * @name MessageQueue#reset()
 * @function
 *
 */
MessageQueue.prototype.reset = function reset() {
    this.currentQueueSize = 0;
    this._participantQueues = {};
};

/**
 * @name MessageQueue#putMessage
 * @function
 *
 * @param {JoynrMessage}
 *            joynrMessage
 */
MessageQueue.prototype.putMessage = function putMessage(message) {
    // drop message if maximum queue size has been reached
    if (message.payload !== undefined) {
        var messageSize = Util.getLengthInBytes(message.payload);
        if (this.currentQueueSize + messageSize <= this.maxQueueSizeInKBytes * 1024) {
            this.currentQueueSize = this.currentQueueSize + messageSize;
            if (this._participantQueues[message.to] === undefined) {
                this._participantQueues[message.to] = new ParticipantQueue();
            }
            this._participantQueues[message.to].putMessage(message, messageSize);
        } else {
            log.error(
                "message cannot be added to message queue, as the queue buffer size has been exceeded",
                DiagnosticTags.forJoynrMessage(message)
            );
        }
    }
};

/**
 * gets the queue messages for the participant
 *
 * @name MessageQueue#getAndRemoveMessages
 * @function
 *
 * @param {String}
 *            participantId
 */
MessageQueue.prototype.getAndRemoveMessages = function getAndRemoveMessages(participantId) {
    var result = [];
    if (this._participantQueues[participantId] !== undefined) {
        var participantQueue = this._participantQueues[participantId];
        this.currentQueueSize -= participantQueue.getSize();
        participantQueue.filterExpiredMessages();
        result = participantQueue.getMessages();
        delete this._participantQueues[participantId];
    }
    return result;
};

/**
 * Shutdown the message queue
 *
 * @function
 * @name MessageQueue#shutdown
 */
MessageQueue.prototype.shutdown = function shutdown() {
    this._participantQueues = {};
    this.currentQueueSize = 0;
    clearInterval(this.cleanupInterval);
};

module.exports = MessageQueue;
<commit_msg>[JS] delete MessageQueue.reset() as it is not used<commit_after>/*jslint es5: true, nomen: true, node: true */

/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

/**
 * The MessageQueue is a joynr internal data structure. The Message Queue caches incoming messages, which cannot be shipped
 * to the correct participant. Once a participant with the matching participantId is registered, the incoming message is forwarded to him
 */
var LoggerFactory = require("../../system/LoggerFactory");
var DiagnosticTags = require("../../system/DiagnosticTags");
var Util = require("../../util/UtilInternal");
var ParticipantQueue = require("./ParticipantQueue");

var log = LoggerFactory.getLogger("joynr/messaging/routing/MessageQueue");
var defaultSettings;
var CHECK_TTL_ON_QUEUED_MESSAGES_INTERVAL_MS = 10000; // a very loose interval because of a second check on return
/**
 * MessageQueue caches incoming messages, and cached messages can be retrieved in case the destination participant becomes visible
 *
 * @constructor
 * @name MessageQueue
 *
 * @param {Object}
 *            settings the settings object holding dependencies
 * @param {Number}
 *            settings.maxQueueSizeInKBytes the maximum buffer size that shall be allocated by the message queue
 *
 * @classdesc The MessageQueue is a joynr internal data structure. The Message Queue caches incoming messages, which cannot be shipped
 * to the correct participant. Once a participant with the matching participantId is registered, the incoming message is forwarded to him
 */
function MessageQueue(settings) {
    this._participantQueues = {};
    Util.extend(this, defaultSettings, settings);
    this.currentQueueSize = 0;

    var that = this;
    this.cleanupInterval = setInterval(function() {
        // TODO: we could call this way more lazy -> make an if and only call this if this.currentQueueSize > 100
        var newSize = 0;
        var id;
        for (id in that._participantQueues) {
            if (that._participantQueues.hasOwnProperty(id)) {
                that._participantQueues[id].filterExpiredMessages();
                var size = that._participantQueues[id].getSize();
                newSize += size;
                if (size === 0) {
                    delete that._participantQueues[id];
                }
            }
        }
        that.currentQueueSize = newSize;
    }, CHECK_TTL_ON_QUEUED_MESSAGES_INTERVAL_MS);
}

MessageQueue.DEFAULT_MAX_QUEUE_SIZE_IN_KBYTES = 10000;

defaultSettings = {
    maxQueueSizeInKBytes: MessageQueue.DEFAULT_MAX_QUEUE_SIZE_IN_KBYTES
};

/**
 * @name MessageQueue#putMessage
 * @function
 *
 * @param {JoynrMessage}
 *            joynrMessage
 */
MessageQueue.prototype.putMessage = function putMessage(message) {
    // drop message if maximum queue size has been reached
    if (message.payload !== undefined) {
        var messageSize = Util.getLengthInBytes(message.payload);
        if (this.currentQueueSize + messageSize <= this.maxQueueSizeInKBytes * 1024) {
            this.currentQueueSize = this.currentQueueSize + messageSize;
            if (this._participantQueues[message.to] === undefined) {
                this._participantQueues[message.to] = new ParticipantQueue();
            }
            this._participantQueues[message.to].putMessage(message, messageSize);
        } else {
            log.error(
                "message cannot be added to message queue, as the queue buffer size has been exceeded",
                DiagnosticTags.forJoynrMessage(message)
            );
        }
    }
};

/**
 * gets the queue messages for the participant
 *
 * @name MessageQueue#getAndRemoveMessages
 * @function
 *
 * @param {String}
 *            participantId
 */
MessageQueue.prototype.getAndRemoveMessages = function getAndRemoveMessages(participantId) {
    var result = [];
    if (this._participantQueues[participantId] !== undefined) {
        var participantQueue = this._participantQueues[participantId];
        this.currentQueueSize -= participantQueue.getSize();
        participantQueue.filterExpiredMessages();
        result = participantQueue.getMessages();
        delete this._participantQueues[participantId];
    }
    return result;
};

/**
 * Shutdown the message queue
 *
 * @function
 * @name MessageQueue#shutdown
 */
MessageQueue.prototype.shutdown = function shutdown() {
    this._participantQueues = {};
    this.currentQueueSize = 0;
    clearInterval(this.cleanupInterval);
};

module.exports = MessageQueue;
<|endoftext|>


<commit_before>'use strict'

global.ECONOMY_CRASHED = 0
global.ECONOMY_FALTERING = 1
global.ECONOMY_DEVELOPING = 2
global.ECONOMY_STABLE = 3
global.ECONOMY_SURPLUS = 4
global.ECONOMY_BURSTING = 5

// Will return true for economic levels at or above these values.
const economySettings = {
  'SUPPLY_TERMINAL': ECONOMY_FALTERING,

  'EXPAND_FROM': ECONOMY_DEVELOPING,
  'WALLBUILDERS': ECONOMY_DEVELOPING,
  'BUILD_STRUCTURES': ECONOMY_DEVELOPING,
  'REMOTE_MINES': ECONOMY_DEVELOPING,

  'EXTRACT_MINERALS': ECONOMY_STABLE,
  'UPGRADE_CONTROLLERS': ECONOMY_STABLE,
  'FILL_NUKER': ECONOMY_STABLE,
  'FILL_POWER_SPAWN': ECONOMY_STABLE,

  'EXTRA_UPGRADERS': ECONOMY_SURPLUS,
  'EXTRA_WALLBUILDERS': ECONOMY_SURPLUS,
  'SHARE_ENERGY': ECONOMY_SURPLUS,

  'MORE_EXTRA_UPGRADERS': ECONOMY_BURSTING,
  'DUMP_ENERGY': ECONOMY_BURSTING
}

// Will return true for economic levels at or below these values.
const economyNegativeSettings = {
  'REQUEST_ENERGY': ECONOMY_FALTERING
}

Room.prototype.isEconomyCapable = function (key) {
  if (Number.isInteger(economySettings[key])) {
    return this.getEconomyLevel() >= economySettings[key]
  }
  if (Number.isInteger(economyNegativeSettings[key])) {
    return this.getEconomyLevel() <= economyNegativeSettings[key]
  }
  return false
}

Room.prototype.getEconomyLevel = function () {
  if (this.getPracticalRoomLevel() < 4) {
    return ECONOMY_STABLE
  }

  const desiredBuffer = this.getDesiredEnergyBuffer()
  const energy = this.getEnergyAmount()

  if (energy < 15000) {
    return ECONOMY_CRASHED
  }

  // When fully developed between 15000 and 280000
  if (energy < (desiredBuffer - 20000)) {
    return ECONOMY_FALTERING
  }

  // When fully developed between 280000 and 300000
  if (energy < (desiredBuffer)) {
    return ECONOMY_DEVELOPING
  }

  // When fully developed between 300000 and 320000
  if (energy < (desiredBuffer + 20000)) {
    return ECONOMY_STABLE
  }

  // Need to ditch energy as we have way too much in storage
  if (_.sum(this.storage.storage) > this.storage.storeCapacity * 0.9) {
    return ECONOMY_BURSTING
  }

  // When fully developed over 320000
  return ECONOMY_SURPLUS
}

Room.prototype.getEnergyAmount = function () {
  let energy = 0
  if (this.storage && this.storage.store[RESOURCE_ENERGY]) {
    energy += this.storage.store[RESOURCE_ENERGY]
  }
  if (this.terminal && this.terminal.store[RESOURCE_ENERGY]) {
    energy += this.terminal.store[RESOURCE_ENERGY]
  }
  return energy
}

Room.prototype.getDesiredEnergyBuffer = function () {
  const roomLevel = this.getPracticalRoomLevel()
  if (roomLevel < 4) {
    return 0
  }
  if (this.name === 'sim') {
    return 40000
  }
  return Math.min((roomLevel - 3) * 100000, 300000)
}

Room.prototype.getSinkLinks = function () {
  if (this.__linksinks) {
    return this.__linksinks
  }
  const links = this.structures[STRUCTURE_LINK]
  const sources = this.find(FIND_SOURCES)
  const sinks = []
  for (const link of links) {
    if (link.pos.getRangeTo(sources[0]) <= 2) {
      continue
    }
    if (sources.length > 1 && link.pos.getRangeTo(sources[1]) <= 2) {
      continue
    }
    sinks.push(link)
  }
  sinks.sort((a, b) => a.energy - b.energy)
  this.__linksinks = sinks
  return sinks
}
<commit_msg>Prioritize non-storage sink links, narrow source link identification<commit_after>'use strict'

global.ECONOMY_CRASHED = 0
global.ECONOMY_FALTERING = 1
global.ECONOMY_DEVELOPING = 2
global.ECONOMY_STABLE = 3
global.ECONOMY_SURPLUS = 4
global.ECONOMY_BURSTING = 5

// Will return true for economic levels at or above these values.
const economySettings = {
  'SUPPLY_TERMINAL': ECONOMY_FALTERING,

  'EXPAND_FROM': ECONOMY_DEVELOPING,
  'WALLBUILDERS': ECONOMY_DEVELOPING,
  'BUILD_STRUCTURES': ECONOMY_DEVELOPING,
  'REMOTE_MINES': ECONOMY_DEVELOPING,

  'EXTRACT_MINERALS': ECONOMY_STABLE,
  'UPGRADE_CONTROLLERS': ECONOMY_STABLE,
  'FILL_NUKER': ECONOMY_STABLE,
  'FILL_POWER_SPAWN': ECONOMY_STABLE,

  'EXTRA_UPGRADERS': ECONOMY_SURPLUS,
  'EXTRA_WALLBUILDERS': ECONOMY_SURPLUS,
  'SHARE_ENERGY': ECONOMY_SURPLUS,

  'MORE_EXTRA_UPGRADERS': ECONOMY_BURSTING,
  'DUMP_ENERGY': ECONOMY_BURSTING
}

// Will return true for economic levels at or below these values.
const economyNegativeSettings = {
  'REQUEST_ENERGY': ECONOMY_FALTERING
}

Room.prototype.isEconomyCapable = function (key) {
  if (Number.isInteger(economySettings[key])) {
    return this.getEconomyLevel() >= economySettings[key]
  }
  if (Number.isInteger(economyNegativeSettings[key])) {
    return this.getEconomyLevel() <= economyNegativeSettings[key]
  }
  return false
}

Room.prototype.getEconomyLevel = function () {
  if (this.getPracticalRoomLevel() < 4) {
    return ECONOMY_STABLE
  }

  const desiredBuffer = this.getDesiredEnergyBuffer()
  const energy = this.getEnergyAmount()

  if (energy < 15000) {
    return ECONOMY_CRASHED
  }

  // When fully developed between 15000 and 280000
  if (energy < (desiredBuffer - 20000)) {
    return ECONOMY_FALTERING
  }

  // When fully developed between 280000 and 300000
  if (energy < (desiredBuffer)) {
    return ECONOMY_DEVELOPING
  }

  // When fully developed between 300000 and 320000
  if (energy < (desiredBuffer + 20000)) {
    return ECONOMY_STABLE
  }

  // Need to ditch energy as we have way too much in storage
  if (_.sum(this.storage.storage) > this.storage.storeCapacity * 0.9) {
    return ECONOMY_BURSTING
  }

  // When fully developed over 320000
  return ECONOMY_SURPLUS
}

Room.prototype.getEnergyAmount = function () {
  let energy = 0
  if (this.storage && this.storage.store[RESOURCE_ENERGY]) {
    energy += this.storage.store[RESOURCE_ENERGY]
  }
  if (this.terminal && this.terminal.store[RESOURCE_ENERGY]) {
    energy += this.terminal.store[RESOURCE_ENERGY]
  }
  return energy
}

Room.prototype.getDesiredEnergyBuffer = function () {
  const roomLevel = this.getPracticalRoomLevel()
  if (roomLevel < 4) {
    return 0
  }
  if (this.name === 'sim') {
    return 40000
  }
  return Math.min((roomLevel - 3) * 100000, 300000)
}

Room.prototype.getSinkLinks = function () {
  if (this.__linksinks) {
    return this.__linksinks
  }
  const links = this.structures[STRUCTURE_LINK]
  const storageLink = this.storage ? this.storage.getLink() : false
  const sources = this.find(FIND_SOURCES)
  const sinks = []
  for (const link of links) {
    if (storageLink && storageLink.id === link.id) {
      continue
    }
    if (link.pos.getRangeTo(sources[0]) <= 2) {
      continue
    }
    if (sources.length > 1 && link.pos.getRangeTo(sources[1].getMiningPosition()) <= 1) {
      continue
    }
    // Don't include links that don't have room for energy.
    if ((link.energyCapacity - link.energy) < 50) {
      continue
    }
    sinks.push(link)
  }
  sinks.sort((a, b) => a.energy - b.energy)
  // Always put storageLink last.
  if (storageLink) {
    sinks.push(storageLink)
  }
  this.__linksinks = sinks
  return sinks
}
<|endoftext|>


<commit_before>import {escapeLatexText} from "./escape-latex"

export class LatexExporterConvert {
    constructor(exporter, imageDB, bibDB) {
        this.exporter = exporter
        this.imageDB = imageDB
        this.bibDB = bibDB
        this.imageIds = []
        this.usedBibDB = {}
        // While walking the tree, we take note of the kinds of features That
        // are present in the file, so that we can assemble an preamble and
        // epilogue based on our findings.
        this.features = {}
    }

    init(docContents) {
        let rawTransformation = this.walkJson(docContents)
        let body = this.postProcess(rawTransformation)
        let preamble = this.assemblePreamble()
        let epilogue = this.assembleEpilogue()
        let latex = this.docDeclaration + preamble + body + epilogue
        let returnObject = {
            latex,
            imageIds: this.imageIds,
            usedBibDB: this.usedBibDB
        }
        return returnObject
    }

    get docDeclaration() {
        return '\\documentclass{article}\n'
    }

    walkJson(node, options = {}) {
        let start = '', content = '', end = '',
            placeFootnotesAfterBlock = false, that = this

        switch(node.type) {
            case 'article':
                start += '\n\\begin{document}\n'
                end = '\n\\end{document}\n' + end
                break
            case 'title':
                start += '\n\\title{'
                end = '}' + end
                break
            case 'subtitle':
                if (node.content) {
                    start += '\n\\subtitle{'
                    end = '}' + end
                    this.features.subtitle = true
                }
                break
            case 'authors':
                if (node.content) {
                    start += '\n\\author{'
                    end = '}' + end
                }
                // We add the maketitle command here. TODO: This relies on the
                // existence of a subtitle node, even if it has no content.
                // It would be better if it wouldn't have to rely on this.
                start += '\n\n\\maketitle\n'
                break
            case 'keywords':
                if (node.content) {
                    start += '\n\\keywords{'
                    end = '}' + end
                    this.features.keywords = true
                }
                break
            case 'abstract':
                if (node.content) {
                    start += '\n\\begin{abstract}\n'
                    end = '\n\\end{abstract}\n' + end
                }
                break
            case 'body':
                break
            case 'paragraph':
                start += '\n\n'
                end = '\n' + end
                break
            case 'heading':
                let level = node.attrs.level
                switch(level) {
                    case 1:
                        start += '\n\n\\section{'
                        break;
                    case 2:
                        start += '\n\n\\subsection{'
                        break;
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                        // TODO: Add support for levels 4/5/6
                        start += '\n\n\\subsubsection{'
                        break;
                }
                end = '}\n\n' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'code':
                start += '\n\\begin{code}\n\n'
                end = '\n\n\\end{code}\n'
                break
            case 'blockquote':
                start += '\n\\begin{quote}\n\n'
                end = '\n\n\\end{quote}\n'
                break
            case 'ordered_list':
                start += '\n\\begin{enumerated}'
                end = '\n\\end{enumerated}' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'bullet_list':
                start += '\n\\begin{itemize}'
                end = '\n\\end{itemize}' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'list_item':
                start += '\n\\item '
                end = '\n' + end
                break
            case 'footnote':
                if (options.onlyFootnoteMarkers) {
                    // We are inside a headline or a list and can only place a
                    // footnote marker here. The footnote will have to be put
                    // beyond the block node instead.
                    start += '\\protect\\footnotemark'
                    options.unplacedFootnotes.push(node.attrs.footnote)
                } else {
                    start += '\\footnote{'
                    content += this.walkJson(node.attrs.footnote, options)
                    end = '}' + end
                }
                break
            case 'text':
                // Check for hyperlink, bold/strong and italic/em
                let hyperlink, strong, em
                if (node.marks) {
                    strong = _.findWhere(node.marks, {type:'strong'})
                    em = _.findWhere(node.marks, {type:'em'})
                    hyperlink = _.findWhere(node.marks, {type:'link'})
                }
                if (em) {
                    start += '\\emph{'
                    end = '}' + end
                }
                if (strong) {
                    start += '\\textbf{'
                    end = '}' + end
                }
                if (hyperlink) {
                    start += `\\href{${hyperlink.attrs.href}}{`
                    end = '}' + end
                    this.features.hyperlinks = true
                }
                content += escapeLatexText(node.text)
                break
            case 'citation':
                let references = node.attrs.references
                let format = node.attrs.format
                let citationCommand = '\\' + format

                if (references.length > 1 &&
                    references.every(ref => !ref.locator && !ref.prefix)
                ) {
                    // multi source citation without page numbers or text before.
                    let citationEntryKeys = []

                    let allCitationItemsPresent = references.map(ref => ref.id).every(
                        function(citationEntry) {
                            let bibDBEntry = that.bibDB.db[citationEntry]
                            if (bibDBEntry) {
                                if (!bibDBEntry) {
                                    // Not present in bibliography database, skip it.
                                    // TODO: Throw an error?
                                    return false
                                }
                                if (!that.usedBibDB[citationEntry]) {
                                    let citationKey = that.createUniqueCitationKey(
                                        bibDBEntry.entry_key
                                    )
                                    that.usedBibDB[citationEntry] = Object.assign({}, bibDBEntry)
                                    that.usedBibDB[citationEntry].entry_key = citationKey
                                }
                                citationEntryKeys.push(that.usedBibDB[citationEntry].entry_key)
                            }
                            return true
                        }
                    )
                    if (allCitationItemsPresent) {
                        citationCommand += `{${citationEntryKeys.join(',')}}`
                    } else {
                        citationCommand = false
                    }
                } else {
                    if (references.length > 1) {
                        citationCommand += 's' // Switching from \autocite to \autocites
                    }

                    let allCitationItemsPresent = references.every(
                        ref => {
                            let bibDBEntry = that.bibDB.db[ref.id]
                            if (!bibDBEntry) {
                                // Not present in bibliography database, skip it.
                                // TODO: Throw an error?
                                return false
                            }

                            if (ref.prefix) {
                                citationCommand += `[${ref.prefix}]`
                                if (!ref.locator) {
                                    citationCommand += '[]'
                                }
                            }
                            if (ref.locator) {
                                citationCommand += `[${ref.locator}]`
                            }
                            citationCommand += '{'

                            if (!that.usedBibDB[ref.id]) {
                                let citationKey = that.createUniqueCitationKey(
                                    bibDBEntry.entry_key
                                )
                                that.usedBibDB[ref.id] = Object.assign({}, bibDBEntry)
                                that.usedBibDB[ref.id].entry_key = citationKey
                            }
                            citationCommand += that.usedBibDB[ref.id].entry_key
                            citationCommand += '}'

                            return true
                        }
                    )

                    if (!allCitationItemsPresent) {
                        citationCommand = false
                    }
                }
                if (citationCommand) {
                    content += citationCommand
                    this.features.citations = true
                }
                break
            case 'figure':
                let latexPackage
                let figureType = node.attrs.figureCategory
                let caption = node.attrs.caption
                let imageDBEntry = this.imageDB.db[node.attrs.image]
                this.imageIds.push(node.attrs.image)
                let filePathName = imageDBEntry.image
                let innerFigure = ''
                if (filePathName) {
                    let filename = filePathName.split('/').pop()
                    if (filename.split('.').pop() === 'svg') {
                        latexPackage = 'includesvg'
                        this.features.SVGs = true
                    } else {
                        latexPackage = 'scaledgraphics'
                        this.features.images = true
                    }
                    innerFigure += `\\${latexPackage}{${filename}}\n`
                } else {
                    let equation = node.attrs.equation
                    innerFigure += `\\begin{displaymath}\n${equation}\n\\end{displaymath}\n`
                }
                if (figureType==='table') {
                    content += `\n\\begin{table}\n\\caption{${caption}}\n${innerFigure}\\end{table}\n`
                } else { // TODO: handle photo figure types in a special way
                    content += `\n\\begin{figure}\n${innerFigure}\\caption{${caption}}\n\\end{figure}\n`
                }
                break
            case 'table':
                start += `\n\n\\begin{tabularx}{\\textwidth}{ |${'X|'.repeat(node.attrs.columns)} }\n\\hline\n\n`
                end += `\n\n\\end{tabularx}`
                this.features.tables = true
                break
            case 'table_row':
                end += ' \\\\ \\hline\n'
                break
            case 'table_cell':
                end += ' & '
                break
            case 'equation':
                content += `$${node.attrs.equation}$`
                break
            default:
                console.warn('Unhandled node type:' + node.type)
                break
        }

        if (node.content) {
            node.content.forEach(child => {
                content += this.walkJson(child, options)
            })
        }

        if (placeFootnotesAfterBlock &&
            options.unplacedFootnotes &&
            options.unplacedFootnotes.length) {
            // There are footnotes that needed to be placed behind the node.
            // This happens in the case of headlines and lists.
            if (options.unplacedFootnotes.length > 1) {
                end += `\\addtocounter{footnote}{-${(options.unplacedFootnotes.length)}}`
                options.unplacedFootnotes.forEach(footnote => {
                    end += '\\stepcounter{footnote}\n'
                    end += '\\footnotetext{'
                    end += this.walkJson(footnote, options)
                    end += '}'
                })
                options.unplacedFootnotes = []
            }
        }

        return start + content + end
    }

    // The database doesn't ensure that citation keys are unique.
    // So here we need to make sure that the same key is not used twice in one
    // document.
    createUniqueCitationKey(suggestedKey) {
        let usedKeys = Object.keys(this.usedBibDB).map(key=>{
            return this.usedBibDB[key].entry_key
        })
        if (usedKeys.includes(suggestedKey)) {
            suggestedKey += 'X'
            return this.createUniqueCitationKey(suggestedKey)
        } else {
            return suggestedKey
        }
    }

    postProcess(latex) {
        return latex
        // join blocks of the same type that follow oneanother.
        .replace(/\\end{code}\n\n\\begin{code}\n\n/g, '')
        .replace(/\\end{quote}\n\n\\begin{quote}\n\n/g, '')
        // Remove the last divider in any any table row.
        .replace(/&  \\\\/g, '\\\\')
        // Remove new lines between table cells.
        .replace(/\n & \n\n/g, ' & ')
        // Remove new lines within itemization
        .replace(/\\item \n\n/g, '\\item ')
    }

    assembleEpilogue() {
        let epilogue = ''
        if (this.features.citations) {
            epilogue += '\n\n\\printbibliography'
        }
        return epilogue
    }

    assemblePreamble() {
        let preamble = '\n\\usepackage[utf8]{luainputenc}'

        if (this.features.subtitle) {
            preamble += `
                \n\\usepackage{titling}
                \n\\newcommand{\\subtitle}[1]{%
                    \n\t\\posttitle{%
                        \n\t\t\\par\\end{center}
                        \n\t\t\\begin{center}\\large#1\\end{center}
                        \n\t\t\\vskip 0.5em}%
                }
            `
        }

        if (this.features.keywords) {
            preamble += `
                \n\\def\\keywords{\\vspace{.5em}
                \n{\\textit{Keywords}:\\,\\relax%
                \n}}
                \n\\def\\endkeywords{\\par}
            `
        }

        if (this.features.hyperlinks) {
            preamble += '\n\\usepackage{hyperref}'
        }

        if (this.features.citations) {
            preamble += `
                \n\\usepackage[backend=biber,hyperref=false,citestyle=authoryear,bibstyle=authoryear]{biblatex}
                \n\\bibliography{bibliography}
            `
        }

        if (this.features.SVGs) {
            preamble += '\n\\usepackage{svg}'
        }

        if (this.features.images) {
            preamble += '\n\\usepackage{graphicx}'
            // The following scales graphics down to text width, but not scaling them up if they are smaller
            preamble += `
                \n\\usepackage{calc}
                \n\\newlength{\\imgwidth}
                \n\\newcommand\\scaledgraphics[1]{%
                \n\\settowidth{\\imgwidth}{\\includegraphics{#1}}%
                \n\\setlength{\\imgwidth}{\\minof{\\imgwidth}{\\textwidth}}%
                \n\\includegraphics[width=\\imgwidth,height=\\textheight,keepaspectratio]{#1}%
                \n}
            `
        }

        if (this.features.tables) {
            preamble += '\n\\usepackage{tabularx}'
        }

        return preamble

    }

}
<commit_msg>fix footnotes in latex export, fixes part of #406<commit_after>import {escapeLatexText} from "./escape-latex"

export class LatexExporterConvert {
    constructor(exporter, imageDB, bibDB) {
        this.exporter = exporter
        this.imageDB = imageDB
        this.bibDB = bibDB
        this.imageIds = []
        this.usedBibDB = {}
        // While walking the tree, we take note of the kinds of features That
        // are present in the file, so that we can assemble an preamble and
        // epilogue based on our findings.
        this.features = {}
    }

    init(docContents) {
        let rawTransformation = this.walkJson(docContents)
        let body = this.postProcess(rawTransformation)
        let preamble = this.assemblePreamble()
        let epilogue = this.assembleEpilogue()
        let latex = this.docDeclaration + preamble + body + epilogue
        let returnObject = {
            latex,
            imageIds: this.imageIds,
            usedBibDB: this.usedBibDB
        }
        return returnObject
    }

    get docDeclaration() {
        return '\\documentclass{article}\n'
    }

    walkJson(node, options = {}) {
        let start = '', content = '', end = '',
            placeFootnotesAfterBlock = false, that = this

        switch(node.type) {
            case 'article':
                start += '\n\\begin{document}\n'
                end = '\n\\end{document}\n' + end
                break
            case 'title':
                start += '\n\\title{'
                end = '}' + end
                break
            case 'subtitle':
                if (node.content) {
                    start += '\n\\subtitle{'
                    end = '}' + end
                    this.features.subtitle = true
                }
                break
            case 'authors':
                if (node.content) {
                    start += '\n\\author{'
                    end = '}' + end
                }
                // We add the maketitle command here. TODO: This relies on the
                // existence of a subtitle node, even if it has no content.
                // It would be better if it wouldn't have to rely on this.
                start += '\n\n\\maketitle\n'
                break
            case 'keywords':
                if (node.content) {
                    start += '\n\\keywords{'
                    end = '}' + end
                    this.features.keywords = true
                }
                break
            case 'abstract':
                if (node.content) {
                    start += '\n\\begin{abstract}\n'
                    end = '\n\\end{abstract}\n' + end
                }
                break
            case 'body':
                break
            case 'paragraph':
                start += '\n\n'
                end = '\n' + end
                break
            case 'heading':
                let level = node.attrs.level
                switch(level) {
                    case 1:
                        start += '\n\n\\section{'
                        break;
                    case 2:
                        start += '\n\n\\subsection{'
                        break;
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                        // TODO: Add support for levels 4/5/6
                        start += '\n\n\\subsubsection{'
                        break;
                }
                end = '}\n\n' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'code':
                start += '\n\\begin{code}\n\n'
                end = '\n\n\\end{code}\n'
                break
            case 'blockquote':
                start += '\n\\begin{quote}\n\n'
                end = '\n\n\\end{quote}\n'
                break
            case 'ordered_list':
                start += '\n\\begin{enumerated}'
                end = '\n\\end{enumerated}' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'bullet_list':
                start += '\n\\begin{itemize}'
                end = '\n\\end{itemize}' + end
                if(!options.onlyFootnoteMarkers) {
                    placeFootnotesAfterBlock = true
                    options = _.clone(options)
                    options.onlyFootnoteMarkers = true
                    options.unplacedFootnotes = []
                }
                break
            case 'list_item':
                start += '\n\\item '
                end = '\n' + end
                break
            case 'footnote':
                if (options.onlyFootnoteMarkers) {
                    // We are inside a headline or a list and can only place a
                    // footnote marker here. The footnote will have to be put
                    // beyond the block node instead.
                    start += '\\protect\\footnotemark{}'
                    options.unplacedFootnotes.push(node.attrs.footnote)
                } else {
                    start += '\\footnote{'
                    node.attrs.footnote.forEach(footPar => {
                        content += this.walkJson(footPar, options).replace(/^\s+|\s+$/g, '')
                    })
                    end = '}' + end
                }
                break
            case 'text':
                // Check for hyperlink, bold/strong and italic/em
                let hyperlink, strong, em
                if (node.marks) {
                    strong = _.findWhere(node.marks, {type:'strong'})
                    em = _.findWhere(node.marks, {type:'em'})
                    hyperlink = _.findWhere(node.marks, {type:'link'})
                }
                if (em) {
                    start += '\\emph{'
                    end = '}' + end
                }
                if (strong) {
                    start += '\\textbf{'
                    end = '}' + end
                }
                if (hyperlink) {
                    start += `\\href{${hyperlink.attrs.href}}{`
                    end = '}' + end
                    this.features.hyperlinks = true
                }
                content += escapeLatexText(node.text)
                break
            case 'citation':
                let references = node.attrs.references
                let format = node.attrs.format
                let citationCommand = '\\' + format

                if (references.length > 1 &&
                    references.every(ref => !ref.locator && !ref.prefix)
                ) {
                    // multi source citation without page numbers or text before.
                    let citationEntryKeys = []

                    let allCitationItemsPresent = references.map(ref => ref.id).every(
                        function(citationEntry) {
                            let bibDBEntry = that.bibDB.db[citationEntry]
                            if (bibDBEntry) {
                                if (!bibDBEntry) {
                                    // Not present in bibliography database, skip it.
                                    // TODO: Throw an error?
                                    return false
                                }
                                if (!that.usedBibDB[citationEntry]) {
                                    let citationKey = that.createUniqueCitationKey(
                                        bibDBEntry.entry_key
                                    )
                                    that.usedBibDB[citationEntry] = Object.assign({}, bibDBEntry)
                                    that.usedBibDB[citationEntry].entry_key = citationKey
                                }
                                citationEntryKeys.push(that.usedBibDB[citationEntry].entry_key)
                            }
                            return true
                        }
                    )
                    if (allCitationItemsPresent) {
                        citationCommand += `{${citationEntryKeys.join(',')}}`
                    } else {
                        citationCommand = false
                    }
                } else {
                    if (references.length > 1) {
                        citationCommand += 's' // Switching from \autocite to \autocites
                    }

                    let allCitationItemsPresent = references.every(
                        ref => {
                            let bibDBEntry = that.bibDB.db[ref.id]
                            if (!bibDBEntry) {
                                // Not present in bibliography database, skip it.
                                // TODO: Throw an error?
                                return false
                            }

                            if (ref.prefix) {
                                citationCommand += `[${ref.prefix}]`
                                if (!ref.locator) {
                                    citationCommand += '[]'
                                }
                            }
                            if (ref.locator) {
                                citationCommand += `[${ref.locator}]`
                            }
                            citationCommand += '{'

                            if (!that.usedBibDB[ref.id]) {
                                let citationKey = that.createUniqueCitationKey(
                                    bibDBEntry.entry_key
                                )
                                that.usedBibDB[ref.id] = Object.assign({}, bibDBEntry)
                                that.usedBibDB[ref.id].entry_key = citationKey
                            }
                            citationCommand += that.usedBibDB[ref.id].entry_key
                            citationCommand += '}'

                            return true
                        }
                    )

                    if (!allCitationItemsPresent) {
                        citationCommand = false
                    }
                }
                if (citationCommand) {
                    content += citationCommand
                    this.features.citations = true
                }
                break
            case 'figure':
                let latexPackage
                let figureType = node.attrs.figureCategory
                let caption = node.attrs.caption
                let imageDBEntry = this.imageDB.db[node.attrs.image]
                this.imageIds.push(node.attrs.image)
                let filePathName = imageDBEntry.image
                let innerFigure = ''
                if (filePathName) {
                    let filename = filePathName.split('/').pop()
                    if (filename.split('.').pop() === 'svg') {
                        latexPackage = 'includesvg'
                        this.features.SVGs = true
                    } else {
                        latexPackage = 'scaledgraphics'
                        this.features.images = true
                    }
                    innerFigure += `\\${latexPackage}{${filename}}\n`
                } else {
                    let equation = node.attrs.equation
                    innerFigure += `\\begin{displaymath}\n${equation}\n\\end{displaymath}\n`
                }
                if (figureType==='table') {
                    content += `\n\\begin{table}\n\\caption{${caption}}\n${innerFigure}\\end{table}\n`
                } else { // TODO: handle photo figure types in a special way
                    content += `\n\\begin{figure}\n${innerFigure}\\caption{${caption}}\n\\end{figure}\n`
                }
                break
            case 'table':
                start += `\n\n\\begin{tabularx}{\\textwidth}{ |${'X|'.repeat(node.attrs.columns)} }\n\\hline\n\n`
                end += `\n\n\\end{tabularx}`
                this.features.tables = true
                break
            case 'table_row':
                end += ' \\\\ \\hline\n'
                break
            case 'table_cell':
                end += ' & '
                break
            case 'equation':
                content += `$${node.attrs.equation}$`
                break
            case 'hard_break':
                content += '\n\n'
                break
            default:
                console.warn('Unhandled node type:' + node.type)
                break
        }

        if (node.content) {
            node.content.forEach(child => {
                content += this.walkJson(child, options)
            })
        }

        if (placeFootnotesAfterBlock &&
            options.unplacedFootnotes &&
            options.unplacedFootnotes.length) {
            // There are footnotes that needed to be placed behind the node.
            // This happens in the case of headlines and lists.
            if (options.unplacedFootnotes.length > 1) {
                end += `\\addtocounter{footnote}{-${(options.unplacedFootnotes.length)}}`
                options.unplacedFootnotes.forEach(footnote => {
                    end += '\\stepcounter{footnote}\n'
                    end += '\\footnotetext{'
                    footnote.forEach(footPar => {
                        end += this.walkJson(footPar, options).replace(/^\s+|\s+$/g, '')
                    })
                    end += '}'
                })
                options.unplacedFootnotes = []
            }
        }

        return start + content + end
    }

    // The database doesn't ensure that citation keys are unique.
    // So here we need to make sure that the same key is not used twice in one
    // document.
    createUniqueCitationKey(suggestedKey) {
        let usedKeys = Object.keys(this.usedBibDB).map(key=>{
            return this.usedBibDB[key].entry_key
        })
        if (usedKeys.includes(suggestedKey)) {
            suggestedKey += 'X'
            return this.createUniqueCitationKey(suggestedKey)
        } else {
            return suggestedKey
        }
    }

    postProcess(latex) {
        return latex
        // join blocks of the same type that follow oneanother.
        .replace(/\\end{code}\n\n\\begin{code}\n\n/g, '')
        .replace(/\\end{quote}\n\n\\begin{quote}\n\n/g, '')
        // Remove the last divider in any any table row.
        .replace(/&  \\\\/g, '\\\\')
        // Remove new lines between table cells.
        .replace(/\n & \n\n/g, ' & ')
        // Remove new lines within itemization
        .replace(/\\item \n\n/g, '\\item ')
    }

    assembleEpilogue() {
        let epilogue = ''
        if (this.features.citations) {
            epilogue += '\n\n\\printbibliography'
        }
        return epilogue
    }

    assemblePreamble() {
        let preamble = '\n\\usepackage[utf8]{luainputenc}'

        if (this.features.subtitle) {
            preamble += `
                \n\\usepackage{titling}
                \n\\newcommand{\\subtitle}[1]{%
                    \n\t\\posttitle{%
                        \n\t\t\\par\\end{center}
                        \n\t\t\\begin{center}\\large#1\\end{center}
                        \n\t\t\\vskip 0.5em}%
                }
            `
        }

        if (this.features.keywords) {
            preamble += `
                \n\\def\\keywords{\\vspace{.5em}
                \n{\\textit{Keywords}:\\,\\relax%
                \n}}
                \n\\def\\endkeywords{\\par}
            `
        }

        if (this.features.hyperlinks) {
            preamble += '\n\\usepackage{hyperref}'
        }

        if (this.features.citations) {
            preamble += `
                \n\\usepackage[backend=biber,hyperref=false,citestyle=authoryear,bibstyle=authoryear]{biblatex}
                \n\\bibliography{bibliography}
            `
        }

        if (this.features.SVGs) {
            preamble += '\n\\usepackage{svg}'
        }

        if (this.features.images) {
            preamble += '\n\\usepackage{graphicx}'
            // The following scales graphics down to text width, but not scaling them up if they are smaller
            preamble += `
                \n\\usepackage{calc}
                \n\\newlength{\\imgwidth}
                \n\\newcommand\\scaledgraphics[1]{%
                \n\\settowidth{\\imgwidth}{\\includegraphics{#1}}%
                \n\\setlength{\\imgwidth}{\\minof{\\imgwidth}{\\textwidth}}%
                \n\\includegraphics[width=\\imgwidth,height=\\textheight,keepaspectratio]{#1}%
                \n}
            `
        }

        if (this.features.tables) {
            preamble += '\n\\usepackage{tabularx}'
        }

        return preamble

    }

}
<|endoftext|>


<commit_before>'use strict';

// TODO - allowDragScroll: 'horizontal' || 'vertical'

//
// Quick usage:
//
//     vz.touch(el, [options], events);
//
//  * el - A DOM element, or array-like container of DOM elements (e.g.
//         jQuery, Array, NodeList).
//
//  * options - Optional map of options to use.  See below for details.
//
//  * events - Map of events to bind.  Supported events: click down up
//             drag.
//
// Event handler work largely like regular old DOM event handlers.  The
// `this` object is set to the target of the event, and a single event
// argument is passed through defined below.  Note that `preventDefault`
// is always called before the event is passed to the handler, but a
// dummy `preventDefault` method is still provided for compatibility.
//
// Event interface:
// {
//   stopPropagation: function,
//   preventDefault: dummy function,
//   target: target element,
//   absolute/relative/delta: {
//     t: time
//     x: window x position
//     y: window y position
//   }
//   dragState: 0|1|2 // starting, continuing, ended
// }
//
// Note that relative, delta, and dragState ONLY appear for drag events
//
// Options:
//
//   Currently a single option is supported, `selector`.  If present,
//   events will only be handled if the target matches `selector`.  This
//   can to used to, for example, bind vztouch to `document.body` and
//   handle events on all `a` tags.  Note that this requires recent
//   browsers in order to function, notably IE9+.
//

(function() {

  ///////////////////////////////////////////////
  // Utility
  ///////////////////////////////////////////////

  var matchesSelector = function() {
    var name = undefined;
    var prefixii = 'webkit moz ms o'.split(/\s+/);
    return function(el, sel) {
      if (name === undefined) {
        name = null;

        if (typeof el.matches == 'function') {
          name = 'matches';
        } else {
          prefixii.forEach(function(p) {
            if (typeof el[p + 'MatchesSelector'] == 'function')
              name = p + 'MatchesSelector';
          });
        }
      } else if (name === null) {
        return false;
      } else {
        return el[name](sel);
      }
    };
  }();

  ///////////////////////////////////////////////
  // Internal flags
  ///////////////////////////////////////////////

  // When true, click events will be fully emulated and the native
  // click event never bound.
  var ignoreNativeClick = false;

  // Sets how many pixels along an axis must be moved to consider an
  // action a drag.
  var DRAG_THRESHOLD = 3;

  // If we're using the stock android browser, we *cannot* bind to
  // click events because the touch events cannot be properly cancelled.
  if (navigator.userAgent.match(/Android/) && !navigator.userAgent.match(/Firefox|Chrome/))
    ignoreNativeClick = true;

  // Does extra logging when set
  var DEBUG = false;

  /////////////////////////////////////////////
  // Public Interface
  /////////////////////////////////////////////

  // Ensure namespace exists
  if (!window.vz)
    window.vz = {};

  // Event types: down, up, drag, click
  vz.touch = function(el, opts, events) {
    // Sanity
    if (!el || el.length === 0)
      return function() {};

    // Handle jQuery, arrays, etc
    if (el.length) {
      var cleanups = [];
      for (var i=0; i<el.length; i++)
        cleanups.push(vz.touch(el[i], opts, events));
      return function() {
        for (var i=0; i<cleanups.length; i++)
          cleanups[i]();
      };
    }

    // Opts is optional
    if (!events) {
      events = opts;
      opts = undefined;
    }
    if (!opts)
      opts = {};

    // Validate events and options
    for (var i in events) if (events.hasOwnProperty(i))
      if (['down', 'up', 'drag', 'click'].indexOf(i) < 0)
        throw new Error('Unsupported event "' + i + '"');
    for (var i in opts) if (opts.hasOwnProperty(i))
      if (['allowDragScroll', 'selector'].indexOf(i) < 0)
        throw new Error('Unsupported option "' + i + '"');

    ////////////////////////////////////////////////////
    // Implementation
    ////////////////////////////////////////////////////

    // Drag state
    var dragInfo = {
      // Start pos
      sx: 0,
      sy: 0,
      // Current pos
      x: 0,
      y: 0,
      // Total movement
      tx: 0,
      ty: 0,

      // Start time
      sd: 0,
      // Current time
      d: 0,
      // Total time
      td: 0,

      // Target drag element
      target: null,

      // Current drag state
      state: 0,
    };

    // Gets controlled by drag and touch events.  When drag goes over
    // a threshold the next click is ignored.  When a touchend finishes
    // WITHIN threshold it will fire click instantly and set this so
    // that the regular touch event doesn't occur.
    var ignoreThisClick = false;

    // When true, drag events are bound to the window.  Reset after
    // a drag ends.
    var dragEventsBound = true;

    // When true, we have sent a drag event to the user and will need
    // to follow up by sending a final null drag to signal the end.
    var dragFired = false;

    // Special handler for preventing text selection while dragging
    var selectionKiller = function(e) {
      if (DEBUG)
        console.log('selectionKiller');

      e.preventDefault();
      e.stopPropagation();
      return false;
    };

    // Gets the window position of an event
    var getPosX = function(e) {
      if (e.touches && e.touches.length)
        return e.touches[0].pageX;
      else if (!e.touches && typeof e.pageX == 'number')
        return e.pageX;
      else if (!e.touches && typeof e.clientX == 'number')
        return e.clientX + document.body.scrollLeft;
      else
        return undefined;
    };
    var getPosY = function(e) {
      if (e.touches && e.touches.length)
        return e.touches[0].pageY;
      else if (!e.touches && typeof e.pageY == 'number')
        return e.pageY;
      else if (!e.touches && typeof e.clientY == 'number')
        return e.clientY + document.body.scrollTop;
      else
      return undefined;
    };

    // Special handler for ending drags regardless of where the cursor is
    var dragEnder = function(e) {
      if (DEBUG)
        console.log('dragEnder', e ? e.type : undefined);

      window.removeEventListener('mousemove', drag, false);
      window.removeEventListener('touchmove', drag, false);
      window.removeEventListener('mouseup', dragEnder, true);
      window.removeEventListener('touchend', dragEnder, true);
      window.removeEventListener('selectstart', selectionKiller, true);

      if (dragEventsBound) {
        dragEventsBound = false;
        if (events.drag && dragFired) {
          dragFired = false;
          events.drag.call(dragInfo.target, {
            stopPropagation: function() { e && e.stopPropagation() },
            preventDefault: function() {},
            target: dragInfo.target,
            absolute: {x: dragInfo.x, y: dragInfo.y, t: +new Date()},
            relative: {x: dragInfo.x - dragInfo.sx,
                       y: dragInfo.y - dragInfo.sy,
                       t: (+new Date()) - dragInfo.st
                      },
            delta: {x: 0, y: 0, t: (+new Date()) - dragInfo.t},
            dragState: 2
          });
        }
      }
    };

    var down = function(e) {
      if (DEBUG)
        console.log('down', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      // Ignore multitouches or non-primary mousebutton clicks
      if ((e.touches && e.touches.length > 2) || (e.button !== undefined && e.button !== 0))
        return;

      // This is the start of a new click; don't ignore it
      ignoreThisClick = false;

      // If the user's listening for down events, pass on through
      if (events.down) {
        e.preventDefault();
        events.down.call(this, {
          stopPropagation: function() { e.stopPropagation(); },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: getPosX(e),
            y: getPosY(e),
            t: +new Date()
          }
        });
      }

      // For dragging via mouse-type events, disable text selection.
      if (events.drag && e.type == 'mousedown') {
        e.preventDefault();
      }

      // For drag events bootstrap the position and element.  Touchstart
      // is similar, because we need to track the start of a potential
      // "click" event.
      if (events.drag || e.type == 'touchstart') {

        // Set drag starting coordinates
        dragInfo.sx = getPosX(e);
        dragInfo.sy = getPosY(e);
        dragInfo.x = dragInfo.sx;
        dragInfo.y = dragInfo.sy;
        dragInfo.tx = 0;
        dragInfo.ty = 0;
        dragInfo.t = dragInfo.st = +new Date();
        dragInfo.target = e.target;
        dragInfo.state = 0;

        // Bind to drag events
        window.addEventListener('mousemove', drag, false);
        window.addEventListener('touchmove', drag, false);
        window.addEventListener('mouseup', dragEnder, true);
        window.addEventListener('touchend', dragEnder, true);
        window.addEventListener('selectstart', selectionKiller, true);
        dragEventsBound = true;
      }
    };

    var up = function(e) {
      if (DEBUG)
        console.log('up', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      var x = 0;
      var y = 0;
      if (events.click || events.up) {
        x = getPosX(e);
        y = getPosY(e);
        if (!x && x !== 0)
          x = dragInfo.x;
        if (!y && y !== 0)
          y = dragInfo.y;
      }

      // If the user's listening for up events, pass on through
      if (events.up) {
        e.preventDefault();
        events.up.call(this, {
          stopPropagation: function() { e.stopPropagation(); },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: x,
            y: y,
            t: +new Date()
          }
        });
      }

      // Optimized click delivery
      if (events.click && !ignoreThisClick) {
        // If we're ignoring native click, simulate a click event.
        // Similarly, if this event came from a touchend, we can trigger
        // our own click and ignore the real click event, which will
        // give snappier performance.
        if (ignoreNativeClick || e.type == 'touchend') {
          e.preventDefault();
          ignoreThisClick = true;
          events.click.call(this, {
            stopPropagation: function() { e.stopPropagation(); },
            preventDefault: function() {},
            target: e.target,
            absolute: {
              x: x,
              y: y,
              t: +new Date()
            }
          });
        }
      }
    };

    var click = function(e) {
      if (DEBUG)
        console.log('click', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      if (!ignoreThisClick && events.click) {
        e.preventDefault();
        events.click.call(this, {
          stopPropagation: function() { e.stopPropagation() },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: getPosX(e),
            y: getPosY(e),
            t: +new Date()
          }
        });
      }
    };

    var drag = function(e) {
      if (DEBUG)
        console.log('drag', e.type);

      // Don't handle multitouch
      if (e.touches && e.touches.length > 1)
        return;

      // New position
      var nx = getPosX(e);
      var ny = getPosY(e);

      // New date
      var nt = +new Date();

      // Prep the data to pass to the client
      var data = {
        stopPropagation: function() { e.stopPropagation() },
        preventDefault: function() {},
        target: dragInfo.target,
        absolute: {x: nx, y: ny, t: nt},
        relative: {x: nx - dragInfo.sx, y: ny - dragInfo.sy, t: nt - dragInfo.st},
        delta: {x: nx - dragInfo.x, y: ny - dragInfo.y, t: nt - dragInfo.t},
        dragState: dragInfo.state
      };

      // Update the last position
      dragInfo.t = nt;
      dragInfo.x = nx;
      dragInfo.y = ny;
      dragInfo.tx += Math.abs(data.delta.x);
      dragInfo.ty += Math.abs(data.delta.y);

      // When true, we've passed the drag threshold and are treating
      // this drag as a drag and not a sloppy click.
      var overThreshold = dragInfo.tx > DRAG_THRESHOLD || dragInfo.ty > DRAG_THRESHOLD;

      // If we've moved more than the drag threshold on either axis, stop
      // click from happening.
      if (!ignoreThisClick && overThreshold)
        ignoreThisClick = true;

      // If we've moved more than the drag treshold on the configured
      // axis (both by default), prevent native scroll from working and
      // then drigger the drag business.
      if (events.drag && overThreshold) {
        e.preventDefault();

        // Pass the drag event on down
        if (events.drag) {
          events.drag.call(dragInfo.target, data);
          dragFired = true;
          dragInfo.state = 1;
        }

        // TODO - Support allowances for scrolling in one direction
      }
    };

    // Bind all our events
    el.addEventListener('touchstart', down, false);
    el.addEventListener('touchend', up, false);
    if (!ignoreNativeClick) {
      el.addEventListener('mousedown', down, false);
      el.addEventListener('mouseup', up, false);
      el.addEventListener('click', click, false);
    }

    // Return a cleanup function
    return function() {
      el.removeEventListener('touchstart', down);
      el.removeEventListener('touchend', up);
      if (!ignoreNativeClick) {
        el.removeEventListener('mousedown', down);
        el.removeEventListener('mouseup', up);
        el.removeEventListener('click', click);
      }

      if (dragEventsBound) {
        dragEventsBound = false;
        dragEnder();
      }
    };
  };
})();
<commit_msg>Shorthand syntax for binding just click event<commit_after>'use strict';

// TODO - allowDragScroll: 'horizontal' || 'vertical'

//
// Quick usage:
//
//     vz.touch(el, [options], events);
//
//  * el - A DOM element, or array-like container of DOM elements (e.g.
//         jQuery, Array, NodeList).
//
//  * options - Optional map of options to use.  See below for details.
//
//  * events - Map of events to bind.  Supported events: click down up
//             drag.
//
// Event handler work largely like regular old DOM event handlers.  The
// `this` object is set to the target of the event, and a single event
// argument is passed through defined below.  Note that `preventDefault`
// is always called before the event is passed to the handler, but a
// dummy `preventDefault` method is still provided for compatibility.
//
// Event interface:
// {
//   stopPropagation: function,
//   preventDefault: dummy function,
//   target: target element,
//   absolute/relative/delta: {
//     t: time
//     x: window x position
//     y: window y position
//   }
//   dragState: 0|1|2 // starting, continuing, ended
// }
//
// Note that relative, delta, and dragState ONLY appear for drag events
//
// Options:
//
//   Currently a single option is supported, `selector`.  If present,
//   events will only be handled if the target matches `selector`.  This
//   can to used to, for example, bind vztouch to `document.body` and
//   handle events on all `a` tags.  Note that this requires recent
//   browsers in order to function, notably IE9+.
//

(function() {

  ///////////////////////////////////////////////
  // Utility
  ///////////////////////////////////////////////

  var matchesSelector = function() {
    var name = undefined;
    var prefixii = 'webkit moz ms o'.split(/\s+/);
    return function(el, sel) {
      if (name === undefined) {
        name = null;

        if (typeof el.matches == 'function') {
          name = 'matches';
        } else {
          prefixii.forEach(function(p) {
            if (typeof el[p + 'MatchesSelector'] == 'function')
              name = p + 'MatchesSelector';
          });
        }
      } else if (name === null) {
        return false;
      } else {
        return el[name](sel);
      }
    };
  }();

  ///////////////////////////////////////////////
  // Internal flags
  ///////////////////////////////////////////////

  // When true, click events will be fully emulated and the native
  // click event never bound.
  var ignoreNativeClick = false;

  // Sets how many pixels along an axis must be moved to consider an
  // action a drag.
  var DRAG_THRESHOLD = 3;

  // If we're using the stock android browser, we *cannot* bind to
  // click events because the touch events cannot be properly cancelled.
  if (navigator.userAgent.match(/Android/) && !navigator.userAgent.match(/Firefox|Chrome/))
    ignoreNativeClick = true;

  // Does extra logging when set
  var DEBUG = false;

  /////////////////////////////////////////////
  // Public Interface
  /////////////////////////////////////////////

  // Ensure namespace exists
  if (!window.vz)
    window.vz = {};

  // Event types: down, up, drag, click
  vz.touch = function(el, opts, events) {
    // Sanity
    if (!el || el.length === 0)
      return function() {};

    // Handle jQuery, arrays, etc
    if (el.length) {
      var cleanups = [];
      for (var i=0; i<el.length; i++)
        cleanups.push(vz.touch(el[i], opts, events));
      return function() {
        for (var i=0; i<cleanups.length; i++)
          cleanups[i]();
      };
    }

    // Opts is optional
    if (!events) {
      events = opts;
      opts = undefined;
    }
    if (!opts)
      opts = {};

    // If events is a function, treat it as shorthand syntax for just
    // binding click.
    if (typeof events == 'function')
      events = {click: events};

    // Validate events and options
    for (var i in events) if (events.hasOwnProperty(i))
      if (['down', 'up', 'drag', 'click'].indexOf(i) < 0)
        throw new Error('Unsupported event "' + i + '"');
    for (var i in opts) if (opts.hasOwnProperty(i))
      if (['allowDragScroll', 'selector'].indexOf(i) < 0)
        throw new Error('Unsupported option "' + i + '"');

    ////////////////////////////////////////////////////
    // Implementation
    ////////////////////////////////////////////////////

    // Drag state
    var dragInfo = {
      // Start pos
      sx: 0,
      sy: 0,
      // Current pos
      x: 0,
      y: 0,
      // Total movement
      tx: 0,
      ty: 0,

      // Start time
      sd: 0,
      // Current time
      d: 0,
      // Total time
      td: 0,

      // Target drag element
      target: null,

      // Current drag state
      state: 0,
    };

    // Gets controlled by drag and touch events.  When drag goes over
    // a threshold the next click is ignored.  When a touchend finishes
    // WITHIN threshold it will fire click instantly and set this so
    // that the regular touch event doesn't occur.
    var ignoreThisClick = false;

    // When true, drag events are bound to the window.  Reset after
    // a drag ends.
    var dragEventsBound = true;

    // When true, we have sent a drag event to the user and will need
    // to follow up by sending a final null drag to signal the end.
    var dragFired = false;

    // Special handler for preventing text selection while dragging
    var selectionKiller = function(e) {
      if (DEBUG)
        console.log('selectionKiller');

      e.preventDefault();
      e.stopPropagation();
      return false;
    };

    // Gets the window position of an event
    var getPosX = function(e) {
      if (e.touches && e.touches.length)
        return e.touches[0].pageX;
      else if (!e.touches && typeof e.pageX == 'number')
        return e.pageX;
      else if (!e.touches && typeof e.clientX == 'number')
        return e.clientX + document.body.scrollLeft;
      else
        return undefined;
    };
    var getPosY = function(e) {
      if (e.touches && e.touches.length)
        return e.touches[0].pageY;
      else if (!e.touches && typeof e.pageY == 'number')
        return e.pageY;
      else if (!e.touches && typeof e.clientY == 'number')
        return e.clientY + document.body.scrollTop;
      else
      return undefined;
    };

    // Special handler for ending drags regardless of where the cursor is
    var dragEnder = function(e) {
      if (DEBUG)
        console.log('dragEnder', e ? e.type : undefined);

      window.removeEventListener('mousemove', drag, false);
      window.removeEventListener('touchmove', drag, false);
      window.removeEventListener('mouseup', dragEnder, true);
      window.removeEventListener('touchend', dragEnder, true);
      window.removeEventListener('selectstart', selectionKiller, true);

      if (dragEventsBound) {
        dragEventsBound = false;
        if (events.drag && dragFired) {
          dragFired = false;
          events.drag.call(dragInfo.target, {
            stopPropagation: function() { e && e.stopPropagation() },
            preventDefault: function() {},
            target: dragInfo.target,
            absolute: {x: dragInfo.x, y: dragInfo.y, t: +new Date()},
            relative: {x: dragInfo.x - dragInfo.sx,
                       y: dragInfo.y - dragInfo.sy,
                       t: (+new Date()) - dragInfo.st
                      },
            delta: {x: 0, y: 0, t: (+new Date()) - dragInfo.t},
            dragState: 2
          });
        }
      }
    };

    var down = function(e) {
      if (DEBUG)
        console.log('down', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      // Ignore multitouches or non-primary mousebutton clicks
      if ((e.touches && e.touches.length > 2) || (e.button !== undefined && e.button !== 0))
        return;

      // This is the start of a new click; don't ignore it
      ignoreThisClick = false;

      // If the user's listening for down events, pass on through
      if (events.down) {
        e.preventDefault();
        events.down.call(this, {
          stopPropagation: function() { e.stopPropagation(); },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: getPosX(e),
            y: getPosY(e),
            t: +new Date()
          }
        });
      }

      // For dragging via mouse-type events, disable text selection.
      if (events.drag && e.type == 'mousedown') {
        e.preventDefault();
      }

      // For drag events bootstrap the position and element.  Touchstart
      // is similar, because we need to track the start of a potential
      // "click" event.
      if (events.drag || e.type == 'touchstart') {

        // Set drag starting coordinates
        dragInfo.sx = getPosX(e);
        dragInfo.sy = getPosY(e);
        dragInfo.x = dragInfo.sx;
        dragInfo.y = dragInfo.sy;
        dragInfo.tx = 0;
        dragInfo.ty = 0;
        dragInfo.t = dragInfo.st = +new Date();
        dragInfo.target = e.target;
        dragInfo.state = 0;

        // Bind to drag events
        window.addEventListener('mousemove', drag, false);
        window.addEventListener('touchmove', drag, false);
        window.addEventListener('mouseup', dragEnder, true);
        window.addEventListener('touchend', dragEnder, true);
        window.addEventListener('selectstart', selectionKiller, true);
        dragEventsBound = true;
      }
    };

    var up = function(e) {
      if (DEBUG)
        console.log('up', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      var x = 0;
      var y = 0;
      if (events.click || events.up) {
        x = getPosX(e);
        y = getPosY(e);
        if (!x && x !== 0)
          x = dragInfo.x;
        if (!y && y !== 0)
          y = dragInfo.y;
      }

      // If the user's listening for up events, pass on through
      if (events.up) {
        e.preventDefault();
        events.up.call(this, {
          stopPropagation: function() { e.stopPropagation(); },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: x,
            y: y,
            t: +new Date()
          }
        });
      }

      // Optimized click delivery
      if (events.click && !ignoreThisClick) {
        // If we're ignoring native click, simulate a click event.
        // Similarly, if this event came from a touchend, we can trigger
        // our own click and ignore the real click event, which will
        // give snappier performance.
        if (ignoreNativeClick || e.type == 'touchend') {
          e.preventDefault();
          ignoreThisClick = true;
          events.click.call(this, {
            stopPropagation: function() { e.stopPropagation(); },
            preventDefault: function() {},
            target: e.target,
            absolute: {
              x: x,
              y: y,
              t: +new Date()
            }
          });
        }
      }
    };

    var click = function(e) {
      if (DEBUG)
        console.log('click', e.type);
      if (opts.selector && !matchesSelector(e.target, opts.selector))
        return;

      if (!ignoreThisClick && events.click) {
        e.preventDefault();
        events.click.call(this, {
          stopPropagation: function() { e.stopPropagation() },
          preventDefault: function() {},
          target: e.target,
          absolute: {
            x: getPosX(e),
            y: getPosY(e),
            t: +new Date()
          }
        });
      }
    };

    var drag = function(e) {
      if (DEBUG)
        console.log('drag', e.type);

      // Don't handle multitouch
      if (e.touches && e.touches.length > 1)
        return;

      // New position
      var nx = getPosX(e);
      var ny = getPosY(e);

      // New date
      var nt = +new Date();

      // Prep the data to pass to the client
      var data = {
        stopPropagation: function() { e.stopPropagation() },
        preventDefault: function() {},
        target: dragInfo.target,
        absolute: {x: nx, y: ny, t: nt},
        relative: {x: nx - dragInfo.sx, y: ny - dragInfo.sy, t: nt - dragInfo.st},
        delta: {x: nx - dragInfo.x, y: ny - dragInfo.y, t: nt - dragInfo.t},
        dragState: dragInfo.state
      };

      // Update the last position
      dragInfo.t = nt;
      dragInfo.x = nx;
      dragInfo.y = ny;
      dragInfo.tx += Math.abs(data.delta.x);
      dragInfo.ty += Math.abs(data.delta.y);

      // When true, we've passed the drag threshold and are treating
      // this drag as a drag and not a sloppy click.
      var overThreshold = dragInfo.tx > DRAG_THRESHOLD || dragInfo.ty > DRAG_THRESHOLD;

      // If we've moved more than the drag threshold on either axis, stop
      // click from happening.
      if (!ignoreThisClick && overThreshold)
        ignoreThisClick = true;

      // If we've moved more than the drag treshold on the configured
      // axis (both by default), prevent native scroll from working and
      // then drigger the drag business.
      if (events.drag && overThreshold) {
        e.preventDefault();

        // Pass the drag event on down
        if (events.drag) {
          events.drag.call(dragInfo.target, data);
          dragFired = true;
          dragInfo.state = 1;
        }

        // TODO - Support allowances for scrolling in one direction
      }
    };

    // Bind all our events
    el.addEventListener('touchstart', down, false);
    el.addEventListener('touchend', up, false);
    if (!ignoreNativeClick) {
      el.addEventListener('mousedown', down, false);
      el.addEventListener('mouseup', up, false);
      el.addEventListener('click', click, false);
    }

    // Return a cleanup function
    return function() {
      el.removeEventListener('touchstart', down);
      el.removeEventListener('touchend', up);
      if (!ignoreNativeClick) {
        el.removeEventListener('mousedown', down);
        el.removeEventListener('mouseup', up);
        el.removeEventListener('click', click);
      }

      if (dragEventsBound) {
        dragEventsBound = false;
        dragEnder();
      }
    };
  };
})();
<|endoftext|>


<commit_before>var fs = require('fs')
var gulp = require('gulp')
var d3 = require('d3')
var Handlebars = require('handlebars')

function template(name) {
  return Handlebars.compile(fs.readFileSync(name, {encoding: 'utf-8'}))
}

function instanta(row_2013, row_2014, type, contact, people) {
  var m = row_2013.cod.match(/^(Judecatoria|Tribunalul|CurteadeApel)(.*)$/)
  var filename = '../_instante/' + type + '/' + m[2].toLowerCase() + '.html'
  var indici_json = JSON.stringify({
    2013: row_2013,
    2014: row_2014,
  })
  var html = template('instanta.html')({
    type: type,
    meta: row_2013,
    indici_json: indici_json,
    indici_json_raw: new Handlebars.SafeString(indici_json),
    people_json: JSON.stringify(people.map(function(p) {
      return p.Prenume + ' ' + p.Nume
    })),
    contact: contact,
  })
  fs.writeFileSync(filename, html)
}

function parchet(row, type) {
  var code = row.name.replace(/[ -]/g, '').toLowerCase()
  var filename = '../_parchete/' + type + '/' + code + '.html'
  var html = template('parchet.html')({
    type: type,
    meta: {nume: row.name.trim()},
    indici_2014_json: JSON.stringify(row),
  })
  fs.writeFileSync(filename, html)
}

function table(name, skip1) {
  var data = fs.readFileSync('tables/' + name + '.tsv', 'utf-8')
  return d3.tsv.parse(data)
}

function by_code(rows) {
  var rv = {}
  rows.forEach(function(row) {
    rv[row.cod] = row
  })
  return rv
}

gulp.task('data', function() {
  var people = {}
  table('oameni').forEach(function(row) {
    var code = row.Instanta
    ;(people[code] = people[code] || []).push(row)
  })
  var contact = {
    judecatorii: by_code(table('judecatorii-instante-contact')),
    tribunale: by_code(table('tribunale-instante-contact')),
    curtideapel: by_code(table('curtideapel-instante-contact')),
  }
  var data_2014 = {
    judecatorii: by_code(table('judecatorii-instante-2014').slice(1)),
    tribunale: by_code(table('tribunale-instante-2014').slice(1)),
    curtideapel: by_code(table('curtideapel-instante-2014').slice(1)),
  }
  table('judecatorii-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.judecatorii[row.cod]
    var row_contact = contact.judecatorii[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'judecatorii', row_contact, people_list)
  })
  table('tribunale-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.tribunale[row.cod]
    var row_contact = contact.tribunale[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'tribunale', row_contact, people_list)
  })
  table('curtideapel-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.curtideapel[row.cod]
    var row_contact = contact.curtideapel[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'curtideapel', row_contact, people_list)
  })
  table('judecatorii-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'judecatorii')
  })
  table('tribunale-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'tribunale')
  })
  table('curtideapel-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'curtideapel')
  })
  table('speciale-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'speciale')
  })

  var perf = {
    instante: {
      judecatorii: [],
      tribunale: [],
      curtideapel: [],
    },
    parchete: {
      judecatorii: [],
      tribunale: [],
      curtideapel: [],
    },
  }

  table('performanta-instante').forEach(function(row) {
    var name = row.name
    var item = {
      name: name,
      perf_2014: row.perf_2014,
      perf_2015: row.perf_2015,
    }
    if(name.match(/^(Judecătoria)(.*)$/)) {
      perf.instante.judecatorii.push(item)
    }
    if(name.match(/^(Tribunalul)(.*)$/)) {
      perf.instante.tribunale.push(item)
    }
    if(name.match(/^(Curtea de Apel)(.*)$/)) {
      perf.instante.curtideapel.push(item)
    }
  })

  table('performanta-parchete').forEach(function(row) {
    var name = row.type + ' ' + row.name.trim()
    var item = {
      name: name,
      perf: row.performance,
    }
    if(name.match(/^(Judecătoria)(.*)$/)) {
      perf.parchete.judecatorii.push(item)
    }
    if(name.match(/^(Tribunalul)(.*)$/)) {
      perf.parchete.tribunale.push(item)
    }
    if(name.match(/^(Curtea de Apel)(.*)$/)) {
      perf.parchete.curtideapel.push(item)
    }
  })

  fs.writeFileSync('../_data/performance.yml', JSON.stringify(perf))
})
<commit_msg>add changes to gulp script to have a field for location only<commit_after>var fs = require('fs')
var gulp = require('gulp')
var d3 = require('d3')
var Handlebars = require('handlebars')

function template(name) {
  return Handlebars.compile(fs.readFileSync(name, {encoding: 'utf-8'}))
}

function instanta(row_2013, row_2014, type, contact, people) {
  var m = row_2013.cod.match(/^(Judecatoria|Tribunalul|CurteadeApel)(.*)$/)
  var filename = '../_instante/' + type + '/' + m[2].toLowerCase() + '.html'
  var indici_json = JSON.stringify({
    2013: row_2013,
    2014: row_2014,
  })
  var html = template('instanta.html')({
    type: type,
    meta: row_2013,
    indici_json: indici_json,
    indici_json_raw: new Handlebars.SafeString(indici_json),
    people_json: JSON.stringify(people.map(function(p) {
      return p.Prenume + ' ' + p.Nume
    })),
    contact: contact,
  })
  fs.writeFileSync(filename, html)
}

function parchet(row, type) {
  var code = row.name.replace(/[ -]/g, '').toLowerCase()
  var filename = '../_parchete/' + type + '/' + code + '.html'
  var html = template('parchet.html')({
    type: type,
    meta: {nume: row.name.trim()},
    indici_2014_json: JSON.stringify(row),
  })
  fs.writeFileSync(filename, html)
}

function table(name, skip1) {
  var data = fs.readFileSync('tables/' + name + '.tsv', 'utf-8')
  return d3.tsv.parse(data)
}

function by_code(rows) {
  var rv = {}
  rows.forEach(function(row) {
    rv[row.cod] = row
  })
  return rv
}

gulp.task('data', function() {
  var people = {}
  table('oameni').forEach(function(row) {
    var code = row.Instanta
    ;(people[code] = people[code] || []).push(row)
  })
  var contact = {
    judecatorii: by_code(table('judecatorii-instante-contact')),
    tribunale: by_code(table('tribunale-instante-contact')),
    curtideapel: by_code(table('curtideapel-instante-contact')),
  }
  var data_2014 = {
    judecatorii: by_code(table('judecatorii-instante-2014').slice(1)),
    tribunale: by_code(table('tribunale-instante-2014').slice(1)),
    curtideapel: by_code(table('curtideapel-instante-2014').slice(1)),
  }
  table('judecatorii-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.judecatorii[row.cod]
    var row_contact = contact.judecatorii[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'judecatorii', row_contact, people_list)
  })
  table('tribunale-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.tribunale[row.cod]
    var row_contact = contact.tribunale[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'tribunale', row_contact, people_list)
  })
  table('curtideapel-instante-2013').slice(1).forEach(function(row) {
    var row_2014 = data_2014.curtideapel[row.cod]
    var row_contact = contact.curtideapel[row.cod]
    var people_list = people[row.cod] || []
    instanta(row, row_2014, 'curtideapel', row_contact, people_list)
  })
  table('judecatorii-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'judecatorii')
  })
  table('tribunale-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'tribunale')
  })
  table('curtideapel-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'curtideapel')
  })
  table('speciale-parchete-2014').slice(1).forEach(function(row) {
    parchet(row, 'speciale')
  })

  var perf = {
    instante: {
      judecatorii: [],
      tribunale: [],
      curtideapel: [],
    },
    parchete: {
      judecatorii: [],
      tribunale: [],
      curtideapel: [],
    },
  }

  table('performanta-instante').forEach(function(row) {
    var name = row.name
    var item = {
      name: name,
      location_name: name.split(" ").slice(1).join(" "),
      perf_2014: row.perf_2014,
      perf_2015: row.perf_2015,
    }
    if(name.match(/^(Judecătoria)(.*)$/)) {
      perf.instante.judecatorii.push(item)
    }
    if(name.match(/^(Tribunalul)(.*)$/)) {
      perf.instante.tribunale.push(item)
    }
    if(name.match(/^(Curtea de Apel)(.*)$/)) {
      item.location_name = name.split(" ").slice(3).join(" ")
      perf.instante.curtideapel.push(item)
    }
  })

  table('performanta-parchete').forEach(function(row) {
    var name = row.type + ' ' + row.name.trim()
    var item = {
      name: name,
      location_name: name.split(" ").slice(1).join(" "),
      perf: row.performance,
    }
    if(name.match(/^(Judecătoria)(.*)$/)) {
      perf.parchete.judecatorii.push(item)
    }
    if(name.match(/^(Tribunalul)(.*)$/)) {
      perf.parchete.tribunale.push(item)
    }
    if(name.match(/^(Curtea de Apel)(.*)$/)) {
      item.location_name = name.split(" ").slice(3).join(" ")
      perf.parchete.curtideapel.push(item);
    }
  })

  fs.writeFileSync('../_data/performance.yml', JSON.stringify(perf))
})
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import { Flex } from 'rebass/styled-components'
import { intlShape } from '@zap/i18n'
import { Bar, Header, Span } from 'components/UI'
import { Form, Input, Label } from 'components/Form'
import messages from './messages'

class SeedConfirm extends React.Component {
  state = {
    seedWordIndexes: [],
  }

  static propTypes = {
    intl: intlShape.isRequired,
    seed: PropTypes.array.isRequired,
    wizardApi: PropTypes.object,
    wizardState: PropTypes.object,
  }

  static defaultProps = {
    wizardApi: {},
    wizardState: {},
  }

  componentDidMount() {
    this.fetchSeedWordIndexes()
  }

  fetchSeedWordIndexes = () => {
    const seedWordIndexes = []
    while (seedWordIndexes.length < 3) {
      const r = Math.floor(Math.random() * 24) + 1
      if (seedWordIndexes.indexOf(r) === -1) {
        seedWordIndexes.push(r)
      }
    }
    this.setState({ seedWordIndexes })
  }

  setFormApi = formApi => {
    this.formApi = formApi
  }

  handleWordChange = (value, fieldIndex, wordIndex) => {
    const error = this.validateWord(wordIndex, value)
    // reset the field state to prevent highlighting as valid.
    if (error) {
      this.formApi.setTouched(`word${fieldIndex}`, false)
      this.formApi.setError(`word${fieldIndex}`, null)
    }
    // Otherwise the word has been determined as valid, mark the field touched to trigger field highlighting.
    else {
      this.formApi.setTouched(`word${fieldIndex}`, true)
    }
  }

  validateWord = (index, word) => {
    const { seed } = this.props
    return !word || word !== seed[index] ? 'incorrect' : undefined
  }

  render() {
    const { wizardApi, wizardState, seed, intl, ...rest } = this.props
    const { seedWordIndexes } = this.state
    const { getApi, onChange, onSubmit, onSubmitFailure } = wizardApi
    const { currentItem } = wizardState

    return (
      <Form
        {...rest}
        getApi={formApi => {
          this.setFormApi(formApi)
          if (getApi) {
            getApi(formApi)
          }
        }}
        onChange={onChange && (formState => onChange(formState, currentItem))}
        onSubmit={onSubmit}
        onSubmitFailure={onSubmitFailure}
      >
        <Header
          subtitle={
            <>

                <FormattedMessage {...messages.retype_seed_description_primary} />
              {' '}
              <FormattedMessage
                {...messages.retype_seed_description_secondary}
                values={{
                  word1: seedWordIndexes[0],
                  word2: seedWordIndexes[1],
                  word3: seedWordIndexes[2],
                }}
              />
            </>
          }
          title={<FormattedMessage {...messages.retype_seed_title} />}
        />

        <Bar my={4} />

        {seedWordIndexes.map((wordIndex, index) => {
          // Only validate if the word has been entered correctly already or the form has been submitted.
          return (
            <Flex key={`word${index}`} justifyContent="flex-start" mb={3}>

                {wordIndex}

              <Input
                field={`word${index}`}
                name={`word${index}`}
                onChange={e => this.handleWordChange(e.target.value, index, wordIndex - 1)}
                placeholder={intl.formatMessage({ ...messages.word_placeholder })}
                validate={value => this.validateWord.call(null, wordIndex - 1, value)}
                validateOnBlur
                validateOnChange
                willAutoFocus={index === 0}
              />
            </Flex>
          )
        })}
      </Form>
    )
  }
}

export default injectIntl(SeedConfirm)
<commit_msg>fix(ui): center seed confirm inputs<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import { Flex } from 'rebass/styled-components'
import { intlShape } from '@zap/i18n'
import { Bar, Header, Span } from 'components/UI'
import { Form, Input, Label } from 'components/Form'
import messages from './messages'

class SeedConfirm extends React.Component {
  state = {
    seedWordIndexes: [],
  }

  static propTypes = {
    intl: intlShape.isRequired,
    seed: PropTypes.array.isRequired,
    wizardApi: PropTypes.object,
    wizardState: PropTypes.object,
  }

  static defaultProps = {
    wizardApi: {},
    wizardState: {},
  }

  componentDidMount() {
    this.fetchSeedWordIndexes()
  }

  fetchSeedWordIndexes = () => {
    const seedWordIndexes = []
    while (seedWordIndexes.length < 3) {
      const r = Math.floor(Math.random() * 24) + 1
      if (seedWordIndexes.indexOf(r) === -1) {
        seedWordIndexes.push(r)
      }
    }
    this.setState({ seedWordIndexes })
  }

  setFormApi = formApi => {
    this.formApi = formApi
  }

  handleWordChange = (value, fieldIndex, wordIndex) => {
    const error = this.validateWord(wordIndex, value)
    // reset the field state to prevent highlighting as valid.
    if (error) {
      this.formApi.setTouched(`word${fieldIndex}`, false)
      this.formApi.setError(`word${fieldIndex}`, null)
    }
    // Otherwise the word has been determined as valid, mark the field touched to trigger field highlighting.
    else {
      this.formApi.setTouched(`word${fieldIndex}`, true)
    }
  }

  validateWord = (index, word) => {
    const { seed } = this.props
    return !word || word !== seed[index] ? 'incorrect' : undefined
  }

  render() {
    const { wizardApi, wizardState, seed, intl, ...rest } = this.props
    const { seedWordIndexes } = this.state
    const { getApi, onChange, onSubmit, onSubmitFailure } = wizardApi
    const { currentItem } = wizardState

    return (
      <Form
        {...rest}
        getApi={formApi => {
          this.setFormApi(formApi)
          if (getApi) {
            getApi(formApi)
          }
        }}
        onChange={onChange && (formState => onChange(formState, currentItem))}
        onSubmit={onSubmit}
        onSubmitFailure={onSubmitFailure}
      >
        <Header
          subtitle={
            <>

                <FormattedMessage {...messages.retype_seed_description_primary} />
              {' '}
              <FormattedMessage
                {...messages.retype_seed_description_secondary}
                values={{
                  word1: seedWordIndexes[0],
                  word2: seedWordIndexes[1],
                  word3: seedWordIndexes[2],
                }}
              />
            </>
          }
          title={<FormattedMessage {...messages.retype_seed_title} />}
        />

        <Bar my={4} />

        <Flex alignItems="center" flexDirection="column">
          {seedWordIndexes.map((wordIndex, index) => {
            // Only validate if the word has been entered correctly already or the form has been submitted.
            return (
              <Flex key={`word${index}`} justifyContent="flex-start" mb={3}>

                  {wordIndex}

                <Input
                  field={`word${index}`}
                  name={`word${index}`}
                  onChange={e => this.handleWordChange(e.target.value, index, wordIndex - 1)}
                  placeholder={intl.formatMessage({ ...messages.word_placeholder })}
                  validate={value => this.validateWord.call(null, wordIndex - 1, value)}
                  validateOnBlur
                  validateOnChange
                  willAutoFocus={index === 0}
                />
              </Flex>
            )
          })}
        </Flex>
      </Form>
    )
  }
}

export default injectIntl(SeedConfirm)
<|endoftext|>