<commit_before>var OpbeatBackend = require('../backend/opbeat_backend')
var ServiceContainer = require('./serviceContainer')

var Subscription = require('../common/subscription')

function TransportMock () {
  this.transactions = []
  this.subscription = new Subscription()
}

TransportMock.prototype.sendTransaction = function (transactions) {
  this.transactions = this.transactions.concat(transactions)
  this.subscription.applyAll(this, [transactions])
}

TransportMock.prototype.subscribe = function (fn) {
  this.subscription.subscribe(fn)
}

function init () {
  var services = new ServiceContainer({logLevel: 'debug'}).services
  var logger = services.logger
  var transactionService = services.transactionService

  var transportMock = new TransportMock()
  var opbeatBackend = new OpbeatBackend(transportMock, logger)
  transactionService.subscribe(function (tr) {
    opbeatBackend.sendTransactions([tr])
  })

  function getTransactions (callback, start, end) {
    if (transportMock.transactions.length >= end) {
      var trs = transportMock.transactions.slice(start, end)
      callback(trs)
      return
    }

    var cancel = transportMock.subscribe(function () {
      logger.debug('Number of transactions: ', transportMock.transactions.length)
      if (transportMock.transactions.length >= end) {
        var trs = transportMock.transactions.slice(start, end)
        callback(trs)
        cancel()
      }
    })
  }

  window.e2e = {
    transactionService: transactionService,
    transportMock: transportMock,
    getTransactions: getTransactions
  }
  return transactionService
}

module.exports = init
<commit_msg>minor fix e2e<commit_after>var OpbeatBackend = require('../backend/opbeat_backend')
var ServiceContainer = require('./serviceContainer')

var Subscription = require('../common/subscription')

function TransportMock () {
  this.transactions = []
  this.subscription = new Subscription()
}

TransportMock.prototype.sendTransaction = function (transactions) {
  this.transactions = this.transactions.concat(transactions)
  this.subscription.applyAll(this, [transactions])
}

TransportMock.prototype.subscribe = function (fn) {
  return this.subscription.subscribe(fn)
}

function init () {
  var services = new ServiceContainer({logLevel: 'debug'}).services
  var logger = services.logger
  var transactionService = services.transactionService

  var transportMock = new TransportMock()
  var opbeatBackend = new OpbeatBackend(transportMock, logger)
  transactionService.subscribe(function (tr) {
    opbeatBackend.sendTransactions([tr])
  })

  function getTransactions (callback, start, end) {
    if (transportMock.transactions.length >= end) {
      var trs = transportMock.transactions.slice(start, end)
      callback(trs)
      return
    }

    var cancel = transportMock.subscribe(function () {
      logger.debug('Number of transactions: ', transportMock.transactions.length)
      if (transportMock.transactions.length >= end) {
        var trs = transportMock.transactions.slice(start, end)
        callback(trs)
        cancel()
      }
    })
  }

  window.e2e = {
    transactionService: transactionService,
    transportMock: transportMock,
    getTransactions: getTransactions
  }
  return transactionService
}

module.exports = init
<|endoftext|>


<commit_before>import { GraphQLList, GraphQLString, GraphQLInt, GraphQLBoolean } from 'graphql';
import { createClient } from 'redis';

import { redisUrl } from '../../config';
import { Product } from '../models';

const AddProduct = {
	name: 'AddProduct',
  type: GraphQLBoolean,
	args: {
		videoId: { type: GraphQLString },
    imageUrls: { type: new GraphQLList(GraphQLString) },
    name: { type: GraphQLString },
    price: { type: GraphQLInt },
    shippingDays: { type: GraphQLInt },
    otherDescription: { type: GraphQLString },
	},
  async resolve(fieldName, args, context, { rootValue: { request } }) {
    if (!request.user) {
      return false;
    }

    const product = await Product.create(args);

    if (product) {
      const redis = createClient(redisUrl);

      redis.set(`live:${args.videoId}:products:latest`, JSON.stringify(args));
      redis.publish(`live:${args.videoId}:products:latest`, JSON.stringify(args));

      redis.quit();

      return true;
    } else {
      return false;
    }
  }
};

export default AddProduct;<commit_msg>Post product to comment.<commit_after>import { GraphQLList, GraphQLString, GraphQLInt, GraphQLBoolean } from 'graphql';
import { createClient } from 'redis';
import fetch from 'node-fetch';

import { redisUrl } from '../../config';
import { Product, Page } from '../models';

const AddProduct = {
	name: 'AddProduct',
  type: GraphQLBoolean,
	args: {
		videoId: { type: GraphQLString },
    imageUrls: { type: new GraphQLList(GraphQLString) },
    name: { type: GraphQLString },
    price: { type: GraphQLInt },
    shippingDays: { type: GraphQLInt },
    otherDescription: { type: GraphQLString },
	},
  async resolve(fieldName, args, context, { rootValue: { request } }) {
    if (!request.user) {
      return false;
    }

    const product = await Product.create(args);

    if (product) {
      const redis = createClient(redisUrl);

      redis.set(`live:${args.videoId}:products:latest`, JSON.stringify(args));
      redis.publish(`live:${args.videoId}:products:latest`, JSON.stringify(args));

      redis.quit();

      const page = await Page.findOne();

      if (page) {
        fetch(`https://graph.facebook.com/v2.8/${page.id}_${videoId}/comments`, {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            access_token: page.accessToken,
            message: `直播主上架了一個商品，快來看看！ https://live-api-explore-production.herokuapp.com/products/${product.id}`
          })
        });
      }

      return true;
    } else {
      return false;
    }
  }
};

export default AddProduct;<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import Realm from 'realm';

export class Period extends Realm.Object {
  numberOfRequisitions() {
    return this.requisitions.length;
  }

  numberOfRequisitionsForProgram(program) {
    return this.requisitions.filtered('program.id = $0', program.id).length;
  }

  addRequisitionIfUnique(requisition) {
    if (this.requisitions.filtered('id == $0', requisition.id).length > 0) return;
    this.addBatch(requisition);
  }
}

export default Period;

Period.schema = {
  name: 'Period',
  primaryKey: 'id',
  properties: {
    id: 'string',
    startDate: { type: 'date', default: new Date() },
    endDate: { type: 'date', default: new Date() },
    name: { type: 'string', default: 'Placeholder Name' },
    periodSchedule: 'PeriodSchedule',
    requisitions: { type: 'list', objectType: 'Requisition' },
  },
};
<commit_msg>add typo fix<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import Realm from 'realm';

export class Period extends Realm.Object {
  numberOfRequisitions() {
    return this.requisitions.length;
  }

  numberOfRequisitionsForProgram(program) {
    return this.requisitions.filtered('program.id = $0', program.id).length;
  }

  addRequisitionIfUnique(requisition) {
    if (this.requisitions.filtered('id == $0', requisition.id).length > 0) return;
    this.requisitions.push(requisition);
  }
}

export default Period;

Period.schema = {
  name: 'Period',
  primaryKey: 'id',
  properties: {
    id: 'string',
    startDate: { type: 'date', default: new Date() },
    endDate: { type: 'date', default: new Date() },
    name: { type: 'string', default: 'Placeholder Name' },
    periodSchedule: 'PeriodSchedule',
    requisitions: { type: 'list', objectType: 'Requisition' },
  },
};
<|endoftext|>


<commit_before>"use strict";

// weapons: 5 choose 1 = 5
// armor: 5 choose 0 + 5 choose 1 = 1 + 5 = 6
// rings: 5 choose 0 + 5 choose 1 + 5 choose 2 = 1 + 5 + 10 = 16
// total loadouts = weapons * armor * rings =  5 * 6 * 16 = 480

let newLoadout = () => {
  return {
    cost: 0,
    damage: 0,
    armor: 0
  };
};

let newLoadoutFrom = (loadout) => {
  return {
    cost: loadout.cost,
    damage: loadout.damage,
    armor: loadout.armor
  };
};

exports.generateFrom = (store) => {
  let loadouts = [];
  for (let weapon of store.weapons) {
    let justTheWeapon = newLoadout();
    justTheWeapon.cost += weapon.cost;
    justTheWeapon.damage += weapon.damage;
    loadouts.push(justTheWeapon);

    for (let armor of store.armors) {
      let weaponAndArmor = newLoadoutFrom(justTheWeapon);
      weaponAndArmor.cost += armor.cost;
      weaponAndArmor.armor += armor.armor;
      loadouts.push(weaponAndArmor);

      // TODO: handle the rings
    }
  }
  return loadouts;
};

exports.generateFromDefaultStore = () => {
  let defaultStore = {};
  return exports.generateLoadoutsFrom(defaultStore);
};
<commit_msg>day 21: first ring is handled, but not yet second.<commit_after>"use strict";

// weapons: 5 choose 1 = 5
// armor: 5 choose 0 + 5 choose 1 = 1 + 5 = 6
// rings: 5 choose 0 + 5 choose 1 + 5 choose 2 = 1 + 5 + 10 = 16
// total loadouts = weapons * armor * rings =  5 * 6 * 16 = 480

let newLoadout = () => {
  return {
    cost: 0,
    damage: 0,
    armor: 0
  };
};

let newLoadoutFrom = (loadout) => {
  return {
    cost: loadout.cost,
    damage: loadout.damage,
    armor: loadout.armor
  };
};

let armorIsInLoadouts = (armor, previousLoadouts) => {
  for (let previousLoadout in previousLoadouts) {
    if (armor === previousLoadout.armor) {
      return true;
    }
  }
  return false;
};

let pickArmorFrom = (store, previousLoadouts) => {
  for (let armor of store.armors) {
    if (!armorIsInLoadouts(armor, previousLoadouts)) {
      return armor;
    }
  }
  return null;
};

exports.generateFrom = (store) => {
  let loadouts = [];
  for (let weapon of store.weapons) {
    let justTheWeapon = newLoadout();
    justTheWeapon.cost += weapon.cost;
    justTheWeapon.damage += weapon.damage;
    loadouts.push(justTheWeapon);

    let weaponAndArmor = newLoadoutFrom(justTheWeapon);
    let chosenArmor = pickArmorFrom(store, loadouts);
    if (chosenArmor) {
      weaponAndArmor.cost += chosenArmor.cost;
      weaponAndArmor.armor += chosenArmor.armor;
      loadouts.push(weaponAndArmor);
    }

    for (let firstRing of store.rings) {
      let singleRingLoadout = newLoadoutFrom(weaponAndArmor);
      singleRingLoadout.cost += firstRing.cost;
      singleRingLoadout.damage += firstRing.damage;
      singleRingLoadout.armor += firstRing.armor;
      loadouts.push(singleRingLoadout);

      for (let secondRing of store.rings) {
        if (secondRing === firstRing) {
          continue;
        }
        let twoRings = newLoadoutFrom(singleRingLoadout);
        twoRings.cost += secondRing.cost;
        twoRings.damage += secondRing.damage;
        twoRings.armor += secondRing.armor;
        loadouts.push(twoRings);
      }
    }
  }
  return loadouts;
};

exports.generateFromDefaultStore = () => {
  let defaultStore = {};
  return exports.generateLoadoutsFrom(defaultStore);
};
<|endoftext|>


<commit_before>'use babel'

import { CompositeDisposable, Directory } from 'atom'
import { isListItem, wrapText } from './functions'

CSON = require('season')
fs = require('fs')
GrammarCompiler = require('./GrammarCompiler')
path = require('path')

module.exports = {
  config: {
    addListItems: {
      title: 'Add new list-items',
      description: 'Automatically add a new list-item after the current (non-empty) one when pressing ENTER'
      type: 'boolean'
      default: true
    },

    disableLanguageGfm: {
      title: 'Disable language-gfm',
      description: 'Disable the default `language-gfm` package as this package is intended as its replacement',
      type: 'boolean',
      default: true
    },

    emphasisShortcuts: {
      title: 'Emphasis shortcuts',
      description: 'Enables keybindings `_` for emphasis, `*` for strong emphasis, and `~` for strike-through on selected text; emphasizing an already emphasized selection will de-emphasize it',
      type: 'boolean',
      default: true
    },

    indentListItems: {
      title: 'Indent list-items',
      description: 'Automatically in- and outdent list-items by pressing `TAB` and `SHIFT+TAB`',
      type: 'boolean',
      default: true
    },

    linkShortcuts: {
      title: 'Link shortcuts',
      description: 'Enables keybindings `@` for converting the selected text to a link and `!` for converting the selected text to an image',
      type: 'boolean',
      default: true
    },

    removeEmptyListItems: {
      title: 'Remove empty list-items',
      description: 'Remove the automatically created empty list-items when left empty, leaving an empty line',
      type: 'boolean',
      default: true
    }
  },

  subscriptions: null,

  activate (state) {
    this.subscriptions = new CompositeDisposable()
    this.addCommands()

    if (atom.config.get('language-markdown.disableLanguageGfm')) {
      if (!atom.packages.isPackageDisabled('language-gfm')) {
        atom.packages.disablePackage('language-gfm')
      }
    }

    this.subscriptions.add(atom.workspace.observeTextEditors(editor => {
      editor.onDidInsertText(event => {
        const grammar = editor.getGrammar()
        if (grammar.name === 'Markdown') {
          if (atom.config.get('language-markdown.addListItems')) {
            if (event.text === '\n') {
              const previousRowNumber = event.range.start.row
              const previousRowRange = editor.buffer.rangeForRow(previousRowNumber)
              const previousLine = editor.getTextInRange(previousRowRange)

              // At this point, it is rather tedious (as far as I know) to get to the tokenized version of {previousLine}. That is the reason why {tokens} a little further down is tokenized. But at this stage, we do need to know if {previousLine} was in fact Markdown, or from a different perspective, not a piece of embedded code. The reason for that is that the tokenized line below is tokenized without any context, so is Markdown by default. Therefore we determine if our current position is part of embedded code or not.
              // @burodepeper

              let isEmbeddedCode = false
              const scopeDescriptor = editor.scopeDescriptorForBufferPosition(previousRowRange.end)
              for (let i = 0; i < scopeDescriptor.scopes.length; i++) {
                const scope = scopeDescriptor.scopes[i]
                if (scope.indexOf('source') !== -1) {
                  isEmbeddedCode = true
                }
              }

              if (!isEmbeddedCode) {
                let { tokens } = grammar.tokenizeLine(previousLine)
                tokens.reverse()
                for (let i = 0; i < tokens.length; i++) {
                  const token = tokens[i]
                  let isPunctuation = false
                  let isListItem = false
                  let typeOfList

                  const scopes = token.scopes.reverse()
                  for (let j = 0; j < scopes.length; j++) {
                    const scope = scopes[j]
                    const classes = scope.split('.')

                    // a list-item is valid when a punctuation class is immediately followed by a non-empty list-item class
                    if (classes.indexOf('punctuation') !== -1) {
                      isPunctuation = true
                    } else if (isPunctuation && classes.indexOf('list') !== -1) {
                      if (classes.indexOf('empty') === -1) {
                        isListItem = true
                        typeOfList = 'unordered'
                        if (classes.indexOf('ordered') !== -1) {
                          typeOfList = 'ordered'
                        }
                        if (classes.indexOf('definition') !== -1) {
                          typeOfList = 'definition'
                        }
                        break
                      } else {
                        isListItem = false
                        isPunctuation = false
                        if (atom.config.get('language-markdown.removeEmptyListItems')) {
                          editor.setTextInBufferRange(previousRowRange, '')
                        }
                      }
                    } else {
                      isPunctuation = false
                    }
                  }

                  if (isListItem && typeOfList !== 'definition') {
                    let text = token.value

                    if (typeOfList === 'ordered') {
                      const length = text.length
                      const punctuation = text.match(/[^\d]+/)
                      const value = parseInt(text) + 1
                      text = value + punctuation

                      if (text.length < length) {
                        for (let j = 0; j < text.length - length + 1; j++) {
                          text = '0' + text
                        }
                      }
                    } else {
                      text = text.replace('x', ' ')
                    }

                    editor.insertText(text + '')
                    break
                  }
                }
              }
            }
          }
        }
      })
    }))
  },

  addCommands () {
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:indent-list-item', (event) => this.indentListItem(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:outdent-list-item', (event) => this.outdentListItem(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:emphasis', (event) => this.emphasizeSelection(event, '_')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:strong-emphasis', (event) => this.emphasizeSelection(event, '**')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:strike-through', (event) => this.emphasizeSelection(event, '~~')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:link', (event) => this.linkSelection(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:image', (event) => this.linkSelection(event, true)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:toggle-task', (event) => this.toggleTask(event)))

    if (atom.inDevMode()) {
      this.subscriptions.add(atom.commands.add('atom-workspace', 'markdown:compile-grammar-and-reload', () => this.compileGrammar()))
    }
  },

  indentListItem (event) {

  },

  outdentListItem (event) {

  },

  emphasizeSelection (event, token) {

  },

  linkSelection (event, isImage) {

  },

  _getEditorAndPosition (event) {

  },

  toggleTask (event) {

  },

  compileGrammar () {
    if (atom.inDevMode()) {
      const compiler = new GrammarCompiler()
      compiler.compile()
    }
  }
}
<commit_msg>Fix typo<commit_after>'use babel'

import { CompositeDisposable, Directory } from 'atom'
import { isListItem, wrapText } from './functions'

CSON = require('season')
fs = require('fs')
GrammarCompiler = require('./GrammarCompiler')
path = require('path')

module.exports = {
  config: {
    addListItems: {
      title: 'Add new list-items',
      description: 'Automatically add a new list-item after the current (non-empty) one when pressing ENTER',
      type: 'boolean',
      default: true
    },

    disableLanguageGfm: {
      title: 'Disable language-gfm',
      description: 'Disable the default `language-gfm` package as this package is intended as its replacement',
      type: 'boolean',
      default: true
    },

    emphasisShortcuts: {
      title: 'Emphasis shortcuts',
      description: 'Enables keybindings `_` for emphasis, `*` for strong emphasis, and `~` for strike-through on selected text; emphasizing an already emphasized selection will de-emphasize it',
      type: 'boolean',
      default: true
    },

    indentListItems: {
      title: 'Indent list-items',
      description: 'Automatically in- and outdent list-items by pressing `TAB` and `SHIFT+TAB`',
      type: 'boolean',
      default: true
    },

    linkShortcuts: {
      title: 'Link shortcuts',
      description: 'Enables keybindings `@` for converting the selected text to a link and `!` for converting the selected text to an image',
      type: 'boolean',
      default: true
    },

    removeEmptyListItems: {
      title: 'Remove empty list-items',
      description: 'Remove the automatically created empty list-items when left empty, leaving an empty line',
      type: 'boolean',
      default: true
    }
  },

  subscriptions: null,

  activate (state) {
    this.subscriptions = new CompositeDisposable()
    this.addCommands()

    if (atom.config.get('language-markdown.disableLanguageGfm')) {
      if (!atom.packages.isPackageDisabled('language-gfm')) {
        atom.packages.disablePackage('language-gfm')
      }
    }

    this.subscriptions.add(atom.workspace.observeTextEditors(editor => {
      editor.onDidInsertText(event => {
        const grammar = editor.getGrammar()
        if (grammar.name === 'Markdown') {
          if (atom.config.get('language-markdown.addListItems')) {
            if (event.text === '\n') {
              const previousRowNumber = event.range.start.row
              const previousRowRange = editor.buffer.rangeForRow(previousRowNumber)
              const previousLine = editor.getTextInRange(previousRowRange)

              // At this point, it is rather tedious (as far as I know) to get to the tokenized version of {previousLine}. That is the reason why {tokens} a little further down is tokenized. But at this stage, we do need to know if {previousLine} was in fact Markdown, or from a different perspective, not a piece of embedded code. The reason for that is that the tokenized line below is tokenized without any context, so is Markdown by default. Therefore we determine if our current position is part of embedded code or not.
              // @burodepeper

              let isEmbeddedCode = false
              const scopeDescriptor = editor.scopeDescriptorForBufferPosition(previousRowRange.end)
              for (let i = 0; i < scopeDescriptor.scopes.length; i++) {
                const scope = scopeDescriptor.scopes[i]
                if (scope.indexOf('source') !== -1) {
                  isEmbeddedCode = true
                }
              }

              if (!isEmbeddedCode) {
                let { tokens } = grammar.tokenizeLine(previousLine)
                tokens.reverse()
                for (let i = 0; i < tokens.length; i++) {
                  const token = tokens[i]
                  let isPunctuation = false
                  let isListItem = false
                  let typeOfList

                  const scopes = token.scopes.reverse()
                  for (let j = 0; j < scopes.length; j++) {
                    const scope = scopes[j]
                    const classes = scope.split('.')

                    // a list-item is valid when a punctuation class is immediately followed by a non-empty list-item class
                    if (classes.indexOf('punctuation') !== -1) {
                      isPunctuation = true
                    } else if (isPunctuation && classes.indexOf('list') !== -1) {
                      if (classes.indexOf('empty') === -1) {
                        isListItem = true
                        typeOfList = 'unordered'
                        if (classes.indexOf('ordered') !== -1) {
                          typeOfList = 'ordered'
                        }
                        if (classes.indexOf('definition') !== -1) {
                          typeOfList = 'definition'
                        }
                        break
                      } else {
                        isListItem = false
                        isPunctuation = false
                        if (atom.config.get('language-markdown.removeEmptyListItems')) {
                          editor.setTextInBufferRange(previousRowRange, '')
                        }
                      }
                    } else {
                      isPunctuation = false
                    }
                  }

                  if (isListItem && typeOfList !== 'definition') {
                    let text = token.value

                    if (typeOfList === 'ordered') {
                      const length = text.length
                      const punctuation = text.match(/[^\d]+/)
                      const value = parseInt(text) + 1
                      text = value + punctuation

                      if (text.length < length) {
                        for (let j = 0; j < text.length - length + 1; j++) {
                          text = '0' + text
                        }
                      }
                    } else {
                      text = text.replace('x', ' ')
                    }

                    editor.insertText(text + '')
                    break
                  }
                }
              }
            }
          }
        }
      })
    }))
  },

  addCommands () {
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:indent-list-item', (event) => this.indentListItem(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:outdent-list-item', (event) => this.outdentListItem(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:emphasis', (event) => this.emphasizeSelection(event, '_')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:strong-emphasis', (event) => this.emphasizeSelection(event, '**')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:strike-through', (event) => this.emphasizeSelection(event, '~~')))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:link', (event) => this.linkSelection(event)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:image', (event) => this.linkSelection(event, true)))
    this.subscriptions.add(atom.commands.add('atom-text-editor', 'markdown:toggle-task', (event) => this.toggleTask(event)))

    if (atom.inDevMode()) {
      this.subscriptions.add(atom.commands.add('atom-workspace', 'markdown:compile-grammar-and-reload', () => this.compileGrammar()))
    }
  },

  indentListItem (event) {

  },

  outdentListItem (event) {

  },

  emphasizeSelection (event, token) {

  },

  linkSelection (event, isImage) {

  },

  _getEditorAndPosition (event) {

  },

  toggleTask (event) {

  },

  compileGrammar () {
    if (atom.inDevMode()) {
      const compiler = new GrammarCompiler()
      compiler.compile()
    }
  }
}
<|endoftext|>


<commit_before>/**
    入驻小区
**/
(function(vc){
    vc.extends({
        data:{
            addStaffStepInfo:{
                $step:{},
                index:0,
                infos:[],
                staffInfo:{
                    orgId:'',
                    username:'',
                    sex:'',
                    email:'',
                    tel:'',
                    address:'',
                }
            }
        },
        _initMethod:function(){
            vc.component._initStep();
        },
        _initEvent:function(){
            vc.on("addStaffStep", "notify", function(_info){
                vc.component.addStaffStepInfo.infos[vc.component.addStaffStepInfo.index] = _info;

                if(vc.component.addStaffStepInfo.index == 1){
                   vc.component.addStaffStepInfo.staffInfo.orgId = _info.orgId
                }

                if(vc.component.addStaffStepInfo.index == 2){
                    vc.copyObject(_info, vc.component.addStaffStepInfo.staffInfo);
                }
            });

        },
        methods:{
            _initStep:function(){
                vc.component.addStaffStepInfo.$step = $("#step");
                vc.component.addStaffStepInfo.$step.step({
                    index: 0,
                    time: 500,
                    title: ["选择分公司","选择部门","员工信息"]
                });
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();
                vc.component._notifyViewOrgInfoComponentData();
            },
            _prevStep:function(){
                vc.component.addStaffStepInfo.$step.prevStep();
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();

                vc.emit('viewOrgInfo', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.emit('addStaffView', 'onIndex', vc.component.addStaffStepInfo.index);

                vc.component._notifyViewOrgInfoComponentData();

            },
            _nextStep:function(){
                var _currentData = vc.component.addStaffStepInfo.infos[vc.component.addStaffStepInfo.index];
                if( _currentData == null || _currentData == undefined){
                    vc.message("请选择或填写必选信息");
                    return ;
                }
                vc.component.addStaffStepInfo.$step.nextStep();
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();

                 vc.emit('viewOrgInfo', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.emit('addStaffView', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.component._notifyViewOrgInfoComponentData();

            },
            _finishStep:function(){

                vc.component.addStaffStepInfo.staffInfo.departmentOrgId = vc.component.addStaffStepInfo.infos[1];
               vc.http.post(
                   'addStaffStepBinding',
                   'binding',
                   JSON.stringify(vc.component.addStaffStepInfo.staffInfo),
                   {
                       emulateJSON:true
                    },
                    function(json,res){
                       if(res.status == 200){

                           vc.message('处理成功',true);
                           //关闭model
                           vc.jumpToPage("/flow/staff?" + vc.objToGetParam(JSON.parse(json)));
                           return ;
                       }
                       vc.message(json);
                    },
                    function(errInfo,error){
                       console.log('请求失败处理');

                       vc.message(errInfo);
                    });
            },
            _notifyViewOrgInfoComponentData:function(){

                if(vc.component.addStaffStepInfo.index == 0){

                    var _tmpBranchOrgInfo = {
                             componentName:'分公司信息',
                             buttonName:'选择分公司',
                             orgName:'',
                             orgLevel:'2',
                             parentOrgId:'',
                             description:'',
                    };

                    if(vc.component.addStaffStepInfo.infos.length >0){
                        _tmpBranchOrgInfo = vc.component.addStaffStepInfo.infos[0];
                    }
                    vc.emit('viewOrgInfo', '_initInfo',_tmpBranchOrgInfo);
                }else if(vc.component.addStaffStepInfo.index == 1){
                    var _tmpBranchOrgInfo = {
                             componentName:'部门信息',
                             buttonName:'选择部门',
                             orgName:'',
                             orgLevel:'3',
                             parentOrgId:vc.component.addStaffStepInfo.infos[0].parentOrgId,
                             description:'',
                    };

                    if(vc.component.addStaffStepInfo.infos.length >1){
                        _tmpBranchOrgInfo = vc.component.addStaffStepInfo.infos[1];
                    }
                    vc.emit('viewOrgInfo', '_initInfo',_tmpBranchOrgInfo);
                }
            }
        }
    });
})(window.vc);
<commit_msg>优化选择部门时的问题<commit_after>/**
    入驻小区
**/
(function(vc){
    vc.extends({
        data:{
            addStaffStepInfo:{
                $step:{},
                index:0,
                infos:[],
                staffInfo:{
                    orgId:'',
                    username:'',
                    sex:'',
                    email:'',
                    tel:'',
                    address:'',
                }
            }
        },
        _initMethod:function(){
            vc.component._initStep();
        },
        _initEvent:function(){
            vc.on("addStaffStep", "notify", function(_info){
                vc.component.addStaffStepInfo.infos[vc.component.addStaffStepInfo.index] = _info;

                if(vc.component.addStaffStepInfo.index == 1){
                   vc.component.addStaffStepInfo.staffInfo.orgId = _info.orgId
                }

                if(vc.component.addStaffStepInfo.index == 2){
                    vc.copyObject(_info, vc.component.addStaffStepInfo.staffInfo);
                }
            });

        },
        methods:{
            _initStep:function(){
                vc.component.addStaffStepInfo.$step = $("#step");
                vc.component.addStaffStepInfo.$step.step({
                    index: 0,
                    time: 500,
                    title: ["选择分公司","选择部门","员工信息"]
                });
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();
                vc.component._notifyViewOrgInfoComponentData();
            },
            _prevStep:function(){
                vc.component.addStaffStepInfo.$step.prevStep();
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();

                vc.emit('viewOrgInfo', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.emit('addStaffView', 'onIndex', vc.component.addStaffStepInfo.index);

                vc.component._notifyViewOrgInfoComponentData();

            },
            _nextStep:function(){
                var _currentData = vc.component.addStaffStepInfo.infos[vc.component.addStaffStepInfo.index];
                if( _currentData == null || _currentData == undefined){
                    vc.message("请选择或填写必选信息");
                    return ;
                }
                vc.component.addStaffStepInfo.$step.nextStep();
                vc.component.addStaffStepInfo.index = vc.component.addStaffStepInfo.$step.getIndex();

                 vc.emit('viewOrgInfo', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.emit('addStaffView', 'onIndex', vc.component.addStaffStepInfo.index);
                vc.component._notifyViewOrgInfoComponentData();

            },
            _finishStep:function(){

                vc.component.addStaffStepInfo.staffInfo.departmentOrgId = vc.component.addStaffStepInfo.infos[1];
               vc.http.post(
                   'addStaffStepBinding',
                   'binding',
                   JSON.stringify(vc.component.addStaffStepInfo.staffInfo),
                   {
                       emulateJSON:true
                    },
                    function(json,res){
                       if(res.status == 200){

                           vc.message('处理成功',true);
                           //关闭model
                           vc.jumpToPage("/flow/staff?" + vc.objToGetParam(JSON.parse(json)));
                           return ;
                       }
                       vc.message(json);
                    },
                    function(errInfo,error){
                       console.log('请求失败处理');

                       vc.message(errInfo);
                    });
            },
            _notifyViewOrgInfoComponentData:function(){

                if(vc.component.addStaffStepInfo.index == 0){

                    var _tmpBranchOrgInfo = {
                             componentName:'分公司信息',
                             buttonName:'选择分公司',
                             orgName:'',
                             orgLevel:'2',
                             parentOrgId:'',
                             description:'',
                    };

                    if(vc.component.addStaffStepInfo.infos.length >0){
                        _tmpBranchOrgInfo = vc.component.addStaffStepInfo.infos[0];
                    }
                    vc.emit('viewOrgInfo', '_initInfo',_tmpBranchOrgInfo);
                }else if(vc.component.addStaffStepInfo.index == 1){
                    var _tmpBranchOrgInfo = {
                             componentName:'部门信息',
                             buttonName:'选择部门',
                             orgName:'',
                             orgLevel:'3',
                             parentOrgId:vc.component.addStaffStepInfo.infos[0].orgId,
                             description:'',
                    };

                    if(vc.component.addStaffStepInfo.infos.length >1){
                        _tmpBranchOrgInfo = vc.component.addStaffStepInfo.infos[1];
                    }
                    vc.emit('viewOrgInfo', '_initInfo',_tmpBranchOrgInfo);
                }
            }
        }
    });
})(window.vc);
<|endoftext|>


<commit_before>'use strict';

var promisify   = require('deferred').promisify
  , ee          = require('event-emitter')
  , fs          = require('fs')
  , typeByStats = require('./type-by-stats')

  , nextTick = process.nextTick
  , lstat = promisify(fs.lstat), watch = fs.watch

  , opts = { persistent: false };

module.exports = function (path, emitter) {
	var stats, fileType, listener, watcher, lock
	  , end, clearLock, close;

	end = function (err) {
		if (emitter) {
			emitter.emit('end', err);
			close();
		}
	};

	close = function () {
		if (emitter) {
			watcher.close();
			emitter = null;
		}
	};

	clearLock = function () { lock = null; };

	listener = function (type) {
		if (lock) return;
		if (lock === false) {
			lock = (type === 'rename');
			return;
		}
		lock = (type === 'rename');
		// We do timeout, as there are cases that reinitializing watcher right away
		// doesn't work as file is not accessible. It gives us false positive that
		// file is removed (and that is not reported by dir watcher on parent dir)
		setTimeout(function () {
			var nwatcher;
			nextTick(clearLock);
			watcher.close();
			try {
				nwatcher = watch(path, opts, listener);
			} catch (e) {
				end(e);
				return;
			}
			watcher = nwatcher;
			watcher.on('error', end);
			if (stats && (lock || stats.isFile())) {
				lstat(path).end(function (nstats) {
					var newFileType, err;
					if (!emitter) {
						return;
					}
					newFileType = typeByStats(nstats);
					if (fileType !== newFileType) {
						err = new Error("File type have changed");
						err.code = 'DIFFTYPE';
						end(err);
						return;
					}
					if (stats.isDirectory() ||
							((stats.ctime.valueOf() !== nstats.ctime.valueOf()) ||
							 ((stats.mtime.valueOf() !== nstats.mtime.valueOf()) ||
								 (stats.size !== nstats.size)))) {
						emitter.emit('change');
					}
					stats = nstats;
				}, end);
			}
		}, 10);
	};

	watcher = watch(path, opts, listener);
	watcher.on('error', end);
	if (!emitter) {
		emitter = ee();
	}
	emitter.end = end;
	emitter.close = close;
	lstat(path)(function (nstats) {
		stats = nstats;
		fileType = typeByStats(stats);
	}, end);
	return emitter;
};
<commit_msg>-- lint<commit_after>'use strict';

var promisify   = require('deferred').promisify
  , ee          = require('event-emitter')
  , fs          = require('fs')
  , typeByStats = require('./type-by-stats')

  , nextTick = process.nextTick
  , lstat = promisify(fs.lstat), watch = fs.watch

  , opts = { persistent: false };

module.exports = function (path, emitter) {
	var stats, fileType, listener, watcher, lock
	  , end, clearLock, close;

	end = function (err) {
		if (emitter) {
			emitter.emit('end', err);
			close();
		}
	};

	close = function () {
		if (emitter) {
			watcher.close();
			emitter = null;
		}
	};

	clearLock = function () { lock = null; };

	listener = function (type) {
		if (lock) return;
		if (lock === false) {
			lock = (type === 'rename');
			return;
		}
		lock = (type === 'rename');
		// We do timeout, as there are cases that reinitializing watcher right away
		// doesn't work as file is not accessible. It gives us false positive that
		// file is removed (and that is not reported by dir watcher on parent dir)
		setTimeout(function () {
			var nwatcher;
			nextTick(clearLock);
			watcher.close();
			try {
				nwatcher = watch(path, opts, listener);
			} catch (e) {
				end(e);
				return;
			}
			watcher = nwatcher;
			watcher.on('error', end);
			if (stats && (lock || stats.isFile())) {
				lstat(path).end(function (nstats) {
					var newFileType, err;
					if (!emitter) {
						return;
					}
					newFileType = typeByStats(nstats);
					if (fileType !== newFileType) {
						err = new Error("File type have changed");
						err.code = 'DIFFTYPE';
						end(err);
						return;
					}
					if (stats.isDirectory() ||
							((stats.ctime.valueOf() !== nstats.ctime.valueOf()) ||
							((stats.mtime.valueOf() !== nstats.mtime.valueOf()) ||
								(stats.size !== nstats.size)))) {
						emitter.emit('change');
					}
					stats = nstats;
				}, end);
			}
		}, 10);
	};

	watcher = watch(path, opts, listener);
	watcher.on('error', end);
	if (!emitter) {
		emitter = ee();
	}
	emitter.end = end;
	emitter.close = close;
	lstat(path)(function (nstats) {
		stats = nstats;
		fileType = typeByStats(stats);
	}, end);
	return emitter;
};
<|endoftext|>


<commit_before>var extractZip = require('extract-zip');
var Download = require('download');
var exec = require('child_process').exec;
var NW_VERSION = '0.12.0';
var osx_64 = './bin/nw/nwjs-v' + NW_VERSION + '-osx-x64/nwjs.app/Contents/MacOS/nwjs';
var linux_64 = './bin/nw/nwjs-v' + NW_VERSION + '-linux-x64/nw';
var os = require('os');
var fs = require('fs');

// we'll assume just 64 bit
if(os.arch() != 'x64'){
    throw 'we only support running tests on 64 bit machines'
}

if(os.platform() === 'darwin'){
    if(!fs.existsSync(osx_64)) {
        new Download({mode: '755', extract: true})
        .get('http://dl.nwjs.io/v0.12.0/nwjs-v' + NW_VERSION + '-osx-x64.zip')
        .dest('./bin/nw')
        .run(function (err, files) {
            if(err){
                return console.error(err);
            }
            runNw(osx_64);
        });
    }
    else{
        runNw(osx_64);
    }

}
else if(os.platform() === 'linux'){
    if(!fs.existsSync(linux_64)) {
        console.log('downloading nw.js for linux to ' + linux_64);
        new Download({mode: '755', extract: true})
        .get('http://dl.nwjs.io/v0.12.0/nwjs-v' + NW_VERSION + '-linux-x64.tar.gz')
        .dest('./bin/nw')
        .run(function (err, files) {
            if(err){
                return console.error(err);
            }
            console.log('sucessfully extracted linux nw.js ');
            runNw(linux_64);
        });
    }
    else{
        runNw(linux_64);
    }
}
else{
    throw 'we only support running tests on mac and linux for now'
}

function runNw(nwPath){
    var nw;
    if(os.platform() === 'darwin'){
        // TODO - What happens to folks running a linux desktop?
        nw = exec('./travis_runner.sh ' + nwPath + ' ./dist/tests');
    }
    else{
        nw = exec(nwPath + ' ./dist/tests');
    }

    nw.stdout.on('data', function (data) {
        process.stdout.write(data);
    });
    var onError = false;
    nw.stderr.on('data', function (data) {
        if(data.indexOf('DEBUG:') === -1 &&
            data.indexOf('DEPRECATION:') === -1 &&
            data.indexOf('(file:') === -1){
            data = data.replace(/\[.*\]/g, "");
            data = data.replace(/\, source.*/g, "");
            data = data.replace(/\"/g, "");

            if (data.match(/ok \d+/) !== null && data.match(/not ok/) === null)
            {
                onError = false;
            }

            if(data.trim().length > 0){
                if(!onError){
                    process.stdout.write(TrimBeginningWhiteSpace(data));
                    if(data.match(/not ok/) !== null){
                        onError = true;
                    }
                }
                else{
                    process.stderr.write(TrimBeginningWhiteSpace(data));
                }
            }
        }
    });
    nw.on('exit', function (code) {
        setTimeout(function(){
            process.exit(code);
        }, 2000);
    });
}

function TrimBeginningWhiteSpace(str){
  while(str.charAt(0) == (" ") ){str = str.substring(1);}
  while(str.charAt(str.length-1) ==" " ){str = str.substring(0,str.length-1);}
  return str;
}<commit_msg>put linux here<commit_after>var extractZip = require('extract-zip');
var Download = require('download');
var exec = require('child_process').exec;
var NW_VERSION = '0.12.0';
var osx_64 = './bin/nw/nwjs-v' + NW_VERSION + '-osx-x64/nwjs.app/Contents/MacOS/nwjs';
var linux_64 = './bin/nw/nwjs-v' + NW_VERSION + '-linux-x64/nw';
var os = require('os');
var fs = require('fs');

// we'll assume just 64 bit
if(os.arch() != 'x64'){
    throw 'we only support running tests on 64 bit machines'
}

if(os.platform() === 'darwin'){
    if(!fs.existsSync(osx_64)) {
        new Download({mode: '755', extract: true})
        .get('http://dl.nwjs.io/v0.12.0/nwjs-v' + NW_VERSION + '-osx-x64.zip')
        .dest('./bin/nw')
        .run(function (err, files) {
            if(err){
                return console.error(err);
            }
            runNw(osx_64);
        });
    }
    else{
        runNw(osx_64);
    }

}
else if(os.platform() === 'linux'){
    if(!fs.existsSync(linux_64)) {
        console.log('downloading nw.js for linux to ' + linux_64);
        new Download({mode: '755', extract: true})
        .get('http://dl.nwjs.io/v0.12.0/nwjs-v' + NW_VERSION + '-linux-x64.tar.gz')
        .dest('./bin/nw')
        .run(function (err, files) {
            if(err){
                return console.error(err);
            }
            console.log('sucessfully extracted linux nw.js ');
            runNw(linux_64);
        });
    }
    else{
        runNw(linux_64);
    }
}
else{
    throw 'we only support running tests on mac and linux for now'
}

function runNw(nwPath){
    var nw;
    if(os.platform() === 'linux'){
        // TODO - What happens to folks running a linux desktop?
        nw = exec('./travis_runner.sh ' + nwPath + ' ./dist/tests');
    }
    else{
        nw = exec(nwPath + ' ./dist/tests');
    }

    nw.stdout.on('data', function (data) {
        process.stdout.write(data);
    });
    var onError = false;
    nw.stderr.on('data', function (data) {
        if(data.indexOf('DEBUG:') === -1 &&
            data.indexOf('DEPRECATION:') === -1 &&
            data.indexOf('(file:') === -1){
            data = data.replace(/\[.*\]/g, "");
            data = data.replace(/\, source.*/g, "");
            data = data.replace(/\"/g, "");

            if (data.match(/ok \d+/) !== null && data.match(/not ok/) === null)
            {
                onError = false;
            }

            if(data.trim().length > 0){
                if(!onError){
                    process.stdout.write(TrimBeginningWhiteSpace(data));
                    if(data.match(/not ok/) !== null){
                        onError = true;
                    }
                }
                else{
                    process.stderr.write(TrimBeginningWhiteSpace(data));
                }
            }
        }
    });
    nw.on('exit', function (code) {
        setTimeout(function(){
            process.exit(code);
        }, 2000);
    });
}

function TrimBeginningWhiteSpace(str){
  while(str.charAt(0) == (" ") ){str = str.substring(1);}
  while(str.charAt(str.length-1) ==" " ){str = str.substring(0,str.length-1);}
  return str;
}<|endoftext|>


<commit_before>import { ref, computed, onUnmounted } from '@vue/composition-api'
import { BridgeEvents, getStorage, parse, setStorage } from '@vue-devtools/shared-utils'
import cloneDeep from 'lodash/cloneDeep'
import Vue from 'vue'
import { formatTime } from '@front/util/format'
import { useApps, getApps } from '../apps'
import { getBridge } from '../bridge'

const STACK_DURATION = 50

const startTime = ref(0)
const endTime = ref(0)
const minTime = ref(0)
const maxTime = ref(0)

const layersPerApp = ref({})
const hiddenLayersPerApp = ref({})
const vScrollPerApp = ref({})

const selectedEvent = ref(null)
const hoverLayerId = ref(null)

function layerFactory (options) {
  return {
    ...options,
    events: [],
    displayedEvents: [],
    eventTimeMap: {}
  }
}

function builtinLayersFactory () {
  return [
    {
      id: 'mouse',
      label: 'Mouse',
      color: 0xA451AF
    },
    {
      id: 'keyboard',
      label: 'Keyboard',
      color: 0x8151AF
    },
    {
      id: 'component-event',
      label: 'Component events',
      color: 0x41B883
    }
  ].map(options => layerFactory(options))
}

const resetCbs = []

export function resetTimeline () {
  selectedEvent.value = null

  const now = Date.now()
  startTime.value = now - 1000
  endTime.value = now
  minTime.value = now - 1000
  maxTime.value = now
  layersPerApp.value = {}
  vScrollPerApp.value = {}
  hoverLayerId.value = null

  fetchLayers()

  hiddenLayersPerApp.value = getStorage('hidden-layers', {})

  for (const cb of resetCbs) {
    cb()
  }
}

export function onTimelineReset (cb) {
  onUnmounted(() => {
    const index = resetCbs.indexOf(cb)
    if (index !== -1) resetCbs.splice(cb)
  })

  resetCbs.push(cb)
}

const addEventCbs = []

export function onEventAdd (cb) {
  onUnmounted(() => {
    const index = addEventCbs.indexOf(cb)
    if (index !== -1) addEventCbs.splice(cb)
  })

  addEventCbs.push(cb)
}

function addEvent (appId, event, layer) {
  event.layer = layer
  event.appId = appId
  layer.events.push(event)
  event.stackedEvents = []
  const wasStacked = stackEvent(event)

  if (!wasStacked) {
    // Update scrollbar
    const scrollTime = event.time + 100
    if (scrollTime > maxTime.value) {
      if (endTime.value === maxTime.value) {
        if (endTime.value - startTime.value > 15000 || startTime.value !== minTime.value) {
          // Autoscroll
          const size = endTime.value - startTime.value
          startTime.value = scrollTime - size
        }
        endTime.value = scrollTime
      }
      maxTime.value = scrollTime
    }
  }

  for (const cb of addEventCbs) {
    cb(event)
  }
}

function stackEvent (event) {
  const roundedTime = Math.round(event.time / STACK_DURATION)
  const wasStacked = !!_stackEvent(event, roundedTime)
  if (!wasStacked) {
    event.layer.eventTimeMap[roundedTime] = event
    event.layer.displayedEvents.push(event)
    event.stackedEvents = [event]
  }
  return wasStacked
}

function _stackEvent (event, roundedTime) {
  const existingEvent = event.layer.eventTimeMap[roundedTime]
  if (existingEvent) {
    existingEvent.stackedEvents.push(event)
    event.stackParent = existingEvent
  }
  return existingEvent
}

export function useTime () {
  return {
    startTime,
    endTime,
    minTime,
    maxTime
  }
}

function getLayers (appId) {
  let layers = layersPerApp.value[appId]
  if (!layers) {
    layers = builtinLayersFactory()
    Vue.set(layersPerApp.value, appId, layers)
    // Read the property again to make it reactive
    layers = layersPerApp.value[appId]
  }
  return layers
}

function getHiddenLayers (appId) {
  let layers = hiddenLayersPerApp.value[appId]
  if (!layers) {
    layers = []
    Vue.set(hiddenLayersPerApp.value, appId, layers)
    // Read the property again to make it reactive
    layers = hiddenLayersPerApp.value[appId]
  }
  return layers
}

export function useLayers () {
  const { currentAppId } = useApps()

  const allLayers = computed(() => getLayers(currentAppId.value))

  function isLayerHidden (layer) {
    const list = getHiddenLayers(currentAppId.value)
    return list.includes(layer.id)
  }

  function setLayerHidden (layer, hidden) {
    const list = getHiddenLayers(currentAppId.value)
    const index = list.indexOf(layer.id)
    if (hidden && index === -1) {
      list.push(layer.id)
    } else if (!hidden && index !== -1) {
      list.splice(index, 1)
    }
    setStorage('hidden-layers', hiddenLayersPerApp.value)
  }

  const layers = computed(() => allLayers.value.filter(l => !isLayerHidden(l)))

  return {
    layers,
    allLayers,
    vScroll: computed({
      get: () => vScrollPerApp.value[currentAppId.value] || 0,
      set: value => {
        Vue.set(vScrollPerApp.value, currentAppId.value, value)
      }
    }),
    isLayerHidden,
    setLayerHidden,
    hoverLayerId
  }
}

export function useSelectedEvent () {
  return {
    selectedEvent,
    selectedStackedEvents: computed(() => selectedEvent.value.stackedEvents.map(e => ({
      data: parse(e.data),
      time: formatTime(e.time, 'ms')
    })))
  }
}

function fetchLayers () {
  getBridge().send(BridgeEvents.TO_BACK_TIMELINE_LAYER_LIST, {})
}

export function setupTimelineBridgeEvents (bridge) {
  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_EVENT, ({ appId, layerId, event }) => {
    const appIds = appId === 'all' ? getApps().map(app => app.id) : [appId]
    for (const appId of appIds) {
      const layer = getLayers(appId).find(l => l.id === layerId)
      if (!layer) {
        console.error(`Layer ${layerId} not found`)
        return
      }

      addEvent(appId, cloneDeep(event), layer)
    }
  })

  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_LAYER_ADD, () => {
    fetchLayers()
  })

  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_LAYER_LIST, ({ layers }) => {
    for (const layer of layers) {
      const existingLayers = getLayers(layer.appId)
      if (!existingLayers.some(l => l.id === layer.id)) {
        existingLayers.push(layerFactory(layer))
      }
    }
  })

  resetTimeline()
}
<commit_msg>fix(timeline): autoscroll wrong duration size<commit_after>import { ref, computed, onUnmounted } from '@vue/composition-api'
import { BridgeEvents, getStorage, parse, setStorage } from '@vue-devtools/shared-utils'
import cloneDeep from 'lodash/cloneDeep'
import Vue from 'vue'
import { formatTime } from '@front/util/format'
import { useApps, getApps } from '../apps'
import { getBridge } from '../bridge'

const STACK_DURATION = 50
const AUTOSCROLL_DURATION = 10000

const startTime = ref(0)
const endTime = ref(0)
const minTime = ref(0)
const maxTime = ref(0)

const layersPerApp = ref({})
const hiddenLayersPerApp = ref({})
const vScrollPerApp = ref({})

const selectedEvent = ref(null)
const hoverLayerId = ref(null)

function layerFactory (options) {
  return {
    ...options,
    events: [],
    displayedEvents: [],
    eventTimeMap: {}
  }
}

function builtinLayersFactory () {
  return [
    {
      id: 'mouse',
      label: 'Mouse',
      color: 0xA451AF
    },
    {
      id: 'keyboard',
      label: 'Keyboard',
      color: 0x8151AF
    },
    {
      id: 'component-event',
      label: 'Component events',
      color: 0x41B883
    }
  ].map(options => layerFactory(options))
}

const resetCbs = []

export function resetTimeline () {
  selectedEvent.value = null

  const now = Date.now()
  startTime.value = now - 1000
  endTime.value = now
  minTime.value = now - 1000
  maxTime.value = now
  layersPerApp.value = {}
  vScrollPerApp.value = {}
  hoverLayerId.value = null

  fetchLayers()

  hiddenLayersPerApp.value = getStorage('hidden-layers', {})

  for (const cb of resetCbs) {
    cb()
  }
}

export function onTimelineReset (cb) {
  onUnmounted(() => {
    const index = resetCbs.indexOf(cb)
    if (index !== -1) resetCbs.splice(cb)
  })

  resetCbs.push(cb)
}

const addEventCbs = []

export function onEventAdd (cb) {
  onUnmounted(() => {
    const index = addEventCbs.indexOf(cb)
    if (index !== -1) addEventCbs.splice(cb)
  })

  addEventCbs.push(cb)
}

function addEvent (appId, event, layer) {
  event.layer = layer
  event.appId = appId
  layer.events.push(event)
  event.stackedEvents = []
  const wasStacked = stackEvent(event)

  if (!wasStacked) {
    // Update scrollbar
    const scrollTime = event.time + 100
    if (scrollTime > maxTime.value) {
      if (endTime.value === maxTime.value) {
        if (endTime.value - startTime.value > AUTOSCROLL_DURATION) {
          // Autoscroll
          startTime.value = scrollTime - AUTOSCROLL_DURATION
        } else if (startTime.value !== minTime.value) {
          // Autoscroll
          startTime.value = scrollTime - (endTime.value - startTime.value)
        }
        endTime.value = scrollTime
      }
      maxTime.value = scrollTime
    }
  }

  for (const cb of addEventCbs) {
    cb(event)
  }
}

function stackEvent (event) {
  const roundedTime = Math.round(event.time / STACK_DURATION)
  const wasStacked = !!_stackEvent(event, roundedTime)
  if (!wasStacked) {
    event.layer.eventTimeMap[roundedTime] = event
    event.layer.displayedEvents.push(event)
    event.stackedEvents = [event]
  }
  return wasStacked
}

function _stackEvent (event, roundedTime) {
  const existingEvent = event.layer.eventTimeMap[roundedTime]
  if (existingEvent) {
    existingEvent.stackedEvents.push(event)
    event.stackParent = existingEvent
  }
  return existingEvent
}

export function useTime () {
  return {
    startTime,
    endTime,
    minTime,
    maxTime
  }
}

function getLayers (appId) {
  let layers = layersPerApp.value[appId]
  if (!layers) {
    layers = builtinLayersFactory()
    Vue.set(layersPerApp.value, appId, layers)
    // Read the property again to make it reactive
    layers = layersPerApp.value[appId]
  }
  return layers
}

function getHiddenLayers (appId) {
  let layers = hiddenLayersPerApp.value[appId]
  if (!layers) {
    layers = []
    Vue.set(hiddenLayersPerApp.value, appId, layers)
    // Read the property again to make it reactive
    layers = hiddenLayersPerApp.value[appId]
  }
  return layers
}

export function useLayers () {
  const { currentAppId } = useApps()

  const allLayers = computed(() => getLayers(currentAppId.value))

  function isLayerHidden (layer) {
    const list = getHiddenLayers(currentAppId.value)
    return list.includes(layer.id)
  }

  function setLayerHidden (layer, hidden) {
    const list = getHiddenLayers(currentAppId.value)
    const index = list.indexOf(layer.id)
    if (hidden && index === -1) {
      list.push(layer.id)
    } else if (!hidden && index !== -1) {
      list.splice(index, 1)
    }
    setStorage('hidden-layers', hiddenLayersPerApp.value)
  }

  const layers = computed(() => allLayers.value.filter(l => !isLayerHidden(l)))

  return {
    layers,
    allLayers,
    vScroll: computed({
      get: () => vScrollPerApp.value[currentAppId.value] || 0,
      set: value => {
        Vue.set(vScrollPerApp.value, currentAppId.value, value)
      }
    }),
    isLayerHidden,
    setLayerHidden,
    hoverLayerId
  }
}

export function useSelectedEvent () {
  return {
    selectedEvent,
    selectedStackedEvents: computed(() => selectedEvent.value.stackedEvents.map(e => ({
      data: parse(e.data),
      time: formatTime(e.time, 'ms')
    })))
  }
}

function fetchLayers () {
  getBridge().send(BridgeEvents.TO_BACK_TIMELINE_LAYER_LIST, {})
}

export function setupTimelineBridgeEvents (bridge) {
  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_EVENT, ({ appId, layerId, event }) => {
    const appIds = appId === 'all' ? getApps().map(app => app.id) : [appId]
    for (const appId of appIds) {
      const layer = getLayers(appId).find(l => l.id === layerId)
      if (!layer) {
        console.error(`Layer ${layerId} not found`)
        return
      }

      addEvent(appId, cloneDeep(event), layer)
    }
  })

  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_LAYER_ADD, () => {
    fetchLayers()
  })

  bridge.on(BridgeEvents.TO_FRONT_TIMELINE_LAYER_LIST, ({ layers }) => {
    for (const layer of layers) {
      const existingLayers = getLayers(layer.appId)
      if (!existingLayers.some(l => l.id === layer.id)) {
        existingLayers.push(layerFactory(layer))
      }
    }
  })

  resetTimeline()
}
<|endoftext|>


<commit_before>import { useEffect, useReducer, useRef } from 'react';
import { useRBACProvider, useAppInfos, useStrapiApp } from '@strapi/helper-plugin';
import getPluginSectionLinks from './utils/getPluginSectionLinks';
import getGeneralLinks from './utils/getGeneralLinks';
import reducer, { initialState } from './reducer';

const useMenu = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { allPermissions } = useRBACProvider();
  const { shouldUpdateStrapi } = useAppInfos();
  const { menu } = useStrapiApp();

  // We are using a ref because we don't want our effect to have this in its dependencies array
  const generalSectionLinksRef = useRef(state.generalSectionLinks);
  const shouldUpdateStrapiRef = useRef(shouldUpdateStrapi);
  // Once in the app lifecycle the menu should not be added into any dependencies array
  const menuRef = useRef(menu);

  const resolvePermissions = async (permissions = allPermissions) => {
    const pluginsSectionLinks = menuRef.current;

    const authorizedPluginSectionLinks = await getPluginSectionLinks(
      permissions,
      pluginsSectionLinks
    );

    const authorizedGeneralSectionLinks = await getGeneralLinks(
      permissions,
      generalSectionLinksRef.current,
      shouldUpdateStrapiRef.current
    );

    dispatch({
      type: 'SET_SECTION_LINKS',
      data: {
        authorizedGeneralSectionLinks,
        authorizedPluginSectionLinks,
      },
    });
    dispatch({ type: 'UNSET_IS_LOADING' });
  };

  const resolvePermissionsRef = useRef(resolvePermissions);

  useEffect(() => {
    resolvePermissionsRef.current(allPermissions);
  }, [allPermissions, dispatch]);

  return state;
};

export default useMenu;
<commit_msg>Fix PR feedback<commit_after>import { useEffect, useReducer, useRef } from 'react';
import { useRBACProvider, useAppInfos, useStrapiApp } from '@strapi/helper-plugin';
import getPluginSectionLinks from './utils/getPluginSectionLinks';
import getGeneralLinks from './utils/getGeneralLinks';
import reducer, { initialState } from './reducer';

const useMenu = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { allPermissions } = useRBACProvider();
  const { shouldUpdateStrapi } = useAppInfos();
  const { menu } = useStrapiApp();

  // We are using a ref because we don't want our effect to have this in its dependencies array
  const generalSectionLinksRef = useRef(state.generalSectionLinks);
  const shouldUpdateStrapiRef = useRef(shouldUpdateStrapi);
  // Once in the app lifecycle the menu should not be added into any dependencies array

  const resolvePermissions = async (permissions = allPermissions) => {
    const pluginsSectionLinks = menu;

    const authorizedPluginSectionLinks = await getPluginSectionLinks(
      permissions,
      pluginsSectionLinks
    );

    const authorizedGeneralSectionLinks = await getGeneralLinks(
      permissions,
      generalSectionLinksRef.current,
      shouldUpdateStrapiRef.current
    );

    dispatch({
      type: 'SET_SECTION_LINKS',
      data: {
        authorizedGeneralSectionLinks,
        authorizedPluginSectionLinks,
      },
    });
    dispatch({ type: 'UNSET_IS_LOADING' });
  };

  const resolvePermissionsRef = useRef(resolvePermissions);

  useEffect(() => {
    resolvePermissionsRef.current(allPermissions);
  }, [allPermissions, dispatch]);

  return state;
};

export default useMenu;
<|endoftext|>


<commit_before>var fs = require('fs');
var net = require('net');
var path = require('path');
var util = require('util');
var actorify = require('actorify');
var spawn = require('child_process').spawn;
var EventEmitter = require('events').EventEmitter;

function Angelo(args) {
  this.filePath = '';
  this.nodeBinary = 'node';

  if (args) {
    // If args is a string, we're going to assume the
    // common case that it's a file path
    if (typeof args === 'string') {
      this.filePath = args;
    } else {
      var keys = Object.keys(args);
      keys.forEach(function(key) {
        this[key] = args[key];
      }, this);
    }
  }
  this.init();
}

util.inherits(Angelo, EventEmitter);

Angelo.prototype.init = function() {
  this.initPlayer();

  setTimeout(function(_this) {
    _this.initConnection();
    _this.initActor();
    _this.actor.send('ready');
  }, 250, this);
};

Angelo.prototype.initPlayer = function() {
  var binFullPath = fs.realpathSync(__filename);
  var binDir = path.dirname(binFullPath);
  var libDir = path.join(binDir, '../lib');
  var playerPath = path.join(libDir, 'mocha-player.js');

  this.player  = spawn(this.nodeBinary, [playerPath, 3000], {detached:false});

  if (!process.hasOwnProperty('children')) {
    process.children = {};
  }
  process.children[this.player.pid] = this.player;

  this.player.on('exit', function() {
    delete process.children[this.pid];
  });

  this.player.stdout.on('data', function(data) {
    process.stdout.write(data);
  });
};

Angelo.prototype.initConnection = function() {
  this.sock = net.connect(3000);

  this.sock.on('error', function() {
    console.log('socket error');
  });
};

Angelo.prototype.initActor = function() {
  this.actor = actorify(this.sock);
  this.send = this.actor.send;

  this.actor.on('readied', function() {
    process.stdout.write('Client received message: readied\n');
    if (this.filePath !== '') {
      this.load();
    }
  }.bind(this));

  this.actor.on('echoed', function(message) {
    process.stdout.write('Client received message: echoed\n');
    if (message) {
      process.stdout.write('Client received echoed content: ' + util.inspect(message) + '\n');
    }
  });

  this.actor.on('loaded', function(playlists) {
    process.stdout.write('Client received message: loaded\n');
    if (playlists) {
      process.stdout.write('Client received load: ' + JSON.stringify(playlists,null,2) + '\n');
    }
    this.playlists = playlists;
    this.emit('loaded');
  }.bind(this));

  this.actor.on('started', function() {
    process.stdout.write('Client received message: started\n');
  });

  this.actor.on('logged', function(message) {
    if (message) {
      process.stdout.write('Client received log: ' + message + '\n');
    }
  });

  this.actor.on('stopped', function(restart) {
    process.stdout.write('Client received message: stopped\n');
    // Re-init everything
    if (restart) {
      setTimeout(function(_this) {
        _this.init();
      }, 250, this);
  }
  }.bind(this));
};

Angelo.prototype.echo = function(message) {
  this.actor.send('echo', message);
};

Angelo.prototype.load = function(newFilePath) {
  if (newFilePath) {
    this.filePath = newFilePath;
  }
  if (this.filePath) {
    this.actor.send('load', this.filePath);
  }
};

Angelo.prototype.play = function() {
  var restart = true;
  this.actor.send('start', restart);
};

Angelo.prototype.playOnce = function() {
  var restart = false;
  this.actor.send('start', restart);
};

Angelo.prototype.stop = function() {
  var restart = false;
  this.actor.send('stop', restart);
};

Angelo.prototype.restart = function() {
  var restart = true;
  this.actor.send('stop', restart);
};

process.on("SIGINT", function() {
  process.stdout.write('Exiting...\n');
  process.exit();
});

process.on('SIGTERM', function() {
  process.stdout.write('Exiting...\n');
  process.exit();
});

process.on('exit', function () {
  // process.stdout.write('Event: "exit"\n');
  if (process.hasOwnProperty('children')) {
    // console.log('Child processes:');
    for (var key in process.children) {
      if (process.children.hasOwnProperty(key)) {
        // console.log('  pid: ' + process.children[key].pid);
        // console.log('  exitCode: ' + process.children[key].exitCode);
        // console.log('  killed: ' + process.children[key].killed);
        if ((process.children[key].exitCode === null) && (process.children[key].killed === false)) {
          process.children[key].kill('SIGINT');
          // console.log("  ... but now it's dead!");
        }
      }
    }
  }
  process.exit();
});

module.exports.Angelo = Angelo;<commit_msg>Get smarter about how much to log<commit_after>var fs = require('fs');
var net = require('net');
var path = require('path');
var util = require('util');
var actorify = require('actorify');
var spawn = require('child_process').spawn;
var EventEmitter = require('events').EventEmitter;

var VERBOSE = false;

function info(message) {
  if (VERBOSE) {
    process.stdout.write(message);
  }
}

function Angelo(args) {
  this.filePath = '';
  this.nodeBinary = 'node';

  if (args) {
    // If args is a string, we're going to assume the
    // common case that it's a file path
    if (typeof args === 'string') {
      this.filePath = args;
    } else {
      var keys = Object.keys(args);
      keys.forEach(function(key) {
        this[key] = args[key];
      }, this);
    }
    if (args.verbose) {
      VERBOSE = true;
    }
  }
  this.init();
}

util.inherits(Angelo, EventEmitter);

Angelo.prototype.init = function() {
  this.initPlayer();

  setTimeout(function(_this) {
    _this.initConnection();
    _this.initActor();
    _this.actor.send('ready');
  }, 250, this);
};

Angelo.prototype.initPlayer = function() {
  var binFullPath = fs.realpathSync(__filename);
  var binDir = path.dirname(binFullPath);
  var libDir = path.join(binDir, '../lib');
  var playerPath = path.join(libDir, 'mocha-player.js');

  this.player  = spawn(this.nodeBinary, [playerPath, 3000], {detached:false});

  if (!process.hasOwnProperty('children')) {
    process.children = {};
  }
  process.children[this.player.pid] = this.player;

  this.player.on('exit', function() {
    delete process.children[this.pid];
  });

  this.player.stdout.on('data', function(data) {
    info(data);
  });
};

Angelo.prototype.initConnection = function() {
  this.sock = net.connect(3000);

  this.sock.on('error', function() {
    console.log('socket error');
  });
};

Angelo.prototype.initActor = function() {
  this.actor = actorify(this.sock);
  this.send = this.actor.send;

  this.actor.on('readied', function() {
    info('Client received message: readied\n');
    if (this.filePath !== '') {
      this.load();
    }
  }.bind(this));

  this.actor.on('echoed', function(message) {
    info('Client received message: echoed\n');
    if (message) {
      info('Client received echoed content: ' + util.inspect(message) + '\n');
    }
  });

  this.actor.on('loaded', function(playlists) {
    info('Client received message: loaded\n');
    if (playlists) {
      info('Client received load: ' + JSON.stringify(playlists,null,2) + '\n');
    }
    this.playlists = playlists;
    this.emit('loaded');
  }.bind(this));

  this.actor.on('started', function() {
    info('Client received message: started\n');
  });

  this.actor.on('logged', function(message) {
    if (message) {
      info('Client received log: ')
      process.stdout.write(message + '\n');
    }
  });

  this.actor.on('stopped', function(restart) {
    info('Client received message: stopped\n');
    // Re-init everything
    if (restart) {
      setTimeout(function(_this) {
        _this.init();
      }, 250, this);
  }
  }.bind(this));
};

Angelo.prototype.echo = function(message) {
  this.actor.send('echo', message);
};

Angelo.prototype.load = function(newFilePath) {
  if (newFilePath) {
    this.filePath = newFilePath;
  }
  if (this.filePath) {
    this.actor.send('load', this.filePath);
  }
};

Angelo.prototype.play = function() {
  var restart = true;
  this.actor.send('start', restart);
};

Angelo.prototype.playOnce = function() {
  var restart = false;
  this.actor.send('start', restart);
};

Angelo.prototype.stop = function() {
  var restart = false;
  this.actor.send('stop', restart);
};

Angelo.prototype.restart = function() {
  var restart = true;
  this.actor.send('stop', restart);
};

process.on("SIGINT", function() {
  info('Exiting...\n');
  process.exit();
});

process.on('SIGTERM', function() {
  info('Exiting...\n');
  process.exit();
});

process.on('exit', function () {
  // info('Event: "exit"\n');
  if (process.hasOwnProperty('children')) {
    // info('Child processes:');
    for (var key in process.children) {
      if (process.children.hasOwnProperty(key)) {
        // info('  pid: ' + process.children[key].pid);
        // info('  exitCode: ' + process.children[key].exitCode);
        // info('  killed: ' + process.children[key].killed);
        if ((process.children[key].exitCode === null) && (process.children[key].killed === false)) {
          process.children[key].kill('SIGINT');
          // info("  ... but now it's dead!");
        }
      }
    }
  }
  process.exit();
});

module.exports.Angelo = Angelo;<|endoftext|>


<commit_before>import { isArray } from '../lib/typeof.js';
import { dispatch } from '../lib/dispatch.js';
import { isUndefined } from '../lib/typeof.js';
import { prop } from '../lib/property.js';

function getValue(property, attrVal) {
    if (attrVal === '' && property.accepts(Boolean)) {
        return true;
    }
    if (!property.accepts(String)) {
        try {
            return JSON.parse(attrVal);
        } catch (ex) {
            //
        }
    }
    return attrVal;
}

function setAttribute(context, attr, value) {
    let currentAttrValue = context.getAttribute(attr);
    if (currentAttrValue !== value) {
        if (value !== null && value !== undefined && value !== false) {
            switch (typeof value) {
            case 'string':
            case 'number':
                context.setAttribute(attr, value);
                break;
            case 'boolean':
                context.setAttribute(attr, '');
            }
        } else if (currentAttrValue !== null) {
            context.removeAttribute(attr);
        }
    }
}

/**
 * Simple Custom Component for properties initialization via attributes.
 *
 * @example
 * my-component.js
 * ```js
 * import { Component, PropertiesMixin, mix } from 'dna/component';
 * export class MyComponent extends mix(Component).with(PropertiesMixin) {
 *   get properties() {
 *     return { name: String };
 *   }
 * }
 * ```
 * app.js
 * ```js
 * import { define } from 'dna/component';
 * import { MyComponent } from './components/my-component/my-component.js';
 * define('my-component', MyComponent);
 * var temp = document.createElement('div');
 * temp.innerHTML = '<my-component name="Albert"></my-component>';
 * var element = temp.firstChild;
 * console.log(element.name); // logs "Albert"
 * ```
 */
export const PropertiesMixin = (SuperClass) => class extends SuperClass {
    /**
     * On `created` callback, apply attributes to properties.
     */
    constructor() {
        super();
        let props = this.properties;
        if (props) {
            if (!isArray(props)) {
                props = [props];
            }
            props = props.reduce((res, partialProps) => {
                for (let k in partialProps) {
                    res[k] = prop(partialProps[k]);
                }
                return res;
            }, {});
        } else {
            props = {};
        }
        Object.defineProperty(this, 'properties', {
            value: props,
            writable: false,
            configurable: true,
        });
        for (let k in props) {
            let prop = props[k];
            prop.named(k).init(this);
            let { attrName, eventName } = prop;
            if (attrName || eventName) {
                prop.observe(() => {
                    if (attrName) {
                        setAttribute(this, attrName, this[prop.name]);
                    }
                    if (eventName) {
                        dispatch(this, eventName);
                    }
                });
            }
        }
    }
    connectedCallback() {
        super.connectedCallback();
        let props = this.properties;
        for (let k in props) {
            let prop = props[k];
            let { attrName } = prop;
            if (attrName) {
                if (isUndefined(this[prop.name])) {
                    if (this.hasAttribute(attrName)) {
                        this[prop.name] = getValue(prop, this.getAttribute(attrName));
                    }
                } else {
                    setAttribute(this, attrName, this[prop.name]);
                }
            }
        }
    }
    /**
     * On `attributeChanged` callback, sync attributes with properties.
     * @param {String} attrName The changed attribute name.
     * @param {*} oldVal The value of the attribute before the change.
     * @param {*} newVal The value of the attribute after the change.
     */
    attributeChangedCallback(attr, oldVal, newVal) {
        super.attributeChangedCallback(attr, oldVal, newVal);
        let props = this.properties;
        for (let k in props) {
            let prop = props[k];
            if (prop.attrName === attr) {
                this[prop.name] = getValue(prop, newVal);
                return;
            }
        }
    }
    /**
     * Create a listener for node's property changes.
     * @param {string} propName The property name to observe.
     * @param {Function} callback The callback to fire.
     * @return {Object} An object with `cancel` method.
     */
    observeProperty(propName, callback) {
        this.properties[propName].observe(callback);
    }
    unobserveProperty(propName, callback) {
        this.properties[propName].unobserve(callback);
    }
};
<commit_msg>feat: auto add prop attribute observer if in observedAttributes<commit_after>import { isArray } from '../lib/typeof.js';
import { dispatch } from '../lib/dispatch.js';
import { isUndefined } from '../lib/typeof.js';
import { prop } from '../lib/property.js';

function getValue(property, attrVal) {
    if (attrVal === '' && property.accepts(Boolean)) {
        return true;
    }
    if (!property.accepts(String)) {
        try {
            return JSON.parse(attrVal);
        } catch (ex) {
            //
        }
    }
    return attrVal;
}

function setAttribute(context, attr, value) {
    let currentAttrValue = context.getAttribute(attr);
    if (currentAttrValue !== value) {
        if (value !== null && value !== undefined && value !== false) {
            switch (typeof value) {
            case 'string':
            case 'number':
                context.setAttribute(attr, value);
                break;
            case 'boolean':
                context.setAttribute(attr, '');
            }
        } else if (currentAttrValue !== null) {
            context.removeAttribute(attr);
        }
    }
}

/**
 * Simple Custom Component for properties initialization via attributes.
 *
 * @example
 * my-component.js
 * ```js
 * import { Component, PropertiesMixin, mix } from 'dna/component';
 * export class MyComponent extends mix(Component).with(PropertiesMixin) {
 *   get properties() {
 *     return { name: String };
 *   }
 * }
 * ```
 * app.js
 * ```js
 * import { define } from 'dna/component';
 * import { MyComponent } from './components/my-component/my-component.js';
 * define('my-component', MyComponent);
 * var temp = document.createElement('div');
 * temp.innerHTML = '<my-component name="Albert"></my-component>';
 * var element = temp.firstChild;
 * console.log(element.name); // logs "Albert"
 * ```
 */
export const PropertiesMixin = (SuperClass) => class extends SuperClass {
    /**
     * On `created` callback, apply attributes to properties.
     */
    constructor() {
        super();
        let props = this.properties;
        if (props) {
            if (!isArray(props)) {
                props = [props];
            }
            props = props.reduce((res, partialProps) => {
                for (let k in partialProps) {
                    res[k] = prop(partialProps[k]);
                }
                return res;
            }, {});
        } else {
            props = {};
        }
        Object.defineProperty(this, 'properties', {
            value: props,
            writable: false,
            configurable: true,
        });
        let observed = this.constructor.observedAttributes || [];
        for (let k in props) {
            let prop = props[k];
            prop.named(k).init(this);
            let { attrName, eventName } = prop;
            if (!attrName && observed.indexOf(k)) {
                prop.attribute(k);
                attrName = k;
            }
            if (attrName || eventName) {
                prop.observe(() => {
                    if (attrName) {
                        setAttribute(this, attrName, this[prop.name]);
                    }
                    if (eventName) {
                        dispatch(this, eventName);
                    }
                });
            }
        }
    }
    connectedCallback() {
        super.connectedCallback();
        let props = this.properties;
        for (let k in props) {
            let prop = props[k];
            let { attrName } = prop;
            if (attrName) {
                if (isUndefined(this[prop.name])) {
                    if (this.hasAttribute(attrName)) {
                        this[prop.name] = getValue(prop, this.getAttribute(attrName));
                    }
                } else {
                    setAttribute(this, attrName, this[prop.name]);
                }
            }
        }
    }
    /**
     * On `attributeChanged` callback, sync attributes with properties.
     * @param {String} attrName The changed attribute name.
     * @param {*} oldVal The value of the attribute before the change.
     * @param {*} newVal The value of the attribute after the change.
     */
    attributeChangedCallback(attr, oldVal, newVal) {
        super.attributeChangedCallback(attr, oldVal, newVal);
        let props = this.properties;
        for (let k in props) {
            let prop = props[k];
            if (prop.attrName === attr) {
                this[prop.name] = getValue(prop, newVal);
                return;
            }
        }
    }
    /**
     * Create a listener for node's property changes.
     * @param {string} propName The property name to observe.
     * @param {Function} callback The callback to fire.
     * @return {Object} An object with `cancel` method.
     */
    observeProperty(propName, callback) {
        this.properties[propName].observe(callback);
    }
    unobserveProperty(propName, callback) {
        this.properties[propName].unobserve(callback);
    }
};
<|endoftext|>


<commit_before>/**
 * Created by austin on 5/9/15.
 */

"use strict";

var _ = require("lodash")
  , minimatch = require("minimatch")

  , dbs = require("../db");

function _buildActionParams(query) {

  var queryFields = Object.keys(dbs._schema);
  return _.map(_.pick(query, queryFields), function (val, key) {
    var obj = {};
    obj[key] = {"$regex": minimatch.makeRe(val)};
    return obj;
  });
}

module.exports.actions = {
  "find": "find"
  , "findOne": "findOne"
};

module.exports.ops = {
  "and": "and",
  "or": "or"
};

module.exports.processRequest = function (collection, query, action, cb) {

  var actionParams = _buildActionParams(query)
    , models = [];

  switch (action) {
    case this.actions.find:

      var op = query.op || this.ops.and;
      if (!_.has(this.ops, op)) {
        var error = new Error("Invalid operation type supplied: " + op);
        error.code = 400;
        return cb(error);
      }

      if (actionParams.length > 1 && op === this.ops.and) {
        // process 'and' operation

        var chain = collection.chain();
        _.each(actionParams, function (actionParam) {
          chain.find(actionParam);
        });
        models = chain.data();
      }
      else if (actionParams.length > 1 && op === this.ops.or) {
        // process 'or' operation

        var keys = {}
          , filter = function (model) {
            if (!_.has(keys, model.$loki)) {
              keys[model.$loki] = true;
              return true;
            }
            else {
              return false;
            }
          };
        models = _.flatten(_.map(actionParams, function (actionParam) {
          return _.filter(collection.find(actionParam), filter);
        }));
      }
      else {
        // singular parameter requested
        models = collection.find(actionParams[0] || {});
      }
      break;
    case this.actions.findOne:

      var model = collection.findOne(_.filter(actionParams, function (param) {
          return _.has(param, "name");
        })[0] || {});

      if (model !== null) {
        models = [model];
      }
      else {
        var error = new Error("Requested library not found.");
        error.code = 404;
        return cb(error);
      }

      // the api v1 specs only attempt to get project files for a version
      // when permorming a '.../libraries/<NAME>/<VERSION>' query
      if (query.version) {
        try {
          models = _selectVersionFiles(query.version, models);
          return cb(null, models);
        }
        catch (err) {
          return cb(err);
        }
      }

      break;
    default:
      return cb(new Error("Invalid action " + action + " request of api.v1"));
  }

  models = _selectFields(query.fields || Object.keys(dbs._schema).join(","), models);
  cb(null, models);
};

function _selectVersionFiles(version, models) {

  var versionFiles = null;
  _.each(models, function (model) {
    var versionAssets = _.find(model.assets, {version: version});
    if (versionAssets) {
      versionFiles = versionAssets.files;
    }
  });

  if (!versionFiles) {
    var error = new Error("Requested version not found.");
    error.code = 404;
    throw error;
  }

  return versionFiles;
}

// pick out only the specified fields to return
function _selectFields(fields, models) {

  return _.map(models, _.partial(_.pick, _, fields.split(",")));
}
<commit_msg>refactor process api request structure<commit_after>/**
 * Created by austin on 5/9/15.
 */

"use strict";

var _ = require("lodash")
  , minimatch = require("minimatch")

  , dbs = require("../db");

function _buildActionParams(query) {

  var queryFields = Object.keys(dbs._schema);
  return _.map(_.pick(query, queryFields), function (val, key) {
    var obj = {};
    obj[key] = {"$regex": minimatch.makeRe(val)};
    return obj;
  });
}

module.exports.actions = {
  "find": "find"
  , "findOne": "findOne"
};

module.exports.ops = {
  "and": "and",
  "or": "or"
};

module.exports.processRequest = function (collection, query, action, cb) {

  var actionParams = _buildActionParams(query);

  switch (action) {
    case this.actions.find:
      _find(collection, query, actionParams, this.ops, cb);
      break;
    case this.actions.findOne:
      _findOne(collection, query, actionParams, cb);
      break;
    default:
      var error = new Error("Invalid action " + action + " request of api.v1");
      error.code = 501;
      return cb(error);
  }
};

// process request for generic query against a cdn collection
function _find(collection, query, actionParams, ops, cb) {

  var models = []
    , op = query.op || ops.and;

  if (!_.has(ops, op)) {
    var error = new Error("Invalid operation type supplied: " + op);
    error.code = 400;
    return cb(error);
  }

  if (actionParams.length > 1 && op === ops.and) {
    // process 'and' operation

    var chain = collection.chain();
    _.each(actionParams, function (actionParam) {
      chain.find(actionParam);
    });
    models = chain.data();
  }
  else if (actionParams.length > 1 && op === ops.or) {
    // process 'or' operation

    var keys = {}
      , filter = function (model) {
        if (!_.has(keys, model.$loki)) {
          keys[model.$loki] = true;
          return true;
        }
        else {
          return false;
        }
      };

    models = _.flatten(_.map(actionParams, function (actionParam) {
      return _.filter(collection.find(actionParam), filter);
    }));
  }
  else {
    // singular parameter requested
    models = collection.find(actionParams[0] || {});
  }

  models = _selectFields(query.fields || Object.keys(dbs._schema).join(","), models);
  cb(null, models);
}

// process request for singular library or singular libraries version files
function _findOne(collection, query, actionParams, cb) {

  var models = [];

  var model = collection.findOne(_.filter(actionParams, function (param) {
      return _.has(param, "name");
    })[0] || {});

  if (model !== null) {
    models = [model];
  }
  else {
    var error = new Error("Requested library not found.");
    error.code = 404;
    return cb(error);
  }

  // the api v1 specs only attempt to get project files for a version
  // when permorming a '.../libraries/<NAME>/<VERSION>' query
  if (query.version) {
    models = _selectVersionFiles(query.version, models);
    if (models) {
      return cb(null, models);
    }
    else {
      var error = new Error("Requested version not found.");
      error.code = 404;
      return cb(error);
    }
  }

  models = _selectFields(query.fields || Object.keys(dbs._schema).join(","), models);
  cb(null, models);
}

function _selectVersionFiles(version, models) {

  var versionFiles = null;
  _.each(models, function (model) {
    var versionAssets = _.find(model.assets, {version: version});
    if (versionAssets) {
      versionFiles = versionAssets.files;
    }
  });

  return versionFiles;
}

// pick out only the specified fields to return
function _selectFields(fields, models) {

  return _.map(models, _.partial(_.pick, _, fields.split(",")));
}
<|endoftext|>


<commit_before>var TradeOfferManager = require('./index.js');
var Async = require('async');
var EconItem = require('./classes/EconItem.js');

TradeOfferManager.prototype._digestDescriptions = function(descriptions) {
	var cache = this._assetCache;

	if(!this._language) {
		return;
	}

	if(descriptions && !(descriptions instanceof Array)) {
		descriptions = Object.keys(descriptions).map(function(key) {
			return descriptions[key];
		});
	}

	(descriptions || []).forEach(function(item) {
		if(!item || !item.appid || !item.classid) {
			return;
		}

		cache[item.appid + '_' + item.classid + '_' + (item.instanceid || '0')] = item;
	});
};

TradeOfferManager.prototype._mapItemsToDescriptions = function(appid, contextid, items) {
	var cache = this._assetCache;

	if(!(items instanceof Array)) {
		items = Object.keys(items).map(function(key) {
			return items[key];
		});
	}

	return items.map(function(item) {
		item.appid = appid || item.appid;
		item.contextid = contextid || item.contextid;

		var key = item.appid + '_' + item.classid + '_' + (item.instanceid || '0');
		if(!cache[key]) {
			// This item isn't in our description cache
			return new EconItem(item);
		}

		for(i in cache[key]) {
			item[i] = cache[key][i];
		}

		return new EconItem(item);
	});
};

TradeOfferManager.prototype._hasDescription = function(item, appid) {
	appid = appid || item.appid;
	return !!this._assetCache[appid + '_' + item.classid + '_' + (item.instanceid || '0')];
};

TradeOfferManager.prototype._requestDescriptions = function(classes, callback) {
	var apps = [];
	var appids = [];

	classes.forEach(function(item) {
		var index = appids.indexOf(item.appid);
		if(index == -1) {
			index = appids.push(item.appid) - 1;
			var arr = [];
			arr.appid = item.appid;
			apps.push(arr);
		}

		// Don't add a class/instanceid pair that we already have in the list
		if(apps[index].indexOf(item.classid + '_' + (item.instanceid || '0')) == -1) {
			apps[index].push(item.classid + '_' + (item.instanceid || '0'));
		}
	});

	Async.map(apps, function(app, cb) {
		var input = {
			"appid": app.appid,
			"language": this._language,
			"class_count": app.length
		};

		app.forEach(function(item, index) {
			var parts = item.split('_');
			input['classid' + index] = parts[0];
			input['instanceid' + index] = parts[1];
		});

		this._apiCall('GET', {"iface": "ISteamEconomy", "method": "GetAssetClassInfo"}, 1, input, function(err, body) {
			if(err) {
				cb(err);
				return;
			}

			if(!body.result || !body.result.success) {
				cb(new Error("Invalid API response"));
				return;
			}

			var items = Object.keys(body.result).map(function(id) {
				if(!id.match(/^\d+(_\d+)?$/)) {
					return null;
				}

				var item = body.result[id];
				item.appid = app.appid;
				return item;
			}).filter(function(item) {
				return !!item;
			});

			cb(null, items);
		});
	}.bind(this), function(err, result) {
		if(err) {
			callback(err);
			return;
		}

		result.forEach(this._digestDescriptions.bind(this));
		callback();
	}.bind(this));
};
<commit_msg>Request up to 100 descriptions in one request (fixes #58)<commit_after>var TradeOfferManager = require('./index.js');
var Async = require('async');
var EconItem = require('./classes/EconItem.js');

const ITEMS_PER_CLASSINFO_REQUEST = 100;

TradeOfferManager.prototype._digestDescriptions = function(descriptions) {
	var cache = this._assetCache;

	if(!this._language) {
		return;
	}

	if(descriptions && !(descriptions instanceof Array)) {
		descriptions = Object.keys(descriptions).map(function(key) {
			return descriptions[key];
		});
	}

	(descriptions || []).forEach(function(item) {
		if(!item || !item.appid || !item.classid) {
			return;
		}

		cache[item.appid + '_' + item.classid + '_' + (item.instanceid || '0')] = item;
	});
};

TradeOfferManager.prototype._mapItemsToDescriptions = function(appid, contextid, items) {
	var cache = this._assetCache;

	if(!(items instanceof Array)) {
		items = Object.keys(items).map(function(key) {
			return items[key];
		});
	}

	return items.map(function(item) {
		item.appid = appid || item.appid;
		item.contextid = contextid || item.contextid;

		var key = item.appid + '_' + item.classid + '_' + (item.instanceid || '0');
		if(!cache[key]) {
			// This item isn't in our description cache
			return new EconItem(item);
		}

		for(i in cache[key]) {
			item[i] = cache[key][i];
		}

		return new EconItem(item);
	});
};

TradeOfferManager.prototype._hasDescription = function(item, appid) {
	appid = appid || item.appid;
	return !!this._assetCache[appid + '_' + item.classid + '_' + (item.instanceid || '0')];
};

TradeOfferManager.prototype._requestDescriptions = function(classes, callback) {
	var apps = [];
	var appids = [];

	// Split this out into appids
	classes.forEach(function(item) {
		var index = appids.indexOf(item.appid);
		if(index == -1) {
			index = appids.push(item.appid) - 1;
			var arr = [];
			arr.appid = item.appid;
			apps.push(arr);
		}

		// Don't add a class/instanceid pair that we already have in the list
		if(apps[index].indexOf(item.classid + '_' + (item.instanceid || '0')) == -1) {
			apps[index].push(item.classid + '_' + (item.instanceid || '0'));
		}
	});

	Async.map(apps, function(app, cb) {
		var chunks = [];
		var items = [];

		// Split this into chunks of ITEMS_PER_CLASSINFO_REQUEST items
		while(app.length > 0) {
			chunks.push(app.splice(0, ITEMS_PER_CLASSINFO_REQUEST));
		}

		Async.each(chunks, function(chunk, chunkCb) {
			var input = {
				"appid": app.appid,
				"language": this._language,
				"class_count": chunk.length
			};

			chunk.forEach(function(item, index) {
				var parts = item.split('_');
				input['classid' + index] = parts[0];
				input['instanceid' + index] = parts[1];
			});

			this.emit('debug', "Requesting classinfo for " + chunk.length + " items");
			this._apiCall('GET', {"iface": "ISteamEconomy", "method": "GetAssetClassInfo"}, 1, input, function(err, body) {
				if(err) {
					chunkCb(err);
					return;
				}

				if(!body.result || !body.result.success) {
					chunkCb(new Error("Invalid API response"));
					return;
				}

				var chunkItems = Object.keys(body.result).map(function(id) {
					if(!id.match(/^\d+(_\d+)?$/)) {
						return null;
					}

					var item = body.result[id];
					item.appid = app.appid;
					return item;
				}).filter(function(item) {
					return !!item;
				});

				items = items.concat(chunkItems);

				chunkCb(null);
			});
		}.bind(this), function(err) {
			if(err) {
				cb(err);
			} else {
				cb(null, items);
			}
		});
	}.bind(this), function(err, result) {
		if(err) {
			callback(err);
			return;
		}

		result.forEach(this._digestDescriptions.bind(this));
		callback();
	}.bind(this));
};
<|endoftext|>