<commit_before>'use strict'

module.exports = function import_ ($void) {
  var $ = $void.$
  var compile = $.compile
  var $Object = $.object
  var Tuple$ = $void.Tuple
  var Symbol$ = $void.Symbol
  var Object$ = $void.Object
  var warn = $void.$warn
  var execute = $void.execute
  var evaluate = $void.evaluate
  var appendExt = $void.appendExt
  var sharedSymbolOf = $void.sharedSymbolOf
  var staticOperator = $void.staticOperator

  var symbolFrom = sharedSymbolOf('from')
  var symbolImport = sharedSymbolOf('import')

  // import: a module from source.
  //   (import src), or
  //   (import field from module), or
  //   (import (fields ...) from module)
  var operator = staticOperator('import', function (space, clause) {
    var clist = clause.$
    if (clist.length < 2) {
      return null
    }
    if (!space.app) {
      warn('import', 'invalid without an app context.')
      return null
    }
    var src
    if (clist.length < 4 || clist[2] !== symbolFrom) {
      // look into current space to have the base uri.
      src = importModule(space, space.local['-app-home'], space.local['-module'],
        evaluate(clist[1], space)
      )
      // clone to protect inner exports object.
      return Object.assign($Object.empty(), src)
    }
    // (import field-or-fields from src)
    src = evaluate(clist[3], space)
    var imported = src instanceof Object$ ? src
      : typeof src !== 'string' ? null : importModule(
        space, space.local['-app-home'], space.local['-module'], src
      )
    if (typeof imported !== 'object') {
      return null // importing failed.
    }

    // find out fields
    var fields = clist[1]
    if (fields instanceof Symbol$) {
      return imported[fields.key] // import only a single field.
    }
    if (!(fields instanceof Tuple$)) {
      return null // invalid field descriptor
    }

    var i
    var flist = fields.$
    fields = []
    for (i = 0; i < flist.length; i++) {
      if (flist[i] instanceof Symbol$) {
        fields.push(flist[i].key)
      }
    }
    // import fields into an array.
    var values = []
    for (i = 0; i < fields.length; i++) {
      var value = imported[fields[i]]
      values.push(typeof value === 'undefined' ? null : value)
    }
    return values
  })

  function importModule (space, appHome, moduleUri, source) {
    if (typeof source !== 'string') {
      if (source instanceof Symbol$) {
        source = source.key
      } else {
        warn('import', 'invalid module source:', source)
        return null
      }
    }
    var type
    var offset = source.indexOf('$')
    if (offset >= 0) {
      type = source.substring(0, ++offset)
      source = source.substring(offset)
    }
    // try to locate the source in dirs.
    var uri = type ? source // native module
      : resolve(appHome, moduleUri, appendExt(source)) || (
        // try to load native Espresso modules.
        $void.require.resolve && $void.require.resolve(source,
          space.local['-app-dir'], $void.$env('user-home'), $void
        )
      )
    if (!uri) {
      return null
    }
    // look up it in cache.
    var module_ = lookupInCache(space.modules, uri, moduleUri)
    if (module_.status) {
      return module_.exports
    }

    module_.status = 100 // indicate loading
    var exporting = (type ? loadNativeModule : loadModule)(
      space, uri, module_, source, moduleUri
    )
    if (!exporting || exporting === module_.exporting) {
      return module_.exports
    }
    module_.exporting = exporting
    var keys = Object.getOwnPropertyNames(exporting)
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i]
      if (!/^[-_]/.test(key)) {
        // only expose public fields.
        // private fields are allowed to support hot-reloading
        module_.exports[key] = exporting[key]
      }
    }
    return module_.exports
  }

  function resolve (appHome, moduleUri, source) {
    var loader = $void.loader
    var isResolved = loader.isResolved(source)
    if (!moduleUri && isResolved) {
      warn('import', "It's forbidden to import a module from an absolute uri.")
      return null
    }
    var dirs = isResolved ? [] : dirsOf(source,
      moduleUri && loader.dir(moduleUri),
      appHome + '/modules',
      $void.$env('user-home') + '/.es/modules',
      $void.$env('home') + '/modules', // working dir
      $void.runtime('home') + '/modules'
    )
    var uri = loader.resolve(source, dirs)
    if (typeof uri === 'string') {
      return uri
    }
    warn('import', 'failed to resolve', source, 'in', dirs)
    return null
  }

  function dirsOf (source, moduleDir, appDir, userDir, homeDir, runtimeDir) {
    return moduleDir
      ? source.startsWith('./') || source.startsWith('../')
        ? [ moduleDir ]
        : [ runtimeDir, appDir, userDir, homeDir ]
      : [ runtimeDir ] // for dynamic or unknown-source code.
  }

  function lookupInCache (modules, uri, moduleUri) {
    var module = modules[uri]
    if (!module) {
      module = modules[uri] = Object.assign(Object.create(null), {
        status: 0, // loading
        exports: $Object.empty(),
        timestamp: Date.now()
      })
    } else if (module.status === 100) {
      warn('import', 'loop dependency when loading', uri, 'from', moduleUri)
    }
    return module
  }

  function loadModule (space, uri, module_, source, moduleUri) {
    try {
      // try to load file
      var doc = $void.loader.load(uri)
      var text = doc[0]
      if (typeof text !== 'string') {
        module_.status = 415 // unsupported media type
        warn('import', 'failed to read', source, 'for', doc[1])
        return null
      }
      // compile text
      var code = compile(text, uri, doc[1])
      if (!(code instanceof Tuple$)) {
        module_.status = 400 //
        warn('import', 'failed to compile', source, 'for', code)
        return null
      }
      // to load module
      var scope = execute(space, code, uri, {
        this: module_.exporting // TODO: reserved to support hot-reloading
      })[1]
      if (scope) {
        // TODO: register monitoring tasks for hot-reloading.
        module_.status = 200
        return scope.exporting
      }
      module_.status = 500
      warn('import', 'failed when executing', code)
    } catch (signal) {
      module_.status = 503
      warn('import', 'invalid call to', signal.id,
        'in', code, 'at', uri, 'from', moduleUri)
    }
    return null
  }

  function loadNativeModule (space, uri, module_, source, moduleUri) {
    try {
      // the native module must export a loader function.
      var importing = $void.require(uri, moduleUri, $void)
      if (typeof importing !== 'function') {
        module_.status = 400
        warn('import', 'invalid native module', source, 'at', uri)
        return null
      }
      var scope = $void.createModuleSpace(uri, space)
      var status = importing.call(
        module_.exporting, // TODO: reserved to support hot reloading.
        scope.exporting, scope.context, $void
      )
      if (status === true) { // the loader can report error details
        // TODO?: register monitoring tasks for hot-reloading.
        module_.status = 200
        return scope.exporting
      }
      module_.status = 500 // internal error
      warn('import', 'failed to import native module of', source,
        'for', status, 'at', uri)
    } catch (err) {
      module_.status = 503 // service unavailable
      warn('import', 'failed to import native module of', source,
        'for', err, 'at', uri, 'from', moduleUri)
    }
    return null
  }

  $void.bindOperatorImport = function (space) {
    return (space.$import = function (uri) {
      if (!uri || typeof uri !== 'string') {
        warn('$import', 'invalid source uri:', uri)
        return null
      }
      return operator(space, new Tuple$([symbolImport, uri]))
    })
  }
}
<commit_msg>revise to unify resolve logic<commit_after>'use strict'

module.exports = function import_ ($void) {
  var $ = $void.$
  var compile = $.compile
  var $Object = $.object
  var Tuple$ = $void.Tuple
  var Symbol$ = $void.Symbol
  var Object$ = $void.Object
  var warn = $void.$warn
  var execute = $void.execute
  var evaluate = $void.evaluate
  var appendExt = $void.appendExt
  var sharedSymbolOf = $void.sharedSymbolOf
  var staticOperator = $void.staticOperator

  var symbolFrom = sharedSymbolOf('from')
  var symbolImport = sharedSymbolOf('import')

  // import: a module from source.
  //   (import src), or
  //   (import field from module), or
  //   (import (fields ...) from module)
  var operator = staticOperator('import', function (space, clause) {
    var clist = clause.$
    if (clist.length < 2) {
      return null
    }
    if (!space.app) {
      warn('import', 'invalid without an app context.')
      return null
    }
    var src
    if (clist.length < 4 || clist[2] !== symbolFrom) {
      // look into current space to have the base uri.
      src = importModule(space, space.local['-app-home'], space.local['-module'],
        evaluate(clist[1], space)
      )
      // clone to protect inner exports object.
      return Object.assign($Object.empty(), src)
    }
    // (import field-or-fields from src)
    src = evaluate(clist[3], space)
    var imported = src instanceof Object$ ? src
      : typeof src !== 'string' ? null : importModule(
        space, space.local['-app-home'], space.local['-module'], src
      )
    if (typeof imported !== 'object') {
      return null // importing failed.
    }

    // find out fields
    var fields = clist[1]
    if (fields instanceof Symbol$) {
      return imported[fields.key] // import only a single field.
    }
    if (!(fields instanceof Tuple$)) {
      return null // invalid field descriptor
    }

    var i
    var flist = fields.$
    fields = []
    for (i = 0; i < flist.length; i++) {
      if (flist[i] instanceof Symbol$) {
        fields.push(flist[i].key)
      }
    }
    // import fields into an array.
    var values = []
    for (i = 0; i < fields.length; i++) {
      var value = imported[fields[i]]
      values.push(typeof value === 'undefined' ? null : value)
    }
    return values
  })

  function importModule (space, appHome, moduleUri, source) {
    if (typeof source !== 'string') {
      if (source instanceof Symbol$) {
        source = source.key
      } else {
        warn('import', 'invalid module source:', source)
        return null
      }
    }
    var type
    var offset = source.indexOf('$')
    if (offset >= 0) {
      type = source.substring(0, ++offset)
      source = source.substring(offset)
    }
    // try to locate the source in dirs.
    var uri = type ? source // native module
      : resolve(appHome, moduleUri, appendExt(source))
    if (!uri) {
      return null
    }
    // look up it in cache.
    var module_ = lookupInCache(space.modules, uri, moduleUri)
    if (module_.status) {
      return module_.exports
    }

    module_.status = 100 // indicate loading
    var exporting = (type ? loadNativeModule : loadModule)(
      space, uri, module_, source, moduleUri
    )
    if (!exporting || exporting === module_.exporting) {
      return module_.exports
    }
    module_.exporting = exporting
    var keys = Object.getOwnPropertyNames(exporting)
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i]
      if (!/^[-_]/.test(key)) {
        // only expose public fields.
        // private fields are allowed to support hot-reloading
        module_.exports[key] = exporting[key]
      }
    }
    return module_.exports
  }

  function resolve (appHome, moduleUri, source) {
    var loader = $void.loader
    var isResolved = loader.isResolved(source)
    if (!moduleUri && isResolved) {
      warn('import', "It's forbidden to import a module from an absolute uri.")
      return null
    }
    var dirs = isResolved ? [] : dirsOf(source,
      moduleUri && loader.dir(moduleUri),
      appHome + '/modules',
      $void.$env('user-home') + '/.es/modules',
      $void.$env('home') + '/modules', // working dir
      $void.runtime('home') + '/modules'
    )
    var uri = loader.resolve(source, dirs)
    if (typeof uri === 'string') {
      return uri
    }
    // try to load native Espresso modules.
    if ($void.require.resolve) {
      return $void.require.resolve(source,
        space.local['-app-dir'], $void.$env('user-home'), $void
      )
    }
    warn('import', 'failed to resolve', source, 'in', dirs)
    return null
  }

  function dirsOf (source, moduleDir, appDir, userDir, homeDir, runtimeDir) {
    return moduleDir
      ? source.startsWith('./') || source.startsWith('../')
        ? [ moduleDir ]
        : [ runtimeDir, appDir, userDir, homeDir ]
      : [ runtimeDir ] // for dynamic or unknown-source code.
  }

  function lookupInCache (modules, uri, moduleUri) {
    var module = modules[uri]
    if (!module) {
      module = modules[uri] = Object.assign(Object.create(null), {
        status: 0, // loading
        exports: $Object.empty(),
        timestamp: Date.now()
      })
    } else if (module.status === 100) {
      warn('import', 'loop dependency when loading', uri, 'from', moduleUri)
    }
    return module
  }

  function loadModule (space, uri, module_, source, moduleUri) {
    try {
      // try to load file
      var doc = $void.loader.load(uri)
      var text = doc[0]
      if (typeof text !== 'string') {
        module_.status = 415 // unsupported media type
        warn('import', 'failed to read', source, 'for', doc[1])
        return null
      }
      // compile text
      var code = compile(text, uri, doc[1])
      if (!(code instanceof Tuple$)) {
        module_.status = 400 //
        warn('import', 'failed to compile', source, 'for', code)
        return null
      }
      // to load module
      var scope = execute(space, code, uri, {
        this: module_.exporting // TODO: reserved to support hot-reloading
      })[1]
      if (scope) {
        // TODO: register monitoring tasks for hot-reloading.
        module_.status = 200
        return scope.exporting
      }
      module_.status = 500
      warn('import', 'failed when executing', code)
    } catch (signal) {
      module_.status = 503
      warn('import', 'invalid call to', signal.id,
        'in', code, 'at', uri, 'from', moduleUri)
    }
    return null
  }

  function loadNativeModule (space, uri, module_, source, moduleUri) {
    try {
      // the native module must export a loader function.
      var importing = $void.require(uri, moduleUri, $void)
      if (typeof importing !== 'function') {
        module_.status = 400
        warn('import', 'invalid native module', source, 'at', uri)
        return null
      }
      var scope = $void.createModuleSpace(uri, space)
      var status = importing.call(
        module_.exporting, // TODO: reserved to support hot reloading.
        scope.exporting, scope.context, $void
      )
      if (status === true) { // the loader can report error details
        // TODO?: register monitoring tasks for hot-reloading.
        module_.status = 200
        return scope.exporting
      }
      module_.status = 500 // internal error
      warn('import', 'failed to import native module of', source,
        'for', status, 'at', uri)
    } catch (err) {
      module_.status = 503 // service unavailable
      warn('import', 'failed to import native module of', source,
        'for', err, 'at', uri, 'from', moduleUri)
    }
    return null
  }

  $void.bindOperatorImport = function (space) {
    return (space.$import = function (uri) {
      if (!uri || typeof uri !== 'string') {
        warn('$import', 'invalid source uri:', uri)
        return null
      }
      return operator(space, new Tuple$([symbolImport, uri]))
    })
  }
}
<|endoftext|>


<commit_before>
// replicates something like an opengl light.
// Fairly bare-bones for now (only diffuse, no attenuation)
Shade.gl_light = function(opts)
{
    opts = _.defaults(opts || {}, {
        light_ambient: Shade.vec(0,0,0,1),
        light_diffuse: Shade.vec(1,1,1,1),
        two_sided: false,
        per_vertex: false
    });
    function vec3(v) {
        return v.type.equals(Shade.Types.vec4) ? v.swizzle("xyz").div(v.at(3)) : v;
    }
    var light_pos = vec3(opts.light_position);
    var vertex_pos = vec3(opts.vertex);
    var material_color = opts.material_color;
    var light_ambient = opts.light_ambient;
    var light_diffuse = opts.light_diffuse;
    var per_vertex = opts.per_vertex;
    var vertex_normal = (opts.normal.type.equals(Shade.Types.vec4) ?
                         opts.normal.swizzle("xyz") :
                         opts.normal).normalize();

    // this must be appropriately transformed
    var N = vertex_normal;
    var L = light_pos.sub(vertex_pos).normalize();
    var v = Shade.max(Shade.ifelse(opts.two_sided,
                                   L.dot(N).abs(),
                                   L.dot(N)), 0);
    if (per_vertex)
        v = Shade.per_vertex(v);

    return Shade.add(light_ambient.mul(material_color),
                     v.mul(light_diffuse).mul(material_color));
};
<commit_msg>deprecate notice<commit_after>// replicates something like an opengl light.
// Fairly bare-bones for now (only diffuse, no attenuation)
// gl_light is deprecated, functionality is being moved to Shade.Light
Shade.gl_light = function(opts)
{
    opts = _.defaults(opts || {}, {
        light_ambient: Shade.vec(0,0,0,1),
        light_diffuse: Shade.vec(1,1,1,1),
        two_sided: false,
        per_vertex: false
    });
    function vec3(v) {
        return v.type.equals(Shade.Types.vec4) ? v.swizzle("xyz").div(v.at(3)) : v;
    }
    var light_pos = vec3(opts.light_position);
    var vertex_pos = vec3(opts.vertex);
    var material_color = opts.material_color;
    var light_ambient = opts.light_ambient;
    var light_diffuse = opts.light_diffuse;
    var per_vertex = opts.per_vertex;
    var vertex_normal = (opts.normal.type.equals(Shade.Types.vec4) ?
                         opts.normal.swizzle("xyz") :
                         opts.normal).normalize();

    // this must be appropriately transformed
    var N = vertex_normal;
    var L = light_pos.sub(vertex_pos).normalize();
    var v = Shade.max(Shade.ifelse(opts.two_sided,
                                   L.dot(N).abs(),
                                   L.dot(N)), 0);
    if (per_vertex)
        v = Shade.per_vertex(v);

    return Shade.add(light_ambient.mul(material_color),
                     v.mul(light_diffuse).mul(material_color));
};
<|endoftext|>


<commit_before>$("document").ready(function(){

    i18next
     .use(i18nextXHRBackend)
     .init(
     {
        backend: {
          loadPath: window.CRM.root + '/locale/'+window.CRM.locale+'/LC_Messages/messages.js'
        }
     });

    $(".multiSearch").select2({
        minimumInputLength: 2,
        ajax: {
            url: function (params){
              return window.CRM.root + "/api/search/" + params.term;
            },
            dataType: 'json',
            delay: 250,
            data: "",
            processResults: function (data, params) {
              var idKey = 1;
              var results = new Array();
              $.each(data.results, function(key, resultGroupJSONText)
              {
                var rawResultGroup = JSON.parse(resultGroupJSONText);
                var groupName = Object.keys(rawResultGroup)[0];
                var ckeys = rawResultGroup[groupName];
                var resultGroup = {
                  id: key,
                  text: groupName,
                  children: []
                };
                idKey++;
                $.each(ckeys, function(ckey, cvalue)
                {
                  var childObject = {
                    id: idKey,
                    text: cvalue.displayName,
                    uri: cvalue.uri
                  };
                  idKey++;
                  resultGroup.children.push(childObject);
                });
                if(resultGroup.children.length > 0)
                  results.push(resultGroup);
              });
              return {results: results};
            },
            cache: true
        }
    });
    $(".multiSearch").on("select2:select",function (e) { window.location.href= e.params.data.uri;});

    $.ajax({
      url: window.CRM.root + "/api/timerjobs/run",
      type: "POST"
    });
    $(".date-picker").datepicker({format:'yyyy-mm-dd', language: window.CRM.lang});

    $(".initials-image").initial();
    $(".maxUploadSize").text(window.CRM.maxUploadSize);

    $("#emptyCart").click(function (e) {
            $.ajax({
                method: "DELETE",
                url: window.CRM.root + "/api/cart/",
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            }).done(function (data) {
                $('#iconCount').text('0');
            });

    });

});

function showGlobalMessage(message, callOutClass) {
    $("#globalMessageText").text(message);
    $("#globalMessageCallOut").addClass("callout-"+callOutClass);
    $("#globalMessage").show("slow");
}
<commit_msg>Update Footer.js<commit_after>$("document").ready(function(){

    i18next
     .use(i18nextXHRBackend)
     .init(
     {
        backend: {
          loadPath: window.CRM.root + '/locale/'+window.CRM.locale+'/LC_MESSAGES/messages.js'
        }
     });

    $(".multiSearch").select2({
        minimumInputLength: 2,
        ajax: {
            url: function (params){
              return window.CRM.root + "/api/search/" + params.term;
            },
            dataType: 'json',
            delay: 250,
            data: "",
            processResults: function (data, params) {
              var idKey = 1;
              var results = new Array();
              $.each(data.results, function(key, resultGroupJSONText)
              {
                var rawResultGroup = JSON.parse(resultGroupJSONText);
                var groupName = Object.keys(rawResultGroup)[0];
                var ckeys = rawResultGroup[groupName];
                var resultGroup = {
                  id: key,
                  text: groupName,
                  children: []
                };
                idKey++;
                $.each(ckeys, function(ckey, cvalue)
                {
                  var childObject = {
                    id: idKey,
                    text: cvalue.displayName,
                    uri: cvalue.uri
                  };
                  idKey++;
                  resultGroup.children.push(childObject);
                });
                if(resultGroup.children.length > 0)
                  results.push(resultGroup);
              });
              return {results: results};
            },
            cache: true
        }
    });
    $(".multiSearch").on("select2:select",function (e) { window.location.href= e.params.data.uri;});

    $.ajax({
      url: window.CRM.root + "/api/timerjobs/run",
      type: "POST"
    });
    $(".date-picker").datepicker({format:'yyyy-mm-dd', language: window.CRM.lang});

    $(".initials-image").initial();
    $(".maxUploadSize").text(window.CRM.maxUploadSize);

    $("#emptyCart").click(function (e) {
            $.ajax({
                method: "DELETE",
                url: window.CRM.root + "/api/cart/",
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            }).done(function (data) {
                $('#iconCount').text('0');
            });

    });

});

function showGlobalMessage(message, callOutClass) {
    $("#globalMessageText").text(message);
    $("#globalMessageCallOut").addClass("callout-"+callOutClass);
    $("#globalMessage").show("slow");
}
<|endoftext|>


<commit_before>import SocialSharingNetwork from './social-sharing-network';
import BaseNetworks from './networks.json';
import Vue from 'vue';

const inBrowser = typeof window !== 'undefined';
let $window = inBrowser ? window : null;

export function mockWindow (self) {
  $window = self || window; // mock window for unit testing
}

export default {
  props: {
    /**
     * URL to share.
     * @var string
     */
    url: {
      type: String,
      default: inBrowser ? window.location.href : ''
    },

    /**
     * Sharing title, if available by network.
     * @var string
     */
    title: {
      type: String,
      default: ''
    },

    /**
     * Sharing description, if available by network.
     * @var string
     */
    description: {
      type: String,
      default: ''
    },

    /**
     * Facebook quote
     * @var string
     */
    quote: {
      type: String,
      default: ''
    },

    /**
     * Twitter hashtags
     * @var string
     */
    hashtags: {
      type: String,
      default: ''
    },

    /**
     * Twitter user.
     * @var string
     */
    twitterUser: {
      type: String,
      default: ''
    },

    /**
     * Flag that indicates if counts should be retrieved.
     * - NOT WORKING IN CURRENT VERSION
     * @var mixed
     */
    withCounts: {
      type: [String, Boolean],
      default: false
    },

    /**
     * Google plus key.
     * @var string
     */
    googleKey: {
      type: String,
      default: undefined
    },

    /**
     * Pinterest Media URL.
     * Specifies the image/media to be used.
     */
    media: {
      type: String,
      default: ''
    },

    /**
     * Network sub component tag.
     * Default to span tag
     */
    networkTag: {
      type: String,
      default: 'span'
    },

    /**
     * Additional or overridden networks.
     * Default to BaseNetworks
     */
    networks: {
      type: Object,
      default: function () {
        return {};
      }
    }
  },

  data () {
    return {
      /**
       * Available sharing networks.
       * @param object
       */
      baseNetworks: BaseNetworks,

      /**
       * Popup settings.
       * @param object
       */
      popup: {
        status: false,
        resizable: true,
        toolbar: false,
        menubar: false,
        scrollbars: false,
        location: false,
        directories: false,
        width: 626,
        height: 436,
        top: 0,
        left: 0,
        window: undefined,
        interval: null
      }
    };
  },

  methods: {
    /**
     * Returns generated sharer url.
     *
     * @param network Social network key.
     */
    createSharingUrl (network) {
      const ua = navigator.userAgent.toLowerCase();

      /**
       * On IOS, SMS sharing link need a special formating
       * Source: https://weblog.west-wind.com/posts/2013/Oct/09/Prefilling-an-SMS-on-Mobile-Devices-with-the-sms-Uri-Scheme#Body-only
        */
      if (network === 'sms' && (ua.indexOf('iphone') > -1 || ua.indexOf('ipad') > -1)) {
        network += '_ios';
      }

      const url = this.baseNetworks[network].sharer;

      /**
       * On IOS, Twitter sharing shouldn't include a hashtag parameter if the hashtag value is empty
       * Source: https://github.com/nicolasbeauvais/vue-social-sharing/issues/143
        */
      if (network === 'twitter' && this.hashtags.length === 0) {
        url.replace('&hashtags=@hashtags', '');
      }

      return url
        .replace(/@url/g, encodeURIComponent(this.url))
        .replace(/@title/g, encodeURIComponent(this.title))
        .replace(/@description/g, encodeURIComponent(this.description))
        .replace(/@quote/g, encodeURIComponent(this.quote))
        .replace(/@hashtags/g, this.generateHashtags(network, this.hashtags))
        .replace(/@media/g, this.media)
        .replace(/@twitteruser/g, this.twitterUser ? '&via=' + this.twitterUser : '');
    },
    /**
     * Encode hashtags for the specified social network.
     *
     * @param  network Social network key
     * @param  hashtags All hashtags specified
     */
    generateHashtags (network, hashtags) {
      if (network === 'facebook' && hashtags.length > 0) {
        return '%23' + hashtags.split(',')[0];
      }

      return hashtags;
    },
    /**
     * Shares URL in specified network.
     *
     * @param network Social network key.
     */
    share (network) {
      this.openSharer(network, this.createSharingUrl(network));

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    },

    /**
     * Touches network and emits click event.
     *
     * @param network Social network key.
     */
    touch (network) {
      window.open(this.createSharingUrl(network), '_self');

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    },

    /**
     * Opens sharer popup.
     *
     * @param network Social network key
     * @param url Url to share.
     */
    openSharer (network, url) {
      // If a popup window already exist it will be replaced, trigger a close event.
      let popupWindow = null;
      if (popupWindow && this.popup.interval) {
        clearInterval(this.popup.interval);

        popupWindow.close();// Force close (for Facebook)

        this.$root.$emit('social_shares_change', network, this.url);
        this.$emit('change', network, this.url);
      }

      popupWindow = window.open(
        url,
        'sharer',
        'status=' + (this.popup.status ? 'yes' : 'no') +
        ',height=' + this.popup.height +
        ',width=' + this.popup.width +
        ',resizable=' + (this.popup.resizable ? 'yes' : 'no') +
        ',left=' + this.popup.left +
        ',top=' + this.popup.top +
        ',screenX=' + this.popup.left +
        ',screenY=' + this.popup.top +
        ',toolbar=' + (this.popup.toolbar ? 'yes' : 'no') +
        ',menubar=' + (this.popup.menubar ? 'yes' : 'no') +
        ',scrollbars=' + (this.popup.scrollbars ? 'yes' : 'no') +
        ',location=' + (this.popup.location ? 'yes' : 'no') +
        ',directories=' + (this.popup.directories ? 'yes' : 'no')
      );

      popupWindow.focus();

      // Create an interval to detect popup closing event
      this.popup.interval = setInterval(() => {
        if (popupWindow.closed) {
          clearInterval(this.popup.interval);

          popupWindow = undefined;

          this.$root.$emit('social_shares_close', network, this.url);
          this.$emit('close', network, this.url);
        }
      }, 500);
    }
  },

  /**
   * Merge base networks list with user's list
   */
  beforeMount () {
    this.baseNetworks = Vue.util.extend(this.baseNetworks, this.networks);
  },

  /**
   * Sets popup default dimensions.
   */
  mounted () {
    if (!inBrowser) {
      return;
    }

    /**
     * Center the popup on dual screens
     * http://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen/32261263
     */
    const dualScreenLeft = $window.screenLeft !== undefined ? $window.screenLeft : screen.left;
    const dualScreenTop = $window.screenTop !== undefined ? $window.screenTop : screen.top;

    const width = $window.innerWidth ? $window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width);
    const height = $window.innerHeight ? $window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height);

    this.popup.left = ((width / 2) - (this.popup.width / 2)) + dualScreenLeft;
    this.popup.top = ((height / 2) - (this.popup.height / 2)) + dualScreenTop;
  },

  /**
   * Set component aliases for buttons and links.
   */
  components: {
    'network': SocialSharingNetwork
  }
};
<commit_msg>Fix unsolved #143<commit_after>import SocialSharingNetwork from './social-sharing-network';
import BaseNetworks from './networks.json';
import Vue from 'vue';

const inBrowser = typeof window !== 'undefined';
let $window = inBrowser ? window : null;

export function mockWindow (self) {
  $window = self || window; // mock window for unit testing
}

export default {
  props: {
    /**
     * URL to share.
     * @var string
     */
    url: {
      type: String,
      default: inBrowser ? window.location.href : ''
    },

    /**
     * Sharing title, if available by network.
     * @var string
     */
    title: {
      type: String,
      default: ''
    },

    /**
     * Sharing description, if available by network.
     * @var string
     */
    description: {
      type: String,
      default: ''
    },

    /**
     * Facebook quote
     * @var string
     */
    quote: {
      type: String,
      default: ''
    },

    /**
     * Twitter hashtags
     * @var string
     */
    hashtags: {
      type: String,
      default: ''
    },

    /**
     * Twitter user.
     * @var string
     */
    twitterUser: {
      type: String,
      default: ''
    },

    /**
     * Flag that indicates if counts should be retrieved.
     * - NOT WORKING IN CURRENT VERSION
     * @var mixed
     */
    withCounts: {
      type: [String, Boolean],
      default: false
    },

    /**
     * Google plus key.
     * @var string
     */
    googleKey: {
      type: String,
      default: undefined
    },

    /**
     * Pinterest Media URL.
     * Specifies the image/media to be used.
     */
    media: {
      type: String,
      default: ''
    },

    /**
     * Network sub component tag.
     * Default to span tag
     */
    networkTag: {
      type: String,
      default: 'span'
    },

    /**
     * Additional or overridden networks.
     * Default to BaseNetworks
     */
    networks: {
      type: Object,
      default: function () {
        return {};
      }
    }
  },

  data () {
    return {
      /**
       * Available sharing networks.
       * @param object
       */
      baseNetworks: BaseNetworks,

      /**
       * Popup settings.
       * @param object
       */
      popup: {
        status: false,
        resizable: true,
        toolbar: false,
        menubar: false,
        scrollbars: false,
        location: false,
        directories: false,
        width: 626,
        height: 436,
        top: 0,
        left: 0,
        window: undefined,
        interval: null
      }
    };
  },

  methods: {
    /**
     * Returns generated sharer url.
     *
     * @param network Social network key.
     */
    createSharingUrl (network) {
      const ua = navigator.userAgent.toLowerCase();

      /**
       * On IOS, SMS sharing link need a special formating
       * Source: https://weblog.west-wind.com/posts/2013/Oct/09/Prefilling-an-SMS-on-Mobile-Devices-with-the-sms-Uri-Scheme#Body-only
        */
      if (network === 'sms' && (ua.indexOf('iphone') > -1 || ua.indexOf('ipad') > -1)) {
        network += '_ios';
      }

      let url = this.baseNetworks[network].sharer;

      /**
       * On IOS, Twitter sharing shouldn't include a hashtag parameter if the hashtag value is empty
       * Source: https://github.com/nicolasbeauvais/vue-social-sharing/issues/143
        */
      if (network === 'twitter' && this.hashtags.length === 0) {
        url = url.replace('&hashtags=@hashtags', '');
      }

      return url
        .replace(/@url/g, encodeURIComponent(this.url))
        .replace(/@title/g, encodeURIComponent(this.title))
        .replace(/@description/g, encodeURIComponent(this.description))
        .replace(/@quote/g, encodeURIComponent(this.quote))
        .replace(/@hashtags/g, this.generateHashtags(network, this.hashtags))
        .replace(/@media/g, this.media)
        .replace(/@twitteruser/g, this.twitterUser ? '&via=' + this.twitterUser : '');
    },
    /**
     * Encode hashtags for the specified social network.
     *
     * @param  network Social network key
     * @param  hashtags All hashtags specified
     */
    generateHashtags (network, hashtags) {
      if (network === 'facebook' && hashtags.length > 0) {
        return '%23' + hashtags.split(',')[0];
      }

      return hashtags;
    },
    /**
     * Shares URL in specified network.
     *
     * @param network Social network key.
     */
    share (network) {
      this.openSharer(network, this.createSharingUrl(network));

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    },

    /**
     * Touches network and emits click event.
     *
     * @param network Social network key.
     */
    touch (network) {
      window.open(this.createSharingUrl(network), '_self');

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    },

    /**
     * Opens sharer popup.
     *
     * @param network Social network key
     * @param url Url to share.
     */
    openSharer (network, url) {
      // If a popup window already exist it will be replaced, trigger a close event.
      let popupWindow = null;
      if (popupWindow && this.popup.interval) {
        clearInterval(this.popup.interval);

        popupWindow.close();// Force close (for Facebook)

        this.$root.$emit('social_shares_change', network, this.url);
        this.$emit('change', network, this.url);
      }

      popupWindow = window.open(
        url,
        'sharer',
        'status=' + (this.popup.status ? 'yes' : 'no') +
        ',height=' + this.popup.height +
        ',width=' + this.popup.width +
        ',resizable=' + (this.popup.resizable ? 'yes' : 'no') +
        ',left=' + this.popup.left +
        ',top=' + this.popup.top +
        ',screenX=' + this.popup.left +
        ',screenY=' + this.popup.top +
        ',toolbar=' + (this.popup.toolbar ? 'yes' : 'no') +
        ',menubar=' + (this.popup.menubar ? 'yes' : 'no') +
        ',scrollbars=' + (this.popup.scrollbars ? 'yes' : 'no') +
        ',location=' + (this.popup.location ? 'yes' : 'no') +
        ',directories=' + (this.popup.directories ? 'yes' : 'no')
      );

      popupWindow.focus();

      // Create an interval to detect popup closing event
      this.popup.interval = setInterval(() => {
        if (popupWindow.closed) {
          clearInterval(this.popup.interval);

          popupWindow = undefined;

          this.$root.$emit('social_shares_close', network, this.url);
          this.$emit('close', network, this.url);
        }
      }, 500);
    }
  },

  /**
   * Merge base networks list with user's list
   */
  beforeMount () {
    this.baseNetworks = Vue.util.extend(this.baseNetworks, this.networks);
  },

  /**
   * Sets popup default dimensions.
   */
  mounted () {
    if (!inBrowser) {
      return;
    }

    /**
     * Center the popup on dual screens
     * http://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen/32261263
     */
    const dualScreenLeft = $window.screenLeft !== undefined ? $window.screenLeft : screen.left;
    const dualScreenTop = $window.screenTop !== undefined ? $window.screenTop : screen.top;

    const width = $window.innerWidth ? $window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width);
    const height = $window.innerHeight ? $window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height);

    this.popup.left = ((width / 2) - (this.popup.width / 2)) + dualScreenLeft;
    this.popup.top = ((height / 2) - (this.popup.height / 2)) + dualScreenTop;
  },

  /**
   * Set component aliases for buttons and links.
   */
  components: {
    'network': SocialSharingNetwork
  }
};
<|endoftext|>


<commit_before>(function(Sparky) {
	"use strict";

	function isAudioParam(object) {
		return window.AudioParam && window.AudioParam.prototype.isPrototypeOf(object);
	}

	function Poll(object, property, fn) {
		var v1 = object[property];
		var active = true;

		function frame() {
			var v2 = object[property];

			if (v1 !== v2) {
				v1 = v2;
				fn();
			}

			if (!active) { return; }

			window.requestAnimationFrame(frame);
		};

		function cancel() {
			active = false;
		}

		window.requestAnimationFrame(frame);

		return cancel;
	}

	var unpollers = [];

	function poll(object, property, fn) {
		unpollers.push([object, property, fn, Poll(object, property, fn)]);
		return object;
	}

	function unpoll(object, property, fn) {
		var n = unpollers.length;
		var unpoller;

		while (n--) {
			unpoller = unpollers[n];

			if (object === unpoller[0] && property === unpoller[1] && fn === unpoller[2]) {
				unpoller[3]();
				unpollers.splice(n, 1);
				return object;
			}
		}

		return object;
	}

	Sparky.observe = function(object, property, fn) {
		// AudioParams objects must be polled, as they cannot be reconfigured
		// to getters/setters, nor can they be Object.observed. And they fail
		// to do both of those completely silently. So we test the scope to see
		// if it is an AudioParam and set the observe and unobserve functions
		// to poll.
		if (isAudioParam(object)) {
			return poll(object, property, fn);
		}

		if (property === 'length') {
			// Observe length and update the DOM on next
			// animation frame if it changes.
			var descriptor = Object.getOwnPropertyDescriptor(object, property);

			if (!descriptor.get && !descriptor.configurable) {
				console.warn('[Sparky] Are you trying to observe an array?. Sparky is going to observe it by polling. You may want to use a Sparky.Collection() to avoid this.');
				return poll(object, property, fn);
			}
		}

		return observe(object, property, fn);
	};

	Sparky.unobserve = function(object, property, fn) {
		if (isAudioParam(object)) {
			return unpoll(object, property, fn);
		}

		if (property === 'length') {
			var descriptor = Object.getOwnPropertyDescriptor(object, property);
			if (!descriptor.get && !descriptor.configurable) {
				return unpoll(object, property, fn);
			}
		}

		return unobserve(object, property, fn);
	};
})(Sparky);<commit_msg>array log<commit_after>(function(Sparky) {
	"use strict";

	function isAudioParam(object) {
		return window.AudioParam && window.AudioParam.prototype.isPrototypeOf(object);
	}

	function Poll(object, property, fn) {
		var v1 = object[property];
		var active = true;

		function frame() {
			var v2 = object[property];

			if (v1 !== v2) {
				v1 = v2;
				fn();
			}

			if (!active) { return; }

			window.requestAnimationFrame(frame);
		};

		function cancel() {
			active = false;
		}

		window.requestAnimationFrame(frame);

		return cancel;
	}

	var unpollers = [];

	function poll(object, property, fn) {
		unpollers.push([object, property, fn, Poll(object, property, fn)]);
		return object;
	}

	function unpoll(object, property, fn) {
		var n = unpollers.length;
		var unpoller;

		while (n--) {
			unpoller = unpollers[n];

			if (object === unpoller[0] && property === unpoller[1] && fn === unpoller[2]) {
				unpoller[3]();
				unpollers.splice(n, 1);
				return object;
			}
		}

		return object;
	}

	Sparky.observe = function(object, property, fn) {
		// AudioParams objects must be polled, as they cannot be reconfigured
		// to getters/setters, nor can they be Object.observed. And they fail
		// to do both of those completely silently. So we test the scope to see
		// if it is an AudioParam and set the observe and unobserve functions
		// to poll.
		if (isAudioParam(object)) {
			return poll(object, property, fn);
		}

		if (property === 'length') {
			// Observe length and update the DOM on next
			// animation frame if it changes.
			var descriptor = Object.getOwnPropertyDescriptor(object, property);

			if (!descriptor.get && !descriptor.configurable) {
				console.warn('[Sparky] "' + property + '" - are you trying to observe an array?. Sparky is going to observe it by polling. You may want to use a Sparky.Collection() to avoid this.', object);
				return poll(object, property, fn);
			}
		}

		return observe(object, property, fn);
	};

	Sparky.unobserve = function(object, property, fn) {
		if (isAudioParam(object)) {
			return unpoll(object, property, fn);
		}

		if (property === 'length') {
			var descriptor = Object.getOwnPropertyDescriptor(object, property);
			if (!descriptor.get && !descriptor.configurable) {
				return unpoll(object, property, fn);
			}
		}

		return unobserve(object, property, fn);
	};
})(Sparky);<|endoftext|>


<commit_before>var React = require('../react');
var log = require('../logger');
var _ = require('../utils/mindash');
var uuid = require('../utils/uuid');
var StoreObserver = require('../storeObserver');
var getFetchResult = require('./getFetchResult');
var getClassName = require("../utils/getClassName");

function createContainer(InnerComponent, config) {
  config = config || {};

  if (!InnerComponent) {
    throw new Error('Must specify an inner component');
  }

  var observer;
  var id = uuid.type('Component');
  var innerComponentDisplayName = InnerComponent.displayName || getClassName(InnerComponent);

  var Container = React.createClass({
    contextTypes: {
      marty: React.PropTypes.object
    },
    componentDidMount() {
      var component = {
        id: id,
        displayName: innerComponentDisplayName
      };

      observer = new StoreObserver({
        component: component,
        onStoreChanged: this.onStoreChanged,
        stores: getStoresToListenTo(config, component)
      });
    },
    onStoreChanged() {
      this.setState(this.getState());
    },
    componentWillUnmount() {
      if (observer) {
        observer.dispose();
      }
    },
    getInitialState() {
      config = _.defaults(config, {
        // Have a default implementation of done so it can be
        // called from other handlers
        done: (results) => {
          return <InnerComponent {...this.props} {...results} />;
        }
      });

      return this.getState();
    },
    getState() {
      // Make the context available so you can call `.for(this)` within the handlers
      config.context = this.context.marty;

      // Make props available so you can pass them to the children
      config.props = this.props;

      return {
        result: getFetchResult(config)
      };
    },
    render() {
      return this.state.result.when({
        done(results) {
          if (_.isFunction(config.done)) {
            return config.done.call(config, results);
          }

          throw new Error('The `done` handler must be a function');
        },
        pending() {
          if (_.isFunction(config.pending)) {
            return config.pending.call(config);
          }

          return

;
        },
        failed(error) {
          if (_.isFunction(config.failed)) {
            return config.failed.call(config, error);
          }

          throw error;
        }
      });
    }
  });

  Container.InnerComponent = InnerComponent;
  Container.displayName = innerComponentDisplayName + 'Container';

  return Container;
}

module.exports = createContainer;

function getStoresToListenTo(config, component) {
  var stores = config.listenTo;

  if (!stores) {
    return [];
  }

  if (!_.isArray(stores)) {
    stores = [stores];
  }

  return _.filter(stores, function (store) {
    var isStore = store.constructor.type === 'Store';

    if (!isStore) {
      log.warn(
        'Warning: Trying to listen to something that isn\'t a store',
        store,
        component.displayName
      );
    }

    return isStore;
  });
}
<commit_msg>Fixed quotes.<commit_after>var React = require('../react');
var log = require('../logger');
var _ = require('../utils/mindash');
var uuid = require('../utils/uuid');
var StoreObserver = require('../storeObserver');
var getFetchResult = require('./getFetchResult');
var getClassName = require('../utils/getClassName');

function createContainer(InnerComponent, config) {
  config = config || {};

  if (!InnerComponent) {
    throw new Error('Must specify an inner component');
  }

  var observer;
  var id = uuid.type('Component');
  var innerComponentDisplayName = InnerComponent.displayName || getClassName(InnerComponent);

  var Container = React.createClass({
    contextTypes: {
      marty: React.PropTypes.object
    },
    componentDidMount() {
      var component = {
        id: id,
        displayName: innerComponentDisplayName
      };

      observer = new StoreObserver({
        component: component,
        onStoreChanged: this.onStoreChanged,
        stores: getStoresToListenTo(config, component)
      });
    },
    onStoreChanged() {
      this.setState(this.getState());
    },
    componentWillUnmount() {
      if (observer) {
        observer.dispose();
      }
    },
    getInitialState() {
      config = _.defaults(config, {
        // Have a default implementation of done so it can be
        // called from other handlers
        done: (results) => {
          return <InnerComponent {...this.props} {...results} />;
        }
      });

      return this.getState();
    },
    getState() {
      // Make the context available so you can call `.for(this)` within the handlers
      config.context = this.context.marty;

      // Make props available so you can pass them to the children
      config.props = this.props;

      return {
        result: getFetchResult(config)
      };
    },
    render() {
      return this.state.result.when({
        done(results) {
          if (_.isFunction(config.done)) {
            return config.done.call(config, results);
          }

          throw new Error('The `done` handler must be a function');
        },
        pending() {
          if (_.isFunction(config.pending)) {
            return config.pending.call(config);
          }

          return

;
        },
        failed(error) {
          if (_.isFunction(config.failed)) {
            return config.failed.call(config, error);
          }

          throw error;
        }
      });
    }
  });

  Container.InnerComponent = InnerComponent;
  Container.displayName = innerComponentDisplayName + 'Container';

  return Container;
}

module.exports = createContainer;

function getStoresToListenTo(config, component) {
  var stores = config.listenTo;

  if (!stores) {
    return [];
  }

  if (!_.isArray(stores)) {
    stores = [stores];
  }

  return _.filter(stores, function (store) {
    var isStore = store.constructor.type === 'Store';

    if (!isStore) {
      log.warn(
        'Warning: Trying to listen to something that isn\'t a store',
        store,
        component.displayName
      );
    }

    return isStore;
  });
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

var _ = require('underscore');

var capitalize = require('underscore.string/capitalize');
var decapitalize = require('underscore.string/decapitalize');

var Server = require('./server.js');

var stream = require('stream');

var Readable = stream.Readable;
var Writable = stream.Writable;
var Duplex = stream.Duplex;
var util = require('util');

var common = require('./common.js');

util.inherits(ServerReadableObjectStream, Readable);

/**
 * Class for representing a gRPC client streaming call as a Node stream on the
 * server side. Extends from stream.Readable.
 * @constructor
 * @param {stream} stream Underlying binary Duplex stream for the call
 */
function ServerReadableObjectStream(stream) {
  var options = {objectMode: true};
  Readable.call(this, options);
  this._stream = stream;
  Object.defineProperty(this, 'cancelled', {
    get: function() { return stream.cancelled; }
  });
  var self = this;
  this._stream.on('cancelled', function() {
    self.emit('cancelled');
  });
  this._stream.on('data', function forwardData(chunk) {
    if (!self.push(chunk)) {
      self._stream.pause();
    }
  });
  this._stream.on('end', function forwardEnd() {
    self.push(null);
  });
  this._stream.pause();
}

/**
 * _read implementation for both types of streams that allow reading.
 * @this {ServerReadableObjectStream|ServerBidiObjectStream}
 * @param {number} size Ignored
 */
function _read(size) {
  this._stream.resume();
}

/**
 * See docs for _read
 */
ServerReadableObjectStream.prototype._read = _read;

util.inherits(ServerWritableObjectStream, Writable);

/**
 * Class for representing a gRPC server streaming call as a Node stream on the
 * server side. Extends from stream.Writable.
 * @constructor
 * @param {stream} stream Underlying binary Duplex stream for the call
 */
function ServerWritableObjectStream(stream) {
  var options = {objectMode: true};
  Writable.call(this, options);
  this._stream = stream;
  this._stream.on('cancelled', function() {
    self.emit('cancelled');
  });
  this.on('finish', function() {
    this._stream.end();
  });
}

/**
 * _write implementation for both types of streams that allow writing
 * @this {ServerWritableObjectStream}
 * @param {*} chunk The value to write to the stream
 * @param {string} encoding Ignored
 * @param {function(Error)} callback Callback to call when finished writing
 */
function _write(chunk, encoding, callback) {
  this._stream.write(chunk, encoding, callback);
}

/**
 * See docs for _write
 */
ServerWritableObjectStream.prototype._write = _write;

/**
 * Creates a binary stream handler function from a unary handler function
 * @param {function(Object, function(Error, *))} handler Unary call handler
 * @return {function(stream)} Binary stream handler
 */
function makeUnaryHandler(handler) {
  /**
   * Handles a stream by reading a single data value, passing it to the handler,
   * and writing the response back to the stream.
   * @param {stream} stream Binary data stream
   */
  return function handleUnaryCall(stream) {
    stream.on('data', function handleUnaryData(value) {
      var call = {request: value};
      Object.defineProperty(call, 'cancelled', {
        get: function() { return stream.cancelled;}
      });
      stream.on('cancelled', function() {
        call.emit('cancelled');
      });
      handler(call, function sendUnaryData(err, value) {
        if (err) {
          stream.emit('error', err);
        } else {
          stream.write(value);
          stream.end();
        }
      });
    });
  };
}

/**
 * Creates a binary stream handler function from a client stream handler
 * function
 * @param {function(Readable, function(Error, *))} handler Client stream call
 *     handler
 * @return {function(stream)} Binary stream handler
 */
function makeClientStreamHandler(handler) {
  /**
   * Handles a stream by passing a deserializing stream to the handler and
   * writing the response back to the stream.
   * @param {stream} stream Binary data stream
   */
  return function handleClientStreamCall(stream) {
    var object_stream = new ServerReadableObjectStream(stream);
    handler(object_stream, function sendClientStreamData(err, value) {
        if (err) {
          stream.emit('error', err);
        } else {
          stream.write(value);
          stream.end();
        }
    });
  };
}

/**
 * Creates a binary stream handler function from a server stream handler
 * function
 * @param {function(Writable)} handler Server stream call handler
 * @return {function(stream)} Binary stream handler
 */
function makeServerStreamHandler(handler) {
  /**
   * Handles a stream by attaching it to a serializing stream, and passing it to
   * the handler.
   * @param {stream} stream Binary data stream
   */
  return function handleServerStreamCall(stream) {
    stream.on('data', function handleClientData(value) {
      var object_stream = new ServerWritableObjectStream(stream);
      object_stream.request = value;
      handler(object_stream);
    });
  };
}

/**
 * Creates a binary stream handler function from a bidi stream handler function
 * @param {function(Duplex)} handler Unary call handler
 * @return {function(stream)} Binary stream handler
 */
function makeBidiStreamHandler(handler) {
  return handler;
}

/**
 * Map with short names for each of the handler maker functions. Used in
 * makeServerConstructor
 */
var handler_makers = {
  unary: makeUnaryHandler,
  server_stream: makeServerStreamHandler,
  client_stream: makeClientStreamHandler,
  bidi: makeBidiStreamHandler
};

/**
 * Creates a constructor for servers with a service defined by the methods
 * object. The methods object has string keys and values of this form:
 * {serialize: function, deserialize: function, client_stream: bool,
 *  server_stream: bool}
 * @param {Object} methods Method descriptor for each method the server should
 *     expose
 * @param {string} prefix The prefex to prepend to each method name
 * @return {function(Object, Object)} New server constructor
 */
function makeServerConstructor(services) {
  var qual_names = [];
  _.each(services, function(service) {
    _.each(service.children, function(method) {
      var name = common.fullyQualifiedName(method);
      if (_.indexOf(qual_names, name) !== -1) {
        throw new Error('Method ' + name + ' exposed by more than one service');
      }
      qual_names.push(name);
    });
  });
  /**
   * Create a server with the given handlers for all of the methods.
   * @constructor
   * @param {Object} service_handlers Map from service names to map from method
   *     names to handlers
   * @param {Object} options Options to pass to the underlying server
   */
  function SurfaceServer(service_handlers, options) {
    var server = new Server(options);
    this.inner_server = server;
    _.each(services, function(service) {
      var service_name = common.fullyQualifiedName(service);
      if (service_handlers[service_name] === undefined) {
        throw new Error('Handlers for service ' +
            service_name + ' not provided.');
      }
      var prefix = '/' + common.fullyQualifiedName(service) + '/';
      _.each(service.children, function(method) {
        var method_type;
        if (method.requestStream) {
          if (method.responseStream) {
            method_type = 'bidi';
          } else {
            method_type = 'client_stream';
          }
        } else {
          if (method.responseStream) {
            method_type = 'server_stream';
          } else {
            method_type = 'unary';
          }
        }
        if (service_handlers[service_name][decapitalize(method.name)] ===
            undefined) {
          throw new Error('Method handler for ' +
              common.fullyQualifiedName(method) + ' not provided.');
        }
        var binary_handler = handler_makers[method_type](
            service_handlers[service_name][decapitalize(method.name)]);
        var serialize = common.serializeCls(
            method.resolvedResponseType.build());
        var deserialize = common.deserializeCls(
            method.resolvedRequestType.build());
        server.register(prefix + capitalize(method.name), binary_handler,
                        serialize, deserialize);
      });
    }, this);
  }

  /**
   * Binds the server to the given port, with SSL enabled if secure is specified
   * @param {string} port The port that the server should bind on, in the format
   *     "address:port"
   * @param {boolean=} secure Whether the server should open a secure port
   * @return {SurfaceServer} this
   */
  SurfaceServer.prototype.bind = function(port, secure) {
    return this.inner_server.bind(port, secure);
  };

  /**
   * Starts the server listening on any bound ports
   * @return {SurfaceServer} this
   */
  SurfaceServer.prototype.listen = function() {
    this.inner_server.start();
    return this;
  };

  /**
   * Shuts the server down; tells it to stop listening for new requests and to
   * kill old requests.
   */
  SurfaceServer.prototype.shutdown = function() {
    this.inner_server.shutdown();
  };

  return SurfaceServer;
}

/**
 * See documentation for makeServerConstructor
 */
exports.makeServerConstructor = makeServerConstructor;
<commit_msg>Added metadata pass-through to server method handlers<commit_after>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

var _ = require('underscore');

var capitalize = require('underscore.string/capitalize');
var decapitalize = require('underscore.string/decapitalize');

var Server = require('./server.js');

var stream = require('stream');

var Readable = stream.Readable;
var Writable = stream.Writable;
var Duplex = stream.Duplex;
var util = require('util');

var common = require('./common.js');

util.inherits(ServerReadableObjectStream, Readable);

/**
 * Class for representing a gRPC client streaming call as a Node stream on the
 * server side. Extends from stream.Readable.
 * @constructor
 * @param {stream} stream Underlying binary Duplex stream for the call
 */
function ServerReadableObjectStream(stream) {
  var options = {objectMode: true};
  Readable.call(this, options);
  this._stream = stream;
  Object.defineProperty(this, 'cancelled', {
    get: function() { return stream.cancelled; }
  });
  var self = this;
  this._stream.on('cancelled', function() {
    self.emit('cancelled');
  });
  this._stream.on('data', function forwardData(chunk) {
    if (!self.push(chunk)) {
      self._stream.pause();
    }
  });
  this._stream.on('end', function forwardEnd() {
    self.push(null);
  });
  this._stream.pause();
}

/**
 * _read implementation for both types of streams that allow reading.
 * @this {ServerReadableObjectStream|ServerBidiObjectStream}
 * @param {number} size Ignored
 */
function _read(size) {
  this._stream.resume();
}

/**
 * See docs for _read
 */
ServerReadableObjectStream.prototype._read = _read;

util.inherits(ServerWritableObjectStream, Writable);

/**
 * Class for representing a gRPC server streaming call as a Node stream on the
 * server side. Extends from stream.Writable.
 * @constructor
 * @param {stream} stream Underlying binary Duplex stream for the call
 */
function ServerWritableObjectStream(stream) {
  var options = {objectMode: true};
  Writable.call(this, options);
  this._stream = stream;
  this._stream.on('cancelled', function() {
    self.emit('cancelled');
  });
  this.on('finish', function() {
    this._stream.end();
  });
}

/**
 * _write implementation for both types of streams that allow writing
 * @this {ServerWritableObjectStream}
 * @param {*} chunk The value to write to the stream
 * @param {string} encoding Ignored
 * @param {function(Error)} callback Callback to call when finished writing
 */
function _write(chunk, encoding, callback) {
  this._stream.write(chunk, encoding, callback);
}

/**
 * See docs for _write
 */
ServerWritableObjectStream.prototype._write = _write;

/**
 * Creates a binary stream handler function from a unary handler function
 * @param {function(Object, function(Error, *), metadata=)} handler Unary call
 *     handler
 * @return {function(stream, metadata=)} Binary stream handler
 */
function makeUnaryHandler(handler) {
  /**
   * Handles a stream by reading a single data value, passing it to the handler,
   * and writing the response back to the stream.
   * @param {stream} stream Binary data stream
   * @param {metadata=} metadata Incoming metadata array
   */
  return function handleUnaryCall(stream, metadata) {
    stream.on('data', function handleUnaryData(value) {
      var call = {request: value};
      Object.defineProperty(call, 'cancelled', {
        get: function() { return stream.cancelled;}
      });
      stream.on('cancelled', function() {
        call.emit('cancelled');
      });
      handler(call, function sendUnaryData(err, value) {
        if (err) {
          stream.emit('error', err);
        } else {
          stream.write(value);
          stream.end();
        }
      }, metadata);
    });
  };
}

/**
 * Creates a binary stream handler function from a client stream handler
 * function
 * @param {function(Readable, function(Error, *), metadata=)} handler Client
 *     stream call handler
 * @return {function(stream, metadata=)} Binary stream handler
 */
function makeClientStreamHandler(handler) {
  /**
   * Handles a stream by passing a deserializing stream to the handler and
   * writing the response back to the stream.
   * @param {stream} stream Binary data stream
   * @param {metadata=} metadata Incoming metadata array
   */
  return function handleClientStreamCall(stream, metadata) {
    var object_stream = new ServerReadableObjectStream(stream);
    handler(object_stream, function sendClientStreamData(err, value) {
        if (err) {
          stream.emit('error', err);
        } else {
          stream.write(value);
          stream.end();
        }
    }, metadata);
  };
}

/**
 * Creates a binary stream handler function from a server stream handler
 * function
 * @param {function(Writable, metadata=)} handler Server stream call handler
 * @return {function(stream, metadata=)} Binary stream handler
 */
function makeServerStreamHandler(handler) {
  /**
   * Handles a stream by attaching it to a serializing stream, and passing it to
   * the handler.
   * @param {stream} stream Binary data stream
   * @param {metadata=} metadata Incoming metadata array
   */
  return function handleServerStreamCall(stream, metadata) {
    stream.on('data', function handleClientData(value) {
      var object_stream = new ServerWritableObjectStream(stream);
      object_stream.request = value;
      handler(object_stream, metadata);
    });
  };
}

/**
 * Creates a binary stream handler function from a bidi stream handler function
 * @param {function(Duplex, metadata=)} handler Unary call handler
 * @return {function(stream, metadata=)} Binary stream handler
 */
function makeBidiStreamHandler(handler) {
  return handler;
}

/**
 * Map with short names for each of the handler maker functions. Used in
 * makeServerConstructor
 */
var handler_makers = {
  unary: makeUnaryHandler,
  server_stream: makeServerStreamHandler,
  client_stream: makeClientStreamHandler,
  bidi: makeBidiStreamHandler
};

/**
 * Creates a constructor for servers with a service defined by the methods
 * object. The methods object has string keys and values of this form:
 * {serialize: function, deserialize: function, client_stream: bool,
 *  server_stream: bool}
 * @param {Object} methods Method descriptor for each method the server should
 *     expose
 * @param {string} prefix The prefex to prepend to each method name
 * @return {function(Object, Object)} New server constructor
 */
function makeServerConstructor(services) {
  var qual_names = [];
  _.each(services, function(service) {
    _.each(service.children, function(method) {
      var name = common.fullyQualifiedName(method);
      if (_.indexOf(qual_names, name) !== -1) {
        throw new Error('Method ' + name + ' exposed by more than one service');
      }
      qual_names.push(name);
    });
  });
  /**
   * Create a server with the given handlers for all of the methods.
   * @constructor
   * @param {Object} service_handlers Map from service names to map from method
   *     names to handlers
   * @param {Object} options Options to pass to the underlying server
   */
  function SurfaceServer(service_handlers, options) {
    var server = new Server(options);
    this.inner_server = server;
    _.each(services, function(service) {
      var service_name = common.fullyQualifiedName(service);
      if (service_handlers[service_name] === undefined) {
        throw new Error('Handlers for service ' +
            service_name + ' not provided.');
      }
      var prefix = '/' + common.fullyQualifiedName(service) + '/';
      _.each(service.children, function(method) {
        var method_type;
        if (method.requestStream) {
          if (method.responseStream) {
            method_type = 'bidi';
          } else {
            method_type = 'client_stream';
          }
        } else {
          if (method.responseStream) {
            method_type = 'server_stream';
          } else {
            method_type = 'unary';
          }
        }
        if (service_handlers[service_name][decapitalize(method.name)] ===
            undefined) {
          throw new Error('Method handler for ' +
              common.fullyQualifiedName(method) + ' not provided.');
        }
        var binary_handler = handler_makers[method_type](
            service_handlers[service_name][decapitalize(method.name)]);
        var serialize = common.serializeCls(
            method.resolvedResponseType.build());
        var deserialize = common.deserializeCls(
            method.resolvedRequestType.build());
        server.register(prefix + capitalize(method.name), binary_handler,
                        serialize, deserialize);
      });
    }, this);
  }

  /**
   * Binds the server to the given port, with SSL enabled if secure is specified
   * @param {string} port The port that the server should bind on, in the format
   *     "address:port"
   * @param {boolean=} secure Whether the server should open a secure port
   * @return {SurfaceServer} this
   */
  SurfaceServer.prototype.bind = function(port, secure) {
    return this.inner_server.bind(port, secure);
  };

  /**
   * Starts the server listening on any bound ports
   * @return {SurfaceServer} this
   */
  SurfaceServer.prototype.listen = function() {
    this.inner_server.start();
    return this;
  };

  /**
   * Shuts the server down; tells it to stop listening for new requests and to
   * kill old requests.
   */
  SurfaceServer.prototype.shutdown = function() {
    this.inner_server.shutdown();
  };

  return SurfaceServer;
}

/**
 * See documentation for makeServerConstructor
 */
exports.makeServerConstructor = makeServerConstructor;
<|endoftext|>


<commit_before>"use strict";

const acorn = require("acorn");
const tt = acorn.tokTypes;

exports.enable = function (parser) {
  parser.checkExports = checkExports;
  parser.parseExport = parseExport;
};

function checkExports(exported, name) {
  if (exported !== void 0) {
    exported[name] = true;
  }
}

function parseExport(node, exported) {
  // export ...
  this.next();

  if (this.type === tt.star) {
    // ... * [as ns[, { x, y as z }]] from '...';
    return parseExportNamespaceSpecifiersAndSource(this, node, exported);
  }
  if (this.type === tt.name && peekNextWith(this, isCommaOrFrom)) {
    // ... def [, * as ns [, { x, y as z }]] from '...';
    return parseExportDefaultSpecifiersAndSource(this, node, exported);
  }
  if (this.type === tt._default) {
    // ... default function|class|=...;
    return parseExportDefaultDeclaration(this, node, exported);
  }
  if (this.shouldParseExportStatement()) {
    // ... var|const|let|function|class ...
    return parseExportNamedDeclaration(this, node, exported);
  }
  // ... { x, y as z } [from '...'];
  return parseExportSpecifiersAndSource(this, node, exported);
}

function getType(parser) {
  return parser.type;
}

function isCommaOrFrom(parser) {
  return parser.type === tt.comma || parser.isContextual("from");
}

function parseExportDefaultDeclaration(parser, node, exported) {
  // ... default function|class|=...;
  exported.default = true;
  parser.next();

  let isAsync;
  if (parser.type === tt._function || (isAsync = parser.isAsyncFunction())) {
    // Parse a function declaration.
    const funcNode = parser.startNode();
    if (isAsync) {
      parser.next();
    }
    parser.next();
    node.declaration = parser.parseFunction(funcNode, "nullableID", false, isAsync);
  } else if (parser.type === tt._class) {
    // Parse a class declaration.
    node.declaration = parser.parseClass(parser.startNode(), "nullableID");
  } else {
    // Parse an assignment expression.
    node.declaration = parser.parseMaybeAssign();
  }
  parser.semicolon();
  return parser.finishNode(node, "ExportDefaultDeclaration");
}

function parseExportDefaultSpecifiersAndSource(parser, node, exported) {
  // ... def [, * as ns [, { x, y as z }]] from '...';
  const specifier = parser.startNode();
  specifier.exported = parser.parseIdent(true);
  node.specifiers = [parser.finishNode(specifier, "ExportDefaultSpecifier")];

  parseExportNamespaceSpecifiersMaybe(parser, node, exported);
  parseExportSpecifiersMaybe(parser, node);
  parseExportFrom(parser, node);
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportFrom(parser, node) {
  // ... from '...';
  parser.expectContextual("from");
  node.source = parser.type === tt.string ? parser.parseExprAtom() : null;
  parser.semicolon();
}

function parseExportNamedDeclaration(parser, node, exported) {
  // ... var|const|let|function|class ...
  node.declaration = parser.parseStatement(true);
  node.source = null;
  node.specifiers = [];

  if (node.declaration.type === "VariableDeclaration") {
    parser.checkVariableExport(exported, node.declaration.declarations);
  } else {
    exported[node.declaration.id.name] = true;
  }
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportNamespaceSpecifiers(parser, node, star, exported) {
  // ... as ns
  parser.expectContextual("as");
  star.exported = parser.parseIdent(true);
  node.specifiers.push(parser.finishNode(star, "ExportNamespaceSpecifier"));
  exported[star.exported.name] = true;
}

function parseExportNamespaceSpecifiersAndSource(parser, node, exported) {
  // ... * [as ns[, { x, y as z }]] from '...';
  const star = parser.startNode();
  let type = "ExportAllDeclaration";

  node.specifiers = [];
  parser.next();

  if (parser.isContextual("as")) {
    type = "ExportNamedDeclaration";
    parseExportNamespaceSpecifiers(parser, node, star, exported);
    parseExportSpecifiersMaybe(parser, node);
  }
  parseExportFrom(parser, node);
  return parser.finishNode(node, type);
}

function parseExportNamespaceSpecifiersMaybe(parser, node, exported) {
  // ... , * as ns
  if (parser.type === tt.comma &&
      peekNextWith(parser, getType) === tt.star) {
    parser.next();
    const star = parser.startNode();
    parser.next();
    parseExportNamespaceSpecifiers(parser, node, star, exported);
  }
}

function parseExportSpecifiersAndSource(parser, node, exported) {
  // ... { x, y as z } [from '...'];
  node.declaration = null;
  node.specifiers = parser.parseExportSpecifiers(exported);

  if (parser.isContextual("from")) {
    parseExportFrom(parser, node, exported);
  } else {
    parser.semicolon();
  }
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportSpecifiersMaybe(parser, node) {
  // ... , { x, y as z }
  if (parser.eat(tt.comma)) {
    const specifiers = node.specifiers;
    specifiers.push.apply(specifiers, parser.parseExportSpecifiers());
  }
}

// Calls the given callback with the state of the parser temporarily advanced
// by calling this.nextToken(), then rolls the parser back to its original state
// and returns the result of the callback.
function peekNextWith(parser, callback) {
  const old = Object.assign(Object.create(null), parser);
  parser.nextToken();
  try {
    return callback(parser);
  } finally {
    Object.assign(parser, old);
  }
}
<commit_msg>Remove checkExport.<commit_after>"use strict";

const acorn = require("acorn");
const tt = acorn.tokTypes;

exports.enable = function (parser) {
  parser.parseExport = parseExport;
};

function parseExport(node, exported) {
  // export ...
  this.next();

  if (this.type === tt.star) {
    // ... * [as ns[, { x, y as z }]] from '...';
    return parseExportNamespaceSpecifiersAndSource(this, node, exported);
  }
  if (this.type === tt.name && peekNextWith(this, isCommaOrFrom)) {
    // ... def [, * as ns [, { x, y as z }]] from '...';
    return parseExportDefaultSpecifiersAndSource(this, node, exported);
  }
  if (this.type === tt._default) {
    // ... default function|class|=...;
    return parseExportDefaultDeclaration(this, node, exported);
  }
  if (this.shouldParseExportStatement()) {
    // ... var|const|let|function|class ...
    return parseExportNamedDeclaration(this, node, exported);
  }
  // ... { x, y as z } [from '...'];
  return parseExportSpecifiersAndSource(this, node, exported);
}

function getType(parser) {
  return parser.type;
}

function isCommaOrFrom(parser) {
  return parser.type === tt.comma || parser.isContextual("from");
}

function parseExportDefaultDeclaration(parser, node, exported) {
  // ... default function|class|=...;
  exported.default = true;
  parser.next();

  let isAsync;
  if (parser.type === tt._function || (isAsync = parser.isAsyncFunction())) {
    // Parse a function declaration.
    const funcNode = parser.startNode();
    if (isAsync) {
      parser.next();
    }
    parser.next();
    node.declaration = parser.parseFunction(funcNode, "nullableID", false, isAsync);
  } else if (parser.type === tt._class) {
    // Parse a class declaration.
    node.declaration = parser.parseClass(parser.startNode(), "nullableID");
  } else {
    // Parse an assignment expression.
    node.declaration = parser.parseMaybeAssign();
  }
  parser.semicolon();
  return parser.finishNode(node, "ExportDefaultDeclaration");
}

function parseExportDefaultSpecifiersAndSource(parser, node, exported) {
  // ... def [, * as ns [, { x, y as z }]] from '...';
  const specifier = parser.startNode();
  specifier.exported = parser.parseIdent(true);
  node.specifiers = [parser.finishNode(specifier, "ExportDefaultSpecifier")];

  parseExportNamespaceSpecifiersMaybe(parser, node, exported);
  parseExportSpecifiersMaybe(parser, node);
  parseExportFrom(parser, node);
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportFrom(parser, node) {
  // ... from '...';
  parser.expectContextual("from");
  node.source = parser.type === tt.string ? parser.parseExprAtom() : null;
  parser.semicolon();
}

function parseExportNamedDeclaration(parser, node, exported) {
  // ... var|const|let|function|class ...
  node.declaration = parser.parseStatement(true);
  node.source = null;
  node.specifiers = [];

  if (node.declaration.type === "VariableDeclaration") {
    parser.checkVariableExport(exported, node.declaration.declarations);
  } else {
    exported[node.declaration.id.name] = true;
  }
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportNamespaceSpecifiers(parser, node, star, exported) {
  // ... as ns
  parser.expectContextual("as");
  star.exported = parser.parseIdent(true);
  node.specifiers.push(parser.finishNode(star, "ExportNamespaceSpecifier"));
  exported[star.exported.name] = true;
}

function parseExportNamespaceSpecifiersAndSource(parser, node, exported) {
  // ... * [as ns[, { x, y as z }]] from '...';
  const star = parser.startNode();
  let type = "ExportAllDeclaration";

  node.specifiers = [];
  parser.next();

  if (parser.isContextual("as")) {
    type = "ExportNamedDeclaration";
    parseExportNamespaceSpecifiers(parser, node, star, exported);
    parseExportSpecifiersMaybe(parser, node);
  }
  parseExportFrom(parser, node);
  return parser.finishNode(node, type);
}

function parseExportNamespaceSpecifiersMaybe(parser, node, exported) {
  // ... , * as ns
  if (parser.type === tt.comma &&
      peekNextWith(parser, getType) === tt.star) {
    parser.next();
    const star = parser.startNode();
    parser.next();
    parseExportNamespaceSpecifiers(parser, node, star, exported);
  }
}

function parseExportSpecifiersAndSource(parser, node, exported) {
  // ... { x, y as z } [from '...'];
  node.declaration = null;
  node.specifiers = parser.parseExportSpecifiers(exported);

  if (parser.isContextual("from")) {
    parseExportFrom(parser, node, exported);
  } else {
    parser.semicolon();
  }
  return parser.finishNode(node, "ExportNamedDeclaration");
}

function parseExportSpecifiersMaybe(parser, node) {
  // ... , { x, y as z }
  if (parser.eat(tt.comma)) {
    const specifiers = node.specifiers;
    specifiers.push.apply(specifiers, parser.parseExportSpecifiers());
  }
}

// Calls the given callback with the state of the parser temporarily advanced
// by calling this.nextToken(), then rolls the parser back to its original state
// and returns the result of the callback.
function peekNextWith(parser, callback) {
  const old = Object.assign(Object.create(null), parser);
  parser.nextToken();
  try {
    return callback(parser);
  } finally {
    Object.assign(parser, old);
  }
}
<|endoftext|>


<commit_before>import { CHANGE_TYPES, generateUUID } from '../database';
const { CREATE, UPDATE, DELETE } = CHANGE_TYPES;
const recordTypesSynced = [
  'ItemBatch',
  'NumberSequence',
  'NumberToReuse',
  'Requisition',
  'RequisitionItem',
  'Stocktake',
  'StocktakeBatch',
  'Transaction',
  'TransactionBatch',
];

/**
 * Maintains the queue of records to be synced: listens to database changes,
 * queues sync records, provides them when asked, and removes them when marked as
 * used. First changed first out, i.e. the oldest changes are synced first.
 */
export class SyncQueue {
  constructor(database) {
    this.database = database;
    this.onDatabaseEvent = this.onDatabaseEvent.bind(this);
    this.databaseListenerId = null;
  }

  /**
   * Start the queue listening to database changes
   * @return {none}
   */
  enable() {
    this.databaseListenerId = this.database.addListener(this.onDatabaseEvent);
  }

  /**
   * Stop the queue listening to database changes
   * @return {none}
   */
  disable() {
    this.database.removeListener(this.databaseListenerId);
  }

  /**
   * Respond to a database change event. Must be called from within a database
   * write transaction.
   * @param  {string} changeType The type of database change, e.g. CREATE, UPDATE, DELETE
   * @param  {string} recordType The type of record changed (from database schema)
   * @param  {object} record     The record changed
   * @param  {string} causedBy   The cause of this database event, either 'sync' or undefined
   * @return {none}
   */
  onDatabaseEvent(changeType, recordType, record, causedBy) {
    if (causedBy === 'sync') return; // Don't re-sync any changes caused by a sync
    if (recordTypesSynced.indexOf(recordType) >= 0) {
      switch (changeType) {
        case CREATE:
        case UPDATE:
        case DELETE: {
<<<<<<< HEAD
          let isDuplicate = false;
          if (!record.id) return;

          if (recordType === 'Transaction' && record.isFinalised) {
            // Remove old snapshots from the same transaction to be sync with lines
            const result = this.database
              .objects('SyncOut')
              .filtered('recordType == $0 && recordId == $1', recordType, record.id);

            Object.entries(result).forEach(([key, value]) => {
              this.database.delete('SyncOut', value);
            });
          } else {
            isDuplicate =
              this.database
                .objects('SyncOut')
                .filtered(
                  'changeType == $0 && recordType == $1 && recordId == $2',
                  changeType,
                  recordType,
                  record.id
                ).length > 0;
          }

          if (!isDuplicate) {
=======
          if (!record.id) return;
          const existingSyncOutRecord = this.database
            .objects('SyncOut')
            .filtered('recordId == $0', record.id)[0];
          if (!existingSyncOutRecord) {
>>>>>>> #332-fix-lines-si-between-mobiles
            this.database.create('SyncOut', {
              id: generateUUID(),
              changeTime: new Date().getTime(),
              changeType: changeType,
              recordType: recordType,
              recordId: record.id,
            });
          } else {
            existingSyncOutRecord.changeTime = new Date().getTime();
            existingSyncOutRecord.changeType = changeType;
            this.database.update('SyncOut', existingSyncOutRecord);
          }
          break;
        }
        default:
          // Not a supported database event, do nothing. E.g. WIPE (takes care of itself)
          break;
      }
    }
  }

  /**
   * Return the number of records in the sync queue.
   * @return {integer} Number of records awaiting sync
   */
  get length() {
    return this.database.objects('SyncOut').length;
  }

  /**
   * Return the next x records to be synced.
   * @param  {integer}   numberOfRecords The number of records to return (defaults to 1)
   * @return {array}                     An array of the top x records in the sync queue
   */
  next(numberOfRecords) {
    const numberToReturn = numberOfRecords || 1;
    const allRecords = this.database.objects('SyncOut').sorted('changeTime');
    return allRecords.slice(0, numberToReturn);
  }

  /**
   * Remove the given records from the sync queue.
   * @param  {array} records An array of the records that have been used
   * @return {none}
   */
  use(records) {
    this.database.write(() => {
      this.database.delete('SyncOut', records);
    });
  }
}
<commit_msg>derped merge<commit_after>import { CHANGE_TYPES, generateUUID } from '../database';
const { CREATE, UPDATE, DELETE } = CHANGE_TYPES;
const recordTypesSynced = [
  'ItemBatch',
  'NumberSequence',
  'NumberToReuse',
  'Requisition',
  'RequisitionItem',
  'Stocktake',
  'StocktakeBatch',
  'Transaction',
  'TransactionBatch',
];

/**
 * Maintains the queue of records to be synced: listens to database changes,
 * queues sync records, provides them when asked, and removes them when marked as
 * used. First changed first out, i.e. the oldest changes are synced first.
 */
export class SyncQueue {
  constructor(database) {
    this.database = database;
    this.onDatabaseEvent = this.onDatabaseEvent.bind(this);
    this.databaseListenerId = null;
  }

  /**
   * Start the queue listening to database changes
   * @return {none}
   */
  enable() {
    this.databaseListenerId = this.database.addListener(this.onDatabaseEvent);
  }

  /**
   * Stop the queue listening to database changes
   * @return {none}
   */
  disable() {
    this.database.removeListener(this.databaseListenerId);
  }

  /**
   * Respond to a database change event. Must be called from within a database
   * write transaction.
   * @param  {string} changeType The type of database change, e.g. CREATE, UPDATE, DELETE
   * @param  {string} recordType The type of record changed (from database schema)
   * @param  {object} record     The record changed
   * @param  {string} causedBy   The cause of this database event, either 'sync' or undefined
   * @return {none}
   */
  onDatabaseEvent(changeType, recordType, record, causedBy) {
    if (causedBy === 'sync') return; // Don't re-sync any changes caused by a sync
    if (recordTypesSynced.indexOf(recordType) >= 0) {
      switch (changeType) {
        case CREATE:
        case UPDATE:
        case DELETE: {
          if (!record.id) return;
          const existingSyncOutRecord = this.database
            .objects('SyncOut')
            .filtered('recordId == $0', record.id)[0];
          if (!existingSyncOutRecord) {
            this.database.create('SyncOut', {
              id: generateUUID(),
              changeTime: new Date().getTime(),
              changeType: changeType,
              recordType: recordType,
              recordId: record.id,
            });
          } else {
            existingSyncOutRecord.changeTime = new Date().getTime();
            existingSyncOutRecord.changeType = changeType;
            this.database.update('SyncOut', existingSyncOutRecord);
          }
          break;
        }
        default:
          // Not a supported database event, do nothing. E.g. WIPE (takes care of itself)
          break;
      }
    }
  }

  /**
   * Return the number of records in the sync queue.
   * @return {integer} Number of records awaiting sync
   */
  get length() {
    return this.database.objects('SyncOut').length;
  }

  /**
   * Return the next x records to be synced.
   * @param  {integer}   numberOfRecords The number of records to return (defaults to 1)
   * @return {array}                     An array of the top x records in the sync queue
   */
  next(numberOfRecords) {
    const numberToReturn = numberOfRecords || 1;
    const allRecords = this.database.objects('SyncOut').sorted('changeTime');
    return allRecords.slice(0, numberToReturn);
  }

  /**
   * Remove the given records from the sync queue.
   * @param  {array} records An array of the records that have been used
   * @return {none}
   */
  use(records) {
    this.database.write(() => {
      this.database.delete('SyncOut', records);
    });
  }
}
<|endoftext|>


<commit_before>"use strict";

(function() {

    //
    // polyfill performance.now()
    //
    if(window.performance && window.performance.now) {
        var now = function() { return performance.now();
    } else if(Date.now) {
        var now = function() { return Date.now(); }
    } else {
        var now = function() { return Date().getTime(); }
    }

    //
    // Encapsulate a task
    //
    function Task(action, timeout) {

        this.timeout = timeout;
        this.expectedStartTime = (timeout ? now()+timeout : 0);
        this.action = action;

    }

    //
    // Encapsulate task priority logic
    //
    function TaskScheduler() {

        this.taskQueue = [];
        this.childSchedulers = [];

    }

}());<commit_msg>Some progress on the task scheduler<commit_after>"use strict";

(function() {

    //
    // polyfill performance.now()
    //
    if(window.performance && window.performance.now) {
        var now = function() { return performance.now();
    } else if(Date.now) {
        var now = function() { return Date.now(); }
    } else {
        var now = function() { return Date().getTime(); }
    }

    //
    // Encapsulate a task
    //
    function Task(action) {
        this.start = action;
    }

    //
    // Encapsulate task priority logic
    //
    function TaskScheduler(parent) {

        this.isRunning = false;
        this.isScheduledNow = false;

        this.taskQueue = [];
        this.delayedTasks = 0;
        this.childSchedulers = [];
        this.parentScheduler = parent;
        if(parent) { parent.childSchedulers.push(this); }

        var This = this;
        This.tryRun = function() {
            if(This.parentScheduler) {
                This.parentScheduler.tryRun();
            } else {
                This.run();
            }
        }
        This.run = function() {

            This.isRunning = true;

            // calling code should not face scheduler errors
            try {

                //
                // walk through all tasks
                //
                if(This.taskQueue.length !== 0) {

                    var task; while(task=This.taskQueue.shift()) {

                        // run the task
                        // (the loop should not break if a task fails)
                        try { task.start(); }
                        catch(ex) { setImmediate(function() { throw ex; }) }

                    }

                }

                //
                // let child schedulers execute if no task is pending
                //
                if(This.delayedTasks !== 0) {

                    for(var i=0; i<This.childSchedulers.length; i++) {

                        // run the scheduler
                        // (the loop should not break if a scheduler fails)
                        try { child.run(); }
                        catch(ex) { setImmediate(function() { throw ex; }) }

                    }

                }

            } catch(ex) { setImmediate(function() { throw ex; }) }

            This.isRunning = false;

        }

    }

    TaskScheduler.prototype.pushTask = function(f) {

        // push the task
        this.taskQueue.push(f);

        // ensure the scheduler will run soon
        this.scheduleNow();

    };

    TaskScheduler.prototype.pushDelayedTask = function(f, scheduler) {

        // ask for a delayed execution
        var This = this;
        var result = scheduler(function() {

            // push the task
            This.pushTask(f);
            This.delayedTasks--;

            // empty the queue
            This.tryRun();

        });

        // record the future task
        this.delayedTasks++;

        // return scheduler-relative info
        return result;

    }

    // aliases for common web functions
    TaskScheduler.prototype.setImmediate = TaskScheduler.prototype.pushTask;
    TaskScheduler.prototype.setTimeout = function(f,d) {
        TaskScheduler.prototype.pushDelayedTask(f, function(f) { setTimeout(f,d) })
    }
    TaskScheduler.prototype.requestAnimationFrame = function(f,d) {
        TaskScheduler.prototype.pushDelayedTask(f, requestAnimationFrame);
    }

    TaskScheduler.prototype.scheduleNow = function() {

        // avoid creating multiple running
        // version of the scheduler
        if(this.isRunning) return;
        if(this.isScheduledNow) return;

        // schedule a new run
        setImmediate(this.tryRun);

    }

}());<|endoftext|>