<commit_before>import React from "react";
import PropTypes from "prop-types";
import Link from "gatsby-link";
import Helmet from "react-helmet";
import styled from "styled-components";
import Footer from "../components/Footer";

import BlogHeader from "../components/BlogHeader";
import GithubRibbon from "../components/GithubRibbon";

import favicon from "../assets/favicon.png";

import { colors } from "../styles/colors";

const { primary } = colors;

require("prism-themes/themes/prism-ghcolors.css");

const Main = styled.main`
  padding: 0 1rem;
`;

const Logo = styled.div`
  display: flex;
  align-items: center;
  padding-bottom: 5px;
  &:hover {
    color: white;
    background: ${primary};
  }
  img: {
    padding: 0 1rem 4px 0;
  }
`;

const blogHeaderLinks = {
  "/about": (
    <Logo>
      <Link to="/">🤟/about</Link>
    </Logo>
  ),
  "/posts": (
    <Logo>
      <Link to="/">🤟/posts</Link>
    </Logo>
  ),
  "/talks": (
    <Logo>
      <Link to="/">🤟/talks</Link>
    </Logo>
  )
};

const TemplateWrapper = ({ children, location }) => (

    <Helmet
      title="ythecombinator's space"
      link={[
        {
          rel: "stylesheet",
          href: "https://fonts.googleapis.com/css?family=Lato|Poppins:700i"
        },
        {
          rel: "shortcut icon",
          type: "image/png",
          href: favicon
        }
      ]}
    />

    <GithubRibbon />

    <BlogHeader>

        {blogHeaderLinks[location.pathname] ? (
          blogHeaderLinks[location.pathname]
        ) : (
          <Logo>
            <Link to={`/${location.pathname.split("/")[1]}`}>
              🤟{location.pathname}
            </Link>
          </Logo>
        )}

    </BlogHeader>

    {children()}

Made with 💖 while high either on ☕ or 🍻 – or both 😂.

);

TemplateWrapper.propTypes = {
  children: PropTypes.func
};

export default TemplateWrapper;
<commit_msg>enhancement(layouts/blog): 🤟 → 🏠 on header links<commit_after>import React from "react";
import PropTypes from "prop-types";
import Link from "gatsby-link";
import Helmet from "react-helmet";
import styled from "styled-components";
import Footer from "../components/Footer";

import BlogHeader from "../components/BlogHeader";
import GithubRibbon from "../components/GithubRibbon";

import favicon from "../assets/favicon.png";

import { colors } from "../styles/colors";

const { primary } = colors;

require("prism-themes/themes/prism-ghcolors.css");

const Main = styled.main`
  padding: 0 1rem;
`;

const Logo = styled.div`
  display: flex;
  align-items: center;
  padding-bottom: 5px;
  &:hover {
    color: white;
    background: ${primary};
  }
  img: {
    padding: 0 1rem 4px 0;
  }
`;

const blogHeaderLinks = {
  "/about": (
    <Logo>
      <Link to="/">🏠 /about</Link>
    </Logo>
  ),
  "/posts": (
    <Logo>
      <Link to="/">🏠 /posts</Link>
    </Logo>
  ),
  "/talks": (
    <Logo>
      <Link to="/">🏠 /talks</Link>
    </Logo>
  )
};

const TemplateWrapper = ({ children, location }) => (

    <Helmet
      title="ythecombinator's space"
      link={[
        {
          rel: "stylesheet",
          href: "https://fonts.googleapis.com/css?family=Lato|Poppins:700i"
        },
        {
          rel: "shortcut icon",
          type: "image/png",
          href: favicon
        }
      ]}
    />

    <GithubRibbon />

    <BlogHeader>

        {blogHeaderLinks[location.pathname] ? (
          blogHeaderLinks[location.pathname]
        ) : (
          <Logo>
            <Link to={`/${location.pathname.split("/")[1]}`}>
              🏠 {location.pathname}
            </Link>
          </Logo>
        )}

    </BlogHeader>

    {children()}

Made with 💖 while high either on ☕ or 🍻 – or both 😂.

);

TemplateWrapper.propTypes = {
  children: PropTypes.func
};

export default TemplateWrapper;
<|endoftext|>


<commit_before>foam.CLASS({
  package: 'foam.demos.graphics',
  name: 'LifeStar',
  extends: 'foam.graphics.Box',

  requires: [ 'foam.graphics.Arc' ],

  classes: [
    {
      name: 'Point',
      extends: 'foam.graphics.Circle',
      properties: [
        'z',
        { name: 'r' },
        { name: 't' },
        { name: 'g' },
        { class: 'Float', name: 'glowRadius' }
      ],
      methods: [
        function rotateY(a) {
          this.z = this.z * Math.cos(a) - this.x * Math.sin(a);
          this.x = this.z * Math.sin(a) + this.x * Math.cos(a);
        },
        function rotateX(a) {
          this.z = this.z * Math.cos(a) - this.y * Math.sin(a);
          this.y = this.z * Math.sin(a) + this.y * Math.cos(a);
        },
        function doTransform(x) {
          var t = this.transform;
          var s = 1 - this.z/5000;
          t.translate(-200,-200);
          t.scale(s, s);
          t.translate(200,200);
          x.transform(t.a, t.d, t.b, t.e, t.c, t.f);
        },
        function polar3D(r, t, g) {
          this.x = Math.sin(t) * Math.cos(g) * r;
          this.y = Math.cos(t) * r;
          this.z = Math.sqrt(200*200 - this.x*this.x - this.y*this.y);
        },
        function paintSelf(x) {
          this.SUPER(x);
          if ( this.glowRadius ) {
            x.globalAlpha = 0.2;
            var oldR = this.radius;
            this.radius = this.glowRadius;
            this.SUPER(x);
            this.radius = oldR;
          }
        }
      ]
    }
  ],

  properties: [
    [ 'n',      128 ],
    [ 'x',      500 ],
    [ 'y',      350 ],
    [ 'width',  1000 ],
    [ 'height', 500 ],
    [ 'time',   0 ],
    [ 'color', 'black' ]
  ],

  methods: [
    function initCView() {
      this.SUPER();
      for ( var i = 0 ; i < this.n ; i++ ) this.addPoint(i);
      for ( var i = 0 ; i < this.n ; i++ ) {
        var p = this.addPoint(i);
        p.z *= -1;
      }
      this.tick();
    },
    function addPoint(i) {
      var p = this.Point.create({
        r: i*200/this.n,
        t: i*Math.PI*20/this.n,
        g: 0, //i*Math.PI/5/this.n,
        radius: 3,
        border: null,
        arcWidth: 0
      });

      p.polar3D(p.r, p.t, p.g);

      this.time$.sub(function() {
        p.rotateY(0.01);
        var on = Math.abs((this.time % this.n - i + this.n)%this.n) < 20
        p.glowRadius = on ? 8 : 0;
        var s = on ? 100 : 70;
        var l = on ?  70 : 30;
        p.color = this.hsl(i*365/this.n, s, l);
      }.bind(this));
      this.addChildren(p);

      return p;
    }
  ],
  listeners: [
    {
      name: 'tick',
      isFramed: true,
      code: function() { this.time++; this.tick(); this.invalidated.pub(); }
    }
  ]
});
<commit_msg>Improved LifeStar demo.<commit_after>foam.CLASS({
  package: 'foam.demos.graphics',
  name: 'LifeStar',
  extends: 'foam.graphics.Box',

  requires: [ 'foam.graphics.Arc' ],

  classes: [
    {
      name: 'Point',
      extends: 'foam.graphics.Circle',
      properties: [
        'z',
        { name: 'r' },
        { name: 't' },
        { name: 'g' },
        { class: 'Float', name: 'glowRadius' }
      ],
      methods: [
        function rotateY(a) {
          this.z = this.z * Math.cos(a) - this.x * Math.sin(a);
          this.x = this.z * Math.sin(a) + this.x * Math.cos(a);
        },
        function rotateX(a) {
          this.z = this.z * Math.cos(a) - this.y * Math.sin(a);
          this.y = this.z * Math.sin(a) + this.y * Math.cos(a);
        },
        function doTransform(x) {
          var t = this.transform;
          var s = 1 - this.z/300;
          t.scale(s, s);
          x.transform(t.a, t.d, t.b, t.e, t.c, t.f);
        },
        function paintSelf(x) {
          this.SUPER(x);
          if ( this.glowRadius ) {
            x.globalAlpha = 0.2;
            var oldR = this.radius;
            this.radius = this.glowRadius;
            this.SUPER(x);
            this.radius = oldR;
          }
        }
      ]
    }
  ],

  properties: [
    [ 'n',      217 ],
    [ 'x',      500 ],
    [ 'y',      350 ],
    [ 'width',  1000 ],
    [ 'height', 500 ],
    [ 'time',   0 ],
    [ 'color', 'black' ]
  ],

  methods: [
    function initCView() {
      this.SUPER();
      for ( var i = 0 ; i < this.n ; i++ ) this.addPoint(i);
      this.tick();
    },
    function addPoint(i) {
      var p = this.Point.create({
        r: Math.sin(Math.PI * i/this.n)*200,
        t: i*Math.PI*20/this.n,
        g: 0, //i*Math.PI/5/this.n,
        radius: 3,
        border: null,
        arcWidth: 0
      });

      p.x = Math.sin(p.t) * Math.cos(p.g) * p.r;
      p.y = Math.cos(p.t) * p.r;
      p.z = Math.sqrt(200*200 - p.x*p.x - p.y*p.y);

      if ( i > this.n/2 ) p.z *= -1;

      this.time$.sub(function() {
        p.rotateY(0.01);
        p.rotateX(0.005);
        var on = Math.abs((this.time % this.n - i + this.n)%this.n) < 20
        p.glowRadius = on ? 8 : 0;
        var s = on ? 100 : 70;
        var l = on ?  70 : 40;
        p.color = this.hsl(i*365/this.n, s, l);
      }.bind(this));
      this.addChildren(p);

      return p;
    }
  ],
  listeners: [
    {
      name: 'tick',
      isFramed: true,
      code: function() { this.time++; this.tick(); this.invalidated.pub(); }
    }
  ]
});
<|endoftext|>


<commit_before>//     NoFlo - Flow-Based Programming for JavaScript
//     (c) 2014-2017 Flowhub UG
//     NoFlo may be freely distributed under the MIT license
//

/* eslint-disable
    no-console,
    no-undef,
*/

// Platform detection method
exports.isBrowser = function isBrowser() {
  if ((typeof process !== 'undefined') && process.execPath && process.execPath.match(/node|iojs/)) {
    return false;
  }
  return true;
};

// Mechanism for showing API deprecation warnings. By default logs the warnings
// but can also be configured to throw instead with the `NOFLO_FATAL_DEPRECATED`
// env var.
exports.deprecated = function deprecated(message) {
  if (exports.isBrowser()) {
    console.warn(message);
    return;
  }
  if (process.env.NOFLO_FATAL_DEPRECATED) {
    throw new Error(message);
  }
  console.warn(message);
};
<commit_msg>Switch to JS modules<commit_after>//     NoFlo - Flow-Based Programming for JavaScript
//     (c) 2014-2017 Flowhub UG
//     NoFlo may be freely distributed under the MIT license
//

/* eslint-disable
    no-console,
    no-undef,
*/

// Platform detection method
export function isBrowser() {
  if ((typeof process !== 'undefined') && process.execPath && process.execPath.match(/node|iojs/)) {
    return false;
  }
  return true;
}

// Mechanism for showing API deprecation warnings. By default logs the warnings
// but can also be configured to throw instead with the `NOFLO_FATAL_DEPRECATED`
// env var.
/**
 * @param {string} message
 * @returns {void}
 */
export function deprecated(message) {
  if (isBrowser()) {
    console.warn(message);
    return;
  }
  if (process.env.NOFLO_FATAL_DEPRECATED) {
    throw new Error(message);
  }
  console.warn(message);
};
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

//
// Compare local API data based on object graph JSON blobs to remote (Cloud
// Datastore) data. Use count-of-entities as a proxy for "needs sync". Use
// SET_MINUS to filter out existing data and upload missing data.
//

const fs = require('fs');
const path = require('path');

global.FOAM_FLAGS = {gcloud: true};
require('foam2');
require('../lib/confluence/set_ops.es6.js');
require('../lib/datastore/datastore_importer.es6.js');
require('../lib/datastore/import_controller.es6.js');
require('../lib/web_apis/release.es6.js');
require('../lib/web_apis/release_interface_relationship.es6.js');
require('../lib/web_apis/web_interface.es6.js');

const credentials = JSON.parse(fs.readFileSync(
    path.resolve(__dirname, '../.local/credentials.json')));

const logger = global.logger =
    foam.lookup('foam.nanos.log.ConsoleLogger').create();

const datastoreCtx = global.datastoreCtx =
    foam.lookup('org.chromium.apis.web.ImportController').create({
      gcloudAuthEmail: credentials.client_email,
      gcloudAuthPrivateKey: credentials.private_key,
      gcloudProjectId: credentials.project_id,
      logger: logger,
    }).ctx;

const MDAO = foam.lookup('foam.dao.MDAO');
const Release = foam.lookup('org.chromium.apis.web.Release');
const WebInterface = foam.lookup('org.chromium.apis.web.WebInterface');
const ReleaseWebInterfaceJunction =
    foam.lookup('org.chromium.apis.web.ReleaseWebInterfaceJunction');
// TODO(markdittmer): Rename ImportController; it's a misnomer (more of a
// ContextContainer, or similar).
const localCtx = global.localCtx =
    foam.lookup('org.chromium.apis.web.ImportController').create({
      releaseDAO: MDAO.create({of: Release}),
      webInterfaceDAO: MDAO.create({of: WebInterface}),
      releaseWebInterfaceJunctionDAO: MDAO.create({
        of: ReleaseWebInterfaceJunction,
      }),
      authAgent: null,
      logger: logger,
    }).ctx;
// TODO(markdittmer): RenameDatastoreImporter; it's a misnomer
// (ObjectGraphDataImporter, maybe?).
const localImporter = global.localImporter =
    foam.lookup('org.chromium.apis.web.DatastoreImporter').create({
      objectGraphPath: path.resolve(__dirname, '../data/og'),
    }, localCtx);

const E = foam.lookup('foam.mlang.ExpressionsSingleton').create();

const putMissing = global.putMissing = function(local, remote) {
  return remote.select(
      E.SET_MINUS(remote, faom.lookup('foam.dao.AnonymousSink').create({
        sink: {
          put: function(o) {
            logger.info('Putting missing (' + local.of.id + '): ' + o.id);
            remote.put(o);
          },
        },
      })));
};

const verify = global.verify = function(local, remote) {
  return Promise.all([local, remote]).then(function(sinks) {
    if (sinks[0].value !== sinks[1].value) {
      logger.error('Counts are different (' + local.of.id + '): ' +
          sinks[0].value + ', ' + sinks[1].value);
      return putMissing(local, remote).then(() => sinks);
    } else {
      logger.info('Counts match (' + local.of.id + ')');
      return sinks;
    }
  });
};

const imported = global.imported = localImporter.import();
global.releaseCounts =
    imported.then(() => verify(localCtx.releaseDAO, datastoreCtx.releaseDAO));
global.apiCounts = imported.then(() => verify(localCtx.webInterfaceDAO,
                                              datastoreCtx.webInterfaceDAO));
global.releaseAPICounts =
    imported.then(() => verify(localCtx.releaseWebInterfaceJunctionDAO,
                               datastoreCtx.releaseWebInterfaceJunctionDAO));
<commit_msg>Fix typos in datastore_update script<commit_after>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

//
// Compare local API data based on object graph JSON blobs to remote (Cloud
// Datastore) data. Use count-of-entities as a proxy for "needs sync". Use
// SET_MINUS to filter out existing data and upload missing data.
//

const fs = require('fs');
const path = require('path');

global.FOAM_FLAGS = {gcloud: true};
require('foam2');
require('../lib/confluence/set_ops.es6.js');
require('../lib/datastore/datastore_importer.es6.js');
require('../lib/datastore/import_controller.es6.js');
require('../lib/web_apis/release.es6.js');
require('../lib/web_apis/release_interface_relationship.es6.js');
require('../lib/web_apis/web_interface.es6.js');

const credentials = JSON.parse(fs.readFileSync(
    path.resolve(__dirname, '../.local/credentials.json')));

const logger = global.logger =
    foam.lookup('foam.nanos.log.ConsoleLogger').create();

const datastoreCtx = global.datastoreCtx =
    foam.lookup('org.chromium.apis.web.ImportController').create({
      gcloudAuthEmail: credentials.client_email,
      gcloudAuthPrivateKey: credentials.private_key,
      gcloudProjectId: credentials.project_id,
      logger: logger,
    }).ctx;

const MDAO = foam.lookup('foam.dao.MDAO');
const Release = foam.lookup('org.chromium.apis.web.Release');
const WebInterface = foam.lookup('org.chromium.apis.web.WebInterface');
const ReleaseWebInterfaceJunction =
    foam.lookup('org.chromium.apis.web.ReleaseWebInterfaceJunction');
// TODO(markdittmer): Rename ImportController; it's a misnomer (more of a
// ContextContainer, or similar).
const localCtx = global.localCtx =
    foam.lookup('org.chromium.apis.web.ImportController').create({
      releaseDAO: MDAO.create({of: Release}),
      webInterfaceDAO: MDAO.create({of: WebInterface}),
      releaseWebInterfaceJunctionDAO: MDAO.create({
        of: ReleaseWebInterfaceJunction,
      }),
      authAgent: null,
      logger: logger,
    }).ctx;
// TODO(markdittmer): RenameDatastoreImporter; it's a misnomer
// (ObjectGraphDataImporter, maybe?).
const localImporter = global.localImporter =
    foam.lookup('org.chromium.apis.web.DatastoreImporter').create({
      objectGraphPath: path.resolve(__dirname, '../data/og'),
    }, localCtx);

const E = foam.lookup('foam.mlang.ExpressionsSingleton').create();

const putMissing = global.putMissing = function(local, remote) {
  return local.select(
      E.SET_MINUS(remote, foam.lookup('foam.dao.AnonymousSink').create({
        sink: {
          put: function(o) {
            logger.info('Putting missing (' + local.of.id + '): ' + o.id);
            remote.put(o);
          },
        },
      })));
};

const verify = global.verify = function(local, remote) {
  return Promise.all([local, remote]).then(function(sinks) {
    if (sinks[0].value !== sinks[1].value) {
      logger.error('Counts are different (' + local.of.id + '): ' +
          sinks[0].value + ', ' + sinks[1].value);
      return putMissing(local, remote).then(() => sinks);
    } else {
      logger.info('Counts match (' + local.of.id + ')');
      return sinks;
    }
  });
};

const imported = global.imported = localImporter.import();
global.releaseCounts =
    imported.then(() => verify(localCtx.releaseDAO, datastoreCtx.releaseDAO));
global.apiCounts = imported.then(() => verify(localCtx.webInterfaceDAO,
                                              datastoreCtx.webInterfaceDAO));
global.releaseAPICounts =
    imported.then(() => verify(localCtx.releaseWebInterfaceJunctionDAO,
                               datastoreCtx.releaseWebInterfaceJunctionDAO));
<|endoftext|>


<commit_before>odoo.define('web.WebClient', function (require) {
"use strict";

var AbstractWebClient = require('web.AbstractWebClient');
var core = require('web.core');
var data = require('web.data');
var data_manager = require('web.data_manager');
var framework = require('web.framework');
var Menu = require('web.Menu');
var Model = require('web.DataModel');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var UserMenu = require('web.UserMenu');

return AbstractWebClient.extend({
    events: {
        'click .oe_logo_edit_admin': 'logo_edit',
        'click .oe_logo img': function(ev) {
            ev.preventDefault();
            return this.clear_uncommitted_changes().then(function() {
                framework.redirect("/web" + (core.debug ? "?debug" : ""));
            });
        },
    },
    show_application: function() {
        var self = this;
        self.toggle_bars(true);

        self.update_logo();

        // Menu is rendered server-side thus we don't want the widget to create any dom
        self.menu = new Menu(self);
        self.menu.setElement(this.$el.parents().find('.oe_application_menu_placeholder'));
        self.menu.on('menu_click', this, this.on_menu_action);

        // Create the user menu (rendered client-side)
        self.user_menu = new UserMenu(self);
        var $user_menu_placeholder = $('body').find('.oe_user_menu_placeholder').show();
        var user_menu_loaded = self.user_menu.appendTo($user_menu_placeholder);

        // Create the systray menu (rendered server-side)
        self.systray_menu = new SystrayMenu(self);
        self.systray_menu.setElement(this.$el.parents().find('.oe_systray'));
        var systray_menu_loaded = self.systray_menu.start();

        // Start the menu once both systray and user menus are rendered
        // to prevent overflows while loading
        $.when(systray_menu_loaded, user_menu_loaded).done(function() {
            self.menu.start();
        });

        self.bind_hashchange();
        self.set_title();
        if (self.client_options.action_post_login) {
            self.action_manager.do_action(self.client_options.action_post_login);
            delete(self.client_options.action_post_login);
        }
    },
    toggle_bars: function(value) {
        this.$('tr:has(td.navbar),.oe_leftbar').toggle(value);
    },
    update_logo: function() {
        var company = session.company_id;
        var img = session.url('/web/binary/company_logo' + '?db=' + session.db + (company ? '&company=' + company : ''));
        this.$('.oe_logo img').attr('src', '').attr('src', img);
        this.$('.oe_logo_edit').toggleClass('oe_logo_edit_admin', session.uid === 1);
    },
    logo_edit: function(ev) {
        var self = this;
        ev.preventDefault();
        self.alive(new Model("res.users").get_func("read")(session.uid, ["company_id"])).then(function(res) {
            self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
                result.res_id = res.company_id[0];
                result.target = "new";
                result.views = [[false, 'form']];
                result.flags = {
                    action_buttons: true,
                    headless: true,
                };
                self.action_manager.do_action(result);
                var form = self.action_manager.dialog_widget.views.form.controller;
                form.on("on_button_cancel", self.action_manager, self.action_manager.dialog_stop);
                form.on('record_saved', self, function() {
                    self.action_manager.dialog_stop();
                    self.update_logo();
                });
            });
        });
        return false;
    },
    bind_hashchange: function() {
        var self = this;
        $(window).bind('hashchange', this.on_hashchange);

        var state = $.bbq.getState(true);
        if (_.isEmpty(state) || state.action === "login") {
            self.menu.is_bound.done(function() {
                new Model("res.users").call("read", [session.uid, ["action_id"]]).done(function(data) {
                    if(data.action_id) {
                        self.action_manager.do_action(data.action_id[0]);
                        self.menu.open_action(data.action_id[0]);
                    } else {
                        var first_menu_id = self.menu.$el.find("a:first").data("menu");
                        if(first_menu_id) {
                            self.menu.menu_click(first_menu_id);
                        }
                    }
                });
            });
        } else {
            $(window).trigger('hashchange');
        }
    },
    on_hashchange: function(event) {
        var self = this;
        var stringstate = event.getState(false);
        if (!_.isEqual(this._current_state, stringstate)) {
            var state = event.getState(true);
            if(!state.action && state.menu_id) {
                self.menu.is_bound.done(function() {
                    self.menu.menu_click(state.menu_id);
                });
            } else {
                state._push_me = false;  // no need to push state back...
                this.action_manager.do_load_state(state, !!this._current_state).then(function () {
                    var action = self.action_manager.get_inner_action();
                    if (action) {
                        self.menu.open_action(action.action_descr.id);
                    }
                });
            }
        }
        this._current_state = stringstate;
    },
    on_menu_action: function(options) {
        var self = this;
        return this.menu_dm.add(data_manager.load_action(options.action_id))
            .then(function (result) {
                return self.action_mutex.exec(function() {
                    if (options.needaction) {
                        result.context = new data.CompoundContext(result.context, {
                            search_default_message_needaction: true,
                            search_disable_custom_filters: true,
                        });
                    }
                    var completed = $.Deferred();
                    $.when(self.action_manager.do_action(result, {
                        clear_breadcrumbs: true,
                        action_menu_id: self.menu.current_menu,
                    })).fail(function() {
                        self.menu.open_menu(options.previous_menu_id);
                    }).always(function() {
                        completed.resolve();
                    });
                    setTimeout(function() {
                        completed.resolve();
                    }, 2000);
                    // We block the menu when clicking on an element until the action has correctly finished
                    // loading. If something crash, there is a 2 seconds timeout before it's unblocked.
                    return completed;
                });
            });
    },
    toggle_fullscreen: function(fullscreen) {
        this._super(fullscreen);
        if (!fullscreen) {
            this.menu.reflow();
        }
    },
});

});
<commit_msg>[FIX] web: traceback when click on 'Edit Company data' button<commit_after>odoo.define('web.WebClient', function (require) {
"use strict";

var AbstractWebClient = require('web.AbstractWebClient');
var core = require('web.core');
var data = require('web.data');
var data_manager = require('web.data_manager');
var framework = require('web.framework');
var Menu = require('web.Menu');
var Model = require('web.DataModel');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var UserMenu = require('web.UserMenu');

return AbstractWebClient.extend({
    events: {
        'click .oe_logo_edit_admin': 'logo_edit',
        'click .oe_logo img': function(ev) {
            ev.preventDefault();
            return this.clear_uncommitted_changes().then(function() {
                framework.redirect("/web" + (core.debug ? "?debug" : ""));
            });
        },
    },
    show_application: function() {
        var self = this;
        self.toggle_bars(true);

        self.update_logo();

        // Menu is rendered server-side thus we don't want the widget to create any dom
        self.menu = new Menu(self);
        self.menu.setElement(this.$el.parents().find('.oe_application_menu_placeholder'));
        self.menu.on('menu_click', this, this.on_menu_action);

        // Create the user menu (rendered client-side)
        self.user_menu = new UserMenu(self);
        var $user_menu_placeholder = $('body').find('.oe_user_menu_placeholder').show();
        var user_menu_loaded = self.user_menu.appendTo($user_menu_placeholder);

        // Create the systray menu (rendered server-side)
        self.systray_menu = new SystrayMenu(self);
        self.systray_menu.setElement(this.$el.parents().find('.oe_systray'));
        var systray_menu_loaded = self.systray_menu.start();

        // Start the menu once both systray and user menus are rendered
        // to prevent overflows while loading
        $.when(systray_menu_loaded, user_menu_loaded).done(function() {
            self.menu.start();
        });

        self.bind_hashchange();
        self.set_title();
        if (self.client_options.action_post_login) {
            self.action_manager.do_action(self.client_options.action_post_login);
            delete(self.client_options.action_post_login);
        }
    },
    toggle_bars: function(value) {
        this.$('tr:has(td.navbar),.oe_leftbar').toggle(value);
    },
    update_logo: function() {
        var company = session.company_id;
        var img = session.url('/web/binary/company_logo' + '?db=' + session.db + (company ? '&company=' + company : ''));
        this.$('.oe_logo img').attr('src', '').attr('src', img);
        this.$('.oe_logo_edit').toggleClass('oe_logo_edit_admin', session.uid === 1);
    },
    logo_edit: function(ev) {
        var self = this;
        ev.preventDefault();
        self.alive(new Model("res.users").get_func("read")(session.uid, ["company_id"])).then(function(res) {
            self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
                result.res_id = res.company_id[0];
                result.target = "new";
                result.views = [[false, 'form']];
                result.flags = {
                    action_buttons: true,
                    headless: true,
                };
                self.action_manager.do_action(result).then(function () {
                    var form = self.action_manager.dialog_widget.views.form.controller;
                    form.on("on_button_cancel", self.action_manager, self.action_manager.dialog_stop);
                    form.on('record_saved', self, function() {
                        self.action_manager.dialog_stop();
                        self.update_logo();
                    });
                });
            });
        });
        return false;
    },
    bind_hashchange: function() {
        var self = this;
        $(window).bind('hashchange', this.on_hashchange);

        var state = $.bbq.getState(true);
        if (_.isEmpty(state) || state.action === "login") {
            self.menu.is_bound.done(function() {
                new Model("res.users").call("read", [session.uid, ["action_id"]]).done(function(data) {
                    if(data.action_id) {
                        self.action_manager.do_action(data.action_id[0]);
                        self.menu.open_action(data.action_id[0]);
                    } else {
                        var first_menu_id = self.menu.$el.find("a:first").data("menu");
                        if(first_menu_id) {
                            self.menu.menu_click(first_menu_id);
                        }
                    }
                });
            });
        } else {
            $(window).trigger('hashchange');
        }
    },
    on_hashchange: function(event) {
        var self = this;
        var stringstate = event.getState(false);
        if (!_.isEqual(this._current_state, stringstate)) {
            var state = event.getState(true);
            if(!state.action && state.menu_id) {
                self.menu.is_bound.done(function() {
                    self.menu.menu_click(state.menu_id);
                });
            } else {
                state._push_me = false;  // no need to push state back...
                this.action_manager.do_load_state(state, !!this._current_state).then(function () {
                    var action = self.action_manager.get_inner_action();
                    if (action) {
                        self.menu.open_action(action.action_descr.id);
                    }
                });
            }
        }
        this._current_state = stringstate;
    },
    on_menu_action: function(options) {
        var self = this;
        return this.menu_dm.add(data_manager.load_action(options.action_id))
            .then(function (result) {
                return self.action_mutex.exec(function() {
                    if (options.needaction) {
                        result.context = new data.CompoundContext(result.context, {
                            search_default_message_needaction: true,
                            search_disable_custom_filters: true,
                        });
                    }
                    var completed = $.Deferred();
                    $.when(self.action_manager.do_action(result, {
                        clear_breadcrumbs: true,
                        action_menu_id: self.menu.current_menu,
                    })).fail(function() {
                        self.menu.open_menu(options.previous_menu_id);
                    }).always(function() {
                        completed.resolve();
                    });
                    setTimeout(function() {
                        completed.resolve();
                    }, 2000);
                    // We block the menu when clicking on an element until the action has correctly finished
                    // loading. If something crash, there is a 2 seconds timeout before it's unblocked.
                    return completed;
                });
            });
    },
    toggle_fullscreen: function(fullscreen) {
        this._super(fullscreen);
        if (!fullscreen) {
            this.menu.reflow();
        }
    },
});

});
<|endoftext|>


<commit_before>/**
 * Returns an Express Router with bindings for the Admin UI static resources,
 * i.e files, less and browserified scripts.
 *
 * Should be included before other middleware (e.g. session management,
 * logging, etc) for reduced overhead.
 */

var browserify = require('../middleware/browserify');
var express = require('express');
var less = require('less-middleware');
var path = require('path');
var str = require('string-to-stream');

function buildFieldTypesStream (fieldTypes) {
	var src = '';
	var types = Object.keys(fieldTypes);
	['Column', 'Field', 'Filter'].forEach(function (i) {
		src += 'exports.' + i + 's = {\n';
		types.forEach(function (type) {
			src += type + ': require("../../fields/types/' + type + '/' + fieldTypes[type] + i + '"),\n';
		});
		src += '};\n';
	});
	return str(src);
}

module.exports = function createStaticRouter (keystone) {
	var router = express.Router();

	/* Prepare browserify bundles */
	var bundles = {
		fields: browserify(buildFieldTypesStream(keystone.fieldTypes), 'FieldTypes'),
		signin: browserify('./Signin/index.js'),
		admin: browserify('./App/index.js'),
	};

	// prebuild static resources on the next tick in keystone dev mode; this
	// improves first-request performance but delays server start
	if (process.env.KEYSTONE_DEV === 'true' || process.env.KEYSTONE_PREBUILD_ADMIN === 'true') {
		bundles.fields.build();
		bundles.signin.build();
		bundles.admin.build();
	}

	/* Prepare LESS options */
	var elementalPath = path.join(path.dirname(require.resolve('elemental')), '..');
	var reactSelectPath = path.join(path.dirname(require.resolve('react-select')), '..');
	var customStylesPath = keystone.getPath('adminui custom styles') || '';

	var lessOptions = {
		render: {
			modifyVars: {
				elementalPath: JSON.stringify(elementalPath),
				reactSelectPath: JSON.stringify(reactSelectPath),
				customStylesPath: JSON.stringify(customStylesPath),
				adminPath: JSON.stringify(keystone.get('admin path')),
			},
		},
	};

	/* Configure router */
	router.use('/styles', less(path.resolve(__dirname + '/../../public/styles'), lessOptions));
	router.use('/styles/fonts', express.static(path.resolve(__dirname + '/../../public/js/lib/tinymce/skins/keystone/fonts')));
	router.get('/js/fields.js', bundles.fields.serve);
	router.get('/js/signin.js', bundles.signin.serve);
	router.get('/js/admin.js', bundles.admin.serve);
	router.use(express.static(path.resolve(__dirname + '/../../public')));

	return router;
};
<commit_msg>Ignoring non-string fieldTypes, fixes #3033<commit_after>/**
 * Returns an Express Router with bindings for the Admin UI static resources,
 * i.e files, less and browserified scripts.
 *
 * Should be included before other middleware (e.g. session management,
 * logging, etc) for reduced overhead.
 */

var browserify = require('../middleware/browserify');
var express = require('express');
var less = require('less-middleware');
var path = require('path');
var str = require('string-to-stream');

function buildFieldTypesStream (fieldTypes) {
	var src = '';
	var types = Object.keys(fieldTypes);
	['Column', 'Field', 'Filter'].forEach(function (i) {
		src += 'exports.' + i + 's = {\n';
		types.forEach(function (type) {
			if (typeof fieldTypes[type] !== 'string') return;
			src += type + ': require("../../fields/types/' + type + '/' + fieldTypes[type] + i + '"),\n';
		});
		src += '};\n';
	});
	return str(src);
}

module.exports = function createStaticRouter (keystone) {
	var router = express.Router();

	/* Prepare browserify bundles */
	var bundles = {
		fields: browserify(buildFieldTypesStream(keystone.fieldTypes), 'FieldTypes'),
		signin: browserify('./Signin/index.js'),
		admin: browserify('./App/index.js'),
	};

	// prebuild static resources on the next tick in keystone dev mode; this
	// improves first-request performance but delays server start
	if (process.env.KEYSTONE_DEV === 'true' || process.env.KEYSTONE_PREBUILD_ADMIN === 'true') {
		bundles.fields.build();
		bundles.signin.build();
		bundles.admin.build();
	}

	/* Prepare LESS options */
	var elementalPath = path.join(path.dirname(require.resolve('elemental')), '..');
	var reactSelectPath = path.join(path.dirname(require.resolve('react-select')), '..');
	var customStylesPath = keystone.getPath('adminui custom styles') || '';

	var lessOptions = {
		render: {
			modifyVars: {
				elementalPath: JSON.stringify(elementalPath),
				reactSelectPath: JSON.stringify(reactSelectPath),
				customStylesPath: JSON.stringify(customStylesPath),
				adminPath: JSON.stringify(keystone.get('admin path')),
			},
		},
	};

	/* Configure router */
	router.use('/styles', less(path.resolve(__dirname + '/../../public/styles'), lessOptions));
	router.use('/styles/fonts', express.static(path.resolve(__dirname + '/../../public/js/lib/tinymce/skins/keystone/fonts')));
	router.get('/js/fields.js', bundles.fields.serve);
	router.get('/js/signin.js', bundles.signin.serve);
	router.get('/js/admin.js', bundles.admin.serve);
	router.use(express.static(path.resolve(__dirname + '/../../public')));

	return router;
};
<|endoftext|>


<commit_before>(function(angular, $, _) {
  // "civicaseActivityContactFilters" is a basic skeletal directive.
  // Example usage:

  angular.module('civicase').directive('civicaseActivityContactFilters', function() {
    return {
      restrict: 'AE',
      replace: true,
      templateUrl: '~/civicase/ActivityContactFilters.html',
      scope: {
        filters: '=civicaseActivityContactFilters'
      },
      link: function($scope, $el, $attr) {
        var ts = $scope.ts = CRM.ts('civicase');

        $scope.$watch('filters', function(){
          // Ensure "All" checkbox renders.
          if ($scope.filters['@involvingContact'] === undefined) {
            $scope.filters['@involvingContact'] = '';
          }
        });

        $scope.$on('civicaseActivityFeed.query', function(event, filters, params) {
          switch (filters['@involvingContact']) {
            case 'myActivities':
              params.contact_id = 'user_contact_id';
              break;

            case 'delegated':
              if (_.isEmpty(params.assignee_contact_id)) {
                params.assignee_contact_id = {'!=': 'user_contact_id'};
              }
              break;

            default:
              break;
          }
        });
      }
    };
  });
})(angular, CRM.$, CRM._);
<commit_msg>CRM-20083 - "Delegated" - Only activities delegated by me<commit_after>(function(angular, $, _) {
  // "civicaseActivityContactFilters" is a basic skeletal directive.
  // Example usage:

  angular.module('civicase').directive('civicaseActivityContactFilters', function() {
    return {
      restrict: 'AE',
      replace: true,
      templateUrl: '~/civicase/ActivityContactFilters.html',
      scope: {
        filters: '=civicaseActivityContactFilters'
      },
      link: function($scope, $el, $attr) {
        var ts = $scope.ts = CRM.ts('civicase');

        $scope.$watch('filters', function(){
          // Ensure "All" checkbox renders.
          if ($scope.filters['@involvingContact'] === undefined) {
            $scope.filters['@involvingContact'] = '';
          }
        });

        $scope.$on('civicaseActivityFeed.query', function(event, filters, params) {
          switch (filters['@involvingContact']) {
            case 'myActivities':
              params.contact_id = 'user_contact_id';
              break;

            case 'delegated':
              if (_.isEmpty(params.assignee_contact_id)) {
                params.assignee_contact_id = {'!=': 'user_contact_id'};
              }
              if (_.isEmpty(params.source_contact_id)) {
                params.source_contact_id = 'user_contact_id';
              }
              break;

            default:
              break;
          }
        });
      }
    };
  });
})(angular, CRM.$, CRM._);
<|endoftext|>


<commit_before>;(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['knockout', 'jquery', 'zeroclipboard', 'osfutils'], factory);
    } else {
        $script.ready(['zeroclipboard'], function (){
            global.PrivateLinkTable  = factory(ko, jQuery, ZeroClipboard);
            $script.done('privateLinkTable');
        });
    }
}(this, function(ko, $, ZeroClipboard) {

    // Make sure ZeroClipboard finds the right flash file
    ZeroClipboard.config({
        moviePath: '/static/vendor/bower_components/zeroclipboard/ZeroClipboard.swf'}
    );

    var updateClipboard = function(target) {

        var client = new ZeroClipboard( target );

        client.on( "load", function(client) {
        // alert( "movie is loaded" );

            client.on( "complete", function(client, args) {
              // `this` is the element that was clicked
                this.blur();
            } );

            client.on("mousedown", function(client,args){
                $(this).addClass("active");
            });

            client.on("mouseup", function(client,args){
                $(this).removeClass("active");
            });

            client.on("mouseover", function(client,args){
                $(this).tooltip("show");
            });

            client.on("mouseout", function(client,args){
                $(this).tooltip("hide");
            });
        });

    };

    function LinkViewModel(data, $root) {

        var self = this;

        self.$root = $root;
        $.extend(self, data);
        self.collapse = "Collapse";
        self.linkName = "Link Name";
        self.readonly = "readonly";
        self.selectText = "this.setSelectionRange(0, this.value.length);";
        self.collapseNode = ko.observable(false);
        self.dateCreated = new $.osf.FormattableDate(data.date_created);
        self.linkUrl = ko.computed(function(){
            return self.$root.nodeUrl() + "?view_only=" + data.key
        });
        self.nodesList = ko.observableArray(data.nodes.slice(0,2));
        self.moreNode = ko.observable(data.nodes.length > 2);
        self.hasMoreText = ko.computed(function(){
            return "And " + (data.nodes.length - 2).toString() + " more";
        });
        self.displayAllNodes = function(){
            self.nodesList(data.nodes);
            self.moreNode(false);
            self.collapseNode(true);
        }

        self.displayTwoNodes = function(){
            self.nodesList(data.nodes.slice(0,2));
            self.moreNode(true);
            self.collapseNode(false);
        }

        self.selectText = function(data,event){
            console.log(event);
            event.target.select();
        }
    }

    function ViewModel(url) {
        var self = this;
        self.url = url;
        self.privateLinks = ko.observableArray();
        self.nodeUrl = ko.observable(null);

        function onFetchSuccess(response) {
            var node = response.node;
            self.privateLinks(ko.utils.arrayMap(node.private_links, function(link) {
                return new LinkViewModel(link, self);
            }));
            self.nodeUrl(node.absolute_url);
        }

        function onFetchError() {
          //TODO
          console.log('an error occurred');
        }

        function fetch() {
            $.ajax({url: url, type: 'GET', dataType: 'json',
              success: onFetchSuccess,
              error: onFetchError
            });
        }

        fetch();

        self.removeLink = function(data){
            var data_to_send={
                'private_link_id': data.id
            };
            bootbox.confirm('Are you sure to remove this private link?', function(result) {
                if (result) {
                    $.ajax({
                        type: "delete",
                        url: nodeApiUrl + "private_link/",
                        contentType: "application/json",
                        dataType: "json",
                        data: JSON.stringify(data_to_send),
                        success: function(response) {
                            self.privateLinks.remove(data);
                        },
                        error: function(xhr) {
                            bootbox.alert("Failed to delete the private link.")
                        }
                    });
                }
             });
        };

        self.updateClipboard = function(elm) {

            var $tr = $(elm);
            // Add this to client
            var target = $tr.find('.copy-button');
            updateClipboard(target);
            $tr.find('.remove-private-link').tooltip();
        };

    }

    function PrivateLinkTable (selector, url) {
        var self = this;
        self.viewModel = new ViewModel(url);
        $.osf.applyBindings(self.viewModel, selector);

    }
    return PrivateLinkTable;

}));
<commit_msg>code cleanup<commit_after>;(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['knockout', 'jquery', 'zeroclipboard', 'osfutils'], factory);
    } else {
        $script.ready(['zeroclipboard'], function (){
            global.PrivateLinkTable  = factory(ko, jQuery, ZeroClipboard);
            $script.done('privateLinkTable');
        });
    }
}(this, function(ko, $, ZeroClipboard) {

    // Make sure ZeroClipboard finds the right flash file
    ZeroClipboard.config({
        moviePath: '/static/vendor/bower_components/zeroclipboard/ZeroClipboard.swf'}
    );

    var updateClipboard = function(target) {

        var client = new ZeroClipboard( target );

        client.on( "load", function(client) {
        // alert( "movie is loaded" );

            client.on( "complete", function(client, args) {
              // `this` is the element that was clicked
                this.blur();
            } );

            client.on("mousedown", function(client,args){
                $(this).addClass("active");
            });

            client.on("mouseup", function(client,args){
                $(this).removeClass("active");
            });

            client.on("mouseover", function(client,args){
                $(this).tooltip("show");
            });

            client.on("mouseout", function(client,args){
                $(this).tooltip("hide");
            });
        });

    };

    function LinkViewModel(data, $root) {

        var self = this;

        self.$root = $root;
        $.extend(self, data);
        self.collapse = "Collapse";
        self.linkName = "Link Name";
        self.readonly = "readonly";
        self.selectText = "this.setSelectionRange(0, this.value.length);";
        self.collapseNode = ko.observable(false);
        self.dateCreated = new $.osf.FormattableDate(data.date_created);
        self.linkUrl = ko.computed(function(){
            return self.$root.nodeUrl() + "?view_only=" + data.key
        });
        self.nodesList = ko.observableArray(data.nodes.slice(0,2));
        self.moreNode = ko.observable(data.nodes.length > 2);
        self.hasMoreText = ko.computed(function(){
            return "And " + (data.nodes.length - 2).toString() + " more";
        });
        self.displayAllNodes = function(){
            self.nodesList(data.nodes);
            self.moreNode(false);
            self.collapseNode(true);
        }

        self.displayTwoNodes = function(){
            self.nodesList(data.nodes.slice(0,2));
            self.moreNode(true);
            self.collapseNode(false);
        }

    }

    function ViewModel(url) {
        var self = this;
        self.url = url;
        self.privateLinks = ko.observableArray();
        self.nodeUrl = ko.observable(null);

        function onFetchSuccess(response) {
            var node = response.node;
            self.privateLinks(ko.utils.arrayMap(node.private_links, function(link) {
                return new LinkViewModel(link, self);
            }));
            self.nodeUrl(node.absolute_url);
        }

        function onFetchError() {
          //TODO
          console.log('an error occurred');
        }

        function fetch() {
            $.ajax({url: url, type: 'GET', dataType: 'json',
              success: onFetchSuccess,
              error: onFetchError
            });
        }

        fetch();

        self.removeLink = function(data){
            var data_to_send={
                'private_link_id': data.id
            };
            bootbox.confirm('Are you sure to remove this private link?', function(result) {
                if (result) {
                    $.ajax({
                        type: "delete",
                        url: nodeApiUrl + "private_link/",
                        contentType: "application/json",
                        dataType: "json",
                        data: JSON.stringify(data_to_send),
                        success: function(response) {
                            self.privateLinks.remove(data);
                        },
                        error: function(xhr) {
                            bootbox.alert("Failed to delete the private link.")
                        }
                    });
                }
             });
        };

        self.updateClipboard = function(elm) {

            var $tr = $(elm);
            // Add this to client
            var target = $tr.find('.copy-button');
            updateClipboard(target);
            $tr.find('.remove-private-link').tooltip();
        };

    }

    function PrivateLinkTable (selector, url) {
        var self = this;
        self.viewModel = new ViewModel(url);
        $.osf.applyBindings(self.viewModel, selector);

    }
    return PrivateLinkTable;

}));
<|endoftext|>


<commit_before>const winston = require('winston');

let logLevel;

switch (process.env.NODE_ENV) {
	case 'development':
		logLevel = 'debug';
		break;
	case 'test':
		logLevel = 'error';
		break;
	case 'production':
	default:
		logLevel = 'info';
}

const logger = winston.createLogger({
	levels: winston.config.syslog.levels,
	format: winston.format.combine(
		winston.format.timestamp(), // adds current timestamp
		winston.format.ms(),	// adds time since last log
		winston.format.simple(), // output as string. Use 'winston.format.prettyPrint()' for well formated json
	),
	transports: [
		new winston.transports.Console({
			level: logLevel,
			handleExceptions: true,
		}),
	],
	exitOnError: false,
});

module.exports = logger;
<commit_msg>workaround to get all messages<commit_after>const winston = require('winston');
const SPLAT = Symbol.for('splat');

let logLevel;

switch (process.env.NODE_ENV) {
	case 'development':
		logLevel = 'debug';
		break;
	case 'test':
		logLevel = 'error';
		break;
	case 'production':
	default:
		logLevel = 'info';
}

// const all = winston.format(function () { return {message: 'abc'}}); //Array.from(arguments).join(' ')} });

function formatObject(param) {
	if (typeof param === 'object') {
		return JSON.stringify(param);
	}
	return param;
}

// workaround to call log functions with multiple message parameter.
// example: logger.info('first', 'secound', 'some other string')
const all = winston.format((info) => {
	const splat = info[SPLAT] || [];

	const isSplatTypeMessage = typeof info.message === 'string'
		&& (info.message.includes('%s') || info.message.includes('%d') || info.message.includes('%j'));
	if (isSplatTypeMessage) {
		return info;
	}
	const message = formatObject(info.message);
	const rest = splat
		.map(formatObject)
		.join(' ');
	info.message = `${message} ${rest}`;
	return info;
});

const logger = winston.createLogger({
	levels: winston.config.syslog.levels,
	format: winston.format.combine(
		all(),
		winston.format.timestamp(), // adds current timestamp
		winston.format.ms(),	// adds time since last log
		winston.format.prettyPrint(), // output as string. Use 'winston.format.prettyPrint()' for well formated json
	),
	transports: [
		new winston.transports.Console({
			level: logLevel,
			handleExceptions: true,
		}),
	],
	exitOnError: false,
});

module.exports = logger;
<|endoftext|>


<commit_before>
'use strict';

const debug = require('debug')('model-pa');
const _ = require('lodash');
const PoliticalParties = require('uk-political-parties');
const xml2js = require('xml2js').parseString;

const db = require('../loki');
const model = require('./index.js');
const f = model.factory;
const Types = require('./types');

exports.SOP_xml_to_PartyNationalResults = function(file, xml) {

  var parties = xml.FirstPastThePostStateOfParties.Parties[0].Party;
  var sop = xml.FirstPastThePostStateOfParties.$;
  var seats_so_far = Number(sop.numberOfResults) || 0;
  var total_seats_available = Number(sop.totalNumberOfConstituencies) || 650;
  var votes_so_far = Number(sop.totalVotes) || 0;

  /*
  TODO: how do we get the size of the turnout? is it the vote size after 650 seats?
  TODO: do we want to use the party's %-change field in any way? <Party percentageChange="+21.58">
  TODO: how do we get seats_change and seats_change_pc? is this only relevant at the end of the night?
  TODO: we need a place in the DB to store high level numbers like turnout and electorate size.
  TODO: might be useful to make a special table of gains an losses for each party
  */
  var others = {};
  others.id = 'other',
  others.election = f.PartyNationalResult({revision: file.revision});
  others.election.other_parties = [];

  var results = parties.reduce(function(result, node) {
    var party = node.$;
    var code = PoliticalParties.paToCode(party.abbreviation);

    var o = {
      pa_number: party.paId,
      election: f.PartyNationalResult({
        votes: party.totalVotes,
        votes_pc: party.percentageShare,
        seats: party.totalSeats,
        seats_pc_so_far: Number(party.totalSeats) / (seats_so_far / 100),
        seats_gain: party.gains,
        seats_loss: party.losses,
        pa_forecast: party.forecastSeats ? Number(party.forecastSeats) : null,
        revision: file.revision
      })
    };

    // Once the last results are called, the PA stop sending a
    // forecast. Fill in the missing data here for anything
    // still needing the forecast.
    if (seats_so_far >= total_seats_available && !o.election.pa_forecast) {
      o.election.pa_forecast = o.election.seats;
    }

    if (PoliticalParties.isKnownParty(code)) {
      o.id = code;
      result.push(o);
    } else {
      o.id = 'other';
      o.election.other_party_name = party.name;

      // for reference, keep are record of all the parties that come under 'other'
      others.election.other_parties.push(o);

      // aggregate the numbers for all the other parties
      others.election.votes += o.election.votes;
      others.election.votes_pc += o.election.votes_pc;
      others.election.seats += o.election.seats;
      others.election.seats_pc += o.election.seats_pc;
      others.election.seats_pc_so_far += o.election.seats_pc_so_far;
      others.election.seats_gain += o.election.seats_gain;
      others.election.seats_loss += o.election.seats_loss;
      others.election.seats_net_gain += o.election.seats_net_gain;
      others.election.pa_forecast += o.election.pa_forecast;
    }
    return result;
  }, []);

  // We don't need so much data for all the 'other' parties.
  others.election.other_parties = others.election.other_parties.map(function(p) {
    return {
      pa_number: p.pa_number,
      name: p.election.other_party_name,
      seats: p.election.seats,
      votes: p.election.votes,
      votes_pc: p.election.votes_pc
    };
  });

  results.push(others);

  // TODO: what we going to do with all the other data?
  return {
    parties: results,
    votes_so_far: votes_so_far,
    seats_so_far: seats_so_far,
    pa_forecast_majority: sop.forecastMajority ? Number(sop.forecastMajority) : null,
    source: {
      message: sop.forecastWinningParty || '',
      note: sop.note || '',
      filename: file.name,
      revision: file.revision,
    }
  };

};

exports.update_party_results = function(file, xml, callback) {

  xml2js(xml, function(parseErr, result) {
    if (parseErr) {
      callback(parseErr);
      return;
    }

    var o = exports.SOP_xml_to_PartyNationalResults(file, result);
    var updating = o.parties.map(function(party) {

      var existing = db.getCollection('parties').findOne({id: party.id});

      if (!existing) {
        console.error('SOP has unknown party');
        return existing;
      }

      var existingElection = existing.elections.ge15;
      var election = party.election;
      var can_update = election.revision > existingElection.revision;

      if (can_update) {
        existingElection.votes = election.votes;
        existingElection.votes_pc = election.votes_pc;
        existingElection.seats = election.seats,
        existingElection.seats_pc = election.seats_pc;
        existingElection.seats_pc_so_far = election.seats_pc_so_far;
        existingElection.seats_gain = election.seats_gain;
        existingElection.seats_loss = election.seats_loss;
        existingElection.seats_net_gain = election.seats_net_gain;
        existingElection.pa_forecast = election.pa_forecast || existingElection.pa_forecast;
        existingElection.revision = election.revision;
        if (election.other_parties) {
          existingElection.other_parties = election.other_parties;
        }
        existingElection.seats_change = existingElection.seats - existing.elections.last.seats;
        existingElection.seats_change_pc = existingElection.seats_pc - existing.elections.last.seats_pc;
      }

      return existing;
    });

    db.getCollection('parties').update(updating);

    // TODO: this is where we would update the db with high level stats for the whole GE

    callback();
  });
};

exports.update_seat_result = function(file, xml, callback) {

  xml2js(xml, function(parseErr, result) {
    if (parseErr) {
      debug('parse err');
      callback(parseErr);
      return;
    }

    var pa_id;
    var type;

    if (file.type === Types.RECOUNT) {
      type = Types.RECOUNT;
      pa_id = result.Recount.Election[0].Constituency[0].$.number;
    } else if (file.type === Types.RUSH) {
      pa_id = result.FirstPastThePostRush.Election[0].Constituency[0].$.number;
      type = Types.RUSH;
    } else if (file.type === Types.RESULT) {
      pa_id = result.FirstPastThePostResult.Election[0].Constituency[0].$.number;
      type = Types.RESULT;
    }

    if (!type) {
      callback(new Error('File type is not recognised'));
      return;
    }

    if (!pa_id) {
      callback(new Error('XML does not have a PA Seat ID'));
      return;
    }

    debug('Find seat data for pa_id=' + pa_id);

    var collection = db.getCollection('seats');
    var seat = collection.findOne({pa_id: pa_id});

    if (!seat) {
      callback(new Error('Cannot find PA Seat ID ' + pa_id + ' in the DB'));
      return;
    }

    var message_context = '. type=' + type + ' file=' + file.name + ' revision=' + file.revision + ' id=' + seat.id + ' name=' + seat.name + ' pa_id=' + pa_id;

    debug('Process type=' + type + message_context);

    if (type === Types.RECOUNT) {
      // TODO: proper recount implementation
      seat.elections.ge15.recount = true;
      collection.update(seat);
      callback();
      return;
    }

    var existing_type = seat.elections.ge15.source && typeof seat.elections.ge15.source.type === 'number' ? seat.elections.ge15.source.type : Types.NOT_CALLED;
    var existing_revision = seat.elections.ge15.source && typeof seat.elections.ge15.source.revision === 'number' ? seat.elections.ge15.source.revision : 0;

    message_context += ' current=(type:' + existing_type + ',revision:' + existing_revision + ')';

    // We only want to think about cancelling the update
    // if we already have results data
    if (existing_type > Types.NOT_CALLED) {

      if (type === Types.RUSH) {

        if (existing_type === Types.RESULT && existing_revision > file.revision) {
          debug('Dont update rush, already have result' + message_context);
          callback();
          return;
        }

        if (existing_revision >= file.revision) {
          debug('Dont update rush, later revision (or correction) already received' + message_context);
          callback();
          return;
        }

      } else if (type === Types.RESULT) {

        if (existing_type === Types.RESULT && existing_revision >= file.revision) {
          debug('Dont update result, later revision already received'  + message_context);
          callback();
          return;
        }

      } else {
        callback(new Error('This should not happen'));
        return;
      }
    }

    debug('Adding ' + (type === Types.RESULT ? 'result' : 'rush') + ' data.'  + message_context);

    // create a new election object the reflect what's
    // contained in the new XML from the PA feed.
    var data = exports.seat_xml_to_result(type, file, result);

    // apply all the new data to the seat object
    seat.elections.ge15 = data;

    // update the object
    collection.update(seat);

// console.dir(seat);
// console.dir(seat.elections.ge15);
    callback();

  });
};

function candidateXMLtoSeatPartyResult(node) {
  var party = node.Party[0].$;
  var pa_party_abbrv = party.abbreviation.toLowerCase();
  // handle Scottish Labour candidates that style themselves as Labout Co-op
  if (pa_party_abbrv === 'lab co-op') {
    party.abbreviation = PoliticalParties.data.lab.id;
  } else if (pa_party_abbrv === 'the speaker' || pa_party_abbrv === 'speaker') {
    party.abbreviation = PoliticalParties.data.c.id;
  }

  var candidate = node.$;
  var code = PoliticalParties.paToCode(party.abbreviation);
  var o = f.SeatPartyResult({
    person: candidate.firstName + ' ' + candidate.surname,
    winner: candidate.elected === '*',
    loser: false,
    votes: Number(party.votes),
    votes_pc: Number(party.percentageShare)
  });

  if (!o.winner && candidate.previousSittingMember === '*') {
    o.loser = candidate.previousSittingMember === '*';
  }

  // TODO: add "person_of_note_field"
  //       by combining some bertha data and PA data

  if (PoliticalParties.isKnownParty(code)) {
    o.party = code;
  } else {
    o.party = 'other';
    o.other_party_name = party.name;
  }
  return o;
}

exports.seat_xml_to_result = function(type, file, xml) {
  var node_name;

  if (type === Types.RUSH) {
    node_name = 'FirstPastThePostRush';
  } else if (type === Types.RESULT){
    node_name = 'FirstPastThePostResult';
  } else {
    throw new Error('Cannot convert type ' + type);
  }
  var node = xml[node_name];

  if (!node) {
    throw new Error('Cannot find node ' + node_name);
  }

  var constituency = node.Election[0].Constituency[0].$;
  var declation_time = node.$.declarationTime ? new Date(node.$.declarationTime) : null;
  var candidates = node.Election[0].Constituency[0].Candidate;

  var data = f.SeatElectionResult({
    turnout: constituency.turnout,
    turnout_pc: constituency.percentageTurnout,
    turnout_pc_change: constituency.percentageChangeTurnout,
    electorate: constituency.electorate,
    change: !!constituency.gainOrHold ? constituency.gainOrHold.toLowerCase() !== 'hold' : false,
  });

  data.source = f.SeatResultDataSource(file, type, declation_time, constituency.paStyleMessageText || '');
  data.results = candidates.map(candidateXMLtoSeatPartyResult);

  var winnerIndex = _.findIndex(data.results, 'winner');
  var winner = winnerIndex !== -1 ? data.results[winnerIndex] : null;

  if (winner) {
    winner.majority = constituency.majority ? Number(constituency.majority) : null;
    winner.majority_pc = constituency.percentageMajority ? Number(constituency.percentageMajority) : null;
    data.winner = winner;
  } else {
    data.winner = f.SeatPartyResult();
  }

  data.others = data.results.reduce(function(others, result) {
    if (result.votes && result.party === 'other') {
      others.votes += result.votes;
      others.votes_pc += result.votes_pc;
    }
    return others;
  }, {votes: 0, votes_pc: 0});

  return data;
};
<commit_msg>Fix Lab Co-op<commit_after>
'use strict';

const debug = require('debug')('model-pa');
const _ = require('lodash');
const PoliticalParties = require('uk-political-parties');
const xml2js = require('xml2js').parseString;

const db = require('../loki');
const model = require('./index.js');
const f = model.factory;
const Types = require('./types');

exports.SOP_xml_to_PartyNationalResults = function(file, xml) {

  var parties = xml.FirstPastThePostStateOfParties.Parties[0].Party;
  var sop = xml.FirstPastThePostStateOfParties.$;
  var seats_so_far = Number(sop.numberOfResults) || 0;
  var total_seats_available = Number(sop.totalNumberOfConstituencies) || 650;
  var votes_so_far = Number(sop.totalVotes) || 0;

  /*
  TODO: how do we get the size of the turnout? is it the vote size after 650 seats?
  TODO: do we want to use the party's %-change field in any way? <Party percentageChange="+21.58">
  TODO: how do we get seats_change and seats_change_pc? is this only relevant at the end of the night?
  TODO: we need a place in the DB to store high level numbers like turnout and electorate size.
  TODO: might be useful to make a special table of gains an losses for each party
  */
  var others = {};
  others.id = 'other',
  others.election = f.PartyNationalResult({revision: file.revision});
  others.election.other_parties = [];

  var results = parties.reduce(function(result, node) {
    var party = node.$;
    var code = PoliticalParties.paToCode(party.abbreviation);

    var o = {
      pa_number: party.paId,
      election: f.PartyNationalResult({
        votes: party.totalVotes,
        votes_pc: party.percentageShare,
        seats: party.totalSeats,
        seats_pc_so_far: Number(party.totalSeats) / (seats_so_far / 100),
        seats_gain: party.gains,
        seats_loss: party.losses,
        pa_forecast: party.forecastSeats ? Number(party.forecastSeats) : null,
        revision: file.revision
      })
    };

    // Once the last results are called, the PA stop sending a
    // forecast. Fill in the missing data here for anything
    // still needing the forecast.
    if (seats_so_far >= total_seats_available && !o.election.pa_forecast) {
      o.election.pa_forecast = o.election.seats;
    }

    if (PoliticalParties.isKnownParty(code)) {
      o.id = code;
      result.push(o);
    } else {
      o.id = 'other';
      o.election.other_party_name = party.name;

      // for reference, keep are record of all the parties that come under 'other'
      others.election.other_parties.push(o);

      // aggregate the numbers for all the other parties
      others.election.votes += o.election.votes;
      others.election.votes_pc += o.election.votes_pc;
      others.election.seats += o.election.seats;
      others.election.seats_pc += o.election.seats_pc;
      others.election.seats_pc_so_far += o.election.seats_pc_so_far;
      others.election.seats_gain += o.election.seats_gain;
      others.election.seats_loss += o.election.seats_loss;
      others.election.seats_net_gain += o.election.seats_net_gain;
      others.election.pa_forecast += o.election.pa_forecast;
    }
    return result;
  }, []);

  // We don't need so much data for all the 'other' parties.
  others.election.other_parties = others.election.other_parties.map(function(p) {
    return {
      pa_number: p.pa_number,
      name: p.election.other_party_name,
      seats: p.election.seats,
      votes: p.election.votes,
      votes_pc: p.election.votes_pc
    };
  });

  results.push(others);

  // TODO: what we going to do with all the other data?
  return {
    parties: results,
    votes_so_far: votes_so_far,
    seats_so_far: seats_so_far,
    pa_forecast_majority: sop.forecastMajority ? Number(sop.forecastMajority) : null,
    source: {
      message: sop.forecastWinningParty || '',
      note: sop.note || '',
      filename: file.name,
      revision: file.revision,
    }
  };

};

exports.update_party_results = function(file, xml, callback) {

  xml2js(xml, function(parseErr, result) {
    if (parseErr) {
      callback(parseErr);
      return;
    }

    var o = exports.SOP_xml_to_PartyNationalResults(file, result);
    var updating = o.parties.map(function(party) {

      var existing = db.getCollection('parties').findOne({id: party.id});

      if (!existing) {
        console.error('SOP has unknown party');
        return existing;
      }

      var existingElection = existing.elections.ge15;
      var election = party.election;
      var can_update = election.revision > existingElection.revision;

      if (can_update) {
        existingElection.votes = election.votes;
        existingElection.votes_pc = election.votes_pc;
        existingElection.seats = election.seats,
        existingElection.seats_pc = election.seats_pc;
        existingElection.seats_pc_so_far = election.seats_pc_so_far;
        existingElection.seats_gain = election.seats_gain;
        existingElection.seats_loss = election.seats_loss;
        existingElection.seats_net_gain = election.seats_net_gain;
        existingElection.pa_forecast = election.pa_forecast || existingElection.pa_forecast;
        existingElection.revision = election.revision;
        if (election.other_parties) {
          existingElection.other_parties = election.other_parties;
        }
        existingElection.seats_change = existingElection.seats - existing.elections.last.seats;
        existingElection.seats_change_pc = existingElection.seats_pc - existing.elections.last.seats_pc;
      }

      return existing;
    });

    db.getCollection('parties').update(updating);

    // TODO: this is where we would update the db with high level stats for the whole GE

    callback();
  });
};

exports.update_seat_result = function(file, xml, callback) {

  xml2js(xml, function(parseErr, result) {
    if (parseErr) {
      debug('parse err');
      callback(parseErr);
      return;
    }

    var pa_id;
    var type;

    if (file.type === Types.RECOUNT) {
      type = Types.RECOUNT;
      pa_id = result.Recount.Election[0].Constituency[0].$.number;
    } else if (file.type === Types.RUSH) {
      pa_id = result.FirstPastThePostRush.Election[0].Constituency[0].$.number;
      type = Types.RUSH;
    } else if (file.type === Types.RESULT) {
      pa_id = result.FirstPastThePostResult.Election[0].Constituency[0].$.number;
      type = Types.RESULT;
    }

    if (!type) {
      callback(new Error('File type is not recognised'));
      return;
    }

    if (!pa_id) {
      callback(new Error('XML does not have a PA Seat ID'));
      return;
    }

    debug('Find seat data for pa_id=' + pa_id);

    var collection = db.getCollection('seats');
    var seat = collection.findOne({pa_id: pa_id});

    if (!seat) {
      callback(new Error('Cannot find PA Seat ID ' + pa_id + ' in the DB'));
      return;
    }

    var message_context = '. type=' + type + ' file=' + file.name + ' revision=' + file.revision + ' id=' + seat.id + ' name=' + seat.name + ' pa_id=' + pa_id;

    debug('Process type=' + type + message_context);

    if (type === Types.RECOUNT) {
      // TODO: proper recount implementation
      seat.elections.ge15.recount = true;
      collection.update(seat);
      callback();
      return;
    }

    var existing_type = seat.elections.ge15.source && typeof seat.elections.ge15.source.type === 'number' ? seat.elections.ge15.source.type : Types.NOT_CALLED;
    var existing_revision = seat.elections.ge15.source && typeof seat.elections.ge15.source.revision === 'number' ? seat.elections.ge15.source.revision : 0;

    message_context += ' current=(type:' + existing_type + ',revision:' + existing_revision + ')';

    // We only want to think about cancelling the update
    // if we already have results data
    if (existing_type > Types.NOT_CALLED) {

      if (type === Types.RUSH) {

        if (existing_type === Types.RESULT && existing_revision > file.revision) {
          debug('Dont update rush, already have result' + message_context);
          callback();
          return;
        }

        if (existing_revision >= file.revision) {
          debug('Dont update rush, later revision (or correction) already received' + message_context);
          callback();
          return;
        }

      } else if (type === Types.RESULT) {

        if (existing_type === Types.RESULT && existing_revision >= file.revision) {
          debug('Dont update result, later revision already received'  + message_context);
          callback();
          return;
        }

      } else {
        callback(new Error('This should not happen'));
        return;
      }
    }

    debug('Adding ' + (type === Types.RESULT ? 'result' : 'rush') + ' data.'  + message_context);

    // create a new election object the reflect what's
    // contained in the new XML from the PA feed.
    var data = exports.seat_xml_to_result(type, file, result);

    // apply all the new data to the seat object
    try{

      var old = seat.elections.ge15;

      if (old.source.message && !data.source.message) {
        data.source.message = old.source.message;
      }

    } catch(e) {}

    seat.elections.ge15 = data;

    // update the object
    collection.update(seat);

// console.dir(seat);
// console.dir(seat.elections.ge15);
    callback();

  });
};

function candidateXMLtoSeatPartyResult(node) {
  var party = node.Party[0].$;
  var pa_party_abbrv = party.abbreviation.toLowerCase();
    // handle Scottish Labour candidates that style themselves as Labout Co-op
  if (pa_party_abbrv === 'lab co-op') {
    party.abbreviation = PoliticalParties.data.lab.pa;
  } else if (pa_party_abbrv === 'the speaker' || pa_party_abbrv === 'speaker') {
    party.abbreviation = PoliticalParties.data.c.pa;
  }

  var candidate = node.$;
  var code = PoliticalParties.paToCode(party.abbreviation);
  var o = f.SeatPartyResult({
    person: candidate.firstName + ' ' + candidate.surname,
    winner: candidate.elected === '*',
    loser: false,
    votes: Number(party.votes),
    votes_pc: Number(party.percentageShare)
  });

  if (!o.winner && candidate.previousSittingMember === '*') {
    o.loser = candidate.previousSittingMember === '*';
  }

  // TODO: add "person_of_note_field"
  //       by combining some bertha data and PA data
  if (PoliticalParties.isKnownParty(code)) {
    o.party = code;
  } else {
    o.party = 'other';
    o.other_party_name = party.name;
  }
  return o;
}

exports.seat_xml_to_result = function(type, file, xml) {
  var node_name;

  if (type === Types.RUSH) {
    node_name = 'FirstPastThePostRush';
  } else if (type === Types.RESULT){
    node_name = 'FirstPastThePostResult';
  } else {
    throw new Error('Cannot convert type ' + type);
  }
  var node = xml[node_name];

  if (!node) {
    throw new Error('Cannot find node ' + node_name);
  }

  var constituency = node.Election[0].Constituency[0].$;
  var declation_time = node.$.declarationTime ? new Date(node.$.declarationTime) : null;
  var candidates = node.Election[0].Constituency[0].Candidate;

  var data = f.SeatElectionResult({
    turnout: constituency.turnout,
    turnout_pc: constituency.percentageTurnout,
    turnout_pc_change: constituency.percentageChangeTurnout,
    electorate: constituency.electorate,
    change: !!constituency.gainOrHold ? constituency.gainOrHold.toLowerCase() !== 'hold' : false,
  });

  data.source = f.SeatResultDataSource(file, type, declation_time, constituency.paStyleMessageText || '');
  data.results = candidates.map(candidateXMLtoSeatPartyResult);

  var winnerIndex = _.findIndex(data.results, 'winner');
  var winner = winnerIndex !== -1 ? data.results[winnerIndex] : null;

  if (winner) {
    winner.majority = constituency.majority ? Number(constituency.majority) : null;
    winner.majority_pc = constituency.percentageMajority ? Number(constituency.percentageMajority) : null;
    data.winner = winner;
  } else {
    data.winner = f.SeatPartyResult();
  }

  data.others = data.results.reduce(function(others, result) {
    if (result.votes && result.party === 'other') {
      others.votes += result.votes;
      others.votes_pc += result.votes_pc;
    }
    return others;
  }, {votes: 0, votes_pc: 0});

  return data;
};
<|endoftext|>