<commit_before>import React, { Component, PropTypes } from 'react'
import R from 'ramda'
import s from './OrganizationEdit.css'
import icons from '../../icons/css/fontello.css'
import history from '../../core/history'

import { taxonomiesWithIcons } from '../../lib/taxonomies'
import { redirectTo } from '../../lib/navigation'
import { uuid } from '../../lib/uuid'
import {
  fetchLocations,
  updateLocation,
  deleteLocation,
  updateOrganization,
  deleteOrganization,
  fetchTaxonomies
} from '../../core/firebaseRestAPI'

import Banner from '../Banner'
import LocationEdit from '../LocationEdit'
import ToggleButton from '../ToggleButton'
import PhoneEdit from '../PhoneEdit'

const changesMessage = "There are unsaved changes. Are you sure you want to discard them?"

const blankPhone = () => ({
  department: "",
  number: ""
})

const blankLocation = (organization) => ({
  id: uuid(),
  description: "",
  latitude: 0,
  longitude: 0,
  name: "",
  organizationId: organization.id || "",
  physicalAddress: {
    address1: "",
    city: ""
  }
})

class OrganizationEdit extends Component {
  constructor(props) {
    const tempProps = Object.assign({}, props)

    super(props)
    this.state = {
      changesExist: false,
      hasSubmit: false,
      submitResult: true,
      organization: tempProps.organization,
      locations: [],
      selectedLocation: null,
      selectedService: null
    }
  }

  componentDidMount() {
    this.refreshLocations()
    this.refreshTaxonomies()
    const currentLocation = window.location.pathname

    history.listenBeforeUnload(_ => (this.state.changesExist ? changesMessage : null))

    // If there are changes and the user tries to click the back button, so we
    // prompt them if it is okay. The caveat is that regardless of the users
    // answer, the history stack and URL have already been modified. So if we
    // are executing the back action (action == POP), then push the current page
    // back onto the stack, otherwise proceed as normal.
    history.listenBefore((location, callback) => {
      if (location.action === "POP" && this.state.changesExist) {
        if (confirm(changesMessage)) {
          callback()
        } else {
          history.push(currentLocation)
        }
      } else {
        callback()
      }
    })
  }

  //TODO: only fetch locations for org rather than filter them down after
  refreshLocations = () => {
    const { organization } = this.state

    fetchLocations()
      .then(locations => (
        locations.filter(location => (
          location.organizationId == organization.id
        ))
      ))
      .then(locations => {
        this.setState({ locations })
      })
  }

  refreshTaxonomies = () => {
    fetchTaxonomies()
      .then(taxonomies => {
        this.setState({
          taxonomies: taxonomiesWithIcons(taxonomies)
        })
      })
  }

  handleDeleteOrganization = () => {
    const { organization } = this.state
    const answer = confirm(`Are you sure you want to delete ${organization.name}? You cannot undo this or recover the data.`)

    if (answer) {
      deleteOrganization(organization.id)
      locations.map(location => {
        deleteLocation(location.id)
      }).then(() => redirectTo('/admin'))
    }
  }

  // Updates our representation of the organization in the state
  handleChange = (property, event) => {
    const { organization } = this.state
    const newOrganization = {}

    newOrganization[property] = event.target.value

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: updatedOrganization,
      changesExist: true,
    })
  }

  handlePhones = (property, newValue, index) => {
    const { organization } = this.state

    const newPhone = {}
    newPhone[property] = newValue

    const newPhones = [...organization.phones]
    newPhones[index] = R.merge(newPhones[index], newPhone)

    const newOrganization = {}
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: updatedOrganization,
      changesExist: true,
    })
  }

  newPhone = () => {
    const { organization } = this.state
    const newPhones = [...organization.phones]
    const newOrganization = {}

    newPhones.push(blankPhone())
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({ organization: updatedOrganization })
  }

  deletePhone = (index) => {
    const { organization } = this.state
    const newPhones = [...organization.phones]
    const newOrganization = {}

    newPhones.splice(index, 1)
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: newOrganization,
      changesExist: true,
    })
  }

  handleStateUpdate = (update) => {
    this.setState(update)
  }

  handleLocations = (newLocation, index, save) => {
    const { locations } = this.state
    const newLocations = [...locations]

    newLocations[index] = newLocation

    if (save) {
      updateLocation(newLocation).then(response => {
        let success = !response.hasOwnProperty('error')
        this.setState({
          hasSubmit: true,
          submitResult: success,
          changesExist: !success
        })
      })
    }

    this.setState({
      locations: newLocations,
      changesExist: !save,
    })
  }

  newLocation = () => {
    const { organization, locations } = this.state
    const newLocations = [...locations]

    const newLocation = blankLocation(organization)
    newLocations.push(newLocation)

    this.setState({
      locations: newLocations,
      selectedLocation: newLocation,
      selectedService: null,
    })
  }

  handleDeleteLocation = (index) => {
    const { locations } = this.state
    const location = locations[index]
    const answer = confirm(`Are you sure you want to delete the location: ${location.name}? You cannot undo this or recover the data.`)

    if (answer) {
      deleteLocation(location.id)
        .then(response => {
          let success = !response.hasOwnProperty('error')
          const newLocations = [...locations]

          if (success) {
            newLocations.splice(index, 1)
            this.setState({
              locations: newLocations,
              selectedLocation: null,
              selectedLocationIndex: null,
              submitResult: success,
              changesExist: false
            })
          }

        })
    }
  }

  handleSubmit = ()  => {
    const { organization, locations } = this.state

    // Clear the banner if you click submit
    this.setState({
      hasSubmit: false
    })

    updateOrganization(organization).then(response => {
      let success = !response.hasOwnProperty('error')
      this.setState({
        hasSubmit: true,
        submitResult: success,
        changesExist: !success
      })
    })

    locations.map(location => {
      updateLocation(location).then(response => {
        let success = !response.hasOwnProperty('error')
        this.setState({
          hasSubmit: true,
          submitResult: success,
          changesExist: !success
        })
      })
    })

    redirectTo('/admin')
  }

  handleReset = () => {
    const { organization } = this.props

    this.setState({
      organization,
      locations: [],
      selectedLocation: null,
      selectedService: null,
      changesExist: false,
    }, _ => {
      this.refreshLocations()
      this.refreshTaxonomies()
    })
  }

  selectLocation = (location, index) => {
    this.setState({
      selectedLocation: location,
      selectedLocationIndex: index,
      selectedService: null,
    })
  }

  locationSelected = (location) => {
    return this.state.selectedLocation && this.state.selectedLocation.id == location.id
  }

  render() {
    const {
      hasSubmit,
      submitResult,
      organization,
      locations,
      selectedLocation,
      selectedLocationIndex,
      selectedService,
      taxonomies
    } = this.state

    return (

          <Banner show={hasSubmit} isGood={submitResult} />

{ organization.name || 'New Organization' }

              Name
              <input
                className={s.input}
                type="text"
                value={organization.name}
                onChange={(e) => this.handleChange('name', e)}
              />

              Website
              <input
                className={s.input}
                type="text"
                value={organization.url}
                onChange={(e) => this.handleChange('url', e)}
              />

              Description
              <textarea
                className={s.input + ' ' + s.description}
                value={organization.longDescription}
                onChange={(e) => this.handleChange('longDescription', e)}
              />

          Phone Numbers
          <button
            className={s.addToSubsection}
            onClick={this.newPhone}
            title={`Click to add a new phone`}>
            + Add
          </button>

          {organization.phones.map((phone, index) => (
            <PhoneEdit
              key={`phone-${index}`}
              phone={phone}
              index={index}
              handleChange={this.handlePhones}
              handleDelete={this.deletePhone} />
          ))}

            Locations
            <button
              className={s.addToSubsection}
              onClick={this.newLocation}
              title={`Click to add a new location`}>
              + Add
            </button>

            {locations.map((location, index) => (
              <ToggleButton
                key={`location-${location.id}`}
                enabled={this.locationSelected(location)}
                onClick={(e) => this.selectLocation(location, index)}
                label={location.name || "Location"}
              />
            ))}

            {selectedLocation ? <LocationEdit
                  location={selectedLocation}
                  index={selectedLocationIndex}
                  selectedService={selectedService}
                  handleStateUpdate={this.handleStateUpdate}
                  handleChange={this.handleLocations}
                  handleDelete={this.handleDeleteLocation}
                  taxonomies={taxonomies}
                /> : null}

          <button className={`${s.buttonStyle} ${s.submitButton}`} onClick={this.handleSubmit}>Submit</button>
          <button className={s.buttonStyle} onClick={this.handleReset}>Reset</button>
          <button className={`${s.buttonStyle} ${s.deleteButton}`} onClick={this.handleDeleteOrganization}>Delete this Organization</button>

    )
  }
}

export default OrganizationEdit
<commit_msg>Fix org deletion<commit_after>import React, { Component, PropTypes } from 'react'
import R from 'ramda'
import s from './OrganizationEdit.css'
import icons from '../../icons/css/fontello.css'
import history from '../../core/history'

import { taxonomiesWithIcons } from '../../lib/taxonomies'
import { redirectTo } from '../../lib/navigation'
import { uuid } from '../../lib/uuid'
import {
  fetchLocations,
  updateLocation,
  deleteLocation,
  updateOrganization,
  deleteOrganization,
  fetchTaxonomies
} from '../../core/firebaseRestAPI'

import Banner from '../Banner'
import LocationEdit from '../LocationEdit'
import ToggleButton from '../ToggleButton'
import PhoneEdit from '../PhoneEdit'

const changesMessage = "There are unsaved changes. Are you sure you want to discard them?"

const blankPhone = () => ({
  department: "",
  number: ""
})

const blankLocation = (organization) => ({
  id: uuid(),
  description: "",
  latitude: 0,
  longitude: 0,
  name: "",
  organizationId: organization.id || "",
  physicalAddress: {
    address1: "",
    city: ""
  }
})

class OrganizationEdit extends Component {
  constructor(props) {
    const tempProps = Object.assign({}, props)

    super(props)
    this.state = {
      changesExist: false,
      hasSubmit: false,
      submitResult: true,
      organization: tempProps.organization,
      locations: [],
      selectedLocation: null,
      selectedService: null
    }
  }

  componentDidMount() {
    this.refreshLocations()
    this.refreshTaxonomies()
    const currentLocation = window.location.pathname

    history.listenBeforeUnload(_ => (this.state.changesExist ? changesMessage : null))

    // If there are changes and the user tries to click the back button, so we
    // prompt them if it is okay. The caveat is that regardless of the users
    // answer, the history stack and URL have already been modified. So if we
    // are executing the back action (action == POP), then push the current page
    // back onto the stack, otherwise proceed as normal.
    history.listenBefore((location, callback) => {
      if (location.action === "POP" && this.state.changesExist) {
        if (confirm(changesMessage)) {
          callback()
        } else {
          history.push(currentLocation)
        }
      } else {
        callback()
      }
    })
  }

  //TODO: only fetch locations for org rather than filter them down after
  refreshLocations = () => {
    const { organization } = this.state

    fetchLocations()
      .then(locations => (
        locations.filter(location => (
          location.organizationId == organization.id
        ))
      ))
      .then(locations => {
        this.setState({ locations })
      })
  }

  refreshTaxonomies = () => {
    fetchTaxonomies()
      .then(taxonomies => {
        this.setState({
          taxonomies: taxonomiesWithIcons(taxonomies)
        })
      })
  }

  handleDeleteOrganization = () => {
    const { organization, locations } = this.state
    const answer = confirm(`Are you sure you want to delete ${organization.name}? You cannot undo this or recover the data.`)

    if (answer) {
      deleteOrganization(organization.id)
      locations.map(location => {
        deleteLocation(location.id)
      })
      redirectTo('/admin')
    }
  }

  // Updates our representation of the organization in the state
  handleChange = (property, event) => {
    const { organization } = this.state
    const newOrganization = {}

    newOrganization[property] = event.target.value

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: updatedOrganization,
      changesExist: true,
    })
  }

  handlePhones = (property, newValue, index) => {
    const { organization } = this.state

    const newPhone = {}
    newPhone[property] = newValue

    const newPhones = [...organization.phones]
    newPhones[index] = R.merge(newPhones[index], newPhone)

    const newOrganization = {}
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: updatedOrganization,
      changesExist: true,
    })
  }

  newPhone = () => {
    const { organization } = this.state
    const newPhones = [...organization.phones]
    const newOrganization = {}

    newPhones.push(blankPhone())
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({ organization: updatedOrganization })
  }

  deletePhone = (index) => {
    const { organization } = this.state
    const newPhones = [...organization.phones]
    const newOrganization = {}

    newPhones.splice(index, 1)
    newOrganization.phones = newPhones

    const updatedOrganization = R.merge(organization, newOrganization)

    this.setState({
      organization: newOrganization,
      changesExist: true,
    })
  }

  handleStateUpdate = (update) => {
    this.setState(update)
  }

  handleLocations = (newLocation, index, save) => {
    const { locations } = this.state
    const newLocations = [...locations]

    newLocations[index] = newLocation

    if (save) {
      updateLocation(newLocation).then(response => {
        let success = !response.hasOwnProperty('error')
        this.setState({
          hasSubmit: true,
          submitResult: success,
          changesExist: !success
        })
      })
    }

    this.setState({
      locations: newLocations,
      changesExist: !save,
    })
  }

  newLocation = () => {
    const { organization, locations } = this.state
    const newLocations = [...locations]

    const newLocation = blankLocation(organization)
    newLocations.push(newLocation)

    this.setState({
      locations: newLocations,
      selectedLocation: newLocation,
      selectedService: null,
    })
  }

  handleDeleteLocation = (index) => {
    const { locations } = this.state
    const location = locations[index]
    const answer = confirm(`Are you sure you want to delete the location: ${location.name}? You cannot undo this or recover the data.`)

    if (answer) {
      deleteLocation(location.id)
        .then(response => {
          let success = !response.hasOwnProperty('error')
          const newLocations = [...locations]

          if (success) {
            newLocations.splice(index, 1)
            this.setState({
              locations: newLocations,
              selectedLocation: null,
              selectedLocationIndex: null,
              submitResult: success,
              changesExist: false
            })
          }

        })
    }
  }

  handleSubmit = ()  => {
    const { organization, locations } = this.state

    // Clear the banner if you click submit
    this.setState({
      hasSubmit: false
    })

    updateOrganization(organization).then(response => {
      let success = !response.hasOwnProperty('error')
      this.setState({
        hasSubmit: true,
        submitResult: success,
        changesExist: !success
      })
    })

    locations.map(location => {
      updateLocation(location).then(response => {
        let success = !response.hasOwnProperty('error')
        this.setState({
          hasSubmit: true,
          submitResult: success,
          changesExist: !success
        })
      })
    })

    redirectTo('/admin')
  }

  handleReset = () => {
    const { organization } = this.props

    this.setState({
      organization,
      locations: [],
      selectedLocation: null,
      selectedService: null,
      changesExist: false,
    }, _ => {
      this.refreshLocations()
      this.refreshTaxonomies()
    })
  }

  selectLocation = (location, index) => {
    this.setState({
      selectedLocation: location,
      selectedLocationIndex: index,
      selectedService: null,
    })
  }

  locationSelected = (location) => {
    return this.state.selectedLocation && this.state.selectedLocation.id == location.id
  }

  render() {
    const {
      hasSubmit,
      submitResult,
      organization,
      locations,
      selectedLocation,
      selectedLocationIndex,
      selectedService,
      taxonomies
    } = this.state

    return (

          <Banner show={hasSubmit} isGood={submitResult} />

{ organization.name || 'New Organization' }

              Name
              <input
                className={s.input}
                type="text"
                value={organization.name}
                onChange={(e) => this.handleChange('name', e)}
              />

              Website
              <input
                className={s.input}
                type="text"
                value={organization.url}
                onChange={(e) => this.handleChange('url', e)}
              />

              Description
              <textarea
                className={s.input + ' ' + s.description}
                value={organization.longDescription}
                onChange={(e) => this.handleChange('longDescription', e)}
              />

          Phone Numbers
          <button
            className={s.addToSubsection}
            onClick={this.newPhone}
            title={`Click to add a new phone`}>
            + Add
          </button>

          {organization.phones.map((phone, index) => (
            <PhoneEdit
              key={`phone-${index}`}
              phone={phone}
              index={index}
              handleChange={this.handlePhones}
              handleDelete={this.deletePhone} />
          ))}

            Locations
            <button
              className={s.addToSubsection}
              onClick={this.newLocation}
              title={`Click to add a new location`}>
              + Add
            </button>

            {locations.map((location, index) => (
              <ToggleButton
                key={`location-${location.id}`}
                enabled={this.locationSelected(location)}
                onClick={(e) => this.selectLocation(location, index)}
                label={location.name || "Location"}
              />
            ))}

            {selectedLocation ? <LocationEdit
                  location={selectedLocation}
                  index={selectedLocationIndex}
                  selectedService={selectedService}
                  handleStateUpdate={this.handleStateUpdate}
                  handleChange={this.handleLocations}
                  handleDelete={this.handleDeleteLocation}
                  taxonomies={taxonomies}
                /> : null}

          <button className={`${s.buttonStyle} ${s.submitButton}`} onClick={this.handleSubmit}>Submit</button>
          <button className={s.buttonStyle} onClick={this.handleReset}>Reset</button>
          <button className={`${s.buttonStyle} ${s.deleteButton}`} onClick={this.handleDeleteOrganization}>Delete this Organization</button>

    )
  }
}

export default OrganizationEdit
<|endoftext|>


<commit_before>var robohydra     = require("robohydra"),
    heads         = robohydra.heads,
    RoboHydraHead = heads.RoboHydraHead;

exports.getBodyParts = function(conf) {
    "use strict";

    var delayMilliseconds = conf.delaymillis || 2000,
        delayPath = conf.delaypath || '/.*',
        delayDisabled = !!conf.delaydisabled;

    conf.robohydra.registerDynamicHead(new RoboHydraHead({
        name: 'delayer',
        path: delayPath,
        handler: function(req, res, next) {
            setTimeout(function() {
                next(req, res);
            }, delayMilliseconds);
        }
    }));

    return {
        heads: [
            new RoboHydraHead({
                name: 'delayer-config',
                detached: delayDisabled,
                path: '/robohydra-admin/delay/:delayValue',
                handler: function(req, res) {
                    delayMilliseconds = parseInt(req.params.delayValue, 10);
                    res.send("Delay is now set to " + delayMilliseconds +
                                 " milliseconds");
                }
            })
        ]
    };
};
<commit_msg>Oops, disabled the wrong head :-(<commit_after>var robohydra     = require("robohydra"),
    heads         = robohydra.heads,
    RoboHydraHead = heads.RoboHydraHead;

exports.getBodyParts = function(conf) {
    "use strict";

    var delayMilliseconds = conf.delaymillis || 2000,
        delayPath = conf.delaypath || '/.*',
        delayDisabled = !!conf.delaydisabled;

    conf.robohydra.registerDynamicHead(new RoboHydraHead({
        name: 'delayer',
        detached: delayDisabled,
        path: delayPath,
        handler: function(req, res, next) {
            setTimeout(function() {
                next(req, res);
            }, delayMilliseconds);
        }
    }));

    return {
        heads: [
            new RoboHydraHead({
                name: 'delayer-config',
                path: '/robohydra-admin/delay/:delayValue',
                handler: function(req, res) {
                    delayMilliseconds = parseInt(req.params.delayValue, 10);
                    res.send("Delay is now set to " + delayMilliseconds +
                                 " milliseconds");
                }
            })
        ]
    };
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'com.google.watlobby',
  name: 'AuthenticatedServer',
  requires: [
    'com.google.watlobby.Server',
    'foam.node.dao.JSONFileDAO',
    'foam.dao.GoogleAuthDAO',
    'foam.dao.auth.Account',
    'foam.dao.AuthorizedDAO',
  ],
  imports: [
    'exportDAO'
  ],
  properties: [
    {
      name: 'server',
      factory: function() { return this.Server.create(); }
    },
    {
      name: 'fs',
      factory: function() { return require('fs'); }
    },
    {
      name: 'accountDAO',
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          daoType: this.JSONFileDAO.xbind({
            filename: global.FOAM_BOOT_DIR + '/../js/com/google/watlobby/accounts_dao.json'
          }),
          model: this.Account
        });
        return this.GoogleAuthDAO.create({
          delegate: this.AuthorizedDAO.create({
            delegate: dao,
            authorizer: this
          }),
          model: this.Account,
          clientId: '495935970762-bmf0no7rttrjnobccog7a4cbnj9irm17.apps.googleusercontent.com'
        });
      }
    },
    {
      name: 'topicDAO',
      factory: function() {
        return this.GoogleAuthDAO.create({
          delegate: this.AuthorizedDAO.create({
            delegate: this.server.topicDAO,
            authorizer: this
          }),
          model: this.server.topicDAO.model,
          clientId: '495935970762-bmf0no7rttrjnobccog7a4cbnj9irm17.apps.googleusercontent.com'
        });
        return dao;
      }
    }
  ],
  methods: [
    function execute() {
      this.exportDAO(this.topicDAO);
      this.exportDAO(this.accountDAO);
    },
    function isAdmin(ret, principal) {
      this.accountDAO.find(principal, {
        put: function(o) {
          ret(o.level == "admin");
        },
        error: function() {
          // auto account creation.
          this.accountDAO.delegate.delegate.put(
            this.Account.create({
              id: principal
            }));
          ret(false);
        }.bind(this)
      });
    },
    function massageForPut(ret, principal, old, obj) {
      // Only put if admin.
      var self = this;
      aseq(
        function(ret) {
          self.isAdmin(ret, principal);
        },
        function(ret, admin) {
          if ( ! admin ) {
            var result = old.deepClone();
            result.selected = obj.selected;
            result.dir = obj.dir;
            ret(result);
          } else {
            ret(obj);
          }
        })(ret);
    },
    function shouldAllowRemove(ret, principal, obj) {
      // Only remove if admin
      this.isAdmin(ret, principal);
    },
    function massageForRead(ret, principal, obj) {
      // All data is public
      ret(obj);
    },
    function decorateForSelect(ret, principal, dao) {
      // All data is public.
      ret(dao);
    }
  ]
});
<commit_msg>WatLobby: Update authenticated server to new authenticator interface. Store emails in auto created users.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'com.google.watlobby',
  name: 'AuthenticatedServer',
  requires: [
    'com.google.watlobby.Server',
    'foam.node.dao.JSONFileDAO',
    'foam.dao.GoogleAuthDAO',
    'foam.dao.auth.Account',
    'foam.dao.AuthorizedDAO',
  ],
  imports: [
    'exportDAO'
  ],
  properties: [
    {
      name: 'server',
      factory: function() { return this.Server.create(); }
    },
    {
      name: 'fs',
      factory: function() { return require('fs'); }
    },
    {
      name: 'accountDAO',
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          daoType: this.JSONFileDAO.xbind({
            filename: global.FOAM_BOOT_DIR + '/../js/com/google/watlobby/accounts_dao.json'
          }),
          model: this.Account
        });
        return this.GoogleAuthDAO.create({
          delegate: this.AuthorizedDAO.create({
            delegate: dao,
            authorizer: this
          }),
          model: this.Account,
          clientId: '495935970762-bmf0no7rttrjnobccog7a4cbnj9irm17.apps.googleusercontent.com'
        });
      }
    },
    {
      name: 'topicDAO',
      factory: function() {
        return this.GoogleAuthDAO.create({
          delegate: this.AuthorizedDAO.create({
            delegate: this.server.topicDAO,
            authorizer: this
          }),
          model: this.server.topicDAO.model,
          clientId: '495935970762-bmf0no7rttrjnobccog7a4cbnj9irm17.apps.googleusercontent.com'
        });
        return dao;
      }
    }
  ],
  methods: [
    function execute() {
      this.exportDAO(this.topicDAO);
      this.exportDAO(this.accountDAO);
    },
    function isAdmin(ret, X) {
      if ( ! X.principal ) {
        ret(false);
        return;
      }

      this.accountDAO.find(X.principal, {
        put: function(o) {
          ret(o.level == "admin");
        },
        error: function() {
          // auto account creation.
          console.log("Auto adding account", X.email, X.principal);
          this.accountDAO.delegate.delegate.put(
            this.Account.create({
              id: X.principal,
              email: X.userInfo.email
            }));
          ret(false);
        }.bind(this)
      });
    },
    function massageForPut(ret, X, old, obj) {
      // Only put if admin.
      var self = this;
      aseq(
        function(ret) {
          self.isAdmin(ret, X);
        },
        function(ret, admin) {
          if ( ! admin ) {
            var result = old.deepClone();
            result.selected = obj.selected;
            result.dir = obj.dir;
            ret(result);
          } else {
            ret(obj);
          }
        })(ret);
    },
    function shouldAllowRemove(ret, X, obj) {
      // Only remove if admin
      this.isAdmin(ret, X);
    },
    function massageForRead(ret, X, obj) {
      // All data is public
      ret(obj);
    },
    function decorateForSelect(ret, X, dao) {
      // All data is public.
      ret(dao);
    }
  ]
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import { store as electronStore } from '@nuclear/core';

export default function (paths) {

  return next => (reducer, initialState, enhancer) => {
    if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
      enhancer = initialState;
      initialState = undefined;
    }

    // retrieve initial states from reducers, to apply prior to merging electron-store persisted-data
    const reducerInitialStates = reducer(undefined, {});

    let finalInitialState = _.merge({}, reducerInitialStates, initialState);

    try {
      for (const path of paths) {
        const persistedValue = electronStore.get(path);
        finalInitialState = _.setWith(_.clone(finalInitialState), path, persistedValue, _.clone); // deep, immutable set
      }
    } catch (e) {
      console.warn(
        'Failed to retrieve initialize state from electron store:',
        e
      );
    }

    const store = next(reducer, finalInitialState, enhancer);
    store.subscribe(() => {
      const state = store.getState();
      try {
        for (const path of paths) {
          const localState = _.get(state, path);
          if (localState) {
            electronStore.set(path, localState);
          }
        }
      } catch (e) {
        console.warn('Unable to persist state to electron store:', e);
      }
    });

    return store;
  };
}
<commit_msg>Fix disk usage issue (#912)<commit_after>import _ from 'lodash';
import { store as electronStore } from '@nuclear/core';

export default function (paths) {

  return next => (reducer, initialState, enhancer) => {
    if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
      enhancer = initialState;
      initialState = undefined;
    }

    // retrieve initial states from reducers, to apply prior to merging electron-store persisted-data
    const reducerInitialStates = reducer(undefined, {});

    let finalInitialState = _.merge({}, reducerInitialStates, initialState);

    try {
      for (const path of paths) {
        const persistedValue = electronStore.get(path);
        finalInitialState = _.setWith(_.clone(finalInitialState), path, persistedValue, _.clone); // deep, immutable set
      }
    } catch (e) {
      console.warn(
        'Failed to retrieve initialize state from electron store:',
        e
      );
    }

    const storeCache = {};

    const store = next(reducer, finalInitialState, enhancer);
    store.subscribe(() => {
      const state = store.getState();
      try {
        for (const path of paths) {
          const localState = _.get(state, path);
          if (localState && !_.isEqual(_.get(storeCache, path), localState) ) {
            _.set(storeCache, path, localState);
            electronStore.set(path, localState);
          }
        }
      } catch (e) {
        console.warn('Unable to persist state to electron store:', e);
      }
    });

    return store;
  };
}
<|endoftext|>


<commit_before>//! moment.js locale configuration
//! locale : Urdu [ur]
//! author : Sawood Alam : https://github.com/ibnesayeed

import moment from '../moment';

var months = [
  'جنوری',
  'فروری',
  'مارچ',
  'اپریل',
  'مئی',
  'جون',
  'جولائی',
  'اگست',
  'ستمبر',
  'اکتوبر',
  'نومبر',
  'دسمبر'
];
var days = [
  'اتوار',
  'پیر',
  'منگل',
  'بدھ',
  'جمعرات',
  'جمعہ',
  'ہفتہ'
];

export default moment.defineLocale('ur', {
    months : months,
    monthsShort : months,
    weekdays : days,
    weekdaysShort : days,
    weekdaysMin : days,
    longDateFormat : {
        LT : 'HH:mm',
        LTS : 'HH:mm:ss',
        L : 'DD/MM/YYYY',
        LL : 'D MMMM YYYY',
        LLL : 'D MMMM YYYY HH:mm',
        LLLL : 'dddd D MMMM YYYY HH:mm'
    },
    calendar : {
        sameDay : '[آج بوقت] LT',
        nextDay : '[کل بوقت] LT',
        nextWeek : 'dddd [بوقت] LT',
        lastDay : '[گذشتہ روز بوقت] LT',
        lastWeek : '[کذشتہ] dddd [بوقت] LT',
        sameElse : 'L'
    },
    relativeTime : {
        future : '%s بعد',
        past : '%s قبل',
        s : 'چند سیکنڈ',
        m : 'ایک منٹ',
        mm : '%d منٹ',
        h : 'ایک گھنٹہ',
        hh : '%d گھنٹے',
        d : 'ایک دن',
        dd : '%d دن',
        M : 'ایک ماہ',
        MM : '%d ماہ',
        y : 'ایک سال',
        yy : '%d سال'
    },
    week : {
        dow : 1, // Monday is the first day of the week.
        doy : 4  // The week that contains Jan 4th is the first week of the year.
    }
});
<commit_msg>Indentation corrected<commit_after>//! moment.js locale configuration
//! locale : Urdu [ur]
//! author : Sawood Alam : https://github.com/ibnesayeed

import moment from '../moment';

var months = [
    'جنوری',
    'فروری',
    'مارچ',
    'اپریل',
    'مئی',
    'جون',
    'جولائی',
    'اگست',
    'ستمبر',
    'اکتوبر',
    'نومبر',
    'دسمبر'
];
var days = [
    'اتوار',
    'پیر',
    'منگل',
    'بدھ',
    'جمعرات',
    'جمعہ',
    'ہفتہ'
];

export default moment.defineLocale('ur', {
    months : months,
    monthsShort : months,
    weekdays : days,
    weekdaysShort : days,
    weekdaysMin : days,
    longDateFormat : {
        LT : 'HH:mm',
        LTS : 'HH:mm:ss',
        L : 'DD/MM/YYYY',
        LL : 'D MMMM YYYY',
        LLL : 'D MMMM YYYY HH:mm',
        LLLL : 'dddd D MMMM YYYY HH:mm'
    },
    calendar : {
        sameDay : '[آج بوقت] LT',
        nextDay : '[کل بوقت] LT',
        nextWeek : 'dddd [بوقت] LT',
        lastDay : '[گذشتہ روز بوقت] LT',
        lastWeek : '[کذشتہ] dddd [بوقت] LT',
        sameElse : 'L'
    },
    relativeTime : {
        future : '%s بعد',
        past : '%s قبل',
        s : 'چند سیکنڈ',
        m : 'ایک منٹ',
        mm : '%d منٹ',
        h : 'ایک گھنٹہ',
        hh : '%d گھنٹے',
        d : 'ایک دن',
        dd : '%d دن',
        M : 'ایک ماہ',
        MM : '%d ماہ',
        y : 'ایک سال',
        yy : '%d سال'
    },
    week : {
        dow : 1, // Monday is the first day of the week.
        doy : 4  // The week that contains Jan 4th is the first week of the year.
    }
});
<|endoftext|>


<commit_before>(function (ns) {

    var common = require("../../base/common.js"),
        Shade = require("../../interfaces.js"),
        Base = require("../../base/index.js"),
        estraverse = require('estraverse');

    // var codegen = require('escodegen');

    var Syntax = common.Syntax,
        TYPES = Shade.TYPES,
        ANNO = common.ANNO;

    /**
     * Transform AST: Eliminate branches due to static conditions
     * and performs constant folding
     * @param {Object} ast
     * @returns Object
     */
    var transform = ns.transform = function (ast, opt) {
        var transformer = new Transformer(opt);
        return transformer.transform(ast);
    }

    var Transformer = function(opt) {
        opt = opt || {};

        this.foldConstants = opt.foldConstants !== undefined ? opt.foldConstants : true;

        this.controller = new estraverse.Controller();
    };

    Transformer.prototype = {
        transform: function (ast) {
            var that = this;
            return this.controller.replace(ast, {
                enter: function (node) {
                    var typeInfo = ANNO(node);
                    if (!typeInfo.isValid()) {
                        return;
                    }

                    switch (node.type) {
                        case Syntax.IfStatement:
                            return that.handleIfStatement(node);
                        case Syntax.ConditionalExpression:
                            return that.handleConditionalExpression(node);
                        case Syntax.LogicalExpression:
                            return that.handleLogicalExpression(node);
                        case Syntax.AssignmentExpression:
                            return that.handleAssignmentExpression(node);
                        case Syntax.VariableDeclarator:
                            return that.handleVariableDeclarator(node);
                        case Syntax.NewExpression:
                            //case Syntax.CallExpression:
                            return that.handleNewExpression(node);
                        case Syntax.VariableDeclaration:
                            return that.handleVariableDeclaration(node);

                    }

                    if(that.foldConstants && isExpression(node.type) && isSimpleStatic(typeInfo)) {
                        return generateLiteralFromTypeInfo(typeInfo);
                    }
                }
            });
        },

        handleIfStatement: function (node) {
            var test = ANNO(node.test);

            if (test.hasStaticValue() || test.canObject()) {
                this.controller.skip();
                var staticValue = test.getStaticTruthValue();
                if (staticValue === true) {
                    return transform(node.consequent);
                }
                if (staticValue === false) {
                    if (node.alternate) {
                        return this.transform(node.alternate);
                    }
                    return {
                        type: Syntax.EmptyStatement
                    }
                }
            }
        },

        handleConditionalExpression: function (node) {
            var test = ANNO(node.test);

            if (test.hasStaticValue() || test.canObject()) {
                this.controller.skip();
                var staticValue = test.getStaticTruthValue();
                if (staticValue === true) {
                    return this.transform(node.consequent);
                } else {
                    return this.transform(node.alternate);
                }
            }
        },

        handleLogicalExpression: function (node) {
            var left = ANNO(node.left);
            var right = ANNO(node.right);
            var leftBool = left.getStaticTruthValue();
            var rightBool = right.getStaticTruthValue();

            if (node.operator === "||") {
                if (leftBool === false) {
                    return node.right;
                }
                if (leftBool === true) {
                    return node.left;
                }
                // Left is dynamic, let's check right
                if (rightBool === false) {
                    return node.left;
                }
            } else if (node.operator === "&&") {
                if (leftBool === false) {
                    return node.left;
                }
                if (leftBool === true) {
                    return node.right;
                }
                // Left is dynamic, let's check right
                if (rightBool === true) {
                    // Now the result type is always the one of the left value
                    return node.left;
                }
                if (rightBool === false) {
                    // Now the result must be false
                    return {
                        type: Syntax.Literal,
                        value: "false",
                        extra: { type: "boolean"}
                    };
                }
            }
        },

        handleAssignmentExpression: function (node) {
            node.right = this.foldConstantExpression(node.right);
            return node;
        },
        handleNewExpression: function (node) {
            var args = node.arguments, newArgs = [];
            args.forEach(function (arg) {
                var typeInfo = ANNO(arg);
                if (isSimpleStatic(typeInfo)) {
                    newArgs.push(generateLiteralFromTypeInfo(typeInfo))
                } else {
                    newArgs.push(arg);
                }
            });
            node.arguments = newArgs;
            return node;
        },

        handleVariableDeclaration: function (node) {
            var declarations = node.declarations, newDeclarations = [];
            declarations.forEach(function (declaration) {
                var typeInfo = ANNO(declaration);
                if (!typeInfo.isUndefined()) {
                    newDeclarations.push(declaration);
                }
            });
            node.declarations = newDeclarations;
            return node;
        },
        handleVariableDeclarator: function (node) {
            if (node.init) {
                node.init = this.foldConstantExpression(node.init);
                return node;
            }
        },
        foldConstantExpression: function (node) {
            var anno = ANNO(node);
            if (this.foldConstants && isSimpleStatic(anno)) {
                return generateLiteralFromTypeInfo(anno);
            }
            return node;
        }

    };

    function isSimpleStatic(typeInfo) {
        return typeInfo.hasStaticValue() && !(typeInfo.isObject() || typeInfo.isNullOrUndefined());
    }

    var c_expressions = [Syntax.BinaryExpression, Syntax.UnaryExpression, Syntax.Identifier];
    function isExpression(type) {
        return c_expressions.indexOf(type) !== -1;
    };

    function generateLiteralFromTypeInfo(typeInfo) {
        var result = {
            type: Syntax.Literal,
            value: typeInfo.getStaticValue(),
            extra: {}
        }
        Base.extend(result.extra, typeInfo.getExtra());
        return result;
    }

}(exports));
<commit_msg>Improved handling of expressions in staticTransformer<commit_after>(function (ns) {

    var common = require("../../base/common.js"),
        Shade = require("../../interfaces.js"),
        Base = require("../../base/index.js"),
        estraverse = require('estraverse');

    // var codegen = require('escodegen');

    var Syntax = common.Syntax,
        TYPES = Shade.TYPES,
        ANNO = common.ANNO;

    /**
     * Transform AST: Eliminate branches due to static conditions
     * and performs constant folding
     * @param {Object} ast
     * @returns Object
     */
    var transform = ns.transform = function (ast, opt) {
        var transformer = new Transformer(opt);
        return transformer.transform(ast);
    }

    var Transformer = function(opt) {
        opt = opt || {};

        this.foldConstants = opt.foldConstants !== undefined ? opt.foldConstants : true;

        this.controller = new estraverse.Controller();
    };

    Transformer.prototype = {
        transform: function (ast) {
            var that = this;
            return this.controller.replace(ast, {
                enter: function (node, parent) {
                    var typeInfo = ANNO(node);
                    if (!typeInfo.isValid()) {
                        return;
                    }

                    switch (node.type) {
                        case Syntax.IfStatement:
                            return that.handleIfStatement(node);
                        case Syntax.ConditionalExpression:
                            return that.handleConditionalExpression(node);
                        case Syntax.LogicalExpression:
                            return that.handleLogicalExpression(node);
                        case Syntax.AssignmentExpression:
                            return that.handleAssignmentExpression(node);
                        case Syntax.VariableDeclarator:
                            return that.handleVariableDeclarator(node);
                        case Syntax.NewExpression:
                            //case Syntax.CallExpression:
                            return that.handleNewExpression(node);
                        case Syntax.VariableDeclaration:
                            return that.handleVariableDeclaration(node);

                    }

                    if(that.foldConstants && isExpression(node.type, parent.type) && isSimpleStatic(typeInfo)) {
                        return generateLiteralFromTypeInfo(typeInfo);
                    }
                }
            });
        },

        handleIfStatement: function (node) {
            var test = ANNO(node.test);

            if (test.hasStaticValue() || test.canObject()) {
                this.controller.skip();
                var staticValue = test.getStaticTruthValue();
                if (staticValue === true) {
                    return transform(node.consequent);
                }
                if (staticValue === false) {
                    if (node.alternate) {
                        return this.transform(node.alternate);
                    }
                    return {
                        type: Syntax.EmptyStatement
                    }
                }
            }
        },

        handleConditionalExpression: function (node) {
            var test = ANNO(node.test);

            if (test.hasStaticValue() || test.canObject()) {
                this.controller.skip();
                var staticValue = test.getStaticTruthValue();
                if (staticValue === true) {
                    return this.transform(node.consequent);
                } else {
                    return this.transform(node.alternate);
                }
            }
        },

        handleLogicalExpression: function (node) {
            var left = ANNO(node.left);
            var right = ANNO(node.right);
            var leftBool = left.getStaticTruthValue();
            var rightBool = right.getStaticTruthValue();

            if (node.operator === "||") {
                if (leftBool === false) {
                    return node.right;
                }
                if (leftBool === true) {
                    return node.left;
                }
                // Left is dynamic, let's check right
                if (rightBool === false) {
                    return node.left;
                }
            } else if (node.operator === "&&") {
                if (leftBool === false) {
                    return node.left;
                }
                if (leftBool === true) {
                    return node.right;
                }
                // Left is dynamic, let's check right
                if (rightBool === true) {
                    // Now the result type is always the one of the left value
                    return node.left;
                }
                if (rightBool === false) {
                    // Now the result must be false
                    return {
                        type: Syntax.Literal,
                        value: "false",
                        extra: { type: "boolean"}
                    };
                }
            }
        },

        handleAssignmentExpression: function (node) {
            node.right = this.foldConstantExpression(node.right);
            return node;
        },
        handleNewExpression: function (node) {
            var args = node.arguments, newArgs = [];
            args.forEach(function (arg) {
                var typeInfo = ANNO(arg);
                if (isSimpleStatic(typeInfo)) {
                    newArgs.push(generateLiteralFromTypeInfo(typeInfo))
                } else {
                    newArgs.push(arg);
                }
            });
            node.arguments = newArgs;
            return node;
        },

        handleVariableDeclaration: function (node) {
            var declarations = node.declarations, newDeclarations = [];
            declarations.forEach(function (declaration) {
                var typeInfo = ANNO(declaration);
                if (!typeInfo.isUndefined()) {
                    newDeclarations.push(declaration);
                }
            });
            node.declarations = newDeclarations;
            return node;
        },
        handleVariableDeclarator: function (node) {
            if (node.init) {
                node.init = this.foldConstantExpression(node.init);
                return node;
            }
        },
        foldConstantExpression: function (node) {
            var anno = ANNO(node);
            if (this.foldConstants && isSimpleStatic(anno)) {
                return generateLiteralFromTypeInfo(anno);
            }
            return node;
        }

    };

    function isSimpleStatic(typeInfo) {
        return typeInfo.hasStaticValue() && !(typeInfo.isObject() || typeInfo.isNullOrUndefined());
    }

    var c_expressions = [Syntax.BinaryExpression, Syntax.UnaryExpression, Syntax.MemberExpression];
    var c_parentLiteralExpressions = [Syntax.BinaryExpression];

    function isExpression(type, parentType) {
        if(type === Syntax.Identifier) {
            return c_parentLiteralExpressions.indexOf(parentType) !== -1;
        }

        return c_expressions.indexOf(type) !== -1;
    };

    function generateLiteralFromTypeInfo(typeInfo) {
        var value = typeInfo.getStaticValue();
        var isNegative = value < 0;

        var result = {
            type: Syntax.Literal,
            value: isNegative ? -value : value,
            extra: {}
        }
        Base.extend(result.extra, typeInfo.getExtra());

        if(isNegative) {
            result.extra.staticValue = -value;
            result = {
                type: Syntax.UnaryExpression,
                operator: "-",
                argument: result,
                extra: {}
            }
            Base.extend(result.extra, typeInfo.getExtra());
        }

        return result;
    }

}(exports));
<|endoftext|>


<commit_before>/**
 *
 * Main process of Electron.js
 */

const electron = require('electron')
const app = electron.app

global.ROOT = __dirname
global.IMAGE_TEMP = `${global.ROOT}/img`

global.hasChanged
global.isNew
global.savePath

// This variable is used to know if the editor have to save
// images inside the tmp folder or in the RASH package
global.isWrapper

global.ASSETS_DIRECTORIES = [
  `${global.ROOT}/js`,
  `${global.ROOT}/css`,
  `${global.ROOT}/fonts`,
  IMAGE_TEMP
]

global.TEMPLATE = 'index.html'
global.SPLASH = 'splash.html'

const {
  BrowserWindow,
  ipcMain,
  dialog,
  Menu
} = electron

const url = require('url')
const path = require('path')
const windowManager = require('electron-window-manager')

const RAJE_FS = require('./modules/raje_fs.js')
const RAJE_MENU = require('./modules/raje_menu.js')

const EDITOR_WINDOW = 'editor'
const SPLASH_WINDOW = 'splash'

const windows = {

  /**
   * Init the windowmanager and open the splash window
   */
  openSplash: function () {

    // Init the window manager
    windowManager.init()

    // Get the url to the splash window
    let splashWindowUrl = url.format({
      pathname: path.join(__dirname, SPLASH),
      protocol: 'file:',
      slashes: true
    })

    // Open the splash window
    windowManager.open(SPLASH_WINDOW, 'RAJE', splashWindowUrl, null, {
      height: 400,
      width: 500,
      resizable: false,
      movable: true,
      fullscreenable: false
    })

    // Set the menu
    Menu.setApplicationMenu(Menu.buildFromTemplate(RAJE_MENU.getSplashMenu()))
  },

  /**
   * Close the splash window
   */
  closeSplash: function () {

    windowManager.close(SPLASH_WINDOW)
  },

  /**
   * Open the editable template
   */
  openEditor: function (localRootPath, size) {

    global.hasChanged = false

    // Set the URL of the document
    let editorWindowUrl
    if (localRootPath) {

      // Remember that the document is already saved
      global.isNew = false
      global.savePath = localRootPath
      global.isWrapper = false

      // TODO check if the document has validated RASH content

      // Get the URL to open the editor
      editorWindowUrl = url.format({
        pathname: localRootPath,
        protocol: 'file:',
        slashes: true
      })

    } else {

      // Remember that the document isn't saved yet
      global.isNew = true
      global.isWrapper = true

      editorWindowUrl = editorWindowUrl = url.format({
        pathname: path.join(__dirname, TEMPLATE),
        protocol: 'file:',
        slashes: true
      })
    }

    // Open the new window with the size given by the splash window
    windowManager.open(EDITOR_WINDOW, 'RAJE', editorWindowUrl, null, {
      width: size.width,
      height: size.height,
      resizable: true
    })

    // Update the app menu
    windows.updateEditorMenu(RAJE_MENU.getEditorMenu(!global.isNew))

    /**
     * Catch the close event
     */
    windowManager.get(EDITOR_WINDOW).object.on('close', event => {

      // If the document is in hasChanged mode (need to be saved)
      if (global.hasChanged) {

        // Cancel the close event
        event.preventDefault()

        // Show the dialog box "the document need to be saved"
        dialog.showMessageBox({
          type: 'warning',
          buttons: ['Save changes', 'Discard changes', 'Cancel, continue editing'],
          title: 'Unsaved changes',
          message: 'The article has been changed, do you want to save the changes?',
          cancelId: 2
        }, (response) => {
          switch (response) {

            // The user wants to save the document
            case 0:
              // TODO save the document
              global.hasChanged = false
              windowManager.get(EDITOR_WINDOW).object.close()
              break

              // The user doesn't want to save the document
            case 1:
              global.hasChanged = false
              windowManager.get(EDITOR_WINDOW).object.close()
              break
          }
        })
      }
    })
  },

  /**
   * Return true to let know that the client has Electron behind
   */
  hasBackend: function () {
    return true
  },

  /**
   *
   */
  updateEditorMenu: function (menu) {
    // Set the menu
    Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
  }
}

/**
 * Event called when the app is ready
 */
app.on('ready', windows.openSplash)

/**
 * This event is called on OSX when the user click on icon in the dock
 */
app.on('activate', (event, hasVisibleWindows) => {

  // If there aren't any open windows
  if (!hasVisibleWindows)
    windows.openSplash()
})

/**
 * On OS X it is common for applications and their menu bar
 * to stay active until the user quits explicitly with Cmd + Q
 */
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('quit', RAJE_FS.removeImageTempFolder)

/**
 * This method is used to call the function that
 * opens the editor with the template
 *
 * Called by the splash window
 */
ipcMain.on('createArticle', (event, arg) => {

  windows.openEditor(null, arg)
  windows.closeSplash()
})

/**
 *
 */
ipcMain.on('openArticle', (event, arg) => {

  // Select the article index
  let localRootPath = dialog.showOpenDialog({
    title: 'Open RASH article',
    properties: [
      'openFile'
    ],
    filters: [{
      name: 'HTML',
      extensions: ['html']
    }]
  })

  if (localRootPath) {

    // Open the first element of what the dialog returns
    windows.openEditor(localRootPath[0], arg)
    windows.closeSplash()
  }
})

/**
 * This method is used to let know to the client that
 * the HTML file it's opened by Electron (not by a browser)
 *
 * If nothing is returned, tinymce isn't initialised
 *
 * Called from the renderer process
 */
ipcMain.on('hasBackendSync', (event, arg) => {
  event.returnValue = windows.hasBackend()
})

/**
 * This method is used to save the current document
 * calling the save dialog (in order to select where the document has to be saved)
 *
 * Then The article is saved by the raje_fs module
 *
 * After the save process, the url is updated loading the saved file url
 *
 * Called from the renderer process
 */
ipcMain.on('saveAsArticle', (event, arg) => {

  // Show save dialog here
  let savePath = dialog.showSaveDialog({
    title: 'Save as',
    defaultPath: arg.title,
    properties: [
      'openDirectory'
    ]
  })

  // If the user select a folder, the article is saved for the first time
  if (savePath) {
    RAJE_FS.saveAsArticle(savePath, arg.document, (err, message) => {
      if (err)
        return console.log(`Error: ${err}`)

      // Store important variables to check the save state
      global.isNew = false
      global.savePath = savePath

      windows.updateEditorMenu(RAJE_MENU.getEditorMenu(!global.isNew))

      // Notify the client
      global.sendNotification({
        text: message,
        type: 'success',
        timeout: 2000
      })
    })
  }
})

/**
 *
 */
ipcMain.on('saveArticle', (event, arg) => {

  // If the document has been saved before
  if (!global.isNew && typeof global.savePath != "undefined") {
    RAJE_FS.saveArticle(global.savePath, arg.document, (err, message) => {
      if (err) return console.log(err)

      // Notify the client
      global.sendNotification({
        text: message,
        type: 'success',
        timeout: 2000
      })
    })
  }
})

/**
 * This method is used to select the image to import in the document
 *
 * When the image is selected it's saved inside the image temporary folder
 * (which is deleted when the app is closed)
 */
ipcMain.on('selectImageSync', (event, arg) => {

  // Show the open dialog with options
  let imagePath = dialog.showOpenDialog({
    filters: [{
      name: 'Images',
      extensions: ['jpg', 'png']
    }]
  })

  // If a file is selected
  if (imagePath[0]) {

    // Save the image in the temporary folder
    RAJE_FS.saveImageTemp(imagePath[0], (err, result) => {

      if (err) return event.returnValue = err

      return event.returnValue = result
    })
  } else
    return event.returnValue = null
})

/**
 *
 */
ipcMain.on('updateDocumentState', (event, arg) => {
  global.hasChanged = arg
})

/**
 * Send a message to the renderer process
 * Start the save as process
 */
global.executeSaveAs = function () {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('executeSaveAs')
}

/**
 * Send a message to the renderer process
 * Start the save process
 */
global.executeSave = function () {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('executeSave')
}

/**
 *
 */
global.sendNotification = function (message) {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('notify', message)
}<commit_msg>Fix path bug opening article<commit_after>/**
 *
 * Main process of Electron.js
 */

const electron = require('electron')
const app = electron.app

global.ROOT = __dirname
global.IMAGE_TEMP = `${global.ROOT}/img`

global.hasChanged
global.isNew
global.savePath

// This variable is used to know if the editor have to save
// images inside the tmp folder or in the RASH package
global.isWrapper

global.ASSETS_DIRECTORIES = [
  `${global.ROOT}/js`,
  `${global.ROOT}/css`,
  `${global.ROOT}/fonts`,
  IMAGE_TEMP
]

global.TEMPLATE = 'index.html'
global.SPLASH = 'splash.html'

const {
  BrowserWindow,
  ipcMain,
  dialog,
  Menu
} = electron

const url = require('url')
const path = require('path')
const windowManager = require('electron-window-manager')

const RAJE_FS = require('./modules/raje_fs.js')
const RAJE_MENU = require('./modules/raje_menu.js')

const EDITOR_WINDOW = 'editor'
const SPLASH_WINDOW = 'splash'

const windows = {

  /**
   * Init the windowmanager and open the splash window
   */
  openSplash: function () {

    // Init the window manager
    windowManager.init()

    // Get the url to the splash window
    let splashWindowUrl = url.format({
      pathname: path.join(__dirname, SPLASH),
      protocol: 'file:',
      slashes: true
    })

    // Open the splash window
    windowManager.open(SPLASH_WINDOW, 'RAJE', splashWindowUrl, null, {
      height: 400,
      width: 500,
      resizable: false,
      movable: true,
      fullscreenable: false
    })

    // Set the menu
    Menu.setApplicationMenu(Menu.buildFromTemplate(RAJE_MENU.getSplashMenu()))
  },

  /**
   * Close the splash window
   */
  closeSplash: function () {

    windowManager.close(SPLASH_WINDOW)
  },

  /**
   * Open the editable template
   */
  openEditor: function (localRootPath, size) {

    global.hasChanged = false

    // Set the URL of the document
    let editorWindowUrl
    if (localRootPath) {

      let getDirectory = function () {

        let tmp = localRootPath.split('/')
        tmp.pop()

        return `${tmp.join('/')}/`
      }

      // Remember that the document is already saved
      global.isNew = false
      global.savePath = getDirectory()
      global.isWrapper = false

      // TODO check if the document has validated RASH content

      // Get the URL to open the editor
      editorWindowUrl = url.format({
        pathname: localRootPath,
        protocol: 'file:',
        slashes: true
      })

    } else {

      // Remember that the document isn't saved yet
      global.isNew = true
      global.isWrapper = true

      editorWindowUrl = editorWindowUrl = url.format({
        pathname: path.join(__dirname, TEMPLATE),
        protocol: 'file:',
        slashes: true
      })
    }

    // Open the new window with the size given by the splash window
    windowManager.open(EDITOR_WINDOW, 'RAJE', editorWindowUrl, null, {
      width: size.width,
      height: size.height,
      resizable: true
    })

    // Update the app menu
    windows.updateEditorMenu(RAJE_MENU.getEditorMenu(!global.isNew))

    /**
     * Catch the close event
     */
    windowManager.get(EDITOR_WINDOW).object.on('close', event => {

      // If the document is in hasChanged mode (need to be saved)
      if (global.hasChanged) {

        // Cancel the close event
        event.preventDefault()

        // Show the dialog box "the document need to be saved"
        dialog.showMessageBox({
          type: 'warning',
          buttons: ['Save changes', 'Discard changes', 'Cancel, continue editing'],
          title: 'Unsaved changes',
          message: 'The article has been changed, do you want to save the changes?',
          cancelId: 2
        }, (response) => {
          switch (response) {

            // The user wants to save the document
            case 0:
              // TODO save the document
              global.hasChanged = false
              windowManager.get(EDITOR_WINDOW).object.close()
              break

              // The user doesn't want to save the document
            case 1:
              global.hasChanged = false
              windowManager.get(EDITOR_WINDOW).object.close()
              break
          }
        })
      }
    })
  },

  /**
   * Return true to let know that the client has Electron behind
   */
  hasBackend: function () {
    return true
  },

  /**
   *
   */
  updateEditorMenu: function (menu) {
    // Set the menu
    Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
  }
}

/**
 * Event called when the app is ready
 */
app.on('ready', windows.openSplash)

/**
 * This event is called on OSX when the user click on icon in the dock
 */
app.on('activate', (event, hasVisibleWindows) => {

  // If there aren't any open windows
  if (!hasVisibleWindows)
    windows.openSplash()
})

/**
 * On OS X it is common for applications and their menu bar
 * to stay active until the user quits explicitly with Cmd + Q
 */
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('quit', RAJE_FS.removeImageTempFolder)

/**
 * This method is used to call the function that
 * opens the editor with the template
 *
 * Called by the splash window
 */
ipcMain.on('createArticle', (event, arg) => {

  windows.openEditor(null, arg)
  windows.closeSplash()
})

/**
 *
 */
ipcMain.on('openArticle', (event, arg) => {

  // Select the article index
  let localRootPath = dialog.showOpenDialog({
    title: 'Open RASH article',
    properties: [
      'openFile'
    ],
    filters: [{
      name: 'HTML',
      extensions: ['html']
    }]
  })

  if (localRootPath) {

    localRootPath = localRootPath[0]

    // Open the first element of what the dialog returns
    windows.openEditor(localRootPath, arg)
    windows.closeSplash()
  }
})

/**
 * This method is used to let know to the client that
 * the HTML file it's opened by Electron (not by a browser)
 *
 * If nothing is returned, tinymce isn't initialised
 *
 * Called from the renderer process
 */
ipcMain.on('hasBackendSync', (event, arg) => {
  event.returnValue = windows.hasBackend()
})

/**
 * This method is used to save the current document
 * calling the save dialog (in order to select where the document has to be saved)
 *
 * Then The article is saved by the raje_fs module
 *
 * After the save process, the url is updated loading the saved file url
 *
 * Called from the renderer process
 */
ipcMain.on('saveAsArticle', (event, arg) => {

  // Show save dialog here
  let savePath = dialog.showSaveDialog({
    title: 'Save as',
    defaultPath: arg.title,
    properties: [
      'openDirectory'
    ]
  })

  // If the user select a folder, the article is saved for the first time
  if (savePath) {
    RAJE_FS.saveAsArticle(savePath, arg.document, (err, message) => {
      if (err)
        return console.log(`Error: ${err}`)

      // Store important variables to check the save state
      global.isNew = false
      global.savePath = savePath

      windows.updateEditorMenu(RAJE_MENU.getEditorMenu(!global.isNew))

      // Notify the client
      global.sendNotification({
        text: message,
        type: 'success',
        timeout: 2000
      })
    })
  }
})

/**
 *
 */
ipcMain.on('saveArticle', (event, arg) => {

  // If the document has been saved before
  if (!global.isNew && typeof global.savePath != "undefined") {
    RAJE_FS.saveArticle(global.savePath, arg.document, (err, message) => {
      if (err) return console.log(err)

      // Notify the client
      global.sendNotification({
        text: message,
        type: 'success',
        timeout: 2000
      })
    })
  }
})

/**
 * This method is used to select the image to import in the document
 *
 * When the image is selected it's saved inside the image temporary folder
 * (which is deleted when the app is closed)
 */
ipcMain.on('selectImageSync', (event, arg) => {

  // Show the open dialog with options
  let imagePath = dialog.showOpenDialog({
    filters: [{
      name: 'Images',
      extensions: ['jpg', 'png']
    }]
  })

  // If a file is selected
  if (imagePath[0]) {

    // Save the image in the temporary folder
    RAJE_FS.saveImageTemp(imagePath[0], (err, result) => {

      if (err) return event.returnValue = err

      return event.returnValue = result
    })
  } else
    return event.returnValue = null
})

/**
 *
 */
ipcMain.on('updateDocumentState', (event, arg) => {
  global.hasChanged = arg
})

/**
 * Send a message to the renderer process
 * Start the save as process
 */
global.executeSaveAs = function () {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('executeSaveAs')
}

/**
 * Send a message to the renderer process
 * Start the save process
 */
global.executeSave = function () {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('executeSave')
}

/**
 *
 */
global.sendNotification = function (message) {
  windowManager.get(EDITOR_WINDOW).object.webContents.send('notify', message)
}<|endoftext|>


<commit_before>"use strict";

import React, { Component } from "react";
import PropTypes from "prop-types";
import { format } from "d3-format";
import { timeFormat } from "d3-time-format";
import displayValuesFor from "./displayValuesFor";
import GenericChartComponent from "../GenericChartComponent";

import { isDefined, functor } from "../utils";
import ToolTipText from "./ToolTipText";
import ToolTipTSpanLabel from "./ToolTipTSpanLabel";

class OHLCTooltip extends Component {
	constructor(props) {
		super(props);
		this.renderSVG = this.renderSVG.bind(this);
	}
	renderSVG(moreProps) {
		const { displayValuesFor } = this.props;
		const {
			xDisplayFormat,
			accessor,
			volumeFormat,
			ohlcFormat,
			percentFormat
		} = this.props;

		const { chartConfig: { width, height } } = moreProps;
		const { displayXAccessor } = moreProps;

		const currentItem = displayValuesFor(this.props, moreProps);

		let displayDate, open, high, low, close, volume, percent;
		displayDate = open = high = low = close = volume = percent = "n/a";

		if (isDefined(currentItem) && isDefined(accessor(currentItem))) {
			const item = accessor(currentItem);
			volume = isDefined(item.volume) ? volumeFormat(item.volume) : "n/a";

			displayDate = xDisplayFormat(displayXAccessor(item));
			open = ohlcFormat(item.open);
			high = ohlcFormat(item.high);
			low = ohlcFormat(item.low);
			close = ohlcFormat(item.close);
			percent = percentFormat((item.close - item.open) / item.open);
		}

		const { origin: originProp } = this.props;
		const origin = functor(originProp);
		const [x, y] = origin(width, height);

		const itemsToDisplay = {
			displayDate,
			open,
			high,
			low,
			close,
			percent,
			volume,
			x,
			y
		};
		return this.props.children(this.props, moreProps, itemsToDisplay);
	}
	render() {
		return (
			<GenericChartComponent
				clip={false}
				svgDraw={this.renderSVG}
				drawOn={["mousemove"]}
			/>
		);
	}
}

OHLCTooltip.propTypes = {
	className: PropTypes.string,
	accessor: PropTypes.func,
	xDisplayFormat: PropTypes.func,
	children: PropTypes.func,
	volumeFormat: PropTypes.func,
	percentFormat: PropTypes.func,
	ohlcFormat: PropTypes.func,
	origin: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
	fontFamily: PropTypes.string,
	fontSize: PropTypes.number,
	onClick: PropTypes.func,
	displayValuesFor: PropTypes.func,
	textFill: PropTypes.string,
	labelFill: PropTypes.string,
	displayTexts: PropTypes.object,
};

const displayTextsDefault = {
	d: "Date: ",
	o: " O: ",
	h: " H: ",
	l: " L: ",
	c: " C: ",
	v: " Vol: "
};

OHLCTooltip.defaultProps = {
	accessor: d => {
		return {
			date: d.date,
			open: d.open,
			high: d.high,
			low: d.low,
			close: d.close,
			volume: d.volume
		};
	},
	xDisplayFormat: timeFormat("%Y-%m-%d"),
	volumeFormat: format(".4s"),
	percentFormat: format(".2%"),
	ohlcFormat: format(".2f"),
	displayValuesFor: displayValuesFor,
	origin: [0, 0],
	children: defaultDisplay,
	displayTexts: displayTextsDefault,
};

function defaultDisplay(props, moreProps, itemsToDisplay) {

	/* eslint-disable */
	const {
		className,
		textFill,
		labelFill,
		onClick,
		fontFamily,
		fontSize,
		displayTexts
	} = props;
	/* eslint-enable */

	const {
		displayDate,
		open,
		high,
		low,
		close,
		volume,
		x,
		y
	} = itemsToDisplay;
	return (
		<g
			className={`react-stockcharts-tooltip-hover ${className}`}
			transform={`translate(${x}, ${y})`}
			onClick={onClick}
		>
			<ToolTipText
				x={0}
				y={0}
				fontFamily={fontFamily}
				fontSize={fontSize}
			>
				<ToolTipTSpanLabel
					fill={labelFill}
					key="label"
					x={0}
					dy="5">{displayTexts.d}</ToolTipTSpanLabel>
				<tspan key="value" fill={textFill}>{displayDate}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_O">{displayTexts.o}</ToolTipTSpanLabel>
				<tspan key="value_O" fill={textFill}>{open}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_H">{displayTexts.h}</ToolTipTSpanLabel>
				<tspan key="value_H" fill={textFill}>{high}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_L">{displayTexts.l}</ToolTipTSpanLabel>
				<tspan key="value_L" fill={textFill}>{low}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_C">{displayTexts.c}</ToolTipTSpanLabel>
				<tspan key="value_C" fill={textFill}>{close}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_Vol">{displayTexts.v}</ToolTipTSpanLabel>
				<tspan key="value_Vol" fill={textFill}>{volume}</tspan>
			</ToolTipText>
		</g>
	);
}

export default OHLCTooltip;
<commit_msg>n/a texts<commit_after>"use strict";

import React, { Component } from "react";
import PropTypes from "prop-types";
import { format } from "d3-format";
import { timeFormat } from "d3-time-format";
import displayValuesFor from "./displayValuesFor";
import GenericChartComponent from "../GenericChartComponent";

import { isDefined, functor } from "../utils";
import ToolTipText from "./ToolTipText";
import ToolTipTSpanLabel from "./ToolTipTSpanLabel";

class OHLCTooltip extends Component {
	constructor(props) {
		super(props);
		this.renderSVG = this.renderSVG.bind(this);
	}
	renderSVG(moreProps) {
		const { displayValuesFor } = this.props;
		const {
			xDisplayFormat,
			accessor,
			volumeFormat,
			ohlcFormat,
			percentFormat,
			displayTexts
		} = this.props;

		const { chartConfig: { width, height } } = moreProps;
		const { displayXAccessor } = moreProps;

		const currentItem = displayValuesFor(this.props, moreProps);

		let displayDate, open, high, low, close, volume, percent;
		displayDate = open = high = low = close = volume = percent = displayTexts.na;

		if (isDefined(currentItem) && isDefined(accessor(currentItem))) {
			const item = accessor(currentItem);
			volume = isDefined(item.volume) ? volumeFormat(item.volume) : displayTexts.na;

			displayDate = xDisplayFormat(displayXAccessor(item));
			open = ohlcFormat(item.open);
			high = ohlcFormat(item.high);
			low = ohlcFormat(item.low);
			close = ohlcFormat(item.close);
			percent = percentFormat((item.close - item.open) / item.open);
		}

		const { origin: originProp } = this.props;
		const origin = functor(originProp);
		const [x, y] = origin(width, height);

		const itemsToDisplay = {
			displayDate,
			open,
			high,
			low,
			close,
			percent,
			volume,
			x,
			y
		};
		return this.props.children(this.props, moreProps, itemsToDisplay);
	}
	render() {
		return (
			<GenericChartComponent
				clip={false}
				svgDraw={this.renderSVG}
				drawOn={["mousemove"]}
			/>
		);
	}
}

OHLCTooltip.propTypes = {
	className: PropTypes.string,
	accessor: PropTypes.func,
	xDisplayFormat: PropTypes.func,
	children: PropTypes.func,
	volumeFormat: PropTypes.func,
	percentFormat: PropTypes.func,
	ohlcFormat: PropTypes.func,
	origin: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
	fontFamily: PropTypes.string,
	fontSize: PropTypes.number,
	onClick: PropTypes.func,
	displayValuesFor: PropTypes.func,
	textFill: PropTypes.string,
	labelFill: PropTypes.string,
	displayTexts: PropTypes.object,
};

const displayTextsDefault = {
	d: "Date: ",
	o: " O: ",
	h: " H: ",
	l: " L: ",
	c: " C: ",
	v: " Vol: ",
	na: "n/a"
};

OHLCTooltip.defaultProps = {
	accessor: d => {
		return {
			date: d.date,
			open: d.open,
			high: d.high,
			low: d.low,
			close: d.close,
			volume: d.volume
		};
	},
	xDisplayFormat: timeFormat("%Y-%m-%d"),
	volumeFormat: format(".4s"),
	percentFormat: format(".2%"),
	ohlcFormat: format(".2f"),
	displayValuesFor: displayValuesFor,
	origin: [0, 0],
	children: defaultDisplay,
	displayTexts: displayTextsDefault,
};

function defaultDisplay(props, moreProps, itemsToDisplay) {

	/* eslint-disable */
	const {
		className,
		textFill,
		labelFill,
		onClick,
		fontFamily,
		fontSize,
		displayTexts
	} = props;
	/* eslint-enable */

	const {
		displayDate,
		open,
		high,
		low,
		close,
		volume,
		x,
		y
	} = itemsToDisplay;
	return (
		<g
			className={`react-stockcharts-tooltip-hover ${className}`}
			transform={`translate(${x}, ${y})`}
			onClick={onClick}
		>
			<ToolTipText
				x={0}
				y={0}
				fontFamily={fontFamily}
				fontSize={fontSize}
			>
				<ToolTipTSpanLabel
					fill={labelFill}
					key="label"
					x={0}
					dy="5">{displayTexts.d}</ToolTipTSpanLabel>
				<tspan key="value" fill={textFill}>{displayDate}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_O">{displayTexts.o}</ToolTipTSpanLabel>
				<tspan key="value_O" fill={textFill}>{open}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_H">{displayTexts.h}</ToolTipTSpanLabel>
				<tspan key="value_H" fill={textFill}>{high}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_L">{displayTexts.l}</ToolTipTSpanLabel>
				<tspan key="value_L" fill={textFill}>{low}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_C">{displayTexts.c}</ToolTipTSpanLabel>
				<tspan key="value_C" fill={textFill}>{close}</tspan>
				<ToolTipTSpanLabel fill={labelFill} key="label_Vol">{displayTexts.v}</ToolTipTSpanLabel>
				<tspan key="value_Vol" fill={textFill}>{volume}</tspan>
			</ToolTipText>
		</g>
	);
}

export default OHLCTooltip;
<|endoftext|>


<commit_before>define( ['dojo/_base/declare',
         'JBrowse/Store/SeqFeature'
        ],
        function( declare, SeqFeatureStore ) {

return declare( SeqFeatureStore,
{
    constructor: function( args ) {
        this.features = {};
        this._calculateStats();
    },

    insert: function( feature ) {
        this.features[ feature.id() ] = feature;
        this._calculateStats();
    },

    delete: function( feature ) {
        delete this.features[ feature.id() ];
        this._calculateStats();
    },

    _calculateStats: function() {
        var minStart = Infinity;
        var maxEnd = -Infinity;
        var featureCount = 0;
        for( var id in this.features ) {
            var f = this.features[id];
            var s = f.get('start');
            var e = f.get('end');
            if( s < minStart )
                minStart = s;

            if( e > maxEnd )
                maxEnd = e;

            featureCount++;
        }

        this.globalStats = {
            featureDensity: featureCount/(maxEnd-minStart+1),
            featureCount: featureCount,
            minStart: minStart,
            maxEnd: maxEnd,
            span: (maxEnd-minStart+1)
        };
    },

    getFeatures: function( query, featCallback, endCallback, errorCallback ) {
        var start = query.start;
        var end = query.end;
        for( var id in this.features ) {
            var f = this.features[id];
            if(! ( f.get('end') < start  || f.get('start') > end ) ) {
                featCallback( f );
            }
        }
        endCallback();
    }
});
});<commit_msg>Added contains(id) method to return feature given a feature id.<commit_after>define( ['dojo/_base/declare',
         'JBrowse/Store/SeqFeature'
        ],
        function( declare, SeqFeatureStore ) {

return declare( SeqFeatureStore,
{
    constructor: function( args ) {
        this.features = {};
        this._calculateStats();
    },

    insert: function( feature ) {
        this.features[ feature.id() ] = feature;
        this._calculateStats();
    },

    delete: function( feature ) {
        delete this.features[ feature.id() ];
        this._calculateStats();
    },

    /* if feature with given id is present in store, return it.  Otherwise return null */
    contains: function( id )  {
	return this.features[ id ];
    },

    _calculateStats: function() {
        var minStart = Infinity;
        var maxEnd = -Infinity;
        var featureCount = 0;
        for( var id in this.features ) {
            var f = this.features[id];
            var s = f.get('start');
            var e = f.get('end');
            if( s < minStart )
                minStart = s;

            if( e > maxEnd )
                maxEnd = e;

            featureCount++;
        }

        this.globalStats = {
            featureDensity: featureCount/(maxEnd-minStart+1),
            featureCount: featureCount,
            minStart: minStart,
            maxEnd: maxEnd,
            span: (maxEnd-minStart+1)
        };
    },

    getFeatures: function( query, featCallback, endCallback, errorCallback ) {
        var start = query.start;
        var end = query.end;
        for( var id in this.features ) {
            var f = this.features[id];
            if(! ( f.get('end') < start  || f.get('start') > end ) ) {
                featCallback( f );
            }
        }
        endCallback();
    }
});
});<|endoftext|>


<commit_before>

app.directive('isoRepeat', function ($timeout) {
    return {
        $scope: {
             items: '=isoRepeat'
        },
        templateUrl: "campers/campers-inner.html",
        link: function ($scope, element, attrs) {
            console.log($scope.campersData)
            console.log('from D')
            var options = {
                animationEngine : 'jquery',
                itemSelector: 'article',
                layoutMode: 'fitRows',
                sortAscending: true
            };

            element.isotope(options);
            $scope.element = element

            $scope.$watch('campersData', function(newVal, oldVal){
               $timeout(function(){
                    element.isotope( 'reloadItems' ).isotope({ sortBy: 'original-order' });
               });
            },true);

            $scope.logHello = function(){
              element.isotope( 'reLayout')
            }
            //FILTERING FUNCTIONS
            // FIRST LEVEL
            $scope.filterFE = function(){
                element.isotope({ filter: '.frontend'});
            };
            $scope.filterAll = function(){
                element.isotope({ filter: '.isotope-item' })
            };
            $scope.filterDataVisual = function(){
                element.isotope({ filter: '.data-visual'})
            }
            $scope.filterBK = function(){
                element.isotope({ filter: '.backend' })
            }
            //SECOND LEVEL FE
              $scope.filterHtml = function(){
                element.isotope({ filter: '.html-css' })
            }

             $scope.filterBootstrap = function(){
                element.isotope({filter: ' .bootstrap'})
            }
            $scope.filterProjFE = function(){
                element.isotope({ filter: ' .FE-projects' })
            }

            $scope.filterOPP = function(){
                element.isotope({ filter: ' .opp-f' })
            }
               $scope.filterBasicAlgho = function(){
             element.isotope({ filter: ' .basic-alghorithm' })
         }

         $scope.filterAjax = function(){
             element.isotope({ filter: '.ajax' })
            }
        $scope.filterInterFE = function(){
            element.isotope({filter: ' .inter-FE'})
            }
              $scope.filterInterAlg = function(){
            element.isotope({filter: ' inter-alghorithm'})
            }
                  $scope.filterAdvAlg = function(){
            element.isotope({filter: 'adv-algorithm'})
            }

            $scope.filterAdvFEProj = function(){
            element.isotope({filter: 'adv-FE-projects'})
        }

 //DATA VISUAL
            $scope.filterSass = function(){
            element.isotope({ filter: ' .sass' })
            }

              $scope.filterReact = function(){
            element.isotope({  filter: '.react' })
            }

               $scope.filterReactProj = function(){
            element.isotope({  filter: '.react-projects' })
            }
                   $scope.filterD3 = function(){
            element.isotope({  filter: '.d3' })
            }

            $scope.filterDVProj = function(){
                element.isotope({  filter: '.data-visual-projects'})
            }

            //BACKEND
            $scope.filterTestD = function(){
                element.isotope({  filter: '.test-debug'})
            }

            $scope.filterNodeEx = function(){
                element.isotope({  filter: '.nodeExpress'})
            }

            $scope.filterGit = function(){
                element.isotope({  filter: '.git'})
            }

            $scope.filterMongoDB = function(){
                element.isotope({  filter: '.MongoDB'})
            }

            $scope.filterWebProj = function(){
                element.isotope({  filter: '.web-project'})
            }

            $scope.filterNBProj = function(){
                 element.isotope({ filter: '.NP-projects'})
            }

        }
    }
});<commit_msg>remove my console log<commit_after>

app.directive('isoRepeat', function ($timeout) {
    return {
        $scope: {
             items: '=isoRepeat'
        },
        templateUrl: "campers/campers-inner.html",
        link: function ($scope, element, attrs) {
            var options = {
                animationEngine : 'jquery',
                itemSelector: 'article',
                layoutMode: 'fitRows',
                sortAscending: true
            };

            element.isotope(options);
            $scope.element = element

            $scope.$watch('campersData', function(newVal, oldVal){
               $timeout(function(){
                    element.isotope( 'reloadItems' ).isotope({ sortBy: 'original-order' });
               });
            },true);

            $scope.logHello = function(){
              element.isotope( 'reLayout')
            }
            //FILTERING FUNCTIONS
            // FIRST LEVEL
            $scope.filterFE = function(){
                element.isotope({ filter: '.frontend'});
            };
            $scope.filterAll = function(){
                element.isotope({ filter: '.isotope-item' })
            };
            $scope.filterDataVisual = function(){
                element.isotope({ filter: '.data-visual'})
            }
            $scope.filterBK = function(){
                element.isotope({ filter: '.backend' })
            }
            //SECOND LEVEL FE
              $scope.filterHtml = function(){
                element.isotope({ filter: '.html-css' })
            }

             $scope.filterBootstrap = function(){
                element.isotope({filter: ' .bootstrap'})
            }
            $scope.filterProjFE = function(){
                element.isotope({ filter: ' .FE-projects' })
            }

            $scope.filterOPP = function(){
                element.isotope({ filter: ' .opp-f' })
            }
               $scope.filterBasicAlgho = function(){
             element.isotope({ filter: ' .basic-alghorithm' })
         }

         $scope.filterAjax = function(){
             element.isotope({ filter: '.ajax' })
            }
        $scope.filterInterFE = function(){
            element.isotope({filter: ' .inter-FE'})
            }
              $scope.filterInterAlg = function(){
            element.isotope({filter: ' inter-alghorithm'})
            }
                  $scope.filterAdvAlg = function(){
            element.isotope({filter: 'adv-algorithm'})
            }

            $scope.filterAdvFEProj = function(){
            element.isotope({filter: 'adv-FE-projects'})
        }

 //DATA VISUAL
            $scope.filterSass = function(){
            element.isotope({ filter: ' .sass' })
            }

              $scope.filterReact = function(){
            element.isotope({  filter: '.react' })
            }

               $scope.filterReactProj = function(){
            element.isotope({  filter: '.react-projects' })
            }
                   $scope.filterD3 = function(){
            element.isotope({  filter: '.d3' })
            }

            $scope.filterDVProj = function(){
                element.isotope({  filter: '.data-visual-projects'})
            }

            //BACKEND
            $scope.filterTestD = function(){
                element.isotope({  filter: '.test-debug'})
            }

            $scope.filterNodeEx = function(){
                element.isotope({  filter: '.nodeExpress'})
            }

            $scope.filterGit = function(){
                element.isotope({  filter: '.git'})
            }

            $scope.filterMongoDB = function(){
                element.isotope({  filter: '.MongoDB'})
            }

            $scope.filterWebProj = function(){
                element.isotope({  filter: '.web-project'})
            }

            $scope.filterNBProj = function(){
                 element.isotope({ filter: '.NP-projects'})
            }

        }
    }
});<|endoftext|>


<commit_before>'use strict';

describe("UserFactory", function() {

	beforeEach(module('isa'));
	beforeEach(module('isa.addressbook.factories'));

	it("should get a factory using the injector", function() {

		inject(function($injector, PersistentFactoryNameResolver) {

			var factory = {};
			var factoryName = "_UserFactoryLocal";

			spyOn($injector, 'get').and.callThrough();
			spyOn(PersistentFactoryNameResolver, 'resolveFactory').and.returnValue(factoryName);

			$injector.get('UserFactory');

			expect($injector.get).toHaveBeenCalled();
			expect($injector.get).toHaveBeenCalledWith(factoryName);

		});

	});

});

describe("_UserFactoryRemote", function() {

	var _UserFactoryRemote;

	beforeEach(module('isa'));
	beforeEach(module("isa.addressbook.factories"));
	beforeEach(inject(function(__UserFactoryRemote_) {
		_UserFactoryRemote = __UserFactoryRemote_;
	}));
	beforeEach(function() {
		jasmine.addMatchers(toHaveSameCtorAs);
	});

	describe("all", function() {

		it("should find all users", function() {
			inject(function(IsometricaUser) {
				spyOn(IsometricaUser, 'find');
				_UserFactoryRemote.all(3);
				expect(IsometricaUser.find).toHaveBeenCalledWith({
					filter: {
						offset: 30,
						limit: 10
					}
				}, jasmine.any(Function), jasmine.any(Function));
			});
		});

		it("should return a promise for the operation", function() {
			inject(function($q) {
				var pr = _UserFactoryRemote.all();
				expect(pr).toHaveSameCtorAs($q.defer());
			});
		});

		it("should resolve promise on success", function() {
			inject(function(IsometricaUser, $scope) {
				var foundUsers = [ {}, {}, {} ];
				var success = jasmine.createSpy();
				spyOn(IsometricaUser, 'find').and.callFake(function(obj, resolve, reject) {
					resolve(foundUsers);
					// See here: http://stackoverflow.com/questions/16323323/promise-callback-not-called-in-angular-js
					// Angular.js has its own event loop. Promise resolutions are propogated asynchronously
					// in the event loop. The event loop is processed every digest cycle, so we need to trigger
					// one with $scope.$apply
					$scope.$apply();
				});
				_UserFactoryRemote.all(0).then(success);
				expect(success).toHaveBeenCalledWith(foundUsers);
			});
		});

		it("should reject promise on failure", function() {

		});

	});

	describe("find", function() {

		it("should find a single user by the given predicate", function() {

		});

		//itShouldWrapOperationInPromise();

	});

});
<commit_msg>1.1 Fixed another issue with using  outside of controller context<commit_after>'use strict';

describe("UserFactory", function() {

	beforeEach(module('isa'));
	beforeEach(module('isa.addressbook.factories'));

	it("should get a factory using the injector", function() {

		inject(function($injector, PersistentFactoryNameResolver) {

			var factory = {};
			var factoryName = "_UserFactoryLocal";

			spyOn($injector, 'get').and.callThrough();
			spyOn(PersistentFactoryNameResolver, 'resolveFactory').and.returnValue(factoryName);

			$injector.get('UserFactory');

			expect($injector.get).toHaveBeenCalled();
			expect($injector.get).toHaveBeenCalledWith(factoryName);

		});

	});

});

describe("_UserFactoryRemote", function() {

	var _UserFactoryRemote;

	beforeEach(module('isa'));
	beforeEach(module("isa.addressbook.factories"));
	beforeEach(inject(function(__UserFactoryRemote_) {
		_UserFactoryRemote = __UserFactoryRemote_;
	}));
	beforeEach(function() {
		jasmine.addMatchers(toHaveSameCtorAs);
	});

	describe("all", function() {

		it("should find all users", function() {
			inject(function(IsometricaUser) {
				spyOn(IsometricaUser, 'find');
				_UserFactoryRemote.all(3);
				expect(IsometricaUser.find).toHaveBeenCalledWith({
					filter: {
						offset: 30,
						limit: 10
					}
				}, jasmine.any(Function), jasmine.any(Function));
			});
		});

		it("should return a promise for the operation", function() {
			inject(function($q) {
				var pr = _UserFactoryRemote.all();
				expect(pr).toHaveSameCtorAs($q.defer());
			});
		});

		it("should resolve promise on success", function() {
			inject(function(IsometricaUser, $rootScope) {
				var foundUsers = [ {}, {}, {} ];
				var success = jasmine.createSpy();
				spyOn(IsometricaUser, 'find').and.callFake(function(obj, resolve, reject) {
					resolve(foundUsers);
				});
				_UserFactoryRemote.all(0).then(success);
				// See here: http://stackoverflow.com/questions/16323323/promise-callback-not-called-in-angular-js
				// Angular.js has its own event loop. Promise resolutions are propogated asynchronously
				// in the event loop. The event loop is processed every digest cycle, so we need to trigger
				// one with $scope.$apply
				$rootScope.$digest();
				expect(success).toHaveBeenCalledWith(foundUsers);
			});
		});

		it("should reject promise on failure", function() {
			inject(function(IsometricaUser, $rootScope) {
				var failure = jasmine.createSpy();
				spyOn(IsometricaUser, 'find').and.callFake(function(obj, resolve, reject) {
					reject('Error');
				});
				_UserFactoryRemote.all(0).then(function() {}, failure);
				$rootScope.$digest();
				expect(failure).toHaveBeenCalledWith('Error');
			});
		});

	});

	describe("find", function() {

		it("should find a single user by the given predicate", function() {

		});

		//itShouldWrapOperationInPromise();

	});

});
<|endoftext|>