<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'
import classnames from 'classnames'
import {
  Button,
  Card,
  CardHeader,
  CardBody,
  CardFooter,
  InputGroup,
  InputGroupAddon,
  Input,
  Form,
  Col,
  Label,
  FormGroup,
  FormText,
  Table,
  Nav,
  NavItem,
  NavLink,
  TabContent,
  TabPane,
  Row
} from 'reactstrap'

import BasicProvider from './BasicProvider'
import SourcePriorities from './SourcePriorities'
import { set } from 'lodash'

function fetchProviders () {
  fetch(`/providers`, {
    credentials: 'include'
  })
    .then(response => response.json())
    .then(data => {
      let selectedProvider = undefined
      let selectedIndex = undefined
      if (this.state.selectedProviderId) {
        selectedProvider = data.find(provider => provider.id === this.state.selectedProviderId)
        selectedIndex = data.findIndex(provider => provider.id === this.state.selectedProviderId)
      }
      if (selectedProvider) {
        selectedProvider.originalId = selectedProvider.id
      }
      this.setState({
        providers: data,
        selectedProvider: selectedProvider ? JSON.parse(JSON.stringify(selectedProvider)) : undefined,
        selectedIndex: selectedIndex
       })
    })
}

function runDiscovery () {
  fetch(`/runDiscovery`, {
    method: 'PUT',
    credentials: 'include'
  })
}

function onRowSelect (row, isSelected, e) {
  // if column index is 2, will not trigger selection
  if (e.target.cellIndex === 2) return false
}

class ProvidersConfiguration extends Component {
  constructor (props) {
    super(props)
    this.state = {
      activeTab: '1',
      providers: [],
      selectedProviderId: this.props.match.params.providerId
    }

    this.fetchProviders = fetchProviders.bind(this)
    this.runDiscovery = runDiscovery.bind(this)
    this.handleProviderChange = this.handleProviderChange.bind(this)
    this.handleProviderPropChange = this.handleProviderChange.bind(this)
    this.handleAddProvider = this.handleAddProvider.bind(this)
    this.handleCancel = this.handleCancel.bind(this)
    this.toggle = this.toggle.bind(this)
    this.handleApply = this.handleApply.bind(this)
    this.handleCancel = this.handleCancel.bind(this)
    this.handleDelete = this.handleDelete.bind(this)
  }

  componentDidMount () {
    this.fetchProviders()
    this.runDiscovery()
  }

  handleProviderChange (event, type) {
    var value =
      event.target.type === 'checkbox'
        ? event.target.checked
        : event.target.value
    if (type === 'number') {
      value = Number(value)
    }
    set(this.state.selectedProvider, event.target.name, value)
    this.setState({
      selectedProvider: this.state.selectedProvider
    })
  }

  handleProviderPropChange(event) {
    this.setState({
      selectedProvider: this.state.selectedProvider
    })
  }

  handleAddProvider (event) {
    var newProvider = {
      type: 'NMEA2000',
      logging: false,
      isNew: true,
      id: '',
      enabled: true,
      options: {},
      editable: true
    }
    this.setState(
      {
        selectedProvider: JSON.parse(JSON.stringify(newProvider)),
        selectedIndex: this.state.providers.length - 1
      },
      () => {
        this.refs['selectedProvider'].scrollIntoView()
      }
    )
  }

  handleApply (event) {
    var isNew = this.state.selectedProvider.isNew
    var wasDiscovered = this.state.selectedProvider.wasDiscovered

    var provider = this.state.selectedProvider
    delete this.state.selectedProvider.json

    var id = this.state.selectedProvider.originalId

    fetch(`/providers/${id && !isNew ? id : ''}`, {
      method: isNew ? 'POST' : 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(this.state.selectedProvider),
      credentials: 'include'
    })
      .then(response => {
        if ( response.ok ) {
          var provider = JSON.parse(JSON.stringify(this.state.selectedProvider))
          delete provider.isNew
          delete provider.wasDiscovered
          delete this.state.selectedProvider.isNew
          if (isNew) {
            this.state.providers.push(provider)
          } else {
            this.state.providers[this.state.selectedIndex] = provider
          }
          if ( wasDiscovered ) {
            this.props.discoveredProviders.splice(this.state.selectedIndex, 1)
          }
          this.setState({
            providers: this.state.providers,
            //discoveredProviders: this.state.discoveredProviders,
            selectedProvider: null,
            selectedIndex: -1
          }, () => {
            this.props.history.push('/serverConfiguration/connections/-')
          })
        }
        return response.text()
      })
      .then(text => {
        alert(text)
      })
  }

  handleCancel (event) {
    this.setState({ selectedProvider: null })
  }

  handleDelete (event) {
    fetch(`/providers/${this.state.selectedProvider.id}`, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json'
      },
      credentials: 'include'
    })
      .then(response => response.text())
      .then(response => {
        this.state.providers.splice(this.state.selectedIndex, 1)
        this.setState({
          providers: this.state.providers,
          selectedProvider: null,
          selectedIndex: -1
        })
        alert(response)
      })
  }

  providerClicked (provider, index) {
    this.setState(
      {
        selectedProvider: {
          ...JSON.parse(JSON.stringify(provider)),
          originalId: provider.id
        },
        selectedIndex: index
      },
      () => {
        this.refs['selectedProvider'].scrollIntoView()
      }
    )
  }

  toggle (tab) {
    if (this.state.activeTab !== tab) {
      this.setState({
        activeTab: tab
      })
    }
  }

  render () {
    return (

        {this.props.discoveredProviders && this.props.discoveredProviders.length > 0 && (
        <Card>
        <CardHeader>Discovered Connections</CardHeader>
          <CardBody>

                  ID
                  Data Type
                  Enabled
                  Logging

                {(this.props.discoveredProviders || []).map((provider, index) => {
                  return (

                      {provider.id}

                        <ProviderType provider={provider} />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.enabled}
                        />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.logging}
                        />

                  )
                })}

          </CardBody>
        </Card>
        )}
        <Card>
        <CardHeader>Connections</CardHeader>
          <CardBody>

                  ID
                  Data Type
                  Enabled
                  Logging

                {(this.state.providers || []).map((provider, index) => {
                  return (

                      {provider.id}

                        <ProviderType provider={provider} />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.enabled}
                        />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.logging}
                        />

                  )
                })}

          </CardBody>
          <CardFooter>
            <Button size='sm' color='primary' onClick={this.handleAddProvider}>
               Add
            </Button>
          </CardFooter>
        </Card>

        {this.state.selectedProvider && (

            <Card>
              <CardBody>
                {this.state.selectedProvider.editable ? (
                  <BasicProvider
                    value={this.state.selectedProvider}
                    onChange={this.handleProviderChange}
                    onPropChange={this.handleProviderPropChange}
                  />
                ) : (
                  <Input
                    type='textarea'
                    name='json'
                    id='json'
                    rows='20'
                    value={this.state.selectedProvider.json}
                    readOnly='true'
                  />
                )}
              </CardBody>
              <CardFooter>
                {this.state.selectedProvider.editable ? (
                  <Row>
                    <Col xs='4' md='1'>
                      <Button
                        size='sm'
                        color='primary'
                        onClick={this.handleApply}
                      >
                         Apply
                      </Button>
                    </Col>
                    <Col xs='4' md='1'>
                      <Button
                        size='sm'
                        color='secondary'
                        onClick={this.handleCancel}
                      >
                         Cancel
                      </Button>
                    </Col>
                    <Col xs='4' md='10' className='text-right'>
                      <Button
                        size='sm'
                        color='danger'
                        onClick={this.handleDelete}
                      >
                         Delete
                      </Button>
                    </Col>
                  </Row>
                ) : (
                  <Row>
                    <Col xs='4' md='12' className='text-right'>
                      <Button
                        size='sm'
                        color='danger'
                        onClick={this.handleDelete}
                      >
                         Delete
                      </Button>
                    </Col>
                  </Row>
                )}
              </CardFooter>
            </Card>

        )}

        <SourcePriorities/>

    )
  }
}

const ApplicableStatus = props => (

{props.applicable ? (props.toggle ? 'Yes' : 'No') : 'N/A'}

)

const ProviderType = props => (

    {props.provider.type}
    {props.provider.type === 'FileStream'
      ? `/${props.provider.options.dataType}`
      : ''}

)
const mapStateToProps = ({ discoveredProviders  }) => ({ discoveredProviders })

export default connect(mapStateToProps)(ProvidersConfiguration)
<commit_msg>fix: scroll properly to connection form's top (#1171)<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'
import classnames from 'classnames'
import {
  Button,
  Card,
  CardHeader,
  CardBody,
  CardFooter,
  InputGroup,
  InputGroupAddon,
  Input,
  Form,
  Col,
  Label,
  FormGroup,
  FormText,
  Table,
  Nav,
  NavItem,
  NavLink,
  TabContent,
  TabPane,
  Row
} from 'reactstrap'

import BasicProvider from './BasicProvider'
import SourcePriorities from './SourcePriorities'
import { set } from 'lodash'

function fetchProviders () {
  fetch(`/providers`, {
    credentials: 'include'
  })
    .then(response => response.json())
    .then(data => {
      let selectedProvider = undefined
      let selectedIndex = undefined
      if (this.state.selectedProviderId) {
        selectedProvider = data.find(provider => provider.id === this.state.selectedProviderId)
        selectedIndex = data.findIndex(provider => provider.id === this.state.selectedProviderId)
      }
      if (selectedProvider) {
        selectedProvider.originalId = selectedProvider.id
      }
      this.setState({
        providers: data,
        selectedProvider: selectedProvider ? JSON.parse(JSON.stringify(selectedProvider)) : undefined,
        selectedIndex: selectedIndex
       })
    })
}

function runDiscovery () {
  fetch(`/runDiscovery`, {
    method: 'PUT',
    credentials: 'include'
  })
}

function onRowSelect (row, isSelected, e) {
  // if column index is 2, will not trigger selection
  if (e.target.cellIndex === 2) return false
}

class ProvidersConfiguration extends Component {
  constructor (props) {
    super(props)
    this.state = {
      activeTab: '1',
      providers: [],
      selectedProviderId: this.props.match.params.providerId
    }

    this.fetchProviders = fetchProviders.bind(this)
    this.runDiscovery = runDiscovery.bind(this)
    this.handleProviderChange = this.handleProviderChange.bind(this)
    this.handleProviderPropChange = this.handleProviderChange.bind(this)
    this.handleAddProvider = this.handleAddProvider.bind(this)
    this.handleCancel = this.handleCancel.bind(this)
    this.toggle = this.toggle.bind(this)
    this.handleApply = this.handleApply.bind(this)
    this.handleCancel = this.handleCancel.bind(this)
    this.handleDelete = this.handleDelete.bind(this)
  }

  componentDidMount () {
    this.fetchProviders()
    this.runDiscovery()
  }

  handleProviderChange (event, type) {
    var value =
      event.target.type === 'checkbox'
        ? event.target.checked
        : event.target.value
    if (type === 'number') {
      value = Number(value)
    }
    set(this.state.selectedProvider, event.target.name, value)
    this.setState({
      selectedProvider: this.state.selectedProvider
    })
  }

  handleProviderPropChange(event) {
    this.setState({
      selectedProvider: this.state.selectedProvider
    })
  }

  handleAddProvider (event) {
    var newProvider = {
      type: 'NMEA2000',
      logging: false,
      isNew: true,
      id: '',
      enabled: true,
      options: {},
      editable: true
    }
    this.setState(
      {
        selectedProvider: JSON.parse(JSON.stringify(newProvider)),
        selectedIndex: this.state.providers.length - 1
      },
      () => {
        this.refs['selectedProvider'].scrollIntoView()
      }
    )
  }

  handleApply (event) {
    var isNew = this.state.selectedProvider.isNew
    var wasDiscovered = this.state.selectedProvider.wasDiscovered

    var provider = this.state.selectedProvider
    delete this.state.selectedProvider.json

    var id = this.state.selectedProvider.originalId

    fetch(`/providers/${id && !isNew ? id : ''}`, {
      method: isNew ? 'POST' : 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(this.state.selectedProvider),
      credentials: 'include'
    })
      .then(response => {
        if ( response.ok ) {
          var provider = JSON.parse(JSON.stringify(this.state.selectedProvider))
          delete provider.isNew
          delete provider.wasDiscovered
          delete this.state.selectedProvider.isNew
          if (isNew) {
            this.state.providers.push(provider)
          } else {
            this.state.providers[this.state.selectedIndex] = provider
          }
          if ( wasDiscovered ) {
            this.props.discoveredProviders.splice(this.state.selectedIndex, 1)
          }
          this.setState({
            providers: this.state.providers,
            //discoveredProviders: this.state.discoveredProviders,
            selectedProvider: null,
            selectedIndex: -1
          }, () => {
            this.props.history.push('/serverConfiguration/connections/-')
          })
        }
        return response.text()
      })
      .then(text => {
        alert(text)
      })
  }

  handleCancel (event) {
    this.setState({ selectedProvider: null })
  }

  handleDelete (event) {
    fetch(`/providers/${this.state.selectedProvider.id}`, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json'
      },
      credentials: 'include'
    })
      .then(response => response.text())
      .then(response => {
        this.state.providers.splice(this.state.selectedIndex, 1)
        this.setState({
          providers: this.state.providers,
          selectedProvider: null,
          selectedIndex: -1
        })
        alert(response)
      })
  }

  providerClicked (provider, index) {
    this.setState(
      {
        selectedProvider: {
          ...JSON.parse(JSON.stringify(provider)),
          originalId: provider.id
        },
        selectedIndex: index
      },
      () => {
        this.refs['selectedProvider'].scrollIntoView()
      }
    )
  }

  toggle (tab) {
    if (this.state.activeTab !== tab) {
      this.setState({
        activeTab: tab
      })
    }
  }

  render () {
    return (

        {this.props.discoveredProviders && this.props.discoveredProviders.length > 0 && (
        <Card>
        <CardHeader>Discovered Connections</CardHeader>
          <CardBody>

                  ID
                  Data Type
                  Enabled
                  Logging

                {(this.props.discoveredProviders || []).map((provider, index) => {
                  return (

                      {provider.id}

                        <ProviderType provider={provider} />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.enabled}
                        />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.logging}
                        />

                  )
                })}

          </CardBody>
        </Card>
        )}
        <Card>
        <CardHeader>Connections</CardHeader>
          <CardBody>

                  ID
                  Data Type
                  Enabled
                  Logging

                {(this.state.providers || []).map((provider, index) => {
                  return (

                      {provider.id}

                        <ProviderType provider={provider} />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.enabled}
                        />

                        <ApplicableStatus
                          applicable={provider.editable}
                          toggle={provider.logging}
                        />

                  )
                })}

          </CardBody>
          <CardFooter>
            <Button size='sm' color='primary' onClick={this.handleAddProvider}>
               Add
            </Button>
          </CardFooter>
        </Card>

        {this.state.selectedProvider && (

            <Card>
              <CardBody>
                {this.state.selectedProvider.editable ? (
                  <BasicProvider
                    value={this.state.selectedProvider}
                    onChange={this.handleProviderChange}
                    onPropChange={this.handleProviderPropChange}
                  />
                ) : (
                  <Input
                    type='textarea'
                    name='json'
                    id='json'
                    rows='20'
                    value={this.state.selectedProvider.json}
                    readOnly='true'
                  />
                )}
              </CardBody>
              <CardFooter>
                {this.state.selectedProvider.editable ? (
                  <Row>
                    <Col xs='4' md='1'>
                      <Button
                        size='sm'
                        color='primary'
                        onClick={this.handleApply}
                      >
                         Apply
                      </Button>
                    </Col>
                    <Col xs='4' md='1'>
                      <Button
                        size='sm'
                        color='secondary'
                        onClick={this.handleCancel}
                      >
                         Cancel
                      </Button>
                    </Col>
                    <Col xs='4' md='10' className='text-right'>
                      <Button
                        size='sm'
                        color='danger'
                        onClick={this.handleDelete}
                      >
                         Delete
                      </Button>
                    </Col>
                  </Row>
                ) : (
                  <Row>
                    <Col xs='4' md='12' className='text-right'>
                      <Button
                        size='sm'
                        color='danger'
                        onClick={this.handleDelete}
                      >
                         Delete
                      </Button>
                    </Col>
                  </Row>
                )}
              </CardFooter>
            </Card>

        )}

        <SourcePriorities/>

    )
  }
}

const ApplicableStatus = props => (

{props.applicable ? (props.toggle ? 'Yes' : 'No') : 'N/A'}

)

const ProviderType = props => (

    {props.provider.type}
    {props.provider.type === 'FileStream'
      ? `/${props.provider.options.dataType}`
      : ''}

)
const mapStateToProps = ({ discoveredProviders  }) => ({ discoveredProviders })

export default connect(mapStateToProps)(ProvidersConfiguration)
<|endoftext|>


<commit_before>
function contentSize(asset, key) {
	key = key || 'data';

	if (!(asset && asset.content && asset.content[key])) {
		return 0;
	}

	var data = asset.content[key];
	if (typeof(data) === 'string') {
		return Buffer.byteLength(data);
	} else {
		return data.length | 0;
	}
}

module.exports = contentSize;
<commit_msg>Support for string/buffers directly.<commit_after>
function contentSize(asset, key) {
	if (typeof(asset) === 'string') {
		return Buffer.byteLength(asset);
	} else if (Buffer.isBuffer(asset)) {
		return asset.length;
	}

	key = key || 'data';

	if (!(asset && asset.content && asset.content[key])) {
		return 0;
	}

	var data = asset.content[key];
	if (typeof(data) === 'string') {
		return Buffer.byteLength(data);
	} else {
		return data.length | 0;
	}
}

module.exports = contentSize;
<|endoftext|>


<commit_before>const expect = require("chai").expect;
const path = require("path");
const helmet = require("helmet");
const { JSDOM } = require("jsdom");
const express = require("express");

describe("Translator", function () {
	let server;

	before(function () {
		const app = express();
		app.use(helmet());
		app.use(function (req, res, next) {
			res.header("Access-Control-Allow-Origin", "*");
			next();
		});
		app.use("/translations", express.static(path.join(__dirname, "..", "..", "..", "tests", "configs", "data")));

		server = app.listen(3000);
	});

	after(function () {
		server.close();
	});

	describe("translate", function () {
		const translations = {
			"MMM-Module": {
				Hello: "Hallo",
				"Hello {username}": "Hallo {username}"
			}
		};

		const coreTranslations = {
			Hello: "XXX",
			"Hello {username}": "XXX",
			FOO: "Foo",
			"BAR {something}": "Bar {something}"
		};

		const translationsFallback = {
			"MMM-Module": {
				Hello: "XXX",
				"Hello {username}": "XXX",
				FOO: "XXX",
				"BAR {something}": "XXX",
				"A key": "A translation"
			}
		};

		const coreTranslationsFallback = {
			FOO: "XXX",
			"BAR {something}": "XXX",
			Hello: "XXX",
			"Hello {username}": "XXX",
			"A key": "XXX",
			Fallback: "core fallback"
		};

		function setTranslations(Translator) {
			Translator.translations = translations;
			Translator.coreTranslations = coreTranslations;
			Translator.translationsFallback = translationsFallback;
			Translator.coreTranslationsFallback = coreTranslationsFallback;
		}

		it("should return custom module translation", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
				expect(translation).to.be.equal("Hallo");
				translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}", { username: "fewieden" });
				expect(translation).to.be.equal("Hallo fewieden");
				done();
			};
		});

		it("should return core translation", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
				expect(translation).to.be.equal("Foo");
				translation = Translator.translate({ name: "MMM-Module" }, "BAR {something}", { something: "Lorem Ipsum" });
				expect(translation).to.be.equal("Bar Lorem Ipsum");
				done();
			};
		});

		it("should return custom module translation fallback", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "A key");
				expect(translation).to.be.equal("A translation");
				done();
			};
		});

		it("should return core translation fallback", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "Fallback");
				expect(translation).to.be.equal("core fallback");
				done();
			};
		});

		it("should return translation with placeholder for missing variables", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}");
				expect(translation).to.be.equal("Hallo {username}");
				done();
			};
		});

		it("should return key if no translation was found", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
				expect(translation).to.be.equal("MISSING");
				done();
			};
		});
	});

	describe("load", function () {
		const mmm = {
			name: "TranslationTest",
			file(file) {
				return `http://localhost:3000/translations/${file}`;
			}
		};

		it("should load translations", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				const file = "TranslationTest.json";

				Translator.load(mmm, file, false, function () {
					const json = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", file));
					expect(Translator.translations[mmm.name]).to.be.deep.equal(json);
					done();
				});
			};
		});

		it("should load translation fallbacks", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				const file = "TranslationTest.json";

				Translator.load(mmm, file, true, function () {
					const json = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", file));
					expect(Translator.translationsFallback[mmm.name]).to.be.deep.equal(json);
					done();
				});
			};
		});

		it("should not load translations, if module fallback exists", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator, XMLHttpRequest } = dom.window;
				const file = "TranslationTest.json";

				XMLHttpRequest.prototype.send = function () {
					throw "Shouldn't load files";
				};

				Translator.translationsFallback[mmm.name] = {
					Hello: "Hallo"
				};

				Translator.load(mmm, file, false, function () {
					expect(Translator.translations[mmm.name]).to.be.undefined;
					expect(Translator.translationsFallback[mmm.name]).to.be.deep.equal({
						Hello: "Hallo"
					});
					done();
				});
			};
		});
	});

	describe("loadCoreTranslations", function () {
		it("should load core translations and fallback", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations("en");

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslations).to.be.deep.equal(en);
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});

		it("should load core fallback if language cannot be found", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations("MISSINGLANG");

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslations).to.be.deep.equal({});
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});
	});

	describe("loadCoreTranslationsFallback", function () {
		it("should load core translations fallback", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslationsFallback();

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});

		it("should load core fallback if language cannot be found", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations();

				setTimeout(function () {
					expect(Translator.coreTranslationsFallback).to.be.deep.equal({});
					done();
				}, 500);
			};
		});
	});
});
<commit_msg>Cleanup test expectation<commit_after>const expect = require("chai").expect;
const path = require("path");
const helmet = require("helmet");
const { JSDOM } = require("jsdom");
const express = require("express");

describe("Translator", function () {
	let server;

	before(function () {
		const app = express();
		app.use(helmet());
		app.use(function (req, res, next) {
			res.header("Access-Control-Allow-Origin", "*");
			next();
		});
		app.use("/translations", express.static(path.join(__dirname, "..", "..", "..", "tests", "configs", "data")));

		server = app.listen(3000);
	});

	after(function () {
		server.close();
	});

	describe("translate", function () {
		const translations = {
			"MMM-Module": {
				Hello: "Hallo",
				"Hello {username}": "Hallo {username}"
			}
		};

		const coreTranslations = {
			Hello: "XXX",
			"Hello {username}": "XXX",
			FOO: "Foo",
			"BAR {something}": "Bar {something}"
		};

		const translationsFallback = {
			"MMM-Module": {
				Hello: "XXX",
				"Hello {username}": "XXX",
				FOO: "XXX",
				"BAR {something}": "XXX",
				"A key": "A translation"
			}
		};

		const coreTranslationsFallback = {
			FOO: "XXX",
			"BAR {something}": "XXX",
			Hello: "XXX",
			"Hello {username}": "XXX",
			"A key": "XXX",
			Fallback: "core fallback"
		};

		function setTranslations(Translator) {
			Translator.translations = translations;
			Translator.coreTranslations = coreTranslations;
			Translator.translationsFallback = translationsFallback;
			Translator.coreTranslationsFallback = coreTranslationsFallback;
		}

		it("should return custom module translation", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
				expect(translation).to.be.equal("Hallo");
				translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}", { username: "fewieden" });
				expect(translation).to.be.equal("Hallo fewieden");
				done();
			};
		});

		it("should return core translation", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
				expect(translation).to.be.equal("Foo");
				translation = Translator.translate({ name: "MMM-Module" }, "BAR {something}", { something: "Lorem Ipsum" });
				expect(translation).to.be.equal("Bar Lorem Ipsum");
				done();
			};
		});

		it("should return custom module translation fallback", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "A key");
				expect(translation).to.be.equal("A translation");
				done();
			};
		});

		it("should return core translation fallback", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "Fallback");
				expect(translation).to.be.equal("core fallback");
				done();
			};
		});

		it("should return translation with placeholder for missing variables", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}");
				expect(translation).to.be.equal("Hallo {username}");
				done();
			};
		});

		it("should return key if no translation was found", function (done) {
			const dom = new JSDOM(`<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				setTranslations(Translator);
				const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
				expect(translation).to.be.equal("MISSING");
				done();
			};
		});
	});

	describe("load", function () {
		const mmm = {
			name: "TranslationTest",
			file(file) {
				return `http://localhost:3000/translations/${file}`;
			}
		};

		it("should load translations", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				const file = "TranslationTest.json";

				Translator.load(mmm, file, false, function () {
					const json = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", file));
					expect(Translator.translations[mmm.name]).to.be.deep.equal(json);
					done();
				});
			};
		});

		it("should load translation fallbacks", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator } = dom.window;
				const file = "TranslationTest.json";

				Translator.load(mmm, file, true, function () {
					const json = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", file));
					expect(Translator.translationsFallback[mmm.name]).to.be.deep.equal(json);
					done();
				});
			};
		});

		it("should not load translations, if module fallback exists", function (done) {
			const dom = new JSDOM(`<script>var Log = {log: function(){}};</script><script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`, { runScripts: "dangerously", resources: "usable" });
			dom.window.onload = function () {
				const { Translator, XMLHttpRequest } = dom.window;
				const file = "TranslationTest.json";

				XMLHttpRequest.prototype.send = function () {
					throw "Shouldn't load files";
				};

				Translator.translationsFallback[mmm.name] = {
					Hello: "Hallo"
				};

				Translator.load(mmm, file, false, function () {
					expect(Translator.translations[mmm.name]).to.be.equal(undefined);
					expect(Translator.translationsFallback[mmm.name]).to.be.deep.equal({
						Hello: "Hallo"
					});
					done();
				});
			};
		});
	});

	describe("loadCoreTranslations", function () {
		it("should load core translations and fallback", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations("en");

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslations).to.be.deep.equal(en);
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});

		it("should load core fallback if language cannot be found", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations("MISSINGLANG");

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslations).to.be.deep.equal({});
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});
	});

	describe("loadCoreTranslationsFallback", function () {
		it("should load core translations fallback", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {en: "http://localhost:3000/translations/en.json"}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslationsFallback();

				const en = require(path.join(__dirname, "..", "..", "..", "tests", "configs", "data", "en.json"));
				setTimeout(function () {
					expect(Translator.coreTranslationsFallback).to.be.deep.equal(en);
					done();
				}, 500);
			};
		});

		it("should load core fallback if language cannot be found", function (done) {
			const dom = new JSDOM(
				`<script>var translations = {}; var Log = {log: function(){}};</script>\
					<script src="${path.join(__dirname, "..", "..", "..", "js", "translator.js")}">`,
				{ runScripts: "dangerously", resources: "usable" }
			);
			dom.window.onload = function () {
				const { Translator } = dom.window;
				Translator.loadCoreTranslations();

				setTimeout(function () {
					expect(Translator.coreTranslationsFallback).to.be.deep.equal({});
					done();
				}, 500);
			};
		});
	});
});
<|endoftext|>


<commit_before>"use strict";

var Promise = require('bluebird');

var AdminCommand = require("./AdminCommand");

var adminCommands = {};

function quotemeta(s) { return s.replace(/\W/g, '\\$&'); }

adminCommands.help = AdminCommand.makeHelpCommand(adminCommands);

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    opts: {
        "team|T": "Filter only rooms for this Slack team domain",
    },
    func: function(bridge, opts, args, respond) {
        var name_filter;

        if (opts.team) {
            name_filter = new RegExp("^" + quotemeta(opts.team) + "\.#");
        }

        var found = 0;
        bridge._rooms.forEach((room) => {
            var matrix_room_ids = room.getMatrixRoomIds();

            var slack_channel_id = room.getSlackChannelId();
            var slack_channel_name = room.getSlackChannelName() || "UNKNOWN";

            if (name_filter && !name_filter.exec(slack_channel_name)) {
                return;
            }

            var slack = slack_channel_name + "(" + slack_channel_id + ")";

            var status = room.getStatus();
            if (status !== "ready") status = status.toUpperCase();

            found++;

            if (!matrix_room_ids.length) {
                respond(status + " " + slack + " unlinked");
            }
            else if (matrix_room_ids.length == 1) {
                respond(status + " " + slack + " -- " + matrix_room_ids[0]);
            }
            else {
                respond(status + " " + slack + " linked:");
                matrix_room_ids.forEach((id) => respond(" +- " + id));
            }
        });

        if (!found) {
            respond("No rooms found");
        }
    },
});

adminCommands.show = new AdminCommand({
    desc: "show a single connected room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        console.log("opts are", opts);
        console.log("opts keys are", Object.keys(opts));

        if (Object.keys(opts).length != 1) {
            return Promise.reject("Require exactly one of --room, --channel or --channel_id");
        }

        var room = (opts.channel_id) ? bridge.getRoomBySlackChannelId(opts.channel_id) :
                   (opts.channel) ? bridge.getRoomBySlackChannelName(opts.channel) :
                   bridge.getRoomByMatrixRoomId(opts.room);

        if (!room) {
            respond("No such room");
            return;
        }

        respond("Bridged Room:");
        respond("  Status: " + room.getStatus());
        respond("  Inbound ID: " + room.getInboundId() || "(legacy)");
        respond("  Slack Name: " + room.getSlackChannelName() || "PENDING");
        respond("  Slack ID: " + room.getSlackChannelId());
        respond("  Token: " + room.getSlackToken());
        respond("  Webhook URI: " + room.getSlackWebhookUri());

        var matrix_room_ids = room.getMatrixRoomIds();

        if (!matrix_room_ids.length) {
            respond("  No Matrix room IDs");
        }
        else if(matrix_room_ids.length === 1) {
            respond("  Matrix room ID: " + matrix_room_ids[0]);
        }
        else {
            respond("  Matrix room IDs:");
            matrix_room_ids.forEach((id) => respond("    " + id));
        }
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
        "token|t": "Slack webhook token",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
            slack_token: opts.token,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        if (!opts.channel && !opts.channel_id) {
            return Promise.reject("Require either --channel or --channel_id");
        }

        return bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

module.exports = adminCommands;
<commit_msg>Don't even attempt to display slack channel ID of new-style rooms in 'list' command<commit_after>"use strict";

var Promise = require('bluebird');

var AdminCommand = require("./AdminCommand");

var adminCommands = {};

function quotemeta(s) { return s.replace(/\W/g, '\\$&'); }

adminCommands.help = AdminCommand.makeHelpCommand(adminCommands);

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    opts: {
        "team|T": "Filter only rooms for this Slack team domain",
    },
    func: function(bridge, opts, args, respond) {
        var name_filter;

        if (opts.team) {
            name_filter = new RegExp("^" + quotemeta(opts.team) + "\.#");
        }

        var found = 0;
        bridge._rooms.forEach((room) => {
            var matrix_room_ids = room.getMatrixRoomIds();

            var slack_channel_id = room.getSlackChannelId();
            var slack_channel_name = room.getSlackChannelName() || "UNKNOWN";

            if (name_filter && !name_filter.exec(slack_channel_name)) {
                return;
            }

            var slack = slack_channel_id ?
                slack_channel_name + "(" + slack_channel_id + ")" :
                slack_channel_name;

            var status = room.getStatus();
            if (status !== "ready") status = status.toUpperCase();

            found++;

            if (!matrix_room_ids.length) {
                respond(status + " " + slack + " unlinked");
            }
            else if (matrix_room_ids.length == 1) {
                respond(status + " " + slack + " -- " + matrix_room_ids[0]);
            }
            else {
                respond(status + " " + slack + " linked:");
                matrix_room_ids.forEach((id) => respond(" +- " + id));
            }
        });

        if (!found) {
            respond("No rooms found");
        }
    },
});

adminCommands.show = new AdminCommand({
    desc: "show a single connected room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        console.log("opts are", opts);
        console.log("opts keys are", Object.keys(opts));

        if (Object.keys(opts).length != 1) {
            return Promise.reject("Require exactly one of --room, --channel or --channel_id");
        }

        var room = (opts.channel_id) ? bridge.getRoomBySlackChannelId(opts.channel_id) :
                   (opts.channel) ? bridge.getRoomBySlackChannelName(opts.channel) :
                   bridge.getRoomByMatrixRoomId(opts.room);

        if (!room) {
            respond("No such room");
            return;
        }

        respond("Bridged Room:");
        respond("  Status: " + room.getStatus());
        respond("  Inbound ID: " + room.getInboundId() || "(legacy)");
        respond("  Slack Name: " + room.getSlackChannelName() || "PENDING");
        respond("  Slack ID: " + room.getSlackChannelId());
        respond("  Token: " + room.getSlackToken());
        respond("  Webhook URI: " + room.getSlackWebhookUri());

        var matrix_room_ids = room.getMatrixRoomIds();

        if (!matrix_room_ids.length) {
            respond("  No Matrix room IDs");
        }
        else if(matrix_room_ids.length === 1) {
            respond("  Matrix room ID: " + matrix_room_ids[0]);
        }
        else {
            respond("  Matrix room IDs:");
            matrix_room_ids.forEach((id) => respond("    " + id));
        }
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
        "token|t": "Slack webhook token",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
            slack_token: opts.token,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        if (!opts.channel && !opts.channel_id) {
            return Promise.reject("Require either --channel or --channel_id");
        }

        return bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

module.exports = adminCommands;
<|endoftext|>


<commit_before>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', function(){

		self.findServer;

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here ..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:

			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));

			// Save client in cache

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:

			this.emit('single-message', data.sender, data.extras);
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<commit_msg>nothing<commit_after>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', function(){

		self.findServer;

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here ..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:

			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));

			// Save client in cache

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(this._channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:

			this.emit('single-message', data.sender, data.extras);
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<|endoftext|>


<commit_before>import { NodeAssembler } from './NodeAssembler'

const { prototype : { map } } = Array
const { Attr, Node : { ELEMENT_NODE }, document } = window
const EMPTY_STRING = ''
const NAMESPACE_SEPARATOR = ':'
const VALUE_PROPERTY_NAME = 'value'

/**
 * @see https://www.w3.org/TR/dom/#interface-attr
 */
export class AttrAssembler extends NodeAssembler {
    /**
     * Remove the attribute from it's owner element
     */
    remove() {
        const ownerElement = this.node.ownerElement
        if(ownerElement) {
            ownerElement.removeAttribute(this.name)
        }
    }

    /**
     * @return {string}
     */
    get name() {
        return this.node.name
    }

    /**
     * @param {ElementAssembler|Element|*} ownerElement
     */
    set ownerElement(ownerElement) {
        const node = this.node
        if(ownerElement) {
            if(ownerElement instanceof NodeAssembler.ElementAssembler) {
                ownerElement.setAttr(node)
            }
            else if(ownerElement.nodeType === ELEMENT_NODE) {
                ownerElement.attributes.setNamedItem(node)
            }
            else {
                const element = new this.constructor.elementAssembler(ownerElement)
                element.setAttr(node)
            }
        }
    }

    /**
     * @returns {ElementAssembler|null}
     */
    get ownerElement() {
        return this.getInstanceOf(this.node.ownerElement)
    }

    /**
     * @returns {ElementAssembler|*|null}
     */
    get parentElement() {
        return this.node.ownerElement && this.ownerElement.parentElement
    }

    /**
     * @param {ParentNodeAssembler|*|null} parentNode
     */
    set parentNode(parentNode) {
        if(this.node.ownerElement) {
            this.ownerElement.parentNode = parentNode
        }
        else throw Error(`Failed to set 'parentNode' on '${ this.constructor.name }': the 'ownerElement' is null.`)
    }

    /**
     * @returns {ParentNodeAssembler|*|null}
     */
    get parentNode() {
        return this.node.ownerElement && this.ownerElement.parentNode
    }

    /**
     * @param {string|*} value
     */
    set value(value) {
        if(this.constructor.removeOnValue(value)) {
            this.remove()
        }
        else this.node.value = value
    }

    /**
     * @returns {string|*}
     */
    get value() {
        return this.node.value
    }

    /**
     * @returns {Attr|*}
     * @override
     */
    static create() {
        return document.createAttributeNS(this.namespace, this.qualifiedName)
    }

    /**
     * @param {ElementAssembler|Element|*} element
     * @returns {AttrAssembler|*}
     */
    static getAttrOf(element) {
        const node = this.getNodeOf(element)
        const attr = node.attributes.getNamedItem(this.qualifiedName)
        return attr && this.getInstanceOf(attr)
    }

    /**
     * @param {string|Element|Document|DocumentFragment} [selectorOrContext=this.selector]
     * @param {Element|Document|DocumentFragment} [context=window.document]
     * @returns {AttrAssembler[]} array of initialized instances
     */
    static init(selectorOrContext, context = document) {
        const localName = this.localName
        if(selectorOrContext.nodeType) {
            context = selectorOrContext
            selectorOrContext = this.selector
        }
        return map.call(context.querySelectorAll(selectorOrContext), ownerElement => {
            const node = ownerElement.attributes[localName]
            return node?
                new this({ node }) :
                new this({ ownerElement })
        })
    }

    /**
     * @param {*} value
     * @returns {boolean}
     */
    static removeOnValue(value) {
        return value === null
    }

    /**
     * @returns {string}
     * @override
     */
    static get defaultPropertyName() {
        return VALUE_PROPERTY_NAME
    }

    /**
     * @returns {null|*}
     */
    static get defaultValue() {
        return null
    }

    /**
     * @returns {interface} Attr
     * @override
     */
    static get interface() {
        return Attr
    }

    /**
     * @returns {string}
     */
    static get localName() {
        return this === AttrAssembler?
            EMPTY_STRING :
            this.name.toLowerCase()
    }

    /**
     * @returns {string}
     */
    static get namespace() {
        return EMPTY_STRING
    }

    /**
     * @returns {string}
     */
    static get prefix() {
        return EMPTY_STRING
    }

    /**
     * @returns {string}
     */
    static get qualifiedName() {
        const { prefix, localName } = this
        return prefix?
            prefix + NAMESPACE_SEPARATOR + localName :
            localName
    }

    /**
     * @returns {string}
     */
    static get selector() {
        return `[${ this.localName }]`
    }
}

NodeAssembler.AttrAssembler = AttrAssembler
<commit_msg>AttrAssembler.parentElement: remove getter<commit_after>import { NodeAssembler } from './NodeAssembler'

const { prototype : { map } } = Array
const { Attr, Node : { ELEMENT_NODE }, document } = window
const EMPTY_STRING = ''
const NAMESPACE_SEPARATOR = ':'
const VALUE_PROPERTY_NAME = 'value'

/**
 * @see https://www.w3.org/TR/dom/#interface-attr
 */
export class AttrAssembler extends NodeAssembler {
    /**
     * Remove the attribute from it's owner element
     */
    remove() {
        const ownerElement = this.node.ownerElement
        if(ownerElement) {
            ownerElement.removeAttribute(this.name)
        }
    }

    /**
     * @return {string}
     */
    get name() {
        return this.node.name
    }

    /**
     * @param {ElementAssembler|Element|*} ownerElement
     */
    set ownerElement(ownerElement) {
        const node = this.node
        if(ownerElement) {
            if(ownerElement instanceof NodeAssembler.ElementAssembler) {
                ownerElement.setAttr(node)
            }
            else if(ownerElement.nodeType === ELEMENT_NODE) {
                ownerElement.attributes.setNamedItem(node)
            }
            else {
                const element = new this.constructor.elementAssembler(ownerElement)
                element.setAttr(node)
            }
        }
    }

    /**
     * @returns {ElementAssembler|null}
     */
    get ownerElement() {
        return this.getInstanceOf(this.node.ownerElement)
    }

    /**
     * @param {ParentNodeAssembler|*|null} parentNode
     */
    set parentNode(parentNode) {
        if(this.node.ownerElement) {
            this.ownerElement.parentNode = parentNode
        }
        else throw Error(`Failed to set 'parentNode' on '${ this.constructor.name }': the 'ownerElement' is null.`)
    }

    /**
     * @returns {ParentNodeAssembler|*|null}
     */
    get parentNode() {
        return this.node.ownerElement && this.ownerElement.parentNode
    }

    /**
     * @param {string|*} value
     */
    set value(value) {
        if(this.constructor.removeOnValue(value)) {
            this.remove()
        }
        else this.node.value = value
    }

    /**
     * @returns {string|*}
     */
    get value() {
        return this.node.value
    }

    /**
     * @returns {Attr|*}
     * @override
     */
    static create() {
        return document.createAttributeNS(this.namespace, this.qualifiedName)
    }

    /**
     * @param {ElementAssembler|Element|*} element
     * @returns {AttrAssembler|*}
     */
    static getAttrOf(element) {
        const node = this.getNodeOf(element)
        const attr = node.attributes.getNamedItem(this.qualifiedName)
        return attr && this.getInstanceOf(attr)
    }

    /**
     * @param {string|Element|Document|DocumentFragment} [selectorOrContext=this.selector]
     * @param {Element|Document|DocumentFragment} [context=window.document]
     * @returns {AttrAssembler[]} array of initialized instances
     */
    static init(selectorOrContext, context = document) {
        const localName = this.localName
        if(selectorOrContext.nodeType) {
            context = selectorOrContext
            selectorOrContext = this.selector
        }
        return map.call(context.querySelectorAll(selectorOrContext), ownerElement => {
            const node = ownerElement.attributes[localName]
            return node?
                new this({ node }) :
                new this({ ownerElement })
        })
    }

    /**
     * @param {*} value
     * @returns {boolean}
     */
    static removeOnValue(value) {
        return value === null
    }

    /**
     * @returns {string}
     * @override
     */
    static get defaultPropertyName() {
        return VALUE_PROPERTY_NAME
    }

    /**
     * @returns {null|*}
     */
    static get defaultValue() {
        return null
    }

    /**
     * @returns {interface} Attr
     * @override
     */
    static get interface() {
        return Attr
    }

    /**
     * @returns {string}
     */
    static get localName() {
        return this === AttrAssembler?
            EMPTY_STRING :
            this.name.toLowerCase()
    }

    /**
     * @returns {string}
     */
    static get namespace() {
        return EMPTY_STRING
    }

    /**
     * @returns {string}
     */
    static get prefix() {
        return EMPTY_STRING
    }

    /**
     * @returns {string}
     */
    static get qualifiedName() {
        const { prefix, localName } = this
        return prefix?
            prefix + NAMESPACE_SEPARATOR + localName :
            localName
    }

    /**
     * @returns {string}
     */
    static get selector() {
        return `[${ this.localName }]`
    }
}

NodeAssembler.AttrAssembler = AttrAssembler
<|endoftext|>


<commit_before>let fs = require('fs');
let glob = require('glob');
let path = require('path');

const contentTypeMappingConst = {
	'.html': 'text/html',
	'.json': 'application/json',
	'.css': 'text/css',
	'.js': 'application/javascript',
	'.ico': 'image/x-icon',
	'.svg': 'image/svg+xml',
	'.eot': 'application/vnd.ms-fontobject',
	'.ttf': 'application/font-sfnt',
	'.woff': 'application/font-woff',
	'.gif': 'image/gif',
	'.zip': 'application/zip',
	'default': 'text/plain'
};

class BucketManager {
	constructor(s3Manager, bucket) {
		this.S3Manager = s3Manager;
		this.Bucket = bucket ? bucket : null;
	}

	Deploy(contentPath, version, cacheControlRegexMap = [], contentTypeMappingOverride = {}) {
		let contentTypeMapping = Object.assign({}, contentTypeMappingConst, contentTypeMappingOverride || {});
		console.log('Deploying Website');
		return new Promise((resolve, reject) => {
			glob(path.join(contentPath, '**'), { nonull: true, dot: true, nodir: true }, (error, files) => {
				error ? reject({ Title: 'Failed to get list of content files', Error: error.stack || error.toString(), Detail: error }) : resolve(files);
			});
		})
		.then(list => {
			let indexList = list.filter(file => file.match('index.html')).sort((a, b) => b.split('/').length - a.split('/').length);
			let sortedList = list.filter(file => !file.match('index.html'));
			return sortedList.concat(indexList).reduce((listPromise, file) => {
				return listPromise.then(() => {
					let relativePath = path.relative(path.resolve(contentPath), path.resolve(file));
					let matchingCacheMap = Array.isArray(cacheControlRegexMap) && cacheControlRegexMap.find(m => {
						return !m.explicit && !m.regex || m.explicit === file || m.regex && m.regex.exec && m.regex.exec(file);
					});
					let cacheControl = matchingCacheMap && matchingCacheMap.value || cacheControlRegexMap[relativePath] || cacheControlRegexMap.default || 600;
					return this.S3Manager.putObject({
						Bucket: this.Bucket,
						Key: path.join(version, relativePath),
						Body: fs.createReadStream(file),
						ContentType: contentTypeMapping[path.extname(file)] || contentTypeMapping.default || 'text/plain',
						CacheControl: typeof maxAge === 'number' ? `public, max-age=${cacheControl}` : cacheControl
					}).promise()
					.then(() => { console.log(`====> ${file}`); })
					.catch(failure => Promise.reject({ File: file, Error: failure.stack || failure.toString(), Detail: failure }));
				});
			}, Promise.resolve())
			.then(() => {
				return { Title: 'Upload Success.', Bucket: this.Bucket, Version: version };
			});
		});
	}

	DeployLambdaPromise(bucket, localPath, remotePath) {
		return this.S3Manager.upload({
			Bucket: bucket || this.Bucket,
			Key: remotePath,
			Body: fs.createReadStream(localPath),
			ContentType: contentTypeMappingConst[path.extname(remotePath)] || contentTypeMappingConst.default || 'text/plain',
			CacheControl: 'public, max-age=10'
		}).promise()
		.then(() => { console.log(`====> ${remotePath}`); })
		.catch(failure => {
			throw { File: localPath, Detail: failure };
		});
	}

	CopyBucket(source, target) {
		let listParams = {
			Bucket: this.Bucket,
			Delimiter: ',',
			EncodingType: 'url',
			//FetchOwner: true || false,
			//MaxKeys: 0
			Prefix: source
		};
		return this.S3Manager.listObjectsV2(listParams).promise()
		.then(data => {
			if (data.IsTruncated) { throw ({ Title: 'Failed to copy source', Error: 'Too many objects present.' }); }
			return data.Contents.map(item => item.Key).filter(key => !key.match(/\/$/)).reduce((listPromise, key) => {
				return listPromise.then(() => {
					return this.S3Manager.copyObject({
						Bucket: this.Bucket,
						Key: path.join(target, path.relative(source, key)),
						CopySource: `${this.Bucket}/${key}`
					}).promise()
					.catch(failure => Promise.reject({ Source: key, Error: failure.stack || failure.toString(), Detail: failure }));
				}).then(() => Promise.resolve({ Title: 'Promote to stage success', Bucket: this.Bucket, Source: source, Target: target }));
			}, Promise.resolve([]));
		});
	}
}

module.exports = BucketManager;
<commit_msg>Fix explicit cache control.<commit_after>let fs = require('fs');
let glob = require('glob');
let path = require('path');

const contentTypeMappingConst = {
	'.html': 'text/html',
	'.json': 'application/json',
	'.css': 'text/css',
	'.js': 'application/javascript',
	'.ico': 'image/x-icon',
	'.svg': 'image/svg+xml',
	'.eot': 'application/vnd.ms-fontobject',
	'.ttf': 'application/font-sfnt',
	'.woff': 'application/font-woff',
	'.gif': 'image/gif',
	'.zip': 'application/zip',
	'default': 'text/plain'
};

class BucketManager {
	constructor(s3Manager, bucket) {
		this.S3Manager = s3Manager;
		this.Bucket = bucket ? bucket : null;
	}

	Deploy(contentPath, version, cacheControlRegexMap = [], contentTypeMappingOverride = {}) {
		let contentTypeMapping = Object.assign({}, contentTypeMappingConst, contentTypeMappingOverride || {});
		console.log('Deploying Website');
		return new Promise((resolve, reject) => {
			glob(path.join(contentPath, '**'), { nonull: true, dot: true, nodir: true }, (error, files) => {
				error ? reject({ Title: 'Failed to get list of content files', Error: error.stack || error.toString(), Detail: error }) : resolve(files);
			});
		})
		.then(list => {
			let indexList = list.filter(file => file.match('index.html')).sort((a, b) => b.split('/').length - a.split('/').length);
			let sortedList = list.filter(file => !file.match('index.html'));
			return sortedList.concat(indexList).reduce((listPromise, file) => {
				return listPromise.then(() => {
					let relativePath = path.relative(path.resolve(contentPath), path.resolve(file));
					let matchingCacheMap = Array.isArray(cacheControlRegexMap) && cacheControlRegexMap.find(m => {
						return !m.explicit && !m.regex || m.explicit === relativePath || m.regex && m.regex.exec && m.regex.exec(file);
					});
					let cacheControl = matchingCacheMap && matchingCacheMap.value || cacheControlRegexMap[relativePath] || cacheControlRegexMap.default || 600;
					return this.S3Manager.putObject({
						Bucket: this.Bucket,
						Key: path.join(version, relativePath),
						Body: fs.createReadStream(file),
						ContentType: contentTypeMapping[path.extname(file)] || contentTypeMapping.default || 'text/plain',
						CacheControl: typeof maxAge === 'number' ? `public, max-age=${cacheControl}` : cacheControl
					}).promise()
					.then(() => { console.log(`====> ${file}`); })
					.catch(failure => Promise.reject({ File: file, Error: failure.stack || failure.toString(), Detail: failure }));
				});
			}, Promise.resolve())
			.then(() => {
				return { Title: 'Upload Success.', Bucket: this.Bucket, Version: version };
			});
		});
	}

	DeployLambdaPromise(bucket, localPath, remotePath) {
		return this.S3Manager.upload({
			Bucket: bucket || this.Bucket,
			Key: remotePath,
			Body: fs.createReadStream(localPath),
			ContentType: contentTypeMappingConst[path.extname(remotePath)] || contentTypeMappingConst.default || 'text/plain',
			CacheControl: 'public, max-age=10'
		}).promise()
		.then(() => { console.log(`====> ${remotePath}`); })
		.catch(failure => {
			throw { File: localPath, Detail: failure };
		});
	}

	CopyBucket(source, target) {
		let listParams = {
			Bucket: this.Bucket,
			Delimiter: ',',
			EncodingType: 'url',
			//FetchOwner: true || false,
			//MaxKeys: 0
			Prefix: source
		};
		return this.S3Manager.listObjectsV2(listParams).promise()
		.then(data => {
			if (data.IsTruncated) { throw ({ Title: 'Failed to copy source', Error: 'Too many objects present.' }); }
			return data.Contents.map(item => item.Key).filter(key => !key.match(/\/$/)).reduce((listPromise, key) => {
				return listPromise.then(() => {
					return this.S3Manager.copyObject({
						Bucket: this.Bucket,
						Key: path.join(target, path.relative(source, key)),
						CopySource: `${this.Bucket}/${key}`
					}).promise()
					.catch(failure => Promise.reject({ Source: key, Error: failure.stack || failure.toString(), Detail: failure }));
				}).then(() => Promise.resolve({ Title: 'Promote to stage success', Bucket: this.Bucket, Source: source, Target: target }));
			}, Promise.resolve([]));
		});
	}
}

module.exports = BucketManager;
<|endoftext|>


<commit_before>/**
 * Expose Canvas Module
 */
whiteboard.Canvas = (function(_){

  /**
   * ----------------
   * Class Definition
   * ----------------
   */

  /**
   * A Canvas knows its ID (for serialization)
   * its name (for user recognition)
   * its strokes
   *
   */
  var Canvas = function(opts) {
    var now = (new Date()).toJSON();
    opts = opts || {};
    this.strokes = opts.strokes || {};
    this.id = opts.id || now;
    this.name = opts.name || now + "-Untitled";
    this.createdAt = opts.createdAt || now;

  };

  /**
   * ----------------
   * Instance Methods
   * ----------------
   */
  Canvas.prototype = {
    createOrUpdateStroke: function(stroke) {
     var strokeExists = this.strokes.hasOwnProperty(stroke.id);
     this.strokes[stroke.id] = stroke;

     if (strokeExists) {
       _.emit('Canvas.strokes.update', _buildStrokesEvent.call(this,stroke, 'update'));
     } else {
       _.emit("Canvas.strokes.create", _buildStrokesEvent.call(this, stroke, 'create'));
     }
    },
    handleStrokeChange: function(event) {
      if (event.action === 'focus' || event.action === 'unfocus')
        return;

      if (event.action === 'destroy') {
        delete this.strokes[event.target.id];
        _.emit('Canvas.strokes.destroy', _buildStrokesEvent.call(this, event.target, 'destroy'));
      } else {
        this.createOrUpdateStroke(event.target);
      }

    }

  };

  /**
   *  ---------------------------
   *  Module Attributes/Functions
   *  ---------------------------
   */

  /**
   * The canvas that is currently being shown/edited
   */
  Canvas.active = null;

  /**
   * Module initialization
   * Sets active canvas from settings
   *
   * Listens for changes to persist in canvas
   *
   * TODO: set up programmable canvas defaults (a la whiteboard.defaults = {})
   *
   */
  Canvas.init = function() {
    this.active = this.active || new Canvas();
    _.on("(StrokeAction|Stroke).*.commit", function(event){
      Canvas.active.handleStrokeChange(event)
    });
  };

  /**
   * -----------------
   * Private Functions
   * -----------------
   */

  function _buildStrokesEvent(stroke, action) {
    return {
      action: action,
      target: {
        canvas: this,
        stroke: stroke
      }
    }
  };

  return Canvas;

})(whiteboard);
<commit_msg>Canvas only listens for non-focus events<commit_after>/**
 * Expose Canvas Module
 */
whiteboard.Canvas = (function(_){

  /**
   * ----------------
   * Class Definition
   * ----------------
   */

  /**
   * A Canvas knows its ID (for serialization)
   * its name (for user recognition)
   * its strokes
   *
   */
  var Canvas = function(opts) {
    var now = (new Date()).toJSON();
    opts = opts || {};
    this.strokes = opts.strokes || {};
    this.id = opts.id || now;
    this.name = opts.name || now + "-Untitled";
    this.createdAt = opts.createdAt || now;

  };

  /**
   * ----------------
   * Instance Methods
   * ----------------
   */
  Canvas.prototype = {
    createOrUpdateStroke: function(stroke) {
     var strokeExists = this.strokes.hasOwnProperty(stroke.id);
     this.strokes[stroke.id] = stroke;

     if (strokeExists) {
       _.emit('Canvas.strokes.update', _buildStrokesEvent.call(this,stroke, 'update'));
     } else {
       _.emit("Canvas.strokes.create", _buildStrokesEvent.call(this, stroke, 'create'));
     }
    },
    handleStrokeChange: function(event) {
      if (event.action === 'focus' || event.action === 'unfocus')
        return;

      if (event.action === 'destroy') {
        delete this.strokes[event.target.id];
        _.emit('Canvas.strokes.destroy', _buildStrokesEvent.call(this, event.target, 'destroy'));
      } else {
        this.createOrUpdateStroke(event.target);
      }

    }

  };

  /**
   *  ---------------------------
   *  Module Attributes/Functions
   *  ---------------------------
   */

  /**
   * The canvas that is currently being shown/edited
   */
  Canvas.active = null;

  /**
   * Module initialization
   * Sets active canvas from settings
   *
   * Listens for changes to persist in canvas
   *
   * TODO: set up programmable canvas defaults (a la whiteboard.defaults = {})
   *
   */
  Canvas.init = function() {
    this.active = this.active || new Canvas();
    _.on("^(StrokeAction|Stroke).(?!(un)?focus)*commit", function(event){
      Canvas.active.handleStrokeChange(event)
    });
  };

  /**
   * -----------------
   * Private Functions
   * -----------------
   */

  function _buildStrokesEvent(stroke, action) {
    return {
      action: action,
      target: {
        canvas: this,
        stroke: stroke
      }
    }
  };

  return Canvas;

})(whiteboard);
<|endoftext|>


<commit_before>'use strict';

const path = require('path');

const escapeRegExp = require('lodash.escaperegexp');
const minimatch = require('minimatch');
const semver = require('semver');

const FileUtils = require('./FileUtils');
const JsModule = require('./JsModule');
const { version } = require('../package.json');

const CONFIG_FILE = '.importjs.json';

const DEFAULT_CONFIG = {
  aliases: {},
  declaration_keyword: 'import',
  named_exports: {},
  environments: [],
  excludes: [],
  group_imports: true,
  ignore_package_prefixes: [],
  import_dev_dependencies: false,
  import_function: 'require',
  lookup_paths: ['.'],
  max_line_length: 80,
  minimum_version: '0.0.0',
  strip_file_extensions: ['.js', '.jsx'],
  strip_from_path: null,
  tab: '  ',
  use_relative_paths: true,
};

const ENVIRONMENT_CORE_MODULES = {
  // As listed in https://github.com/nodejs/node/tree/master/lib
  node: [
    'assert',
    'buffer',
    'child_process',
    'cluster',
    'console',
    'constants',
    'crypto',
    'dgram',
    'dns',
    'domain',
    'events',
    'fs',
    'http',
    'https',
    'module',
    'net',
    'os',
    'path',
    'process',
    'punycode',
    'querystring',
    'readline',
    'repl',
    'stream',
    'string_decoder',
    'sys',
    'timers',
    'tls',
    'tty',
    'url',
    'util',
    'v8',
    'vm',
    'zlib',
  ],
};

// Class that initializes configuration from a .importjs.json file
class Configuration {
  constructor(pathToCurrentFile) {
    this.pathToCurrentFile = this._normalizePath(pathToCurrentFile);
    this.configs = [];
    const userConfig = FileUtils.readJsonFile(CONFIG_FILE);
    if (userConfig) {
      if (Array.isArray(userConfig)) {
        // Clone array to prevent mutating the original.
        this.configs.push(...Array.from(userConfig).reverse());
      } else {
        this.configs.push(userConfig);
      }
    }
    this.configs.push(DEFAULT_CONFIG);

    this._checkCurrentVersion();
  }

  /**
   * @param {String} key
   * @param {String} opts.fromFile
   * @return {Object} a configuration value
   */
  get(key, { fromFile } = {}) {
    return this.configs.find((config) => {
      const appliesTo = config.applies_to || '**';
      const appliesFrom = config.applies_from || '**';
      if (!(key in config)) {
        return false;
      }

      if (!minimatch(this.pathToCurrentFile, this._normalizePath(appliesTo))) {
        // This configuration does not apply to the current file being edited.
        return false;
      }

      if (!fromFile) {
        return true;
      }

      return minimatch(
        this._normalizePath(fromFile),
        this._normalizePath(appliesFrom)
      );
    })[key];
  }

  /**
   * @param {String} variableName
   * @param {?String} pathToCurrentFile
   * @return {?JsModule}
   */
  resolveAlias(variableName, pathToCurrentFile) {
    let importPath = this.get('aliases')[variableName];
    if (!importPath) {
      return null;
    }

    importPath = importPath.path || importPath; // path may be an object

    if (pathToCurrentFile && pathToCurrentFile.length) {
      // aliases can have dynamic `{filename}` parts
      importPath = importPath.replace(/\{filename\}/,
        path.basename(pathToCurrentFile, path.extname(pathToCurrentFile)));
    }
    return new JsModule({ importPath });
  }

  /**
   * @param {String} variableName
   * @return {?JsModule}
   */
  resolveNamedExports(variableName) {
    const allNamedExports = this.get('named_exports');
    const importPath = Object.keys(allNamedExports).find(
      (key) => allNamedExports[key].indexOf(variableName) !== -1);

    if (!importPath) {
      return undefined;
    }

    const jsModule = new JsModule({ importPath });
    jsModule.hasNamedExports = true;
    return jsModule;
  }

  /**
   * @return {Array<String>}
   */
  packageDependencies() {
    const packageJson = FileUtils.readJsonFile('package.json');
    if (!packageJson) {
      return [];
    }

    const keys = ['dependencies', 'peerDependencies'];
    if (this.get('import_dev_dependencies')) {
      keys.push('devDependencies');
    }
    const result = [];
    keys.forEach((key) => {
      if (Object.prototype.hasOwnProperty.call(packageJson, key)) {
        result.push(...Object.keys(packageJson[key]));
      }
    });
    return result;
  }

  /**
   * @return {Array<String>}
   */
  environmentCoreModules() {
    const result = [];
    this.get('environments').forEach((environment) => {
      result.push(...ENVIRONMENT_CORE_MODULES[environment]);
    });
    return result;
  }

  /**
   * @param {String} path
   * @return {String}
   */
  _normalizePath(rawPath) {
    if (!rawPath) {
      return './';
    }
    const normalized = rawPath.replace(RegExp(`^${escapeRegExp(process.cwd())}`), '.');
    if (normalized.startsWith('.')) {
      return normalized;
    }
    return `./${normalized}`;
  }

  /**
   * Checks that the current version is bigger than the `minimum_version`
   * defined in config.
   * @throws Error if current version is less than the `minimum_version` defined
   * in config.
   */
  _checkCurrentVersion() {
    const minimumVersion = this.get('minimum_version');

    if (semver.gte(version, minimumVersion)) {
      return;
    }

    throw Error(
      'The .importjs.json file for this project requires version ' +
      `${minimumVersion} or newer. You are using ${version}.`
    );
  }
}

module.exports = Configuration;
<commit_msg>Remove process from node core modules list<commit_after>'use strict';

const path = require('path');

const escapeRegExp = require('lodash.escaperegexp');
const minimatch = require('minimatch');
const semver = require('semver');

const FileUtils = require('./FileUtils');
const JsModule = require('./JsModule');
const { version } = require('../package.json');

const CONFIG_FILE = '.importjs.json';

const DEFAULT_CONFIG = {
  aliases: {},
  declaration_keyword: 'import',
  named_exports: {},
  environments: [],
  excludes: [],
  group_imports: true,
  ignore_package_prefixes: [],
  import_dev_dependencies: false,
  import_function: 'require',
  lookup_paths: ['.'],
  max_line_length: 80,
  minimum_version: '0.0.0',
  strip_file_extensions: ['.js', '.jsx'],
  strip_from_path: null,
  tab: '  ',
  use_relative_paths: true,
};

const ENVIRONMENT_CORE_MODULES = {
  // As listed in https://github.com/nodejs/node/tree/master/lib
  //
  // Note that we do not include `process` in this list because that is
  // available globally in node environments and will cause the following error
  // if imported:
  //
  //   Error: Cannot find module 'process' from 'Foo.js'
  node: [
    'assert',
    'buffer',
    'child_process',
    'cluster',
    'console',
    'constants',
    'crypto',
    'dgram',
    'dns',
    'domain',
    'events',
    'fs',
    'http',
    'https',
    'module',
    'net',
    'os',
    'path',
    'punycode',
    'querystring',
    'readline',
    'repl',
    'stream',
    'string_decoder',
    'sys',
    'timers',
    'tls',
    'tty',
    'url',
    'util',
    'v8',
    'vm',
    'zlib',
  ],
};

// Class that initializes configuration from a .importjs.json file
class Configuration {
  constructor(pathToCurrentFile) {
    this.pathToCurrentFile = this._normalizePath(pathToCurrentFile);
    this.configs = [];
    const userConfig = FileUtils.readJsonFile(CONFIG_FILE);
    if (userConfig) {
      if (Array.isArray(userConfig)) {
        // Clone array to prevent mutating the original.
        this.configs.push(...Array.from(userConfig).reverse());
      } else {
        this.configs.push(userConfig);
      }
    }
    this.configs.push(DEFAULT_CONFIG);

    this._checkCurrentVersion();
  }

  /**
   * @param {String} key
   * @param {String} opts.fromFile
   * @return {Object} a configuration value
   */
  get(key, { fromFile } = {}) {
    return this.configs.find((config) => {
      const appliesTo = config.applies_to || '**';
      const appliesFrom = config.applies_from || '**';
      if (!(key in config)) {
        return false;
      }

      if (!minimatch(this.pathToCurrentFile, this._normalizePath(appliesTo))) {
        // This configuration does not apply to the current file being edited.
        return false;
      }

      if (!fromFile) {
        return true;
      }

      return minimatch(
        this._normalizePath(fromFile),
        this._normalizePath(appliesFrom)
      );
    })[key];
  }

  /**
   * @param {String} variableName
   * @param {?String} pathToCurrentFile
   * @return {?JsModule}
   */
  resolveAlias(variableName, pathToCurrentFile) {
    let importPath = this.get('aliases')[variableName];
    if (!importPath) {
      return null;
    }

    importPath = importPath.path || importPath; // path may be an object

    if (pathToCurrentFile && pathToCurrentFile.length) {
      // aliases can have dynamic `{filename}` parts
      importPath = importPath.replace(/\{filename\}/,
        path.basename(pathToCurrentFile, path.extname(pathToCurrentFile)));
    }
    return new JsModule({ importPath });
  }

  /**
   * @param {String} variableName
   * @return {?JsModule}
   */
  resolveNamedExports(variableName) {
    const allNamedExports = this.get('named_exports');
    const importPath = Object.keys(allNamedExports).find(
      (key) => allNamedExports[key].indexOf(variableName) !== -1);

    if (!importPath) {
      return undefined;
    }

    const jsModule = new JsModule({ importPath });
    jsModule.hasNamedExports = true;
    return jsModule;
  }

  /**
   * @return {Array<String>}
   */
  packageDependencies() {
    const packageJson = FileUtils.readJsonFile('package.json');
    if (!packageJson) {
      return [];
    }

    const keys = ['dependencies', 'peerDependencies'];
    if (this.get('import_dev_dependencies')) {
      keys.push('devDependencies');
    }
    const result = [];
    keys.forEach((key) => {
      if (Object.prototype.hasOwnProperty.call(packageJson, key)) {
        result.push(...Object.keys(packageJson[key]));
      }
    });
    return result;
  }

  /**
   * @return {Array<String>}
   */
  environmentCoreModules() {
    const result = [];
    this.get('environments').forEach((environment) => {
      result.push(...ENVIRONMENT_CORE_MODULES[environment]);
    });
    return result;
  }

  /**
   * @param {String} path
   * @return {String}
   */
  _normalizePath(rawPath) {
    if (!rawPath) {
      return './';
    }
    const normalized = rawPath.replace(RegExp(`^${escapeRegExp(process.cwd())}`), '.');
    if (normalized.startsWith('.')) {
      return normalized;
    }
    return `./${normalized}`;
  }

  /**
   * Checks that the current version is bigger than the `minimum_version`
   * defined in config.
   * @throws Error if current version is less than the `minimum_version` defined
   * in config.
   */
  _checkCurrentVersion() {
    const minimumVersion = this.get('minimum_version');

    if (semver.gte(version, minimumVersion)) {
      return;
    }

    throw Error(
      'The .importjs.json file for this project requires version ' +
      `${minimumVersion} or newer. You are using ${version}.`
    );
  }
}

module.exports = Configuration;
<|endoftext|>