<commit_before>import {
  camelCase,
  isArray,
  merge
} from './utils';
import {
  block_statement,
  empty_statement,
  function_statement,
  infix_statement,
  multi_line_statement,
  token_statement
} from './statement';
import builtinMacros from './builtin-macros';

function letToVar([cmd, ...vars], options) {
  const varPairs = [];
  for (let i = 0; i < vars.length; i += 2) {
    let name = vars[ i ];
    let val = vars[ i + 1 ];

    if (name && val) {
      varPairs.push(infix_statement({
        statements: [
          token_statement({ token: `var ${name}`}),
          toJsTree(val, { embedded: true })
        ],
        separator: ' = ',
        terminate: true
      }));
    }
  }

  if (varPairs.length < 1) {
    return empty_statement();
  }

  return multi_line_statement(merge(options, {
    statements: varPairs
  }));
}

function math_operator([operator, ...params], options) {
  return infix_statement(merge(options, {
    statements: params.map(param => toJsTree(param, { embedded: true })),
    separator: ` ${operator} `
  }));
}

function define_function([operator, name, params, ...body], options) {
  if (isArray(name)) {
    body.unshift(params);
    params = name;
    name = "";
  }
  params = params.join(', ');

  let final = body.pop();
  if (final) {
    final = toJsTree(final, { returnStatement: true, terminate: true });
  } else {
    final = token_statement({ token: 'null', returnStatement: true, terminate: true });
  }

  let statements = body.map(s => toJsTree(s, { terminate: true }));
  statements.push(final);

  return block_statement(merge(options, {
    openBlock: `function ${name}(${params}) {`,
    statements,
    closeBlock: `}`
  }));
}

function define_module([operator, name, ...body], options) {
  const statements = body.map(s => toJsTree(s, { terminate: true }));

  return block_statement(merge(options, {
    openBlock: `module('${name}', function (require, export) {`,
    statements,
    closeBlock: `})`
  }));
}

function module_require([operator, moduleName, reqTokens], options) {
  const statements = reqTokens.map(token => token_statement({
    token: `var ${token} = ${moduleName}['${token}']`,
    terminate: true
  }));

  statements.unshift(token_statement({
    token: `var ${moduleName} = require('${moduleName}')`,
    terminate: true
  }));

  return multi_line_statement(merge(options, { statements }));
}

function module_export([operator, moduleName, statement], options) {
  return function_statement(merge(options, {
    openStatement: `export(`,
    parameters: [
      token_statement({ token: `'${moduleName}'` }),
      toJsTree(statement, { embedded: true })
    ],
    closeStatement: `)`
  }));
}

function function_call([fn, ...params], options) {
  return function_statement({
    openStatement: `${fn}(`,
    parameters: params.map(p => toJsTree(p, { embedded: true })),
    closeStatement: `)`
  });
}

export const toJsTree = function (arr, options = { }) {
  arr = builtinMacros(arr, options);

  if (!isArray(arr)) {
    return token_statement(merge(options, { token: arr }));
  }

  switch(arr[0]) {
    case 'function': return define_function(arr, options);
    case 'module': return define_module(arr, options);
    case 'require': return module_require(arr, options);
    case 'export': return module_export(arr, options);
    case 'let': return letToVar(arr, options);
    case '+': return math_operator(arr, options);
    case '-': return math_operator(arr, options);
    case '*': return math_operator(arr, options);
    case '/': return math_operator(arr, options);
  }

  return function_call(arr, options);
};
<commit_msg>forgot to add the logical operators, which fails most of the tests<commit_after>import {
  camelCase,
  isArray,
  merge
} from './utils';
import {
  block_statement,
  empty_statement,
  function_statement,
  infix_statement,
  multi_line_statement,
  token_statement
} from './statement';
import builtinMacros from './builtin-macros';

function letToVar([cmd, ...vars], options) {
  const varPairs = [];
  for (let i = 0; i < vars.length; i += 2) {
    let name = vars[ i ];
    let val = vars[ i + 1 ];

    if (name && val) {
      varPairs.push(infix_statement({
        statements: [
          token_statement({ token: `var ${name}`}),
          toJsTree(val, { embedded: true })
        ],
        separator: ' = ',
        terminate: true
      }));
    }
  }

  if (varPairs.length < 1) {
    return empty_statement();
  }

  return multi_line_statement(merge(options, {
    statements: varPairs
  }));
}

function math_operator([operator, ...params], options) {
  return infix_statement(merge(options, {
    statements: params.map(param => toJsTree(param, { embedded: true })),
    separator: ` ${operator} `
  }));
}

function logical_operator([operator, ...params], options) {
  // TODO
}

function define_function([operator, name, params, ...body], options) {
  if (isArray(name)) {
    body.unshift(params);
    params = name;
    name = "";
  }
  params = params.join(', ');

  let final = body.pop();
  if (final) {
    final = toJsTree(final, { returnStatement: true, terminate: true });
  } else {
    final = token_statement({ token: 'null', returnStatement: true, terminate: true });
  }

  let statements = body.map(s => toJsTree(s, { terminate: true }));
  statements.push(final);

  return block_statement(merge(options, {
    openBlock: `function ${name}(${params}) {`,
    statements,
    closeBlock: `}`
  }));
}

function define_module([operator, name, ...body], options) {
  const statements = body.map(s => toJsTree(s, { terminate: true }));

  return block_statement(merge(options, {
    openBlock: `module('${name}', function (require, export) {`,
    statements,
    closeBlock: `})`
  }));
}

function module_require([operator, moduleName, reqTokens], options) {
  const statements = reqTokens.map(token => token_statement({
    token: `var ${token} = ${moduleName}['${token}']`,
    terminate: true
  }));

  statements.unshift(token_statement({
    token: `var ${moduleName} = require('${moduleName}')`,
    terminate: true
  }));

  return multi_line_statement(merge(options, { statements }));
}

function module_export([operator, moduleName, statement], options) {
  return function_statement(merge(options, {
    openStatement: `export(`,
    parameters: [
      token_statement({ token: `'${moduleName}'` }),
      toJsTree(statement, { embedded: true })
    ],
    closeStatement: `)`
  }));
}

function function_call([fn, ...params], options) {
  return function_statement({
    openStatement: `${fn}(`,
    parameters: params.map(p => toJsTree(p, { embedded: true })),
    closeStatement: `)`
  });
}

export const toJsTree = function (arr, options = { }) {
  arr = builtinMacros(arr, options);

  if (!isArray(arr)) {
    return token_statement(merge(options, { token: arr }));
  }

  switch(arr[0]) {
    case 'function': return define_function(arr, options);
    case 'module': return define_module(arr, options);
    case 'require': return module_require(arr, options);
    case 'export': return module_export(arr, options);
    case 'let': return letToVar(arr, options);
    case '+': return math_operator(arr, options);
    case '-': return math_operator(arr, options);
    case '*': return math_operator(arr, options);
    case '/': return math_operator(arr, options);
    case '=': return logical_operator(arr, options);
    case '>': return logical_operator(arr, options);
    case '<': return logical_operator(arr, options);
    case '>=': return logical_operator(arr, options);
    case '<=': return logical_operator(arr, options);
  }

  return function_call(arr, options);
};
<|endoftext|>


<commit_before>// This file belongs to Whendle, a clock application for the Palm Pre
// http://github.com/dylanmei/Whendle

//
// Copyright (C) 2009 Dylan Meissner (dylanmei@gmail.com)
//
// Permission is hereby granted, free of charge, to any person otaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

Whendle.Clock = Class.create({
	initialize: function(id, timezone, offset, location) {
		this.id = id || 0;
		this.timezone = timezone || '';
		this.offset = offset || 0;
		this._location = location || new Whendle.Location();
	}
});

Whendle.Clock.from_location = function(location) {
	return new Whendle.Clock(0, '', 0, location);
}

with (Whendle.Clock.prototype) {
	__defineGetter__('location', function() { return this._location.name; });
	__defineGetter__('area', function() { return this._location.area; });
	__defineGetter__('country', function() { return this._location.country; });
	__defineGetter__('district', function() { return this._location.district; });
	__defineGetter__('latitude', function() { return this._location.latitude; });
	__defineGetter__('longitude', function() { return this._location.longitude; });
}

Whendle.Clock.Format_place = function(location, district, country) {
	return  district + ', ' + country;
}

Whendle.Clock.Format_day = function(today, other_day) {
	var here = today.clone().hour(0).minute(0).second(0);
	var there = other_day.clone().hour(0).minute(0).second(0);
	return there.compare(here) < 0
		? $.string('day_Yesterday', 'Yesterday') : there.compare(here) > 0
			? $.string('day_Tomorrow', 'Tomorrow') : $.string('day_Today', 'Today');
}

Whendle.Clock.Format_time = function(time, pattern) {
	var hour = time.hour()
	var minute = time.minute().toPaddedString(2);

	if (pattern == 'HH12') {
		var template = hour < 12 ? $.string('time_HH12am', '#{hours}:#{minutes} am') : $.string('time_HH12pm', '#{hours}:#{minutes} pm');
		return template.interpolate({ 'hours': (hour % 12 || 12), 'minutes': minute });
	}

	return $.string('time_HH24', '#{hours}:#{minutes}')
		.interpolate({ 'hours': hour, 'minutes': minute });
}<commit_msg>cleanup location name/district/country anomolies<commit_after>// This file belongs to Whendle, a clock application for the Palm Pre
// http://github.com/dylanmei/Whendle

//
// Copyright (C) 2009 Dylan Meissner (dylanmei@gmail.com)
//
// Permission is hereby granted, free of charge, to any person otaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

Whendle.Clock = Class.create({
	initialize: function(id, timezone, offset, location) {
		this.id = id || 0;
		this.timezone = timezone || '';
		this.offset = offset || 0;
		this._location = location || new Whendle.Location();
	}
});

Whendle.Clock.from_location = function(location) {
	return new Whendle.Clock(0, '', 0, location);
}

with (Whendle.Clock.prototype) {
	__defineGetter__('location', function() { return this._location.name; });
	__defineGetter__('area', function() { return this._location.area; });
	__defineGetter__('country', function() { return this._location.country; });
	__defineGetter__('district', function() { return this._location.district; });
	__defineGetter__('latitude', function() { return this._location.latitude; });
	__defineGetter__('longitude', function() { return this._location.longitude; });
}

Whendle.Clock.Format_place = function(name, district, country) {
	return new Whendle.Location(name, district, country).area;
}

Whendle.Clock.Format_day = function(today, other_day) {
	var here = today.clone().hour(0).minute(0).second(0);
	var there = other_day.clone().hour(0).minute(0).second(0);
	return there.compare(here) < 0
		? $.string('day_Yesterday', 'Yesterday') : there.compare(here) > 0
			? $.string('day_Tomorrow', 'Tomorrow') : $.string('day_Today', 'Today');
}

Whendle.Clock.Format_time = function(time, pattern) {
	var hour = time.hour()
	var minute = time.minute().toPaddedString(2);

	if (pattern == 'HH12') {
		var template = hour < 12 ? $.string('time_HH12am', '#{hours}:#{minutes} am') : $.string('time_HH12pm', '#{hours}:#{minutes} pm');
		return template.interpolate({ 'hours': (hour % 12 || 12), 'minutes': minute });
	}

	return $.string('time_HH24', '#{hours}:#{minutes}')
		.interpolate({ 'hours': hour, 'minutes': minute });
}<|endoftext|>


<commit_before>(function (angular, buildfire) {
    "use strict";
    angular
        .module('folderPluginWidget')

    .directive("loadImage", function () {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                element.attr("src", "../../../styles/media/holder-" + attrs.loadImage + ".gif");

                attrs.$observe('finalSrc', function () {
                    var _img = attrs.finalSrc;

                    if (attrs.cropType == 'resize') {
                        buildfire.imageLib.local.resizeImage(_img, {
                            width: attrs.cropWidth,
                            height: attrs.cropHeight
                        }, function (err, imgUrl) {
                            _img = imgUrl;
                            replaceImg(_img);
                        });
                    } else {
                        buildfire.imageLib.local.cropImage(_img, {
                            width: attrs.cropWidth,
                            height: attrs.cropHeight
                        }, function (err, imgUrl) {
                            _img = imgUrl;
                            replaceImg(_img);
                        });
                    }
                });

                function replaceImg(finalSrc) {
                    var elem = $("<img>");
                    elem[0].onload = function () {
                        element.attr("src", finalSrc);
                        elem.remove();
                    };
                    elem.attr("src", finalSrc);
                }
            }
        };
    })

    .directive('backImg', ["$rootScope", function ($rootScope) {
        return function (scope, element, attrs) {
            attrs.$observe('backImg', function (value) {
                if (value) {
                    var imgUrl = buildfire.imageLib.resizeImage(value, {
                        width: window.innerWidth,
                        disablePixelRation : true
                    });
                    if (imgUrl) {
                        element.attr("style", 'background:url(' + imgUrl + ') !important ; background-size: 100% 100% !important;');
                    } else {
                        element.attr("style", 'background-color:white');
                    }
                    element.css({
                        'background-size': '100% 100% !important'
                    });
                }
                else {
                    element.attr("style", 'background-color:white');
                    element.css({
                        'background-size': 'cover !important'
                    });
                }
            });
        };
    }])

    .directive('imgPreload', ['$rootScope', function ($rootScope) {
        return {
            restrict: 'A',
            scope: {
                ngSrc: '@'
            },
            link: function (scope, element, attrs) {
                element.on('load', function () {
                    element.addClass('in');
                }).on('error', function () {
                    //
                });

                scope.$watch('ngSrc', function (newVal) {
                    element.removeClass('in');
                });
            }
        };
    }])

    .directive('emitLastRepeaterElement', function () {
        return function (scope) {
            if (scope.$last) {
                scope.$emit('LastRepeaterElement');
            }
        };
    })

    .directive('imageCarousel', function ($timeout) {
        return {
            restrict: 'A',
            scope: {},
            link: function (scope, elem, attrs) {
                scope.carousel = null;
                scope.timeout = null;
                function initCarousel() {
                    if (scope.timeout) {
                        $timeout.cancel(scope.timeout);
                    }
                    if (scope.carousel) {
                        scope.carousel.trigger("destroy.owl.carousel");
                        $(elem).find(".owl-stage-outer").remove();
                    }
                    scope.carousel = null;
                    scope.timeout = $timeout(function () {
                        var obj = {
                            loop: false,
                            nav: false,
                            items: 1
                        };
                        scope.carousel = $(elem).owlCarousel(obj);
                    }, 100);
                }

                initCarousel();
                attrs.$observe("imageCarousel", function (newVal, oldVal) {
                    if (newVal) {
                        if (scope.carousel) {
                            initCarousel();
                        }
                    }
                });
            }
        }
    });
})(window.angular, window.buildfire);<commit_msg>Revert "disable Pixel Ratio when resizing image on widget"<commit_after>(function (angular, buildfire) {
    "use strict";
    angular
        .module('folderPluginWidget')

    .directive("loadImage", function () {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                element.attr("src", "../../../styles/media/holder-" + attrs.loadImage + ".gif");

                attrs.$observe('finalSrc', function () {
                    var _img = attrs.finalSrc;

                    if (attrs.cropType == 'resize') {
                        buildfire.imageLib.local.resizeImage(_img, {
                            width: attrs.cropWidth,
                            height: attrs.cropHeight
                        }, function (err, imgUrl) {
                            _img = imgUrl;
                            replaceImg(_img);
                        });
                    } else {
                        buildfire.imageLib.local.cropImage(_img, {
                            width: attrs.cropWidth,
                            height: attrs.cropHeight
                        }, function (err, imgUrl) {
                            _img = imgUrl;
                            replaceImg(_img);
                        });
                    }
                });

                function replaceImg(finalSrc) {
                    var elem = $("<img>");
                    elem[0].onload = function () {
                        element.attr("src", finalSrc);
                        elem.remove();
                    };
                    elem.attr("src", finalSrc);
                }
            }
        };
    })

    .directive('backImg', ["$rootScope", function ($rootScope) {
        return function (scope, element, attrs) {
            attrs.$observe('backImg', function (value) {
                if (value) {
                    var imgUrl = buildfire.imageLib.resizeImage(value, {
                        width: window.innerWidth
                    });
                    if (imgUrl) {
                        element.attr("style", 'background:url(' + imgUrl + ') !important ; background-size: 100% 100% !important;');
                    } else {
                        element.attr("style", 'background-color:white');
                    }
                    element.css({
                        'background-size': '100% 100% !important'
                    });
                }
                else {
                    element.attr("style", 'background-color:white');
                    element.css({
                        'background-size': 'cover !important'
                    });
                }
            });
        };
    }])

    .directive('imgPreload', ['$rootScope', function ($rootScope) {
        return {
            restrict: 'A',
            scope: {
                ngSrc: '@'
            },
            link: function (scope, element, attrs) {
                element.on('load', function () {
                    element.addClass('in');
                }).on('error', function () {
                    //
                });

                scope.$watch('ngSrc', function (newVal) {
                    element.removeClass('in');
                });
            }
        };
    }])

    .directive('emitLastRepeaterElement', function () {
        return function (scope) {
            if (scope.$last) {
                scope.$emit('LastRepeaterElement');
            }
        };
    })

    .directive('imageCarousel', function ($timeout) {
        return {
            restrict: 'A',
            scope: {},
            link: function (scope, elem, attrs) {
                scope.carousel = null;
                scope.timeout = null;
                function initCarousel() {
                    if (scope.timeout) {
                        $timeout.cancel(scope.timeout);
                    }
                    if (scope.carousel) {
                        scope.carousel.trigger("destroy.owl.carousel");
                        $(elem).find(".owl-stage-outer").remove();
                    }
                    scope.carousel = null;
                    scope.timeout = $timeout(function () {
                        var obj = {
                            loop: false,
                            nav: false,
                            items: 1
                        };
                        scope.carousel = $(elem).owlCarousel(obj);
                    }, 100);
                }

                initCarousel();
                attrs.$observe("imageCarousel", function (newVal, oldVal) {
                    if (newVal) {
                        if (scope.carousel) {
                            initCarousel();
                        }
                    }
                });
            }
        }
    });
})(window.angular, window.buildfire);<|endoftext|>


<commit_before>const { api, _, Action } = require("../../")
const path = require('path')
const dir = path.join(api.config.path, "friends")
const Flume = require('flumedb')
const OffsetLog = require('flumelog-offset')
const codec = require('flumecodec')
const Reduce = require('flumeview-reduce')
const Abortable = require('pull-abortable')

module.exports = () => {

  const db = Flume(OffsetLog(dir, { codec: codec.json })).use('view', Reduce(1, function (acc, item) {
    if (acc == null) acc = {}
    if (item.id) {
      if (acc[item.id] && item.ts > acc[item.id].ts) acc[item.id] = item
      if (!acc[item.id]) acc[item.id] = item
      //if (acc[item.id].delete === true) delete acc[item.id]
    }
    return acc
  }))

  api.friends = {}
  api.actions.friends = {}

  api.friends.add = api.actions.friends.add = Action({
    type: "async",
    input: "string",
    desc: "Adds a friend",
    run: (key, cb) => {
      if (db.closed) return cb(Error('cannot call: api.friends.add, flumedb instance is closed'))
      const item = {
        id: key,
        ts: Date.now()
      }
      db.append(item, (err, sec) => {
        if (db.closed) return cb(Error('cannot call: api.friends.add, flumedb instance is closed'))
        if (err) return cb(err)
        db.view.get((err, res) => {
          if (err) return cb(err)
          cb(null, res && res[key] ? res[key] : item)
        })
      })
    }
  })

  api.friends.remove = api.actions.friends.remove = Action({
    type: "async",
    input: "string",
    run: (key, cb) => {
      db.append({
        id: key,
        ts: Date.now(),
        delete: true
      }, (err, sec) => {
        if (err) return cb(err)
        db.view.get(function (err, res) {
          if (err) return cb(err)
          cb(null, res[key] ? true : false)
        })
      })
    }
  })

  api.friends.isFriend = function (id, cb) {
    if (db.closed) return cb(Error('cannot call: api.friends.isFriend, flumedb instance is closed'))

    db.view.get((err, friends) => {
      if (err) return cb(err)
      if (!friends) return cb(null, false)
      if (id && friends[id] && friends[id].delete === true) return cb(null, false)
      cb(null, id && friends[id] ? true : false)
    })
  }

  api.friends.ls = api.actions.friends.ls = Action({
    type: "source",
    input: { live: "boolean|string", old: "boolean|string" },
    desc: "Returns all friends",
    usage: {
      live: "Receive all friends until cancelled",
      old: "Recive all old friends"
    },
    defaults: {
      live: false,
      old: true
    },
    run: (opts) => {
      opts.old = opts.old === "true" || opts.old === true ? true : false
      opts.live = opts.live === "true" || opts.live === true ? true : false
      opts.seqs = false
      opts.sync = false
      if (db.closed) return _.error(cb(Error('cannot call: api.friends.ls, flumedb instance is closed')))
      return db.stream(opts)
    }
  })

  const ls = {}
  const sync = () => {
    return _.asyncMap((item, cb) => {
      db.view.get((err, friends) => {
        if (err) return cb(null, item)
        const friend = friends ? friends[item.id] : undefined
        if ((friend && friend.ts < item.ts) || !friend) return db.append(item, () => cb(null, item));
        return cb(null, item)
      })
    })
  }

  _(api.events(), api.events.on({
    closer: (e) => {
      try {
        if (!(e.peer.friends && e.peer.friends.ls)) return;
        if (!ls[e.id]) {
          const done = () => {
            if (ls[e.id]) {
              ls[e.id].abort(true)
              delete ls[e.id]

              api.log.info('Stop listening to live friend changes from', e.peerID, "on", api.id)
            }
          }

          ls[e.id] = Abortable(done)
          api.log.info('Listen to live friend changes from', e.peerID, "on", api.id)
          _(e.peer.friends.ls({ old: true, live: true }), ls[e.id], sync(), _.onEnd(done))
        }
      }
      catch (err) {
        api.log.error("Friend api error", err.message || err)
      }

      api.log.debug('peer is closer', e.peerID)
    },
    notcloser: (e) => {

      if (ls[e.id]) {
        ls[e.id].abort(true)
        delete ls[e.id]
      }

      api.log.debug('peer is not closer', e.peerID)
    },
    replicate: (e) => {
      try {
        api.log('Replicating friends from peer', e.peerID)

        _(e.peer.friends.ls({ old: true, live: false }), sync(), _.onEnd((err) => {
          if (err) api.log.error("Friend api replication error", err.message || err)
        }))

        api.log('Friends from', e.peerID, 'replicated')
      }
      catch (err) {
        api.log.error("Friend api replication error", err.message || err)
      }
    },
    end: () => { }
  }))

  const events = _.events()
  db.view.ready(() => { events.emit({ type: "ready" }) })

  const end = events.end
  events.end = (err) => {
    db.close(() => { })
    end(err)
  }

  api.config.authenticate = function (id, cb) {

    if (this.protocol && this.protocol.indexOf("+unix") !== -1) {
      return db.view.get((err, item) => {
        if (err) return api.friends.add(id, () => { return cb(null, "friend") });
        if (item && item[id] && item[id].delete !== true) return cb(null, "friend")

        return api.friends.add(id, () => {
          return cb(null, "friend")
        })
      })
    }

    api.friends.isFriend(id, (err, friend) => {
      if (err) return cb(err)
      if (friend) return cb(null, "friend")
      return cb("access denied for " + id);
    })
  }

  return events
}<commit_msg>fix for api.friends.remove<commit_after>const { api, _, Action } = require("../../")
const path = require('path')
const dir = path.join(api.config.path, "friends")
const Flume = require('flumedb')
const OffsetLog = require('flumelog-offset')
const codec = require('flumecodec')
const Reduce = require('flumeview-reduce')
const Abortable = require('pull-abortable')

module.exports = () => {

  const db = Flume(OffsetLog(dir, { codec: codec.json })).use('view', Reduce(1, function (acc, item) {
    if (acc == null) acc = {}
    if (item.id) {
      if (acc[item.id] && item.ts > acc[item.id].ts) acc[item.id] = item
      if (!acc[item.id]) acc[item.id] = item
      //if (acc[item.id].delete === true) delete acc[item.id]
    }
    return acc
  }))

  api.friends = {}
  api.actions.friends = {}

  api.friends.add = api.actions.friends.add = Action({
    type: "async",
    input: "string",
    desc: "Adds a friend",
    run: (key, cb) => {
      if (db.closed) return cb(Error('cannot call: api.friends.add, flumedb instance is closed'))
      const item = {
        id: key,
        ts: Date.now()
      }
      db.append(item, (err, sec) => {
        if (db.closed) return cb(Error('cannot call: api.friends.add, flumedb instance is closed'))
        if (err) return cb(err)
        db.view.get((err, res) => {
          if (err) return cb(err)
          cb(null, res && res[key] ? res[key] : item)
        })
      })
    }
  })

  api.friends.remove = api.actions.friends.remove = Action({
    type: "async",
    input: "string",
    run: (key, cb) => {
      db.append({
        id: key,
        ts: Date.now(),
        delete: true
      }, (err, sec) => {
        if (err) return cb(err)
        db.view.get(function (err, res) {
          if (err) return cb(err)
          cb(null, res[key] && res[key].delete ? true : false)
        })
      })
    }
  })

  api.friends.isFriend = function (id, cb) {
    if (db.closed) return cb(Error('cannot call: api.friends.isFriend, flumedb instance is closed'))

    db.view.get((err, friends) => {
      if (err) return cb(err)
      if (!friends) return cb(null, false)
      if (id && friends[id] && friends[id].delete === true) return cb(null, false)
      cb(null, id && friends[id] ? true : false)
    })
  }

  api.friends.ls = api.actions.friends.ls = Action({
    type: "source",
    input: { live: "boolean|string", old: "boolean|string" },
    desc: "Returns all friends",
    usage: {
      live: "Receive all friends until cancelled",
      old: "Recive all old friends"
    },
    defaults: {
      live: false,
      old: true
    },
    run: (opts) => {
      opts.old = opts.old === "true" || opts.old === true ? true : false
      opts.live = opts.live === "true" || opts.live === true ? true : false
      opts.seqs = false
      opts.sync = false
      if (db.closed) return _.error(cb(Error('cannot call: api.friends.ls, flumedb instance is closed')))
      return db.stream(opts)
    }
  })

  const ls = {}
  const sync = () => {
    return _.asyncMap((item, cb) => {
      db.view.get((err, friends) => {
        if (err) return cb(null, item)
        const friend = friends ? friends[item.id] : undefined
        if ((friend && friend.ts < item.ts) || !friend) return db.append(item, () => cb(null, item));
        return cb(null, item)
      })
    })
  }

  _(api.events(), api.events.on({
    closer: (e) => {
      try {
        if (!(e.peer.friends && e.peer.friends.ls)) return;
        if (!ls[e.id]) {
          const done = () => {
            if (ls[e.id]) {
              ls[e.id].abort(true)
              delete ls[e.id]

              api.log.info('Stop listening to live friend changes from', e.peerID, "on", api.id)
            }
          }

          ls[e.id] = Abortable(done)
          api.log.info('Listen to live friend changes from', e.peerID, "on", api.id)
          _(e.peer.friends.ls({ old: true, live: true }), ls[e.id], sync(), _.onEnd(done))
        }
      }
      catch (err) {
        api.log.error("Friend api error", err.message || err)
      }

      api.log.debug('peer is closer', e.peerID)
    },
    notcloser: (e) => {

      if (ls[e.id]) {
        ls[e.id].abort(true)
        delete ls[e.id]
      }

      api.log.debug('peer is not closer', e.peerID)
    },
    replicate: (e) => {
      try {
        api.log('Replicating friends from peer', e.peerID)

        _(e.peer.friends.ls({ old: true, live: false }), sync(), _.onEnd((err) => {
          if (err) api.log.error("Friend api replication error", err.message || err)
        }))

        api.log('Friends from', e.peerID, 'replicated')
      }
      catch (err) {
        api.log.error("Friend api replication error", err.message || err)
      }
    },
    end: () => { }
  }))

  const events = _.events()
  db.view.ready(() => { events.emit({ type: "ready" }) })

  const end = events.end
  events.end = (err) => {
    db.close(() => { })
    end(err)
  }

  api.config.authenticate = function (id, cb) {

    if (this.protocol && this.protocol.indexOf("+unix") !== -1) {
      return db.view.get((err, item) => {
        if (err) return api.friends.add(id, () => { return cb(null, "friend") });
        if (item && item[id] && item[id].delete !== true) return cb(null, "friend")

        return api.friends.add(id, () => {
          return cb(null, "friend")
        })
      })
    }

    api.friends.isFriend(id, (err, friend) => {
      if (err) return cb(err)
      if (friend) return cb(null, "friend")
      return cb("access denied for " + id);
    })
  }

  return events
}<|endoftext|>


<commit_before>// grab our dom elements
let displayBox = document.querySelector('.current-exercise'),
    catalogBox = document.querySelector('.catalog-box'),
    resetButton = document.querySelector('.reset');

// set default exercises if none exist in localStorage
if (!window.localStorage.getItem('exercises')) {
  setDefaultCatalog();
}

// click the 💪 to reset to defaults
resetButton.addEventListener('click', resetRefresh);

function resetRefresh() {
  setDefaultCatalog();
  displayExercise();
  displayCatalog();
}
// set a variable for the localStorage 'exercises' item
let localCatalog = JSON.parse(localStorage.getItem('exercises')) || {};

// define default set of exercises
function setDefaultCatalog() {
  let catalog = {
    ex01: { name: 'Push Ups', reps: 10 },
    ex02: { name: 'Sit Ups', reps: 30 },
    ex03: { name: 'Lunges', reps: 30 },
    ex04: { name: 'Squats', reps: 15 },
    ex05: { name: 'Jumping Jacks', reps: 20 }
  }
  // write exercises to localStorage
  localStorage.setItem('exercises', JSON.stringify(catalog));

  // update to latest data
  localCatalog = JSON.parse(localStorage.getItem('exercises'));
}

// save changes to localStorage upon each 'input' event
catalogBox.addEventListener('input', function (event) {
  // make a copy of the existing localStorage data
  let newCatalog = localCatalog;

  // grab the data-item names for elements being currently edited
  let focusedParentName = event.target.parentElement.getAttribute('data-item');
  let focusedChildName = event.target.getAttribute('data-item');

  // update relevant datum within the newCatalog with user input/changes
  newCatalog[focusedParentName][focusedChildName] = event.target.innerHTML;

  // push changes to localStorage
  localStorage.setItem('exercises', JSON.stringify(newCatalog));

}, false)

// this is what will be read for the final output to display
let output = {
  exercise: 0,
  reps: 0
};

// create html elements for each exercises + reps based on data from localStorage
function displayCatalog() {
  // get current list of <dl> exercises
  let catalogChildren = document.querySelectorAll('dl');
  // remove existing children to start fresh
  if (catalogChildren) {
    catalogChildren.forEach(function(child) {
      catalogBox.removeChild(child);
    });
  }

  for (var item in localCatalog) {

    if (typeof localCatalog[item] !== 'function') {

      let exerciseSet = document.createElement('dl'),
        nameBox = document.createElement('dt'),
        repsBox = document.createElement('dd');

      exerciseSet.setAttribute('data-item', item);

      nameBox.contentEditable = true;
      repsBox.contentEditable = true;

      nameBox.setAttribute('data-item', 'name');
      repsBox.setAttribute('data-item', 'reps');

      nameBox.textContent = localCatalog[item].name;
      repsBox.textContent = localCatalog[item].reps;

      exerciseSet.appendChild(nameBox);
      exerciseSet.appendChild(repsBox);

      catalogBox.appendChild(exerciseSet);
    }
  };
};

// chooses a random exercise and sets value to global 'output' var
function pickRandomExercise() {
  // make an array out of the localStorage object
  var keys = Object.keys(localCatalog);

  // generate a random number within the range of elements localCatalog
  var rand = Math.floor(Math.random() * keys.length);

  // set the object property based on above random number
  var prop = keys[rand];

  // output the property's name and reps
  output.exercise = localCatalog[prop].name;
  output.reps = localCatalog[prop].reps;
}

// displays the 'output' values in the large, center HTML .displayBox
function displayExercise() {
  pickRandomExercise();
  displayBox.innerHTML = `${output.reps} <span class="multiplier">×</span> ${output.exercise}`;
};

// initialize the app
displayExercise();
displayCatalog();

// add the 'loaded' class upon successful document load
window.onload = function(e) {
  document.querySelector('body').className = 'loaded';
}
<commit_msg>start with the default catalog instead of a blank object<commit_after>// localStorage.removeItem('exercises');

// grab our dom elements
let displayBox = document.querySelector('.current-exercise'),
    catalogBox = document.querySelector('.catalog-box'),
    resetButton = document.querySelector('.reset');

// define a default set of exercises
let catalog = {
  ex01: { name: 'Push Ups', reps: 10 },
  ex02: { name: 'Sit Ups', reps: 30 },
  ex03: { name: 'Lunges', reps: 30 },
  ex04: { name: 'Squats', reps: 15 },
  ex05: { name: 'Jumping Jacks', reps: 20 }
};

// set a variable for the localStorage 'exercises' item
let localCatalog = JSON.parse(localStorage.getItem('exercises')) || catalog;

// set default exercises if none exist in localStorage
if (!window.localStorage.getItem('exercises')) {
  setDefaultCatalog();
}

// click the 💪 to reset to defaults
resetButton.addEventListener('click', resetRefresh);

function resetRefresh() {
  // remove localStorage item
  localStorage.removeItem('exercises');

  // update localStorage...
  setDefaultCatalog();

  // display the results
  displayExercise();
  displayCatalog();
}

// define default set of exercises
function setDefaultCatalog() {
  // write exercises to localStorage
  localStorage.setItem('exercises', JSON.stringify(catalog));

  // update to latest data
  localCatalog = JSON.parse(localStorage.getItem('exercises'));
}

// save changes to localStorage upon each 'input' event
catalogBox.addEventListener('input', function (event) {
  // make a copy of the existing localStorage data
  let newCatalog = localCatalog;

  // grab the data-item names for elements being currently edited
  let focusedParentName = event.target.parentElement.getAttribute('data-item');
  let focusedChildName = event.target.getAttribute('data-item');

  // update relevant datum within the newCatalog with user input/changes
  newCatalog[focusedParentName][focusedChildName] = event.target.innerHTML;

  // push changes to localStorage
  localStorage.setItem('exercises', JSON.stringify(newCatalog));

}, false)

// this is what will be read for the final output to display
let output = {
  exercise: 0,
  reps: 0
};

// create html elements for each exercises + reps based on data from localStorage
function displayCatalog() {
  // get current list of <dl> exercises
  let catalogChildren = document.querySelectorAll('dl');
  // remove existing children to start fresh
  if (catalogChildren) {
    catalogChildren.forEach(function(child) {
      catalogBox.removeChild(child);
    });
  }

  for (var item in localCatalog) {

    if (typeof localCatalog[item] !== 'function') {

      let exerciseSet = document.createElement('dl'),
        nameBox = document.createElement('dt'),
        repsBox = document.createElement('dd');

      exerciseSet.setAttribute('data-item', item);

      nameBox.contentEditable = true;
      repsBox.contentEditable = true;

      nameBox.setAttribute('data-item', 'name');
      repsBox.setAttribute('data-item', 'reps');

      nameBox.textContent = localCatalog[item].name;
      repsBox.textContent = localCatalog[item].reps;

      exerciseSet.appendChild(nameBox);
      exerciseSet.appendChild(repsBox);

      catalogBox.appendChild(exerciseSet);
    }
  };
};

// chooses a random exercise and sets value to global 'output' var
function pickRandomExercise() {
  // make an array out of the localStorage object
  var keys = Object.keys(localCatalog);

  // generate a random number within the range of elements localCatalog
  var rand = Math.floor(Math.random() * keys.length);

  // set the object property based on above random number
  var prop = keys[rand];

  // output the property's name and reps
  output.exercise = localCatalog[prop].name;
  output.reps = localCatalog[prop].reps;
}

// displays the 'output' values in the large, center HTML .displayBox
function displayExercise() {
  pickRandomExercise();
  displayBox.innerHTML = `${output.reps} <span class="multiplier">×</span> ${output.exercise}`;
};

// initialize the app
displayExercise();
displayCatalog();

// add the 'loaded' class upon successful document load
window.onload = function(e) {
  document.querySelector('body').className = 'loaded';
}
<|endoftext|>


<commit_before>import {
  CREATE,
  DELETE,
  fetchUtils,
  GET_LIST,
  GET_MANY,
  GET_MANY_REFERENCE,
  GET_ONE,
  UPDATE,
} from 'admin-on-rest';
import isPlainObject from 'lodash.isplainobject';
import fetchHydra from './fetchHydra';

/**
 * Transforms a JSON-LD document to an admin-on-rest compatible document
 *
 * @param {number} maxDepth
 * @param {number} depth
 */
export const transformJsonLdDocumentToAORDocument = (
  maxDepth = 2,
  depth = 1,
) => documents => {
  if (!isPlainObject(documents) && !Array.isArray(documents)) {
    return documents;
  }

  documents = Array.isArray(documents)
    ? Array.from(documents)
    : Object.assign({}, documents, {
        originId: documents.id,
        id: documents['@id'],
      });

  if (depth < maxDepth) {
    depth++;

    if (Array.isArray(documents)) {
      documents = documents.map(document =>
        transformJsonLdDocumentToAORDocument(maxDepth, depth)(document),
      );
    } else {
      Object.keys(documents).forEach(key => {
        documents[key] = transformJsonLdDocumentToAORDocument(maxDepth, depth)(
          documents[key],
        );
      });
    }
  }

  return documents;
};

/**
 * Maps admin-on-rest queries to a Hydra powered REST API
 *
 * @see http://www.hydra-cg.com/
 *
 * @example
 * CREATE   => POST http://my.api.url/posts/123
 * DELETE   => DELETE http://my.api.url/posts/123
 * GET_LIST => GET http://my.api.url/posts
 * GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * GET_ONE  => GET http://my.api.url/posts/123
 * UPDATE   => PUT http://my.api.url/posts/123
 */
export default ({entrypoint, resources = []}, httpClient = fetchHydra) => {
  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertAORDataToHydraData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = [];
    resource.fields.forEach(({name, normalizeData}) => {
      if (!(name in data) || undefined === normalizeData) {
        return;
      }

      fieldData[name] = normalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Object}
   */
  const convertAORRequestToHydraRequest = (type, resource, params) => {
    switch (type) {
      case CREATE:
        return convertAORDataToHydraData(resource, params.data).then(data => ({
          options: {
            body: JSON.stringify(data),
            method: 'POST',
          },
          url: `${entrypoint}/${resource}`,
        }));

      case DELETE:
        return Promise.resolve({
          options: {
            method: 'DELETE',
          },
          url: entrypoint + params.id,
        });

      case GET_LIST: {
        const {pagination: {page}} = params;

        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${fetchUtils.queryParameters({
            ...params.filter,
            page,
          })}`,
        });
      }

      case GET_MANY_REFERENCE:
        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${fetchUtils.queryParameters({
            [params.target]: params.id,
          })}`,
        });

      case GET_ONE:
        return Promise.resolve({
          options: {},
          url: entrypoint + params.id,
        });

      case UPDATE:
        return convertAORDataToHydraData(resource, params.data).then(data => ({
          options: {
            body: JSON.stringify(data),
            method: 'PUT',
          },
          url: entrypoint + params.id,
        }));

      default:
        throw new Error(`Unsupported fetch action type ${type}`);
    }
  };

  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertHydraDataToAORData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = {};
    resource.fields.forEach(({name, denormalizeData}) => {
      if (!(name in data) || undefined === denormalizeData) {
        return;
      }

      fieldData[name] = denormalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} response
   * @param {string} resource
   * @param {string} type
   *
   * @returns {Promise}
   */
  const convertHydraResponseToAORResponse = (type, resource, response) => {
    switch (type) {
      case GET_LIST:
        // TODO: support other prefixes than "hydra:"
        return Promise.resolve(
          response.json['hydra:member'].map(
            transformJsonLdDocumentToAORDocument(),
          ),
        )
          .then(data =>
            Promise.all(
              data.map(data => convertHydraDataToAORData(resource, data)),
            ),
          )
          .then(data => ({data, total: response.json['hydra:totalItems']}));

      default:
        return Promise.resolve(
          transformJsonLdDocumentToAORDocument()(response.json),
        )
          .then(data => convertHydraDataToAORData(resource, data))
          .then(data => ({data}));
    }
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Promise}
   */
  const fetchApi = (type, resource, params) => {
    // Hydra doesn't handle WHERE IN requests, so we fallback to calling GET_ONE n times instead
    if (GET_MANY === type) {
      return Promise.all(
        params.ids.map(id => fetchApi(GET_ONE, resource, {id})),
      ).then(responses => ({data: responses}));
    }

    return convertAORRequestToHydraRequest(type, resource, params)
      .then(({url, options}) => httpClient(url, options))
      .then(response =>
        convertHydraResponseToAORResponse(type, resource, response),
      );
  };

  return fetchApi;
};
<commit_msg>fix lint<commit_after>import {
  CREATE,
  DELETE,
  fetchUtils,
  GET_LIST,
  GET_MANY,
  GET_MANY_REFERENCE,
  GET_ONE,
  UPDATE,
} from 'admin-on-rest';
import isPlainObject from 'lodash.isplainobject';
import fetchHydra from './fetchHydra';

/**
 * Transforms a JSON-LD document to an admin-on-rest compatible document
 *
 * @param {number} maxDepth
 * @param {number} depth
 */
export const transformJsonLdDocumentToAORDocument = (
  maxDepth = 2,
  depth = 1,
) => documents => {
  if (!isPlainObject(documents) && !Array.isArray(documents)) {
    return documents;
  }

  documents = Array.isArray(documents)
    ? Array.from(documents)
    : Object.assign({}, documents, {
        originId: documents.id,
        id: documents['@id'],
      });

  if (depth < maxDepth) {
    if (Array.isArray(documents)) {
      documents = documents.map(document =>
        transformJsonLdDocumentToAORDocument(maxDepth, depth + 1)(document),
      );
    } else {
      Object.keys(documents).forEach(key => {
        documents[key] = transformJsonLdDocumentToAORDocument(
          maxDepth,
          depth + 1,
        )(documents[key]);
      });
    }
  }

  return documents;
};

/**
 * Maps admin-on-rest queries to a Hydra powered REST API
 *
 * @see http://www.hydra-cg.com/
 *
 * @example
 * CREATE   => POST http://my.api.url/posts/123
 * DELETE   => DELETE http://my.api.url/posts/123
 * GET_LIST => GET http://my.api.url/posts
 * GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * GET_ONE  => GET http://my.api.url/posts/123
 * UPDATE   => PUT http://my.api.url/posts/123
 */
export default ({entrypoint, resources = []}, httpClient = fetchHydra) => {
  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertAORDataToHydraData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = [];
    resource.fields.forEach(({name, normalizeData}) => {
      if (!(name in data) || undefined === normalizeData) {
        return;
      }

      fieldData[name] = normalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Object}
   */
  const convertAORRequestToHydraRequest = (type, resource, params) => {
    switch (type) {
      case CREATE:
        return convertAORDataToHydraData(resource, params.data).then(data => ({
          options: {
            body: JSON.stringify(data),
            method: 'POST',
          },
          url: `${entrypoint}/${resource}`,
        }));

      case DELETE:
        return Promise.resolve({
          options: {
            method: 'DELETE',
          },
          url: entrypoint + params.id,
        });

      case GET_LIST: {
        const {pagination: {page}} = params;

        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${fetchUtils.queryParameters({
            ...params.filter,
            page,
          })}`,
        });
      }

      case GET_MANY_REFERENCE:
        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${fetchUtils.queryParameters({
            [params.target]: params.id,
          })}`,
        });

      case GET_ONE:
        return Promise.resolve({
          options: {},
          url: entrypoint + params.id,
        });

      case UPDATE:
        return convertAORDataToHydraData(resource, params.data).then(data => ({
          options: {
            body: JSON.stringify(data),
            method: 'PUT',
          },
          url: entrypoint + params.id,
        }));

      default:
        throw new Error(`Unsupported fetch action type ${type}`);
    }
  };

  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertHydraDataToAORData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = {};
    resource.fields.forEach(({name, denormalizeData}) => {
      if (!(name in data) || undefined === denormalizeData) {
        return;
      }

      fieldData[name] = denormalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} response
   * @param {string} resource
   * @param {string} type
   *
   * @returns {Promise}
   */
  const convertHydraResponseToAORResponse = (type, resource, response) => {
    switch (type) {
      case GET_LIST:
        // TODO: support other prefixes than "hydra:"
        return Promise.resolve(
          response.json['hydra:member'].map(
            transformJsonLdDocumentToAORDocument(),
          ),
        )
          .then(data =>
            Promise.all(
              data.map(data => convertHydraDataToAORData(resource, data)),
            ),
          )
          .then(data => ({data, total: response.json['hydra:totalItems']}));

      default:
        return Promise.resolve(
          transformJsonLdDocumentToAORDocument()(response.json),
        )
          .then(data => convertHydraDataToAORData(resource, data))
          .then(data => ({data}));
    }
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Promise}
   */
  const fetchApi = (type, resource, params) => {
    // Hydra doesn't handle WHERE IN requests, so we fallback to calling GET_ONE n times instead
    if (GET_MANY === type) {
      return Promise.all(
        params.ids.map(id => fetchApi(GET_ONE, resource, {id})),
      ).then(responses => ({data: responses}));
    }

    return convertAORRequestToHydraRequest(type, resource, params)
      .then(({url, options}) => httpClient(url, options))
      .then(response =>
        convertHydraResponseToAORResponse(type, resource, response),
      );
  };

  return fetchApi;
};
<|endoftext|>


<commit_before>var httpProxy = require('http-proxy')
	, from = process.argv[2]
	, to = process.argv[3]
if (!from || !to) {
	return console.error("Usage: node proxy.js <from> <to>\n"
		+ "  `from` and `to` are port numbers"
		+ "  don't forget `sudo` if `from` is 80")
}
httpProxy.createProxyServer({
	target: 'http://localhost:' + to
}).listen(from)
console.log("Forwarding port "
	+ from
	+ " to port "
	+ to)<commit_msg>Add error listener<commit_after>var httpProxy = require('http-proxy')
	, from = process.argv[2]
	, to = process.argv[3]
	, server

if (!from || !to) {
	return console.error("Usage: node proxy.js <from> <to>\n"
		+ "  `from` and `to` are port numbers"
		+ "  don't forget `sudo` if `from` is 80")
}

server = httpProxy.createProxyServer({
	target: 'http://localhost:' + to
})
server.on('error', function (err) {
	console.error("Oops", err)
})
server.listen(from)
console.log("Forwarding port "
	+ from
	+ " to port "
	+ to)<|endoftext|>


<commit_before>importModule('core.string');

/**
 * Parse a skin from a resource and render it using the given context.
 * @param skinOrResource
 * @param context
 */
function renderSkin(skinOrPath, context) {
    skin = (skinOrPath instanceof Skin) ?
           skinOrResource : createSkin(getResource(skinOrPath));
    skin.render(context);
}

/**
 * Parse a skin from a resource.
 * @param resource
 */
function createSkin(resource) {
    var mainSkin = [];
    var subSkins = {};
    var currentSkin = mainSkin;
    var parentSkin = null;
    parseSkin(resource, function(part) {
        if (part.name == 'extends') {
            var skinPath = part.getParameter(1);
            var skinResource = resource.getRepository().getResource(skinPath);
            parentSkin = createSkin(skinResource);
        } else if (part.name == 'subskin')  {
            var skinName = part.getParameter('name', 1);
            currentSkin = [];
            subSkins[skinName] = currentSkin;
        } else {
            currentSkin[currentSkin.length] = part;
        }
    });
    // normalization: cut trailing whitespace so it's
    // easier to tell if main skin shoule be inherited
    var lastPart = mainSkin[mainSkin.length - 1];
    if (typeof(lastPart) == 'string' && lastPart.trim() == '') {
        mainSkin.pop();
    }
    return new Skin(mainSkin, subSkins, parentSkin);
}

/**
 * The Skin object. This takes an array of skin parts (literal strings and MacroTags)
 * and a dictionary of subskins.
 * @param mainSkin an array of skin parts: string literals and macro tags
 * @param subSkins a dictionary of named skin components
 */
function Skin(mainSkin, subSkins, parentSkin) {

    var self = this;

    this.render = function(context) {
        if (mainSkin.length == 0 && parentSkin) {
            renderInternal(parentSkin.getSkinParts(), context);
        } else {
            renderInternal(mainSkin, context);
        }
    };

    this.renderSubskin = function(skinName, context) {
        if (!subSkins[skinName] && parentSkin) {
            renderInternal(parentSkin.getSkinParts(skinName), context);
        } else {
            renderInternal(subSkins[skinName], context);
        }
    };

    this.getSubskin = function(skinName) {
        return new Skin(subSkins[skinName], subSkins, resource);
    };

    this.getSkinParts = function(skinName) {
        var parts = skinName ? subSkins[skinName] : mainSkin;
        if (!parts || (!skinName && parts.length == 0)) {
            return parentSkin ? parentSkin.getSkinParts(skinName) : null;
        }
        return parts;
    }

    var renderInternal = function(parts, context) {
        for each (var part in parts) {
            if (part.args) {
                if (part.name) {
                    evaluateMacro(part, context);
                }
            } else {
                res.write(part);
            }
        }
    };

    var evaluateMacro = function(macro, context, paramIndex) {
        paramIndex = paramIndex || 0;
        var name = macro.getParameter(paramIndex);
        if (name in builtins) {
            builtins[name](macro, context, paramIndex);
        } else {
            var value = evaluateExpression(name,  context);
            if (value != null && value != "") {
                res.write(macro.getParameter('prefix') || '');
                res.write(value);
                res.write(macro.getParameter('suffix') || '');
            } else {
                res.write(macro.getParameter('default') || '');
            }
        }
    };

    var evaluateExpression = function(expression, context) {
        var path = expression.split('.');
        var elem = context;
        for each (var name in path) {
            elem = elem[name];
            if (!elem) break;
        }
        if (elem instanceof Function) {
            return elem();
        } else {
            return elem;
        }
    };

    // builtin macro handlers
    var builtins = {
        render: function(macro, context, paramIndex) {
            var skinName = macro.getParameter(paramIndex + 1);
            self.renderSubskin(skinName, context);
        },
        // experimental if tag
        "if": function(macro, context, paramIndex) {
            var condition = macro.getParameter(paramIndex + 1);
            if (evaluateExpression(condition, context)) {
                evaluateMacro(macro, context, paramIndex + 2);
            }
        }
    };

    this.toString = function() {
        return "[Skin Object]";
    }

}
<commit_msg>* Fix variable name, add var.<commit_after>importModule('core.string');

/**
 * Parse a skin from a resource and render it using the given context.
 * @param skinOrResource
 * @param context
 */
function renderSkin(skinOrPath, context) {
    var skin = (skinOrPath instanceof Skin) ?
           skinOrPath : createSkin(getResource(skinOrPath));
    skin.render(context);
}

/**
 * Parse a skin from a resource.
 * @param resource
 */
function createSkin(resource) {
    var mainSkin = [];
    var subSkins = {};
    var currentSkin = mainSkin;
    var parentSkin = null;
    parseSkin(resource, function(part) {
        if (part.name == 'extends') {
            var skinPath = part.getParameter(1);
            var skinResource = resource.getRepository().getResource(skinPath);
            parentSkin = createSkin(skinResource);
        } else if (part.name == 'subskin')  {
            var skinName = part.getParameter('name', 1);
            currentSkin = [];
            subSkins[skinName] = currentSkin;
        } else {
            currentSkin[currentSkin.length] = part;
        }
    });
    // normalization: cut trailing whitespace so it's
    // easier to tell if main skin shoule be inherited
    var lastPart = mainSkin[mainSkin.length - 1];
    if (typeof(lastPart) == 'string' && lastPart.trim() == '') {
        mainSkin.pop();
    }
    return new Skin(mainSkin, subSkins, parentSkin);
}

/**
 * The Skin object. This takes an array of skin parts (literal strings and MacroTags)
 * and a dictionary of subskins.
 * @param mainSkin an array of skin parts: string literals and macro tags
 * @param subSkins a dictionary of named skin components
 */
function Skin(mainSkin, subSkins, parentSkin) {

    var self = this;

    this.render = function(context) {
        if (mainSkin.length == 0 && parentSkin) {
            renderInternal(parentSkin.getSkinParts(), context);
        } else {
            renderInternal(mainSkin, context);
        }
    };

    this.renderSubskin = function(skinName, context) {
        if (!subSkins[skinName] && parentSkin) {
            renderInternal(parentSkin.getSkinParts(skinName), context);
        } else {
            renderInternal(subSkins[skinName], context);
        }
    };

    this.getSubskin = function(skinName) {
        return new Skin(subSkins[skinName], subSkins, resource);
    };

    this.getSkinParts = function(skinName) {
        var parts = skinName ? subSkins[skinName] : mainSkin;
        if (!parts || (!skinName && parts.length == 0)) {
            return parentSkin ? parentSkin.getSkinParts(skinName) : null;
        }
        return parts;
    }

    var renderInternal = function(parts, context) {
        for each (var part in parts) {
            if (part.args) {
                if (part.name) {
                    evaluateMacro(part, context);
                }
            } else {
                res.write(part);
            }
        }
    };

    var evaluateMacro = function(macro, context, paramIndex) {
        paramIndex = paramIndex || 0;
        var name = macro.getParameter(paramIndex);
        if (name in builtins) {
            builtins[name](macro, context, paramIndex);
        } else {
            var value = evaluateExpression(name,  context);
            if (value != null && value != "") {
                res.write(macro.getParameter('prefix') || '');
                res.write(value);
                res.write(macro.getParameter('suffix') || '');
            } else {
                res.write(macro.getParameter('default') || '');
            }
        }
    };

    var evaluateExpression = function(expression, context) {
        var path = expression.split('.');
        var elem = context;
        for each (var name in path) {
            elem = elem[name];
            if (!elem) break;
        }
        if (elem instanceof Function) {
            return elem();
        } else {
            return elem;
        }
    };

    // builtin macro handlers
    var builtins = {
        render: function(macro, context, paramIndex) {
            var skinName = macro.getParameter(paramIndex + 1);
            self.renderSubskin(skinName, context);
        },
        // experimental if tag
        "if": function(macro, context, paramIndex) {
            var condition = macro.getParameter(paramIndex + 1);
            if (evaluateExpression(condition, context)) {
                evaluateMacro(macro, context, paramIndex + 2);
            }
        }
    };

    this.toString = function() {
        return "[Skin Object]";
    }

}
<|endoftext|>


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

        // must always be running by...
        // nohup ./serve&

        var express = require('express');

        var app = express();
        var bodyParser = require("body-parser");

        app.disable('view cache');
        app.set('json spaces', 4);
        app.use(bodyParser.urlencoded(
        {
            extended: true
        }));
        app.use(bodyParser.json());

        var http = require('http');
        var url = require('url');
        var queryString = require('querystring');
        var path = require('path');
        var R = require('ramda');
        var debounce = require('lodash.debounce');

        var s3 = require('../s3client');

        var promise = require("bluebird");
        var mongodb = promise.promisifyAll(require("mongodb"));

        var bucket = 'functal-images';
        var bucketJson = 'functal-json';

        var images = [];

        //--------- throttle

        var throttle = function(fn, wait)
        {
            return debounce(fn, wait,
            {
                leading: true,
                trailing: true,
                maxWait: wait
            });
        };

        //--------- serve a file

        var sendFile = function(res, filename)
        {
            var filepath = path.join(process.cwd(), filename);

            res.sendFile(filepath, function(err)
            {
                if (err)
                {
                    console.log(err);
                    res.status(err.status).end();
                }
                else
                {
                    // console.log('Sent:', filename);
                }
            });
        };

        //--------- sync votes

        var updateMemoryImage = function(doc)
        {
            var image = R.find(function(i)
            {
                return i.name === doc.name;
            }, images);

            if (image)
            {
                image.likes = doc.likes;
                image.dislikes = doc.dislikes;
            }
        };

        //--------- load votes

        var loadVotes = function(db)
        {
            return new Promise(function(resolve, reject)
            {
                var dbImages = db.collection('images');

                dbImages.find(
                {
                    name:
                    {
                        $in: R.pluck('name', images)
                    }
                }).toArrayAsync().then(function(docs)
                {
                    // set votes in memory

                    R.forEach(function(doc)
                    {
                        updateMemoryImage(doc);

                    }, docs);

                    resolve();
                }, function(err)
                {
                    reject("error in loadVotes:" + err);
                });
            });
        };

        //---------- get images on s3

        var getImageList = function(db)
        {
            return new Promise(function(resolve, reject)
            {
                console.log('load list from s3', (new Date()).toString());

                s3.list(bucket).then(function(result)
                {
                    // console.log(result.files);

                    images = R.map(function(img)
                    {
                        return {
                            name: img.Key,
                            likes: 0,
                            dislikes: 0
                        };
                    }, result.files);

                    images = R.reverse(images);

                    // load votes
                    loadVotes(db).then(function()
                    {
                        // delete unpopular
                        var unpopular = R.filter(function(i)
                        {
                            return i.dislikes > i.likes;
                        }, images);

                        R.forEach(function(img)
                        {
                            console.log('delete ', img.name, 'dislikes', img.dislikes, 'likes', img.likes);

                            s3.delete(bucket, img.name)
                                .then(function()
                                {
                                    return s3.delete(bucketJson, img.name.replace(/(png|jpg)$/, 'json'));
                                });
                        }, unpopular);

                        // only return populer
                        images = R.filter(function(i)
                        {
                            return i.likes >= i.dislikes;
                        }, images);

                        resolve();
                    });

                }, function()
                {
                    reject('error in getImageList');
                });
            });
        };

        //--------- database

        mongodb.connectAsync(process.env.mongo_functal).then(function(db)
            {
                //------- db functions

                var dbImages = db.collection('images');

                // db setup
                // db.images.createIndex({name: 1})

                // debug
                var listVotes = function()
                {
                    dbImages.find().toArrayAsync().then(function(docs)
                    {
                        console.log(docs);
                    });
                };

                //--- image list refresh

                // hourly
                var getImagesHourly = throttle(getImageList, 60 * 60000);

                // after admin
                var getImagesSoon = debounce(getImageList, 1 * 60000);

                // initial load of image list

                getImagesHourly(db).then(function()
                {
                    console.log('images', images.length);
                });

                // --- start express

                http.createServer(app).listen(process.env.PORT || 8083);

                //--- routing

                //------------ files
                app.get(/\.(js|css|png|jpg|html)$/, function(req, res)
                {
                    var uri = url.parse(req.url, true, false);

                    sendFile(res, uri.pathname);
                });

                //------------- home page
                app.get('/', function(req, res)
                {
                    listVotes();

                    sendFile(res, '/views/index.html');
                });

                app.get('/getimages', function(req, res)
                {
                    // throttled
                    getImagesHourly(db);

                    res.jsonp(
                    {
                        images: images
                    });
                });

                //------------- delete image on s3
                app.post('/delete', function(req, res)
                {
                    var key = req.body.key;

                    s3.delete(bucket, key)
                        .then(function()
                        {
                            return s3.delete(bucketJson, key.replace(/(png|jpg)$/, 'json'));
                        })
                        .then(function(result)
                        {
                            res.json(result);
                        });

                    // remove from local list
                    images = R.reject(function(img)
                    {
                        return img === key;
                    }, images);

                    // debounced update
                    getImagesSoon(db);
                });

                //---------- vote
                app.get('/vote', function(req, res)
                {
                    var uri = url.parse(req.url);
                    var query = queryString.parse(uri.query);
                    var data = JSON.parse(query.data);

                    // updates image votes, adding to db if necessary

                    dbImages.findOneAsync(
                    {
                        name: data.name
                    }).then(function(image)
                    {
                        if (!image)
                        {
                            image = {
                                name: data.name,
                                likes: data.like,
                                dislikes: data.dislike
                            };
                        }
                        else
                        {
                            image.likes += data.like;
                            image.dislikes += data.dislike;
                        }

                        dbImages.update(
                            {
                                name: image.name
                            },
                            image,
                            {
                                upsert: true
                            });

                        updateMemoryImage(image);

                        res.jsonp(
                        {
                            status: 'ok',
                            image: image
                        });
                    });
                });
            })
            .catch(function(e)
            {
                console.log('mongo error', e.message);
                console.log('did you?:\nmongod --config /usr/local/etc/mongod.conf');
                throw e;
            });
    }());
<commit_msg>no -ve votes<commit_after>(
    function()
    {
        "use strict";

        // must always be running by...
        // nohup ./serve&

        var express = require('express');

        var app = express();
        var bodyParser = require("body-parser");

        app.disable('view cache');
        app.set('json spaces', 4);
        app.use(bodyParser.urlencoded(
        {
            extended: true
        }));
        app.use(bodyParser.json());

        var http = require('http');
        var url = require('url');
        var queryString = require('querystring');
        var path = require('path');
        var R = require('ramda');
        var debounce = require('lodash.debounce');

        var s3 = require('../s3client');

        var promise = require("bluebird");
        var mongodb = promise.promisifyAll(require("mongodb"));

        var bucket = 'functal-images';
        var bucketJson = 'functal-json';

        var images = [];

        //--------- throttle

        var throttle = function(fn, wait)
        {
            return debounce(fn, wait,
            {
                leading: true,
                trailing: true,
                maxWait: wait
            });
        };

        //--------- serve a file

        var sendFile = function(res, filename)
        {
            var filepath = path.join(process.cwd(), filename);

            res.sendFile(filepath, function(err)
            {
                if (err)
                {
                    console.log(err);
                    res.status(err.status).end();
                }
                else
                {
                    // console.log('Sent:', filename);
                }
            });
        };

        //--------- sync votes

        var updateMemoryImage = function(doc)
        {
            var image = R.find(function(i)
            {
                return i.name === doc.name;
            }, images);

            if (image)
            {
                image.likes = doc.likes;
                image.dislikes = doc.dislikes;
            }
        };

        //--------- load votes

        var loadVotes = function(db)
        {
            return new Promise(function(resolve, reject)
            {
                var dbImages = db.collection('images');

                dbImages.find(
                {
                    name:
                    {
                        $in: R.pluck('name', images)
                    }
                }).toArrayAsync().then(function(docs)
                {
                    // set votes in memory

                    R.forEach(function(doc)
                    {
                        updateMemoryImage(doc);

                    }, docs);

                    resolve();
                }, function(err)
                {
                    reject("error in loadVotes:" + err);
                });
            });
        };

        //---------- get images on s3

        var getImageList = function(db)
        {
            return new Promise(function(resolve, reject)
            {
                console.log('load list from s3', (new Date()).toString());

                s3.list(bucket).then(function(result)
                {
                    // console.log(result.files);

                    images = R.map(function(img)
                    {
                        return {
                            name: img.Key,
                            likes: 0,
                            dislikes: 0
                        };
                    }, result.files);

                    images = R.reverse(images);

                    // load votes
                    loadVotes(db).then(function()
                    {
                        // delete unpopular
                        var unpopular = R.filter(function(i)
                        {
                            return i.dislikes > i.likes;
                        }, images);

                        R.forEach(function(img)
                        {
                            console.log('delete ', img.name, 'dislikes', img.dislikes, 'likes', img.likes);

                            s3.delete(bucket, img.name)
                                .then(function()
                                {
                                    return s3.delete(bucketJson, img.name.replace(/(png|jpg)$/, 'json'));
                                });
                        }, unpopular);

                        // only return populer
                        images = R.filter(function(i)
                        {
                            return i.likes >= i.dislikes;
                        }, images);

                        resolve();
                    });

                }, function(err)
                {
                    console.log('error in getImageList', err);
                    reject('error in getImageList');
                });
            });
        };

        //--------- database

        mongodb.connectAsync(process.env.mongo_functal).then(function(db)
            {
                //------- db functions

                var dbImages = db.collection('images');

                // db setup
                // db.images.createIndex({name: 1})

                // debug
                var listVotes = function()
                {
                    dbImages.find().toArrayAsync().then(function(docs)
                    {
                        console.log(docs);
                    });
                };

                //--- image list refresh

                // hourly
                var getImagesHourly = throttle(getImageList, 60 * 60000);

                // after admin
                var getImagesSoon = debounce(getImageList, 1 * 60000);

                // initial load of image list

                getImagesHourly(db).then(function()
                {
                    console.log('images', images.length);
                }, function(err)
                {
                    console.log('error in initial getImagesHourly', err);
                });

                // --- start express

                http.createServer(app).listen(process.env.PORT || 8083);

                //--- routing

                //------------ files
                app.get(/\.(js|css|png|jpg|html)$/, function(req, res)
                {
                    var uri = url.parse(req.url, true, false);

                    sendFile(res, uri.pathname);
                });

                //------------- home page
                app.get('/', function(req, res)
                {
                    listVotes();

                    sendFile(res, '/views/index.html');
                });

                app.get('/getimages', function(req, res)
                {
                    // throttled
                    getImagesHourly(db);

                    res.jsonp(
                    {
                        images: images
                    });
                });

                //------------- delete image on s3
                app.post('/delete', function(req, res)
                {
                    var key = req.body.key;

                    s3.delete(bucket, key)
                        .then(function()
                        {
                            return s3.delete(bucketJson, key.replace(/(png|jpg)$/, 'json'));
                        })
                        .then(function(result)
                        {
                            res.json(result);
                        });

                    // remove from local list
                    images = R.reject(function(img)
                    {
                        return img === key;
                    }, images);

                    // debounced update
                    getImagesSoon(db);
                });

                //---------- vote
                app.get('/vote', function(req, res)
                {
                    var uri = url.parse(req.url);
                    var query = queryString.parse(uri.query);
                    var data = JSON.parse(query.data);

                    // updates image votes, adding to db if necessary

                    dbImages.findOneAsync(
                    {
                        name: data.name
                    }).then(function(image)
                    {
                        if (!image)
                        {
                            image = {
                                name: data.name,
                                likes: data.like,
                                dislikes: data.dislike
                            };
                        }
                        else
                        {
                            image.likes = Math.max(0, image.likes + data.like);
                            image.dislikes = Math.max(0, image.dislikes + data.dislike);
                        }

                        dbImages.update(
                            {
                                name: image.name
                            },
                            image,
                            {
                                upsert: true
                            });

                        updateMemoryImage(image);

                        res.jsonp(
                        {
                            status: 'ok',
                            image: image
                        });
                    });
                });
            })
            .catch(function(e)
            {
                console.log('mongo error', e.message);
                console.log('did you?:\nmongod --config /usr/local/etc/mongod.conf');
                throw e;
            });
    }());
<|endoftext|>


<commit_before>var Crafty = require('./core');
require('./2D');
require('./animation');
require('./canvas');
require('./collision');
require('./color');
require('./controls');
require('./DebugLayer');
require('./device');
require('./diamondiso');
require('./DOM');
require('./drawing');
require('./extensions');
require('./HashMap');
require('./html');
require('./isometric');
require('./keycodes');
require('./loader');
require('./math');
require('./model');
require('./particles');
require('./scenes');
require('./sound');
require('./sprite-animation');
require('./sprite');
require('./storage');
require('./text');
require('./time');
require('./version');
require('./viewport');

window.Crafty = Crafty;
module.exports = Crafty;<commit_msg>If window is not defined<commit_after>var Crafty = require('./core');
require('./2D');
require('./animation');
require('./canvas');
require('./collision');
require('./color');
require('./controls');
require('./DebugLayer');
require('./device');
require('./diamondiso');
require('./DOM');
require('./drawing');
require('./extensions');
require('./HashMap');
require('./html');
require('./isometric');
require('./keycodes');
require('./loader');
require('./math');
require('./model');
require('./particles');
require('./scenes');
require('./sound');
require('./sprite-animation');
require('./sprite');
require('./storage');
require('./text');
require('./time');
require('./version');
require('./viewport');

if(window) window.Crafty = Crafty;

module.exports = Crafty;<|endoftext|>


<commit_before>var express = require('express')
  , morgan = require('morgan')
  , serve_static = require('serve-static')
  , http = require('http')
  , net = require('net')
  , WSS = require('websocket').server
  , child_process = require('child_process')
  , util = require('util')
  , EventEmitter = require('events').EventEmitter
  , ipv6 = require('ipv6')
  , lib_fonts = require('./lib/fonts');

var app = exports.app = express()
  // .use(morgan('combined'))
  .use(serve_static('public'));

app.get('/fonts', function (req, res) {
    lib_fonts.list_fonts(req.query.filter)
      .when(function (err, fonts) {
        if (err)
          return res.send(500, err);
        res.send(fonts);
      });
  })

var server = exports.server = http.createServer(app)

if (require.main === module)
  server.listen(3000);

var screens = [41];

var wss = new WSS({
    httpServer: server
  , autoAcceptConnections: false
});

function X11Proxy (screen, connection, window_manager) {
  var self = this;
  this.screen = screen;
  this.connection = connection;

  this.id = ['family', 'address', 'port']
    .map(function (k) { return connection.socket._peername[k] })
    .join(':');
  this.client_sockets = {};
  this.ping = {
      counter: 0
    , interval: null
    , timeout: null
    , start: null
    , results: []
    , average: 0
  };
  this.processes = [];
  this.connection.on('message', this.data.bind(this));
  this.connection.on('close', this.close.bind(this));
  this.connection.sendUTF('SCR ' + this.screen);
  this.server_socket = net.createServer(this.newClient.bind(this)).listen(6000 + this.screen);
  if (window_manager)
    setTimeout(function () {
      self.spawnProcess(window_manager, []); //['-fn', 'cursor']);
    }, 750);
}
util.inherits(X11Proxy, EventEmitter);
X11Proxy.prototype.newClient = function (socket) {
  var self = this
    , idBuf = new Buffer(19)
    , idStr;
  idBuf.fill(0);
  idBuf.writeUInt16BE(socket.remotePort, 16);
  if (net.isIPv4(socket.remoteAddress)) {
    idBuf.writeUInt8(4, 18);
    idBuf = socket.remoteAddress.split('.')
      .reduce(
          function (o, v, i) {
            o.writeUInt8(v, i);
            return o;
          }
        , idBuf
      );
  } else {
    idBuf.writeUInt8(6, 18);
    idBuf = (new ipv6.v6.Address(socket.remoteAddress)).parsedAddress
      .reduce(
          function (o, v, i) {
            o.writeUInt16BE(v, i * 2);
            return o;
          }
        , idBuf
      );
  }
  idStr = idBuf.toString('hex');

  this.client_sockets[idStr] = socket;
  this.connection.sendUTF('NEW ' + idStr);
  socket.on('close', function () {
    self.connection.sendUTF('END ' + idStr);
    delete self.client_sockets[idStr];
  });
  socket.on('data', function (data) {
    var buffer = new Buffer(data.length + 19);
    idBuf.copy(buffer, 0)
    data.copy(buffer, 19);
    self.connection.sendBytes(buffer);
  });
}
X11Proxy.prototype.data = function (message) {
  if (message.type === 'utf8') {
    var data = (message.utf8Data || '').split(' ');
    switch (data[0]) {
      case 'PONG':
        if (data[1] == this.ping.counter - 1) {
          this.ping.results.unshift(Date.now() - this.ping.start);
          this.ping.results.splice(10, 10);
          this.ping.average = this.ping.results.reduce(function (o, v) { return o + v }) / this.ping.results.length
          clearTimeout(this.ping.timeout);
          this.ping.timeout = null;
        } else {
          console.log('Out of order ping', data[1], this.ping.counter - 1);
        }
      break;
    }
  } else {
    var data = message.binaryData
      , length = data.readUInt8(0)
      , id = data.toString('ascii', 1, length + 1);
    if (this.client_sockets[id] && this.client_sockets[id].writable) {
      this.client_sockets[id].write(data.slice(length + 1));
    } else {
      console.error('Socket closed already', length, id);
      this.connection.sendUTF('END ' + id);
    }
  }
}
X11Proxy.prototype.close = function () {
  console.log('closed');
  clearTimeout(this.ping.timeout);
  clearInterval(this.ping.interval);
  this.processes.forEach(function (process) {
    process.kill();
  });
  Object.keys(this.client_sockets).forEach(function (id) {
    this.client_sockets[id].end();
  }, this);
  try {
    this.server_socket.close();
  } catch (e) {}
  screens.push(this.screen);
}
X11Proxy.prototype.spawnProcess = function (command, arguments) {
  var env = {}
    , prefix
    , child;
  Object.keys(process.env)
    .forEach(function (k) {
      env[k] = process.env[k];
    });
  env.DISPLAY = 'localhost:' + this.screen;
  this.processes.push(
    child = child_process.spawn(command, arguments || [], { env: env })
  );
  prefix = [this.id, child.pid, command, ': \t'].join(' ');
  function handleOutput (data) {
    console.log(prefix, data.toString().replace('\n', '\n' + prefix + ' '));
  }
  child.stdout.on('data', handleOutput);
  child.stderr.on('data', handleOutput);
}

wss.on('request', function (req) {
  var screen = screens.shift();

  if (!(req.origin && screen)) {
    console.log('reject');
    return req.reject();
  }
  console.log('New client');
  var proxy = new X11Proxy(screen, req.accept('x11-proxy', req.origin), 'xeyes'); //, 'blackbox' Don't load blackbox by default
/*
  ping_interval = setInterval(function () {
    var counter = ping_counter ++;
    con.sendUTF('PING ' + counter);
    ping_start = Date.now();
    ping_timeout = setTimeout(function () {
      console.log('Ping timeout', counter);
      ping_timeout = null;
    }, 500);
  }, 5000);
*/
});

<commit_msg>Fixed proxy depencancy on the deprecated ipv6 module<commit_after>var express = require('express')
  , morgan = require('morgan')
  , serve_static = require('serve-static')
  , http = require('http')
  , net = require('net')
  , WSS = require('websocket').server
  , child_process = require('child_process')
  , util = require('util')
  , EventEmitter = require('events').EventEmitter
  , ip = require('ip-address')
  , lib_fonts = require('./lib/fonts');

var app = exports.app = express()
  // .use(morgan('combined'))
  .use(serve_static('public'));

app.get('/fonts', function (req, res) {
    lib_fonts.list_fonts(req.query.filter)
      .when(function (err, fonts) {
        if (err)
          return res.send(500, err);
        res.send(fonts);
      });
  })

var server = exports.server = http.createServer(app)

if (require.main === module)
  server.listen(3000);

var screens = [41];

var wss = new WSS({
    httpServer: server
  , autoAcceptConnections: false
});

function X11Proxy (screen, connection, window_manager) {
  var self = this;
  this.screen = screen;
  this.connection = connection;

  this.id = ['family', 'address', 'port']
    .map(function (k) { return connection.socket._peername[k] })
    .join(':');
  this.client_sockets = {};
  this.ping = {
      counter: 0
    , interval: null
    , timeout: null
    , start: null
    , results: []
    , average: 0
  };
  this.processes = [];
  this.connection.on('message', this.data.bind(this));
  this.connection.on('close', this.close.bind(this));
  this.connection.sendUTF('SCR ' + this.screen);
  this.server_socket = net.createServer(this.newClient.bind(this)).listen(6000 + this.screen);
  if (window_manager)
    setTimeout(function () {
      self.spawnProcess(window_manager, []); //['-fn', 'cursor']);
    }, 750);
}
util.inherits(X11Proxy, EventEmitter);
X11Proxy.prototype.newClient = function (socket) {
  var self = this
    , idBuf = new Buffer(19)
    , idStr;
  idBuf.fill(0);
  idBuf.writeUInt16BE(socket.remotePort, 16);
  if (net.isIPv4(socket.remoteAddress)) {
    idBuf.writeUInt8(4, 18);
    idBuf = socket.remoteAddress.split('.')
      .reduce(
          function (o, v, i) {
            o.writeUInt8(v, i);
            return o;
          }
        , idBuf
      );
  } else {
    idBuf.writeUInt8(6, 18);
    idBuf = (new ip.v6.Address(socket.remoteAddress)).parsedAddress
      .reduce(
          function (o, v, i) {
            o.writeUInt16BE(v, i * 2);
            return o;
          }
        , idBuf
      );
  }
  idStr = idBuf.toString('hex');

  this.client_sockets[idStr] = socket;
  this.connection.sendUTF('NEW ' + idStr);
  socket.on('close', function () {
    self.connection.sendUTF('END ' + idStr);
    delete self.client_sockets[idStr];
  });
  socket.on('data', function (data) {
    var buffer = new Buffer(data.length + 19);
    idBuf.copy(buffer, 0)
    data.copy(buffer, 19);
    self.connection.sendBytes(buffer);
  });
}
X11Proxy.prototype.data = function (message) {
  if (message.type === 'utf8') {
    var data = (message.utf8Data || '').split(' ');
    switch (data[0]) {
      case 'PONG':
        if (data[1] == this.ping.counter - 1) {
          this.ping.results.unshift(Date.now() - this.ping.start);
          this.ping.results.splice(10, 10);
          this.ping.average = this.ping.results.reduce(function (o, v) { return o + v }) / this.ping.results.length
          clearTimeout(this.ping.timeout);
          this.ping.timeout = null;
        } else {
          console.log('Out of order ping', data[1], this.ping.counter - 1);
        }
      break;
    }
  } else {
    var data = message.binaryData
      , length = data.readUInt8(0)
      , id = data.toString('ascii', 1, length + 1);
    if (this.client_sockets[id] && this.client_sockets[id].writable) {
      this.client_sockets[id].write(data.slice(length + 1));
    } else {
      console.error('Socket closed already', length, id);
      this.connection.sendUTF('END ' + id);
    }
  }
}
X11Proxy.prototype.close = function () {
  console.log('closed');
  clearTimeout(this.ping.timeout);
  clearInterval(this.ping.interval);
  this.processes.forEach(function (process) {
    process.kill();
  });
  Object.keys(this.client_sockets).forEach(function (id) {
    this.client_sockets[id].end();
  }, this);
  try {
    this.server_socket.close();
  } catch (e) {}
  screens.push(this.screen);
}
X11Proxy.prototype.spawnProcess = function (command, arguments) {
  var env = {}
    , prefix
    , child;
  Object.keys(process.env)
    .forEach(function (k) {
      env[k] = process.env[k];
    });
  env.DISPLAY = 'localhost:' + this.screen;
  this.processes.push(
    child = child_process.spawn(command, arguments || [], { env: env })
  );
  prefix = [this.id, child.pid, command, ': \t'].join(' ');
  function handleOutput (data) {
    console.log(prefix, data.toString().replace('\n', '\n' + prefix + ' '));
  }
  child.stdout.on('data', handleOutput);
  child.stderr.on('data', handleOutput);
}

wss.on('request', function (req) {
  var screen = screens.shift();

  if (!(req.origin && screen)) {
    console.log('reject');
    return req.reject();
  }
  console.log('New client');
  var proxy = new X11Proxy(screen, req.accept('x11-proxy', req.origin), 'xeyes'); //, 'blackbox' Don't load blackbox by default
/*
  ping_interval = setInterval(function () {
    var counter = ping_counter ++;
    con.sendUTF('PING ' + counter);
    ping_start = Date.now();
    ping_timeout = setTimeout(function () {
      console.log('Ping timeout', counter);
      ping_timeout = null;
    }, 500);
  }, 5000);
*/
});

<|endoftext|>