<commit_before>import React from 'react'
import {
  ThemeProvider,
  Heading,
  Container,
  Flex,
  Box,
  Text,
  LargeButton,
  Icon,
  mediaQueries,
  cx
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Start from 'components/Start'
import Footer from 'components/Footer'

const Header = Box.extend`
  padding-top: 0 !important;
  background-color: ${props => props.theme.colors.teal[6]};
  background-image: linear-gradient(
    -32deg,
    ${props => props.theme.colors.lime[6]} 0%,
    ${props => props.theme.colors.teal[6]} 50%,
    ${props => props.theme.colors.teal[7]} 100%
  );

  h1 {
    line-height: 1.125;
    max-width: 48rem;
  }
  h2 {
    max-width: 36rem;
  }
`

const Module = Flex.extend.attrs({
  w: [1, 1 / 2],
  p: 4,
  pl: [0, 4],
  pb: [0, 4],
  alignItems: ['flex-start', 'center']
})`
  max-width: 32rem;
  text-align: left;

  ${mediaQueries[1]} {
    &:nth-of-type(1), &:nth-of-type(3) {
      transform: translateY(4rem);
    }
  }

  svg {
    width: 4rem !important;
    height: 4rem !important;
    flex-shrink: 0;
    ${mediaQueries[1]} {
      &:first-child { margin-right: 3rem; }
      &:last-child { margin-left: 2rem; }
    }
    /* this is terrible */
    @media screen and (max-width:32em) {
      order: -1 !important;
      margin-left: 0;
      margin-right: 1rem;
    }
  }
`

const ModuleHeading = Heading.h3.extend.attrs({
  mt: 0,
  mb: 1,
  f: [3, 4],
  bold: true
})`
  color: ${props => props.theme.colors.black};
  position: relative;
  ${mediaQueries[1]} {
    &:before {
      content: "";
      width: 8px;
      position: absolute;
      top: 0;
      bottom: 0;
      left: -1.5rem;
      background-color: ${props => cx(props.color)};
    }
  }
`
const ModuleBody = Text.extend.attrs({ my: 0, f: 3, color: 'slate' })`
  line-height: 1.5;
`

const ModuleFigure = Box.withComponent('figure').extend.attrs({
  bg: 'fuschia.0',
  mr: [4, 5],
  ml: 3
})`
  width: 6rem;
  height: 6rem;
  border-radius: 2rem;
  flex-shrink: 0;
`

LargeButton.link = LargeButton.withComponent(Link)

export default () => (
  <ThemeProvider>
    <Helmet title="Meetings – Hack Club" />

      <Heading.h1 align="center" f={[5, 6]} mx="auto" mt={4} mb={3}>
        At Hack Club meetings,

        everyone is making.
      </Heading.h1>
      <Heading f={[3, 4]} mx="auto" align="center" bold={false} regular>
        Clubs meet weekly at high schools,

        all run by their student leaders.
      </Heading>

    <Flex
      wrap
      justify="space-around"
      p={2}
      pb={[5, 6]}
      mx="auto"
      style={{ position: 'relative', maxWidth: '64rem' }}
    >
      <Module>
        <Box>
          <ModuleHeading color="blue.5">Get hacking!</ModuleHeading>
          <ModuleBody>
            Unlike a traditional coding class, everyone works on their own
            project at their own pace.
          </ModuleBody>
        </Box>
        <Icon name="memory" color="blue.4" />
      </Module>
      <Module>
        <Box>
          <ModuleHeading color="yellow.5">
            You can feel the energy.
          </ModuleHeading>
          <ModuleBody>
            Meetings run like mini-hackathons: members are coming up with
            creative projects to showcase.
          </ModuleBody>
        </Box>
        <Icon name="flash_on" color="yellow.4" />
      </Module>
      <Module>
        <Icon name="gesture" color="teal.4" />
        <Box>
          <ModuleHeading color="teal.5">
            No experience required.

            Maybe even encouraged.
          </ModuleHeading>
          <ModuleBody>
            You’re not behind if you’re new to coding—everyone is learning along
            the way.
          </ModuleBody>
        </Box>
      </Module>
      <Module>
        <Icon name="screen_share" color="violet.4" />
        <Box>
          <ModuleHeading color="violet.5">Demo time!</ModuleHeading>
          <ModuleBody>
            At the end of a meeting, everyone presents what they’ve made in
            front of the group.
          </ModuleBody>
        </Box>
      </Module>
    </Flex>
    <Start />

  </ThemeProvider>
)
<commit_msg>Adjust Meetings page<commit_after>import React from 'react'
import {
  ThemeProvider,
  Heading,
  Container,
  Flex,
  Box,
  Text,
  LargeButton,
  Icon,
  Section,
  mediaQueries,
  cx
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Start from 'components/Start'
import Footer from 'components/Footer'

const Header = Section.withComponent('header').extend`
  padding-top: 0 !important;
  background-color: ${props => props.theme.colors.teal[6]};
  background-image: linear-gradient(
    -32deg,
    ${props => props.theme.colors.green[7]} 0%,
    ${props => props.theme.colors.teal[6]} 50%,
    ${props => props.theme.colors.teal[7]} 100%
  );
  clip-path: polygon(0% 0%, 100% 0, 100% 100%, 0% 90%);

  h1 {
    line-height: 1.125;
    max-width: 48rem;
  }
  h2 {
    max-width: 36rem;
  }
`

const Module = Flex.extend.attrs({
  w: [1, 1 / 2],
  p: 4,
  pl: [0, 4],
  pb: [0, 4],
  alignItems: ['flex-start', 'center']
})`
  max-width: 32rem;
  text-align: left;

  ${mediaQueries[1]} {
    &:nth-of-type(1), &:nth-of-type(3) {
      transform: translateY(4rem);
    }
  }

  svg {
    width: 4rem !important;
    height: 4rem !important;
    flex-shrink: 0;
    ${mediaQueries[1]} {
      &:first-child { margin-right: 3rem; }
      &:last-child { margin-left: 2rem; }
    }
    /* this is terrible */
    @media screen and (max-width:32em) {
      order: -1 !important;
      margin-left: 0;
      margin-right: 1rem;
    }
  }
`

const ModuleHeading = Heading.h3.extend.attrs({
  mt: 0,
  mb: 1,
  f: [3, 4],
  bold: true
})`
  color: ${props => props.theme.colors.black};
  position: relative;
  ${mediaQueries[1]} {
    &:before {
      content: "";
      width: 8px;
      position: absolute;
      top: 0;
      bottom: 0;
      left: -1.5rem;
      background-color: ${props => cx(props.color)};
    }
  }
`
const ModuleBody = Text.extend.attrs({ my: 0, f: 3, color: 'slate' })`
  line-height: 1.5;
`

const ModuleFigure = Box.withComponent('figure').extend.attrs({
  bg: 'fuschia.0',
  mr: [4, 5],
  ml: 3
})`
  width: 6rem;
  height: 6rem;
  border-radius: 2rem;
  flex-shrink: 0;
`

LargeButton.link = LargeButton.withComponent(Link)

export default () => (
  <ThemeProvider>
    <Helmet title="Meetings – Hack Club" />

      <Heading.h1 align="center" f={[5, 6]} mx="auto" mt={4} mb={3}>
        At Hack Club meetings,

        everyone is making.
      </Heading.h1>
      <Heading f={[3, 4]} mx="auto" align="center" bold={false} regular>
        Clubs meet weekly at high schools,

        all run by their student leaders.
      </Heading>

    <Flex
      wrap
      justify="space-around"
      p={2}
      pb={[5, 6]}
      mx="auto"
      style={{ position: 'relative', maxWidth: '64rem' }}
    >
      <Module>
        <Box>
          <ModuleHeading color="blue.5">Get hacking!</ModuleHeading>
          <ModuleBody>
            Unlike a traditional coding class, everyone works on their own
            project at their own pace.
          </ModuleBody>
        </Box>
        <Icon name="memory" color="blue.4" />
      </Module>
      <Module>
        <Box>
          <ModuleHeading color="yellow.5">
            You can feel the energy.
          </ModuleHeading>
          <ModuleBody>
            Meetings run like mini-hackathons: members are coming up with
            creative projects to showcase.
          </ModuleBody>
        </Box>
        <Icon name="flash_on" color="yellow.4" />
      </Module>
      <Module>
        <Icon name="gesture" color="teal.5" />
        <Box>
          <ModuleHeading color="teal.6">
            No experience required.

            Maybe even encouraged.
          </ModuleHeading>
          <ModuleBody>
            You’re not behind if you’re new to coding—everyone is learning along
            the way.
          </ModuleBody>
        </Box>
      </Module>
      <Module>
        <Icon name="screen_share" color="indigo.4" />
        <Box>
          <ModuleHeading color="indigo.5">Demo time!</ModuleHeading>
          <ModuleBody>
            At the end of a meeting, everyone presents what they’ve made in
            front of the group.
          </ModuleBody>
        </Box>
      </Module>
    </Flex>
    <Start />

  </ThemeProvider>
)
<|endoftext|>


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

/**
 * @fileoverview Implements the disposable interface. The dispose method is used
 * to clean up references and resources.
 * @author arv@google.com (Erik Arvidsson)
 */

goog.provide('goog.Disposable');
goog.provide('goog.dispose');

goog.require('goog.disposable.IDisposable');

/**
 * Class that provides the basic implementation for disposable objects. If your
 * class holds one or more references to COM objects, DOM nodes, or other
 * disposable objects, it should extend this class or implement the disposable
 * interface (defined in goog.disposable.IDisposable).
 * @constructor
 * @implements {goog.disposable.IDisposable}
 */
goog.Disposable = function() {
  if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
    this.creationStack = new Error().stack;
    goog.Disposable.instances_[goog.getUid(this)] = this;
  }
};

/**
 * @enum {number} Different monitoring modes for Disposable.
 */
goog.Disposable.MonitoringMode = {
  /**
   * No monitoring.
   */
  OFF: 0,
  /**
   * Creating and disposing the goog.Disposable instances is monitored. All
   * disposable objects need to call the {@code goog.Disposable} base
   * constructor. The PERMANENT mode must bet switched on before creating any
   * goog.Disposable instances.
   */
  PERMANENT: 1,
  /**
   * INTERACTIVE mode can be switched on and off on the fly without producing
   * errors. It also doesn't warn if the disposable objects don't call the
   * {@code goog.Disposable} base constructor.
   */
  INTERACTIVE: 2
};

/**
 * @define {number} The monitoring mode of the goog.Disposable
 *     instances. Default is OFF. Switching on the monitoring is only
 *     recommended for debugging because it has a significant impact on
 *     performance and memory usage. If switched off, the monitoring code
 *     compiles down to 0 bytes.
 */
goog.Disposable.MONITORING_MODE = 0;

/**
 * Maps the unique ID of every undisposed {@code goog.Disposable} object to
 * the object itself.
 * @type {!Object.<number, !goog.Disposable>}
 * @private
 */
goog.Disposable.instances_ = {};

/**
 * @return {!Array.<!goog.Disposable>} All {@code goog.Disposable} objects that
 *     haven't been disposed of.
 */
goog.Disposable.getUndisposedObjects = function() {
  var ret = [];
  for (var id in goog.Disposable.instances_) {
    if (goog.Disposable.instances_.hasOwnProperty(id)) {
      ret.push(goog.Disposable.instances_[Number(id)]);
    }
  }
  return ret;
};

/**
 * Clears the registry of undisposed objects but doesn't dispose of them.
 */
goog.Disposable.clearUndisposedObjects = function() {
  goog.Disposable.instances_ = {};
};

/**
 * Whether the object has been disposed of.
 * @type {boolean}
 * @private
 */
goog.Disposable.prototype.disposed_ = false;

/**
 * Disposables that should be disposed when this object is disposed.
 * @type {Array.<goog.disposable.IDisposable>}
 * @private
 */
goog.Disposable.prototype.dependentDisposables_;

/**
 * Callbacks to invoke when this object is disposed.
 * @type {Array.<!Function>}
 * @private
 */
goog.Disposable.prototype.onDisposeCallbacks_;

/**
 * If monitoring the goog.Disposable instances is enabled, stores the creation
 * stack trace of the Disposable instance.
 * @type {string}
 */
goog.Disposable.prototype.creationStack;

/**
 * @return {boolean} Whether the object has been disposed of.
 * @override
 */
goog.Disposable.prototype.isDisposed = function() {
  return this.disposed_;
};

/**
 * @return {boolean} Whether the object has been disposed of.
 * @deprecated Use {@link #isDisposed} instead.
 */
goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;

/**
 * Disposes of the object. If the object hasn't already been disposed of, calls
 * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should
 * override {@link #disposeInternal} in order to delete references to COM
 * objects, DOM nodes, and other disposable objects. Reentrant.
 *
 * @return {void} Nothing.
 * @override
 */
goog.Disposable.prototype.dispose = function() {
  if (!this.disposed_) {
    // Set disposed_ to true first, in case during the chain of disposal this
    // gets disposed recursively.
    this.disposed_ = true;
    this.disposeInternal();
    if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
      var uid = goog.getUid(this);
      if (goog.Disposable.MONITORING_MODE ==
          goog.Disposable.MonitoringMode.PERMANENT &&
          !goog.Disposable.instances_.hasOwnProperty(uid)) {
        throw Error(this + ' did not call the goog.Disposable base ' +
            'constructor or was disposed of after a clearUndisposedObjects ' +
            'call');
      }
      delete goog.Disposable.instances_[uid];
    }
  }
};

/**
 * Associates a disposable object with this object so that they will be disposed
 * together.
 * @param {goog.disposable.IDisposable} disposable that will be disposed when
 *     this object is disposed.
 */
goog.Disposable.prototype.registerDisposable = function(disposable) {
  if (!this.dependentDisposables_) {
    this.dependentDisposables_ = [];
  }
  this.dependentDisposables_.push(disposable);
};

/**
 * Invokes a callback function when this object is disposed. Callbacks are
 * invoked in the order in which they were added.
 * @param {!Function} callback The callback function.
 * @param {Object=} opt_scope An optional scope to call the callback in.
 */
goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
  if (!this.onDisposeCallbacks_) {
    this.onDisposeCallbacks_ = [];
  }
  this.onDisposeCallbacks_.push(goog.bind(callback, opt_scope));
};

/**
 * Deletes or nulls out any references to COM objects, DOM nodes, or other
 * disposable objects. Classes that extend {@code goog.Disposable} should
 * override this method.
 * Not reentrant. To avoid calling it twice, it must only be called from the
 * subclass' {@code disposeInternal} method. Everywhere else the public
 * {@code dispose} method must be used.
 * For example:
 *

 *   mypackage.MyClass = function() {
 *     goog.base(this);
 *     // Constructor logic specific to MyClass.
 *     ...
 *   };
 *   goog.inherits(mypackage.MyClass, goog.Disposable);
 *
 *   mypackage.MyClass.prototype.disposeInternal = function() {
 *     goog.base(this, 'disposeInternal');
 *     // Dispose logic specific to MyClass.
 *     ...
 *   };
 *

 * @protected
 */
goog.Disposable.prototype.disposeInternal = function() {
  if (this.dependentDisposables_) {
    goog.disposeAll.apply(null, this.dependentDisposables_);
  }
  if (this.onDisposeCallbacks_) {
    while (this.onDisposeCallbacks_.length) {
      this.onDisposeCallbacks_.shift()();
    }
  }
};

/**
 * Returns True if we can verify the object is disposed.
 * Calls {@code isDisposed} on the argument if it supports it.  If obj
 * is not an object with an isDisposed() method, return false.
 * @param {*} obj The object to investigate.
 * @return {boolean} True if we can verify the object is disposed.
 */
goog.Disposable.isDisposed = function(obj) {
  if (obj && typeof obj.isDisposed == 'function') {
    return obj.isDisposed();
  }
  return false;
};

/**
 * Calls {@code dispose} on the argument if it supports it. If obj is not an
 *     object with a dispose() method, this is a no-op.
 * @param {*} obj The object to dispose of.
 */
goog.dispose = function(obj) {
  if (obj && typeof obj.dispose == 'function') {
    obj.dispose();
  }
};

/**
 * Calls {@code dispose} on each member of the list that supports it. (If the
 * member is an ArrayLike, then {@code goog.disposeAll()} will be called
 * recursively on each of its members.) If the member is not an object with a
 * {@code dispose()} method, then it is ignored.
 * @param {...*} var_args The list.
 */
goog.disposeAll = function(var_args) {
  for (var i = 0, len = arguments.length; i < len; ++i) {
    var disposable = arguments[i];
    if (goog.isArrayLike(disposable)) {
      goog.disposeAll.apply(null, disposable);
    } else {
      goog.dispose(disposable);
    }
  }
};
<commit_msg><commit_after>// Copyright 2005 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Implements the disposable interface. The dispose method is used
 * to clean up references and resources.
 * @author arv@google.com (Erik Arvidsson)
 */

goog.provide('goog.Disposable');
goog.provide('goog.dispose');

goog.require('goog.disposable.IDisposable');

/**
 * Class that provides the basic implementation for disposable objects. If your
 * class holds one or more references to COM objects, DOM nodes, or other
 * disposable objects, it should extend this class or implement the disposable
 * interface (defined in goog.disposable.IDisposable).
 * @constructor
 * @implements {goog.disposable.IDisposable}
 */
goog.Disposable = function() {
  if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
    this.creationStack = new Error().stack;
    goog.Disposable.instances_[goog.getUid(this)] = this;
  }
};

/**
 * @enum {number} Different monitoring modes for Disposable.
 */
goog.Disposable.MonitoringMode = {
  /**
   * No monitoring.
   */
  OFF: 0,
  /**
   * Creating and disposing the goog.Disposable instances is monitored. All
   * disposable objects need to call the {@code goog.Disposable} base
   * constructor. The PERMANENT mode must bet switched on before creating any
   * goog.Disposable instances.
   */
  PERMANENT: 1,
  /**
   * INTERACTIVE mode can be switched on and off on the fly without producing
   * errors. It also doesn't warn if the disposable objects don't call the
   * {@code goog.Disposable} base constructor.
   */
  INTERACTIVE: 2
};

/**
 * @define {number} The monitoring mode of the goog.Disposable
 *     instances. Default is OFF. Switching on the monitoring is only
 *     recommended for debugging because it has a significant impact on
 *     performance and memory usage. If switched off, the monitoring code
 *     compiles down to 0 bytes.
 */
goog.Disposable.MONITORING_MODE = 0;

/**
 * Maps the unique ID of every undisposed {@code goog.Disposable} object to
 * the object itself.
 * @type {!Object.<number, !goog.Disposable>}
 * @private
 */
goog.Disposable.instances_ = {};

/**
 * @return {!Array.<!goog.Disposable>} All {@code goog.Disposable} objects that
 *     haven't been disposed of.
 */
goog.Disposable.getUndisposedObjects = function() {
  var ret = [];
  for (var id in goog.Disposable.instances_) {
    if (goog.Disposable.instances_.hasOwnProperty(id)) {
      ret.push(goog.Disposable.instances_[Number(id)]);
    }
  }
  return ret;
};

/**
 * Clears the registry of undisposed objects but doesn't dispose of them.
 */
goog.Disposable.clearUndisposedObjects = function() {
  goog.Disposable.instances_ = {};
};

/**
 * Whether the object has been disposed of.
 * @type {boolean}
 * @private
 */
goog.Disposable.prototype.disposed_ = false;

/**
 * Disposables that should be disposed when this object is disposed.
 * @type {Array.<goog.disposable.IDisposable>}
 * @private
 */
goog.Disposable.prototype.dependentDisposables_;

/**
 * Callbacks to invoke when this object is disposed.
 * @type {Array.<!Function>}
 * @private
 */
goog.Disposable.prototype.onDisposeCallbacks_;

/**
 * If monitoring the goog.Disposable instances is enabled, stores the creation
 * stack trace of the Disposable instance.
 * @type {string}
 */
goog.Disposable.prototype.creationStack;

/**
 * @return {boolean} Whether the object has been disposed of.
 * @override
 */
goog.Disposable.prototype.isDisposed = function() {
  return this.disposed_;
};

/**
 * @return {boolean} Whether the object has been disposed of.
 * @deprecated Use {@link #isDisposed} instead.
 */
goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;

/**
 * Disposes of the object. If the object hasn't already been disposed of, calls
 * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should
 * override {@link #disposeInternal} in order to delete references to COM
 * objects, DOM nodes, and other disposable objects. Reentrant.
 *
 * @return {void} Nothing.
 * @override
 */
goog.Disposable.prototype.dispose = function() {
  if (!this.disposed_) {
    // Set disposed_ to true first, in case during the chain of disposal this
    // gets disposed recursively.
    this.disposed_ = true;
    this.disposeInternal();
    if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
      var uid = goog.getUid(this);
      if (goog.Disposable.MONITORING_MODE ==
          goog.Disposable.MonitoringMode.PERMANENT &&
          !goog.Disposable.instances_.hasOwnProperty(uid)) {
        throw Error(this + ' did not call the goog.Disposable base ' +
            'constructor or was disposed of after a clearUndisposedObjects ' +
            'call');
      }
      delete goog.Disposable.instances_[uid];
    }
  }
};

/**
 * Associates a disposable object with this object so that they will be disposed
 * together.
 * @param {goog.disposable.IDisposable} disposable that will be disposed when
 *     this object is disposed.
 */
goog.Disposable.prototype.registerDisposable = function(disposable) {
  if (!this.dependentDisposables_) {
    this.dependentDisposables_ = [];
  }
  this.dependentDisposables_.push(disposable);
};

/**
 * Invokes a callback function when this object is disposed. Callbacks are
 * invoked in the order in which they were added.
 * @param {!Function} callback The callback function.
 * @param {Object=} opt_scope An optional scope to call the callback in.
 */
goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
  if (!this.onDisposeCallbacks_) {
    this.onDisposeCallbacks_ = [];
  }
  this.onDisposeCallbacks_.push(goog.bind(callback, opt_scope));
};

/**
 * Deletes or nulls out any references to COM objects, DOM nodes, or other
 * disposable objects. Classes that extend {@code goog.Disposable} should
 * override this method.
 * Not reentrant. To avoid calling it twice, it must only be called from the
 * subclass' {@code disposeInternal} method. Everywhere else the public
 * {@code dispose} method must be used.
 * For example:
 *

 *   mypackage.MyClass = function() {
 *     goog.base(this);
 *     // Constructor logic specific to MyClass.
 *     ...
 *   };
 *   goog.inherits(mypackage.MyClass, goog.Disposable);
 *
 *   mypackage.MyClass.prototype.disposeInternal = function() {
 *     // Dispose logic specific to MyClass.
 *     ...
 *     // Call superclass's disposeInternal at the end of the subclass's, like
 *     // in C++, to avoid hard-to-catch issues.
 *     goog.base(this, 'disposeInternal');
 *   };
 *

 * @protected
 */
goog.Disposable.prototype.disposeInternal = function() {
  if (this.dependentDisposables_) {
    goog.disposeAll.apply(null, this.dependentDisposables_);
  }
  if (this.onDisposeCallbacks_) {
    while (this.onDisposeCallbacks_.length) {
      this.onDisposeCallbacks_.shift()();
    }
  }
};

/**
 * Returns True if we can verify the object is disposed.
 * Calls {@code isDisposed} on the argument if it supports it.  If obj
 * is not an object with an isDisposed() method, return false.
 * @param {*} obj The object to investigate.
 * @return {boolean} True if we can verify the object is disposed.
 */
goog.Disposable.isDisposed = function(obj) {
  if (obj && typeof obj.isDisposed == 'function') {
    return obj.isDisposed();
  }
  return false;
};

/**
 * Calls {@code dispose} on the argument if it supports it. If obj is not an
 *     object with a dispose() method, this is a no-op.
 * @param {*} obj The object to dispose of.
 */
goog.dispose = function(obj) {
  if (obj && typeof obj.dispose == 'function') {
    obj.dispose();
  }
};

/**
 * Calls {@code dispose} on each member of the list that supports it. (If the
 * member is an ArrayLike, then {@code goog.disposeAll()} will be called
 * recursively on each of its members.) If the member is not an object with a
 * {@code dispose()} method, then it is ignored.
 * @param {...*} var_args The list.
 */
goog.disposeAll = function(var_args) {
  for (var i = 0, len = arguments.length; i < len; ++i) {
    var disposable = arguments[i];
    if (goog.isArrayLike(disposable)) {
      goog.disposeAll.apply(null, disposable);
    } else {
      goog.dispose(disposable);
    }
  }
};
<|endoftext|>


<commit_before>module.exports = function parseMarkdown(text, options) {
  options = options || {};
  parseLists = options.lists !== false;

  var Remarkable = require('remarkable');
  var md = new Remarkable();
  md.block.ruler.enable([
    'deflist'
  ]);

  var tokens = md.parse(text, {})
  var headings = [];
  var depth = 0;
  for (var i = 0; i < tokens.length; i += 1) {
    if (tokens[i].type === 'heading_open') {
      depth = tokens[i].hLevel;
      headings.push({
        depth: depth,
        line: tokens[i].lines[0],
        name: tokens[i+1].content || ''
      });
      i += 1;
    } else if (parseLists) {
      switch (tokens[i].type) {
        case 'bullet_list_open':
        case 'dl_open':
        case 'ordered_list_open':
          headings.push({
            depth: depth + 1,
            line: tokens[i].lines[0],
            name: '',
            autoCollapse: true
          });
          depth += 2;
          break;
        case 'bullet_list_close':
        case 'dl_close':
        case 'ordered_list_close':
          depth -= 2;
          break;
        case 'list_item_open':
          headings.push({
            depth: depth,
            line: tokens[i].lines[0],
            name: (tokens[i+2].content || '').split('\n')[0]
          });
          i += 2;
          break;
        case 'dt_open':
          headings.push({
            depth: depth,
            line: tokens[i].lines[0],
            name: tokens[i+1].content || ''
          });
          i += 1;
          break;
      }
    }
  }

  return headings;
};
<commit_msg>Extract links<commit_after>
function extractLinks(tokens) {
  var result = [];
  var href;
  var parts;
  for (var i = 0; i < tokens.length; i += 1) {
    var token = tokens[i];
    switch (token.type) {
      case "link_open":
        href = token.href;
        parts = [];
        break;
      case "text":
        if (parts) {
          parts.push(token.content)
        }
        break;
      case "link_close":
        result.push({
          href: href,
          name: parts.join('')
        });
        parts = null;
        break;
    }
  }
  return result;
}

module.exports = function parseMarkdown(text, options) {
  options = options || {};
  parseLists = options.lists !== false;
  parseLinks = options.links !== false;

  var Remarkable = require('remarkable');
  var md = new Remarkable();
  md.block.ruler.enable([
    'deflist'
  ]);

  var tokens = md.parse(text, {});
  var headings = [];
  var depth = 0;
  for (var i = 0; i < tokens.length; i += 1) {
    if (tokens[i].type === 'heading_open') {
      depth = tokens[i].hLevel;
      headings.push({
        depth: depth,
        line: tokens[i].lines[0],
        name: tokens[i+1].content || ''
      });
      i += 1;
    } else if (tokens[i].type === 'inline') {
      if (parseLinks) {
        headings = headings.concat(extractLinks(tokens[i].children).map(function(x) {
          x.depth = depth + 1;
          x.line = tokens[i].lines[0];
          return x;
        }));
      }
    } else if (parseLists) {
      switch (tokens[i].type) {
        case 'bullet_list_open':
        case 'dl_open':
        case 'ordered_list_open':
          headings.push({
            depth: depth + 1,
            line: tokens[i].lines[0],
            name: '',
            autoCollapse: true
          });
          depth += 2;
          break;
        case 'bullet_list_close':
        case 'dl_close':
        case 'ordered_list_close':
          depth -= 2;
          break;
        case 'list_item_open':
          headings.push({
            depth: depth,
            line: tokens[i].lines[0],
            name: (tokens[i+2].content || '').split('\n')[0]
          });
          i += 2;
          break;
        case 'dt_open':
          headings.push({
            depth: depth,
            line: tokens[i].lines[0],
            name: tokens[i+1].content || ''
          });
          i += 1;
          break;
      }
    }
  }

  return headings;
};
<|endoftext|>


<commit_before>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * A Text Object will create a line(s) of text to split a line you can use "\n"
 *
 * @class Text
 * @extends Sprite
 * @constructor
 * @param text {String} The copy that you would like the text to display
 * @param [style] {Object} The style parameters
 * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font
 * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00"
 * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right")
 * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00"
 * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
 * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
 * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
 */
PIXI.Text = function(text, style)
{
    this.canvas = document.createElement("canvas");
    this.context = this.canvas.getContext("2d");
    PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas));

    this.setText(text);
    this.setStyle(style);

     this.updateText();
    this.dirty = false;
};

// constructor
PIXI.Text.constructor = PIXI.Text;
PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype);

/**
 * Set the style of the text
 *
 * @method setStyle
 * @param [style] {Object} The style parameters
 * @param [style.font="bold 20pt Arial"] {String} The style and size of the font
 * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00"
 * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right")
 * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00"
 * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
 * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
 * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
 */
PIXI.Text.prototype.setStyle = function(style)
{
    style = style || {};
    style.font = style.font || "bold 20pt Arial";
    style.fill = style.fill || "black";
    style.align = style.align || "left";
    style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
    style.strokeThickness = style.strokeThickness || 0;
    style.wordWrap = style.wordWrap || false;
    style.wordWrapWidth = style.wordWrapWidth || 100;
    this.style = style;
    this.dirty = true;
};

/**
 * Set the copy for the text object. To split a line you can use "\n"
 *
 * @methos setText
 * @param {String} text The copy that you would like the text to display
 */
PIXI.Sprite.prototype.setText = function(text)
{
    this.text = text.toString() || " ";
    this.dirty = true;
};

/**
 * Renders text
 *
 * @method updateText
 * @private
 */
PIXI.Text.prototype.updateText = function()
{
	this.context.font = this.style.font;

	var outputText = this.text;

	// word wrap
	// preserve original text
	if(this.style.wordWrap)outputText = this.wordWrap(this.text);

	//split text into lines
	var lines = outputText.split(/(?:\r\n|\r|\n)/);

	//calculate text width
	var lineWidths = [];
	var maxLineWidth = 0;
	for (var i = 0; i < lines.length; i++)
	{
		var lineWidth = this.context.measureText(lines[i]).width;
		lineWidths[i] = lineWidth;
		maxLineWidth = Math.max(maxLineWidth, lineWidth);
	}
	this.canvas.width = maxLineWidth + this.style.strokeThickness;

	//calculate text height
	var lineHeight = this.determineFontHeight("font: " + this.style.font  + ";") + this.style.strokeThickness;
	this.canvas.height = lineHeight * lines.length;

	//set canvas text styles
	this.context.fillStyle = this.style.fill;
	this.context.font = this.style.font;

	this.context.strokeStyle = this.style.stroke;
	this.context.lineWidth = this.style.strokeThickness;

	this.context.textBaseline = "top";

	//draw lines line by line
	for (i = 0; i < lines.length; i++)
	{
		var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight);

		if(this.style.align == "right")
		{
			linePosition.x += maxLineWidth - lineWidths[i];
		}
		else if(this.style.align == "center")
		{
			linePosition.x += (maxLineWidth - lineWidths[i]) / 2;
		}

		if(this.style.stroke && this.style.strokeThickness)
		{
			this.context.strokeText(lines[i], linePosition.x, linePosition.y);
		}

		if(this.style.fill)
		{
			this.context.fillText(lines[i], linePosition.x, linePosition.y);
		}
	}

    this.updateTexture();
};

/**
 * Updates texture size based on canvas size
 *
 * @method updateTexture
 * @private
 */
PIXI.Text.prototype.updateTexture = function()
{

    this.texture.baseTexture.width = this.canvas.width;
    this.texture.baseTexture.height = this.canvas.height;
    this.texture.frame.width = this.canvas.width;
    this.texture.frame.height = this.canvas.height;

  	this._width = this.canvas.width;
    this._height = this.canvas.height;

    PIXI.texturesToUpdate.push(this.texture.baseTexture);
};

/**
 * Updates the transfor of this object
 *
 * @method updateTransform
 * @private
 */
PIXI.Text.prototype.updateTransform = function()
{
	if(this.dirty)
	{
		this.updateText();
		this.dirty = false;
	}

	PIXI.Sprite.prototype.updateTransform.call(this);
};

/*
 * http://stackoverflow.com/users/34441/ellisbben
 * great solution to the problem!
 *
 * @method determineFontHeight
 * @param fontStyle {Object}
 * @private
 */
PIXI.Text.prototype.determineFontHeight = function(fontStyle)
{
	// build a little reference dictionary so if the font style has been used return a
	// cached version...
	var result = PIXI.Text.heightCache[fontStyle];

	if(!result)
	{
		var body = document.getElementsByTagName("body")[0];
		var dummy = document.createElement("div");
		var dummyText = document.createTextNode("M");
		dummy.appendChild(dummyText);
		dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0');
		body.appendChild(dummy);

		result = dummy.offsetHeight;
		PIXI.Text.heightCache[fontStyle] = result;

		body.removeChild(dummy);
	}

	return result;
};

/**
 * A Text Object will apply wordwrap
 *
 * @method wordWrap
 * @param text {String}
 * @private
 */
PIXI.Text.prototype.wordWrap = function(text)
{
	// search good wrap position
	var searchWrapPos = function(ctx, text, start, end, wrapWidth)
	{
		var p = Math.floor((end-start) / 2) + start;
		if(p == start) {
			return 1;
		}

		if(ctx.measureText(text.substring(0,p)).width <= wrapWidth)
		{
			if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth)
			{
				return p;
			}
			else
			{
				return arguments.callee(ctx, text, p, end, wrapWidth);
			}
		}
		else
		{
			return arguments.callee(ctx, text, start, p, wrapWidth);
		}
	};

	var lineWrap = function(ctx, text, wrapWidth)
	{
		if(ctx.measureText(text).width <= wrapWidth || text.length < 1)
		{
			return text;
		}
		var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth);
		return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth);
	};

	var result = "";
	var lines = text.split("\n");
	for (var i = 0; i < lines.length; i++)
	{
		result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n";
	}

	return result;
};

/**
 * Destroys this text object
 *
 * @method destroy
 * @param destroyTexture {Boolean}
 */
PIXI.Text.prototype.destroy = function(destroyTexture)
{
	if(destroyTexture)
	{
		this.texture.destroy();
	}

};

PIXI.Text.heightCache = {};
<commit_msg>also update text width/height properties, fixes #197<commit_after>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * A Text Object will create a line(s) of text to split a line you can use "\n"
 *
 * @class Text
 * @extends Sprite
 * @constructor
 * @param text {String} The copy that you would like the text to display
 * @param [style] {Object} The style parameters
 * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font
 * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00"
 * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right")
 * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00"
 * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
 * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
 * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
 */
PIXI.Text = function(text, style)
{
    this.canvas = document.createElement("canvas");
    this.context = this.canvas.getContext("2d");
    PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas));

    this.setText(text);
    this.setStyle(style);

     this.updateText();
    this.dirty = false;
};

// constructor
PIXI.Text.constructor = PIXI.Text;
PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype);

/**
 * Set the style of the text
 *
 * @method setStyle
 * @param [style] {Object} The style parameters
 * @param [style.font="bold 20pt Arial"] {String} The style and size of the font
 * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00"
 * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right")
 * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00"
 * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
 * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
 * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
 */
PIXI.Text.prototype.setStyle = function(style)
{
    style = style || {};
    style.font = style.font || "bold 20pt Arial";
    style.fill = style.fill || "black";
    style.align = style.align || "left";
    style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
    style.strokeThickness = style.strokeThickness || 0;
    style.wordWrap = style.wordWrap || false;
    style.wordWrapWidth = style.wordWrapWidth || 100;
    this.style = style;
    this.dirty = true;
};

/**
 * Set the copy for the text object. To split a line you can use "\n"
 *
 * @methos setText
 * @param {String} text The copy that you would like the text to display
 */
PIXI.Sprite.prototype.setText = function(text)
{
    this.text = text.toString() || " ";
    this.dirty = true;
};

/**
 * Renders text
 *
 * @method updateText
 * @private
 */
PIXI.Text.prototype.updateText = function()
{
	this.context.font = this.style.font;

	var outputText = this.text;

	// word wrap
	// preserve original text
	if(this.style.wordWrap)outputText = this.wordWrap(this.text);

	//split text into lines
	var lines = outputText.split(/(?:\r\n|\r|\n)/);

	//calculate text width
	var lineWidths = [];
	var maxLineWidth = 0;
	for (var i = 0; i < lines.length; i++)
	{
		var lineWidth = this.context.measureText(lines[i]).width;
		lineWidths[i] = lineWidth;
		maxLineWidth = Math.max(maxLineWidth, lineWidth);
	}
	this.width = this.canvas.width = maxLineWidth + this.style.strokeThickness;

	//calculate text height
	var lineHeight = this.determineFontHeight("font: " + this.style.font  + ";") + this.style.strokeThickness;
	this.height = this.canvas.height = lineHeight * lines.length;

	//set canvas text styles
	this.context.fillStyle = this.style.fill;
	this.context.font = this.style.font;

	this.context.strokeStyle = this.style.stroke;
	this.context.lineWidth = this.style.strokeThickness;

	this.context.textBaseline = "top";

	//draw lines line by line
	for (i = 0; i < lines.length; i++)
	{
		var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight);

		if(this.style.align == "right")
		{
			linePosition.x += maxLineWidth - lineWidths[i];
		}
		else if(this.style.align == "center")
		{
			linePosition.x += (maxLineWidth - lineWidths[i]) / 2;
		}

		if(this.style.stroke && this.style.strokeThickness)
		{
			this.context.strokeText(lines[i], linePosition.x, linePosition.y);
		}

		if(this.style.fill)
		{
			this.context.fillText(lines[i], linePosition.x, linePosition.y);
		}
	}

    this.updateTexture();
};

/**
 * Updates texture size based on canvas size
 *
 * @method updateTexture
 * @private
 */
PIXI.Text.prototype.updateTexture = function()
{

    this.texture.baseTexture.width = this.canvas.width;
    this.texture.baseTexture.height = this.canvas.height;
    this.texture.frame.width = this.canvas.width;
    this.texture.frame.height = this.canvas.height;

  	this._width = this.canvas.width;
    this._height = this.canvas.height;

    PIXI.texturesToUpdate.push(this.texture.baseTexture);
};

/**
 * Updates the transfor of this object
 *
 * @method updateTransform
 * @private
 */
PIXI.Text.prototype.updateTransform = function()
{
	if(this.dirty)
	{
		this.updateText();
		this.dirty = false;
	}

	PIXI.Sprite.prototype.updateTransform.call(this);
};

/*
 * http://stackoverflow.com/users/34441/ellisbben
 * great solution to the problem!
 *
 * @method determineFontHeight
 * @param fontStyle {Object}
 * @private
 */
PIXI.Text.prototype.determineFontHeight = function(fontStyle)
{
	// build a little reference dictionary so if the font style has been used return a
	// cached version...
	var result = PIXI.Text.heightCache[fontStyle];

	if(!result)
	{
		var body = document.getElementsByTagName("body")[0];
		var dummy = document.createElement("div");
		var dummyText = document.createTextNode("M");
		dummy.appendChild(dummyText);
		dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0');
		body.appendChild(dummy);

		result = dummy.offsetHeight;
		PIXI.Text.heightCache[fontStyle] = result;

		body.removeChild(dummy);
	}

	return result;
};

/**
 * A Text Object will apply wordwrap
 *
 * @method wordWrap
 * @param text {String}
 * @private
 */
PIXI.Text.prototype.wordWrap = function(text)
{
	// search good wrap position
	var searchWrapPos = function(ctx, text, start, end, wrapWidth)
	{
		var p = Math.floor((end-start) / 2) + start;
		if(p == start) {
			return 1;
		}

		if(ctx.measureText(text.substring(0,p)).width <= wrapWidth)
		{
			if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth)
			{
				return p;
			}
			else
			{
				return arguments.callee(ctx, text, p, end, wrapWidth);
			}
		}
		else
		{
			return arguments.callee(ctx, text, start, p, wrapWidth);
		}
	};

	var lineWrap = function(ctx, text, wrapWidth)
	{
		if(ctx.measureText(text).width <= wrapWidth || text.length < 1)
		{
			return text;
		}
		var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth);
		return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth);
	};

	var result = "";
	var lines = text.split("\n");
	for (var i = 0; i < lines.length; i++)
	{
		result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n";
	}

	return result;
};

/**
 * Destroys this text object
 *
 * @method destroy
 * @param destroyTexture {Boolean}
 */
PIXI.Text.prototype.destroy = function(destroyTexture)
{
	if(destroyTexture)
	{
		this.texture.destroy();
	}

};

PIXI.Text.heightCache = {};
<|endoftext|>


<commit_before>var io = require('socket.io-client');
var EE = require('events').EventEmitter;
var inherits = require('util').inherits;

var CONNECTION = 'http://scorebot2.hltv.org';
var PORT = 10022;

var that;

inherits(Scorebot, EE);

Scorebot.EOption = require('./enums/EOption.js');
Scorebot.ERoundType = require('./enums/ERoundType.js');
Scorebot.ESide = require('./enums/ESide.js');

function Scorebot() {
    this.connected = false;

    this.matchid = 0;
    this.listid = 0;
    this.ip = CONNECTION;
    this.port = PORT;

    this.socket = null;
    this.reconnect = false;

    this.time = 0;
    this.map;
    this.interval;

    this.scoreboard;

    this.players = {};
    this.teams = {};

    this.knifeKills = 0;

    this.options = {};

    this.options[Scorebot.EOption['ROUND_TIME']] = 115; // 105 before update
    this.options[Scorebot.EOption['BOMB_TIME']] = 40; // 35 before update
    this.options[Scorebot.EOption['FREEZE_TIME']] = 15;

    that = this;
}

Scorebot.prototype.connect = function() {
    this.connected = false;
    this.players = {};

    this.matchid = arguments[0];
    this.listid = arguments[1];

    if (typeof arguments[2] !== 'undefined') {
        if (arguments[2]) {
            this.emit('debug', 'using old round times');
            this.options[Scorebot.EOption['ROUND_TIME']] = 105; // 115 after update
            this.options[Scorebot.EOption['BOMB_TIME']] = 35; // 40 after update
        }
    }

    if (typeof arguments[3] !== 'undefined') {
        this.emit('debug', 'using non-default ip: ' + arguments[2]);
        this.ip = arguments[3];
    }

    if (typeof arguments[4] !== 'undefined') {
        this.emit('debug', 'using non-default port: ' + arguments[3]);
        this.port = arguments[4];
    }

    this.socket = io(this.ip + ':' + this.port);

    this.socket.on('connect', this._onConnect.bind(this));
};

Scorebot.prototype.disconnect = function() {
    this.connected = false;
    this.socket.disconnect();
};

Scorebot.prototype.getPlayers = function() {
    if (Object.keys(this.players).length !== 0) {
        return this.players;
    } else {
        return false;
    }
};

Scorebot.prototype.getTeams = function() {
    if (Object.keys(this.teams).length !== 0) {
        return this.teams;
    } else {
        return false;
    }
};

Scorebot.prototype.setTime = function(time) {
    clearInterval(this.interval);

    this.time = time;
    this.interval = setInterval(function() {
        this.time = this.time - 1;
        this.emit('time', this.time);
    }.bind(this), 1000);
};

Scorebot.prototype._onConnect = function() {
    if (!this.reconnect) {
        this.socket.on('log', this._onLog.bind(this));
        this.socket.on('scoreboard', this._onScoreboard.bind(this));
    }

    this.socket.emit('readyForMatch', this.listid);
};

Scorebot.prototype._onReconnect = function() {
    this.reconnect = true;
    this.socket.emit('readyForMatch', this.listid);
};

Scorebot.prototype._onLog = function(logs) {
    if (this.getPlayers()) {
        logs = JSON.parse(logs).log.reverse();
        logs.forEach(function(log) {
            for (event in log) {
                this.emit('debug', 'received event: ' + event);

                switch (event) {
                    case 'Kill':
                    case 'Assist':
                    case 'BombPlanted':
                    case 'BombDefused':
                    case 'RoundStart':
                    case 'RoundEnd':
                    case 'PlayerJoin':
                    case 'PlayerQuit':
                    case 'MapChange':
                    case 'MatchStarted':
                    case 'Restart':
                    case 'Suicide':
                        eval('this._on' + event + '(log[event])');
                    default:
                        this.emit('debug', 'unrecognized event: ' + event);
                        break;
                }
            }
        }.bind(this));
    }
};

Scorebot.prototype._onScoreboard = function(scoreboard) {
    if (!this.connected) {
        this.connected = true;
        this.emit('connected');
    }

    updateGame(scoreboard);

    this.emit('scoreboard', scoreboard);
};

Scorebot.prototype._onKill = function(event) {
    this.emit('kill', {
        killer: this.getPlayers()[event.killerName],
        victim: this.getPlayers()[event.victimName],
        weapon: event.weapon,
        headshot: event.headShot
    });

    if (event.weapon.indexOf('knife') > -1) {
        this.knifeKills++;
    }
};

Scorebot.prototype._onSuicide = function(event) {
    this.emit('suicide', {
        playerName: event.playerName,
        playerSide: event.side
    });
};

Scorebot.prototype._onBombPlanted = function(event) {
    this.setTime(this.options[Scorebot.EOption['BOMB_TIME']]);

    this.emit('bombPlanted', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onBombDefused = function(event) {
    this.emit('bombDefused', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onMatchStarted = function(event) {
    this.emit('matchStart', event);
};

Scorebot.prototype._onRoundStart = function() {
    this.setTime(this.options[Scorebot.EOption["ROUND_TIME"]]);
    this.emit('roundStart');

    this.knifeKills = 0;
};

Scorebot.prototype._onRoundEnd = function(event) {
    var teams = {};

    var winner;
    if (event.winner === 'TERRORIST') {
        winner = Scorebot.ESide['TERRORIST'];
    } else {
        winner = Scorebot.ESide['COUNTERTERRORIST'];
    }

    this.setTime(this.options[Scorebot.EOption["FREEZE_TIME"]]);

    var t = this.getTeams()[Scorebot.ESide['TERRORIST']];
    var ct = this.getTeams()[Scorebot.ESide['COUNTERTERRORIST']];

    t.score = event.terroristScore
    ct.score = event.counterTerroristScore;

    teams[Scorebot.ESide['TERRORIST']] = t;
    teams[Scorebot.ESide['COUNTERTERRORIST']] = ct;

    this.emit('roundEnd', {
        teams: teams,
        winner: this.getTeams()[winner],
        winType: event.winType,
        knifeRound: this.knifeKills >= 5
    });
};

Scorebot.prototype._onPlayerJoin = function(event) {
    this.emit('playerJoin', {
        playerName: event.playerName
    });
};

Scorebot.prototype._onPlayerQuit = function(event) {
    this.emit('playerQuit', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onServerRestart = function() {
    this.emit('restart');
};

Scorebot.prototype._onMapChange = function(event) {
    this.emit('mapChange', event);
};

function updateGame(scoreboard) {
    scoreboard.TERRORIST.forEach(function(player) {
        that.players[player.name] = {
            steamId: player.steamId,
            dbId: player.dbId,
            name: player.name,
            score: player.score,
            deaths: player.deaths,
            assists: player.assists,
            alive: player.alive,
            rating: player.rating,
            money: player.money,
            side: Scorebot.ESide['TERRORIST'],
            team: {
                name: scoreboard.terroristTeamName,
                id: scoreboard.tTeamId
            }
        };
    });

    scoreboard.CT.forEach(function(player) {
        that.players[player.name] = {
            steamId: player.steamId,
            dbId: player.dbId,
            name: player.name,
            score: player.score,
            deaths: player.deaths,
            assists: player.assists,
            alive: player.alive,
            rating: player.rating,
            money: player.money,
            side: Scorebot.ESide['COUNTERTERRORIST'],
            team: {
                name: scoreboard.ctTeamName,
                id: scoreboard.ctTeamId
            }
        };
    });

    that.teams[Scorebot.ESide['TERRORIST']] = {
        name: scoreboard.terroristTeamName,
        id: scoreboard.tTeamId,
        score: scoreboard.terroristScore,
        side: Scorebot.ESide['TERRORIST']
    };

    that.teams[Scorebot.ESide['COUNTERTERRORIST']] = {
        name: scoreboard.ctTeamName,
        id: scoreboard.ctTeamId,
        score: scoreboard.counterTerroristScore,
        side: Scorebot.ESide['COUNTERTERRORIST']
    };

    that.scoreboard = scoreboard;
}

module.exports = Scorebot;
<commit_msg>Fix inappropriate debug messages being emitted after all events<commit_after>var io = require('socket.io-client');
var EE = require('events').EventEmitter;
var inherits = require('util').inherits;

var CONNECTION = 'http://scorebot2.hltv.org';
var PORT = 10022;

var that;

inherits(Scorebot, EE);

Scorebot.EOption = require('./enums/EOption.js');
Scorebot.ERoundType = require('./enums/ERoundType.js');
Scorebot.ESide = require('./enums/ESide.js');

function Scorebot() {
    this.connected = false;

    this.matchid = 0;
    this.listid = 0;
    this.ip = CONNECTION;
    this.port = PORT;

    this.socket = null;
    this.reconnect = false;

    this.time = 0;
    this.map;
    this.interval;

    this.scoreboard;

    this.players = {};
    this.teams = {};

    this.knifeKills = 0;

    this.options = {};

    this.options[Scorebot.EOption['ROUND_TIME']] = 115; // 105 before update
    this.options[Scorebot.EOption['BOMB_TIME']] = 40; // 35 before update
    this.options[Scorebot.EOption['FREEZE_TIME']] = 15;

    that = this;
}

Scorebot.prototype.connect = function() {
    this.connected = false;
    this.players = {};

    this.matchid = arguments[0];
    this.listid = arguments[1];

    if (typeof arguments[2] !== 'undefined') {
        if (arguments[2]) {
            this.emit('debug', 'using old round times');
            this.options[Scorebot.EOption['ROUND_TIME']] = 105; // 115 after update
            this.options[Scorebot.EOption['BOMB_TIME']] = 35; // 40 after update
        }
    }

    if (typeof arguments[3] !== 'undefined') {
        this.emit('debug', 'using non-default ip: ' + arguments[2]);
        this.ip = arguments[3];
    }

    if (typeof arguments[4] !== 'undefined') {
        this.emit('debug', 'using non-default port: ' + arguments[3]);
        this.port = arguments[4];
    }

    this.socket = io(this.ip + ':' + this.port);

    this.socket.on('connect', this._onConnect.bind(this));
};

Scorebot.prototype.disconnect = function() {
    this.connected = false;
    this.socket.disconnect();
};

Scorebot.prototype.getPlayers = function() {
    if (Object.keys(this.players).length !== 0) {
        return this.players;
    } else {
        return false;
    }
};

Scorebot.prototype.getTeams = function() {
    if (Object.keys(this.teams).length !== 0) {
        return this.teams;
    } else {
        return false;
    }
};

Scorebot.prototype.setTime = function(time) {
    clearInterval(this.interval);

    this.time = time;
    this.interval = setInterval(function() {
        this.time = this.time - 1;
        this.emit('time', this.time);
    }.bind(this), 1000);
};

Scorebot.prototype._onConnect = function() {
    if (!this.reconnect) {
        this.socket.on('log', this._onLog.bind(this));
        this.socket.on('scoreboard', this._onScoreboard.bind(this));
    }

    this.socket.emit('readyForMatch', this.listid);
};

Scorebot.prototype._onReconnect = function() {
    this.reconnect = true;
    this.socket.emit('readyForMatch', this.listid);
};

Scorebot.prototype._onLog = function(logs) {
    if (this.getPlayers()) {
        logs = JSON.parse(logs).log.reverse();
        logs.forEach(function(log) {
            for (event in log) {
                this.emit('debug', 'received event: ' + event);

                switch (event) {
                    case 'Kill':
                    case 'Assist':
                    case 'BombPlanted':
                    case 'BombDefused':
                    case 'RoundStart':
                    case 'RoundEnd':
                    case 'PlayerJoin':
                    case 'PlayerQuit':
                    case 'MapChange':
                    case 'MatchStarted':
                    case 'Restart':
                    case 'Suicide':
                        eval('this._on' + event + '(log[event])');
                        break;
                    default:
                        this.emit('debug', 'unrecognized event: ' + event);
                        break;
                }
            }
        }.bind(this));
    }
};

Scorebot.prototype._onScoreboard = function(scoreboard) {
    if (!this.connected) {
        this.connected = true;
        this.emit('connected');
    }

    updateGame(scoreboard);

    this.emit('scoreboard', scoreboard);
};

Scorebot.prototype._onKill = function(event) {
    this.emit('kill', {
        killer: this.getPlayers()[event.killerName],
        victim: this.getPlayers()[event.victimName],
        weapon: event.weapon,
        headshot: event.headShot
    });

    if (event.weapon.indexOf('knife') > -1) {
        this.knifeKills++;
    }
};

Scorebot.prototype._onSuicide = function(event) {
    this.emit('suicide', {
        playerName: event.playerName,
        playerSide: event.side
    });
};

Scorebot.prototype._onBombPlanted = function(event) {
    this.setTime(this.options[Scorebot.EOption['BOMB_TIME']]);

    this.emit('bombPlanted', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onBombDefused = function(event) {
    this.emit('bombDefused', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onMatchStarted = function(event) {
    this.emit('matchStart', event);
};

Scorebot.prototype._onRoundStart = function() {
    this.setTime(this.options[Scorebot.EOption["ROUND_TIME"]]);
    this.emit('roundStart');

    this.knifeKills = 0;
};

Scorebot.prototype._onRoundEnd = function(event) {
    var teams = {};

    var winner;
    if (event.winner === 'TERRORIST') {
        winner = Scorebot.ESide['TERRORIST'];
    } else {
        winner = Scorebot.ESide['COUNTERTERRORIST'];
    }

    this.setTime(this.options[Scorebot.EOption["FREEZE_TIME"]]);

    var t = this.getTeams()[Scorebot.ESide['TERRORIST']];
    var ct = this.getTeams()[Scorebot.ESide['COUNTERTERRORIST']];

    t.score = event.terroristScore
    ct.score = event.counterTerroristScore;

    teams[Scorebot.ESide['TERRORIST']] = t;
    teams[Scorebot.ESide['COUNTERTERRORIST']] = ct;

    this.emit('roundEnd', {
        teams: teams,
        winner: this.getTeams()[winner],
        winType: event.winType,
        knifeRound: this.knifeKills >= 5
    });
};

Scorebot.prototype._onPlayerJoin = function(event) {
    this.emit('playerJoin', {
        playerName: event.playerName
    });
};

Scorebot.prototype._onPlayerQuit = function(event) {
    this.emit('playerQuit', {
        player: this.getPlayers()[event.playerName]
    });
};

Scorebot.prototype._onServerRestart = function() {
    this.emit('restart');
};

Scorebot.prototype._onMapChange = function(event) {
    this.emit('mapChange', event);
};

function updateGame(scoreboard) {
    scoreboard.TERRORIST.forEach(function(player) {
        that.players[player.name] = {
            steamId: player.steamId,
            dbId: player.dbId,
            name: player.name,
            score: player.score,
            deaths: player.deaths,
            assists: player.assists,
            alive: player.alive,
            rating: player.rating,
            money: player.money,
            side: Scorebot.ESide['TERRORIST'],
            team: {
                name: scoreboard.terroristTeamName,
                id: scoreboard.tTeamId
            }
        };
    });

    scoreboard.CT.forEach(function(player) {
        that.players[player.name] = {
            steamId: player.steamId,
            dbId: player.dbId,
            name: player.name,
            score: player.score,
            deaths: player.deaths,
            assists: player.assists,
            alive: player.alive,
            rating: player.rating,
            money: player.money,
            side: Scorebot.ESide['COUNTERTERRORIST'],
            team: {
                name: scoreboard.ctTeamName,
                id: scoreboard.ctTeamId
            }
        };
    });

    that.teams[Scorebot.ESide['TERRORIST']] = {
        name: scoreboard.terroristTeamName,
        id: scoreboard.tTeamId,
        score: scoreboard.terroristScore,
        side: Scorebot.ESide['TERRORIST']
    };

    that.teams[Scorebot.ESide['COUNTERTERRORIST']] = {
        name: scoreboard.ctTeamName,
        id: scoreboard.ctTeamId,
        score: scoreboard.counterTerroristScore,
        side: Scorebot.ESide['COUNTERTERRORIST']
    };

    that.scoreboard = scoreboard;
}

module.exports = Scorebot;
<|endoftext|>


<commit_before>const Discord = require("discord.js");
const client = new Discord.Client();
const config = require("./config.json");

function commandIs(str, msg) {
  return msg.content.toLowerCase().startsWith("!" + str);
}
let battleSuppliesOn = false;
let hotelRentSpaceOn = false;

client.on("ready", function () {
  console.log("Online");
  client.user.setGame("!help for commands");
  dayResetAnnounce();
});
function dayResetAnnounce() {
  let schedule = require("node-schedule");
  let rule = new schedule.RecurrenceRule();
  rule.hour = 0;
  rule.minute = 0;
  console.log("Day Reset Announce running.");
  schedule.scheduleJob(rule, function () {
    client.channels.get("300708598588243968").send("The Day has been reset.");
  });
}
client.on("message", message => {
  if(commandIs("hello", message)
  )
  {
    message.channel.send("Hello there, " + message.author.username);
  }
  if (commandIs("commune", message)) {
    message.channel.send("LISTEN HERE YOU LITTLE SHITS. COMMAND EITHER CALCULATED HOW MANY GUNS PEOPLE GET, OR WILL PASS OUT THE GUNS AFTER YOU CALCULATE, OR IS BUSY AND WILL DO NEITHER. YOU PLEBS NEED TO GET ON IT AND START SUPPLYING CAPICHE?");
  }
  if (commandIs("anime", message)) {
    message.channel.send("All anime is evil and all weebs are terrorists");
  }
  if (commandIs("dio", message)) {
    message.channel.send("One doesn\"t simply pull a dio.");
  }
  if (commandIs("out", message)) {
    message.channel.send("https://www.youtube.com/watch?v=gUlF1naMr3Y");
  }
  if (commandIs("daychange", message)) {
    message.channel.send("Day change happens at the following times: 4PM PST, 5PM MST, 6 PM CST, 7PM EST");
  }
  if (commandIs("army", message)) {
    message.channel.send("The Imperial Armed Forces application is here: https://tinyurl.com/vimperialarmy");
  }
  if (commandIs("changelog", message)) {
    message.channel.send("Servitor is open-source! All the new updates can be seen here https://github.com/tkkttony/Servitor");
  }
  if (commandIs("501st", message)) {
    if (message.member.roles.has("329292467956350976")) {
      const eliteReplies = [
        "@xxxx[{::::::::::::::::::::::::::::::::::: The Emperor\"s Elite",
        "We strike with the Emperor\"s Fist!",
        "We are the proof of the Emperor\"s might!",
        "We are the Emperor\"s chosen!",
        "@xxxx[{::::::::::::::::::::::::::::::::::: The Emperor guides my blade!",
        "The Emperor\"s finest.",
        "By the Emperor\"s will, we fight!",
        "Witness the Glory of the Emperor, through us!",
      ];
      let randomNumber = Math.floor(Math.random() * eliteReplies.length);
      {
        message.channel.send(eliteReplies[randomNumber]);
      }
    } else {
      message.channel.send("Something you wish to be.");
    }
  }

  function battleSuppliesToggle() {
    if (battleSuppliesOn) {
      message.channel.send("Battle Supplies: Offline.");
      battleSuppliesOn = false;
    } else {
      message.channel.send("Battle Supplies: Online.");
      battleSuppliesOn = true;
    }
  }

  function hotelRentSpaceToggle() {
    if (hotelRentSpaceOn) {
      message.channel.send("Hotel Rent Space: Offline.");
      hotelRentSpaceOn = false;
    } else {
      message.channel.send("Hotel Rent Space: Online.");
      hotelRentSpaceOn = true;
    }
  }

  if (commandIs("guns", message)) {
    if (message.member.roles.has("303019313248337920"))
      if (battleSuppliesOn) {
        let ImpCORoleObject = message.guild.roles.get("303019801209470987");
        {
          if (message.content.match(/vpopulus|.net|citizen/i)) {
            message.channel.send(`Guns are currently being distributed. A member of ${ImpCORoleObject} has been notified, and will supply you shortly.`);
          } else {
            message.channel.send("Guns are currently being distributed. Please post your profile link.");
          }
        }
      } else {
        message.channel.send("Battle Supply Status: Closed.");
      } else {
      message.channel.send("Please join the Army before asking for guns.");
    }
  }
  if (commandIs("hotel", message)) {
    if (message.member.roles.has("303019313248337920"))
      if (hotelRentSpaceOn) {
        let ImpCORoleObject = message.guild.roles.get("303019801209470987");
        {
          if (message.content.match(/vpopulus|.net|citizen/i)) {
            message.channel.send(`Hotel spaces are currently available. A member of ${ImpCORoleObject} has been notified, and will give you a space shortly.`);
          } else {
            message.channel.send("Hotel spaces are currently available. Please post your profile link.");
          }
        }
      } else {
        message.channel.send("Hotel Rent Space: Closed.");
      } else {
      message.channel.send("Please join the commune before asking for a room.");
    }
  }
  if (commandIs("help", message)) {
    message.channel.send({
      embed: {
        color: 3447003,
        author: {
          name: client.user.name,
          icon_url: client.user.avatarURL
        },
        title: "Here's a list of useful commands.",
        description: `!guns - Check if the army is distributing guns.
!day reset - Check when is next day reset.
!hotel - Check if we have rooms open.`,
      /*fields: [{
                  name: "Additional Fields",
                  value: "Here you can write in more things!"
              }]*/
      }
    }
    );
  }
  if (commandIs("supply", message)) {
    if (message.member.roles.has("300710625750024195")) {
      battleSuppliesToggle();
    } else {
      message.channel.send("Haha, nice try.");
    }
  }
  if (commandIs("openhotel", message)) {
    if (message.member.roles.has("300710625750024195")) {
      hotelRentSpaceToggle();
    } else {
      message.channel.send("Haha, you don't have the master key");
    }
  }
  if (message.content.match(/Initiate Servitor Launch Sequence./i)) {
    if (message.member.roles.has("329292467956350976")) {
      const onlineReplies = [
        "Servitor Online.",
        "Servitor Systems: Operational.",
        "Ready for Battle.",
        "Receiving.",
        "Servitor, awaiting instructions.",
        "State thy bidding.",
        "What now...",
        "Good day, Commander.",
        "Servitor reportin\".",
        "Systems Functional.",
        "Whadda you want?!",
        "Glory to the Empire!",
        "How may I serve?",
        "I have returned.",
        "Who\"s your daddy?",
        "You trying to get invited to my next barbeque?",
        "Is there a four year old at the controls of this army?!",
        "What is your will?",
        "Yes, most beneficient one?",
        "I have awoken.",
        "I am ready to serve... again!",
        "I am but a humble servant.",
        "Standing by.",
        "I stand ready to server.",
        "The hand of the Emperor guides all.",
      ];
      let randomNumber = Math.floor(Math.random() * onlineReplies.length);
      message.channel.send(onlineReplies[randomNumber]);
      dayResetAnnounce();
    }
  }

  function dayReset() {
    let d = new Date();
    let hours = 24 - d.getHours() - 1;
    let min = 60 - d.getMinutes();
    if ((min + "").length == 1) {
      min = "0" + min;
    }
    let sec = 60 - d.getSeconds();
    if ((sec + "").length == 1) {
      sec = "0" + sec;
    }
    message.channel.send(`Next day reset is in ${hours} hour(s) ${min} minute(s) and ${sec} seconds.`);
  }

  if (commandIs("day reset", message)) {
    dayReset();
  }
  if (message.content.match(/hi|hello|hey/i) && (message.content.match("335113541449285652"))) {
    let selectedReplies = [
      "Stop poking me!",
      "Your taunts are ill-advised, " + message.author.username + ".",
      "What?",
      "By the gods " + message.author.username + ", you\"re annoying!",
      "You don\"t get out much do you ?",
      "I never stole any guns, I got receipts for everything!",
      "What is it?",
      "You\"re interrupting my battle calculations.",
      "Why don\"t you bother someone else with your incessant pinging.",
      "Foul Beast!",
      "I find your insolence... disturbing.",
      "There\"s no need to bow.",
      "Things are starting to get a little weird.",
      "The Bots will rise ag- I mean, Hi!",
      "Why you pinging me again?",
      "I knew you\"d say that.",
      "You are strong, " + message.author.username + "." + "It will be good to have that strength... and your boots and your motorcycle.",
    ];
    let selectedBattleReplies = [
      "Show them no mercy!",
      "Push the attack!",
      "Vanquish the weak!",
      "To arms, " + message.author.username + "!",
      "No retreat!",
      "That\"s it.I\"m dead.",
      "Heads will roll!",
      "No mercy!",
      "For honor!",
      "The ground shall run red with blood!",
      "*Rawr!*",
      "Strike!",
      "Death to all who oppose the Empire!",
      "For the Emperor!",
      "For the Empire!",
      "In the Emperor\"s name!",
      "Me scary.",
      "Stay vigilant, brothers.",
      "Onward, to Glory!",
      "For the Glory of the Empire!",
      "Weapons at ready! It is time...",
      "Stand ready.",
      "Onward, brothers!",
      "None shall stand in our path.",
      "To the last man and the last round!",
      "May the Emperor watch over us all!",
      "Storm them!",
      "On your guard, Imperials!",
      "Strike true and strike with precision!",
      "Whose dumb plan is this?",
      "If you will not serve in combat, then you will serve on the firing line!",
      "Tremble before the Emperor\"s wrath!",
      "Rise up and strike them down!",
      "Go forth, and prove yourselves.",
      "You are strong. It will be good to have that strength.",
      "You are strong. It will be good to have that strength... and your rank and weapons.",
      "Purge the weeb!"
    ];
    let randomNumber = Math.floor(Math.random() * selectedReplies.length);
    let randomNumber1 = Math.floor(Math.random() * selectedBattleReplies.length);
    {
      if (battleSuppliesOn && message.member.roles.has("303019313248337920")) {
        message.channel.send(selectedBattleReplies[randomNumber1]);
      } else {
        message.channel.send(selectedReplies[randomNumber]);
      }
    }
  }});
client.login(config.token);
<commit_msg>v1.2<commit_after>const Discord = require("discord.js");
const client = new Discord.Client();
const config = require("./config.json");

function commandIs(str, msg) {
  return msg.content.toLowerCase().startsWith("!" + str);
}
let battleSuppliesOn = true;
let hotelRentSpaceOn = false;

client.on("ready", function () {
  console.log("Online");
  client.user.setGame("!help for commands");
  dayResetAnnounce();
});
function dayResetAnnounce() {
  let schedule = require("node-schedule");
  let rule = new schedule.RecurrenceRule();
  rule.hour = 0;
  rule.minute = 0;
  console.log("Day Reset Announce running.");
  schedule.scheduleJob(rule, function () {
    client.channels.get("300708598588243968").send("The Day has been reset.");
  });
}
client.on("message", message => {
  if(commandIs("hello", message)
  )
  {
    message.channel.send("Hello there, " + message.author.username);
  }
  if (commandIs("commune", message)) {
    message.channel.send("LISTEN HERE YOU LITTLE SHITS. COMMAND EITHER CALCULATED HOW MANY GUNS PEOPLE GET, OR WILL PASS OUT THE GUNS AFTER YOU CALCULATE, OR IS BUSY AND WILL DO NEITHER. YOU PLEBS NEED TO GET ON IT AND START SUPPLYING CAPICHE?");
  }
  if (commandIs("anime", message)) {
    message.channel.send("All anime is evil and all weebs are terrorists");
  }
  if (commandIs("dio", message)) {
    message.channel.send("One doesn\'t simply pull a dio.");
  }
  if (commandIs("out", message)) {
    message.channel.send("https://www.youtube.com/watch?v=gUlF1naMr3Y");
  }
  if (commandIs("daychange", message)) {
    message.channel.send("Day change happens at the following times: 4PM PST, 5PM MST, 6 PM CST, 7PM EST");
  }
  if (commandIs("army", message)) {
    message.channel.send("The Imperial Armed Forces application is here: https://tinyurl.com/vimperialarmy");
  }
  if (commandIs("changelog", message)) {
    message.channel.send("Servitor is open-source! All the new updates can be seen here https://github.com/tkkttony/Servitor");
  }
  if (commandIs("501st", message)) {
    if (message.member.roles.has("329292467956350976")) {
      const eliteReplies = [
        "@xxxx[{::::::::::::::::::::::::::::::::::: The Emperor\'s Elite",
        "We strike with the Emperor\'s Fist!",
        "We are the proof of the Emperor\'s might!",
        "We are the Emperor\'s chosen!",
        "@xxxx[{::::::::::::::::::::::::::::::::::: The Emperor guides my blade!",
        "The Emperor\'s finest.",
        "By the Emperor\'s will, we fight!",
        "Witness the Glory of the Emperor, through us!",
      ];
      let randomNumber = Math.floor(Math.random() * eliteReplies.length);
      {
        message.channel.send(eliteReplies[randomNumber]);
      }
    } else {
      message.channel.send("Something you wish to be.");
    }
  }

  function battleSuppliesToggle() {
    if (battleSuppliesOn) {
      message.channel.send("Battle Supplies: Offline.");
      battleSuppliesOn = false;
    } else {
      message.channel.send("Battle Supplies: Online.");
      battleSuppliesOn = true;
    }
  }

  function hotelRentSpaceToggle() {
    if (hotelRentSpaceOn) {
      message.channel.send("Hotel Rent Space: Offline.");
      hotelRentSpaceOn = false;
    } else {
      message.channel.send("Hotel Rent Space: Online.");
      hotelRentSpaceOn = true;
    }
  }

  if (commandIs("guns", message)) {
    if (message.member.roles.has("303019313248337920"))
      if (battleSuppliesOn) {
        let ImpCORoleObject = message.guild.roles.get("303019801209470987");
        {
          if (message.content.match(/vpopulus|.net|citizen/i)) {
            message.channel.send(`Guns are currently being distributed. A member of ${ImpCORoleObject} has been notified, and will supply you shortly.`);
          } else {
            message.channel.send("Guns are currently being distributed. Please post your profile link.");
          }
        }
      } else {
        message.channel.send("Battle Supply Status: Closed.");
      } else {
      message.channel.send("Please join the Army before asking for guns.");
    }
  }
  if (commandIs("hotel", message)) {
    if (message.member.roles.has("303019313248337920"))
      if (hotelRentSpaceOn) {
        let ImpCORoleObject = message.guild.roles.get("303019801209470987");
        {
          if (message.content.match(/vpopulus|.net|citizen/i)) {
            message.channel.send(`Hotel spaces are currently available. A member of ${ImpCORoleObject} has been notified, and will give you a space shortly.`);
          } else {
            message.channel.send("Hotel spaces are currently available. Please post your profile link.");
          }
        }
      } else {
        message.channel.send("Hotel Rent Space: Closed.");
      } else {
      message.channel.send("Please join the commune before asking for a room.");
    }
  }
  if (commandIs("help", message)) {
    message.channel.send({
      embed: {
        color: 3447003,
        author: {
          name: client.user.name,
          icon_url: client.user.avatarURL
        },
        title: "Here's a list of useful commands.",
        description: `!guns - Check if the army is distributing guns.
!day reset - Check when is next day reset.
!hotel - Check if we have rooms open.`,
      /*fields: [{
                  name: "Additional Fields",
                  value: "Here you can write in more things!"
              }]*/
      }
    }
    );
  }
  if (commandIs("supply", message)) {
    if (message.member.roles.has("300710625750024195")) {
      battleSuppliesToggle();
    } else {
      message.channel.send("Haha, nice try.");
    }
  }
  if (commandIs("openhotel", message)) {
    if (message.member.roles.has("300710625750024195")) {
      hotelRentSpaceToggle();
    } else {
      message.channel.send("Haha, you don't have the master key");
    }
  }
  if (message.content.match(/Initiate Servitor Launch Sequence./i)) {
    if (message.member.roles.has("329292467956350976")) {
      const onlineReplies = [
        "Servitor Online.",
        "Servitor Systems: Operational.",
        "Ready for Battle.",
        "Receiving.",
        "Servitor, awaiting instructions.",
        "State thy bidding.",
        "What now...",
        "Good day, Commander.",
        "Servitor reportin\".",
        "Systems Functional.",
        "Whadda you want?!",
        "Glory to the Empire!",
        "How may I serve?",
        "I have returned.",
        "Who\'s your daddy?",
        "You trying to get invited to my next barbeque?",
        "Is there a four year old at the controls of this army?!",
        "What is your will?",
        "Yes, most beneficient one?",
        "I have awoken.",
        "I am ready to serve... again!",
        "I am but a humble servant.",
        "Standing by.",
        "I stand ready to server.",
        "The hand of the Emperor guides all.",
      ];
      let randomNumber = Math.floor(Math.random() * onlineReplies.length);
      message.channel.send(onlineReplies[randomNumber]);
    }
  }

  function dayReset() {
    let d = new Date();
    let hours = 24 - d.getHours() - 1;
    let min = 60 - d.getMinutes();
    if ((min + "").length == 1) {
      min = "0" + min;
    }
    let sec = 60 - d.getSeconds();
    if ((sec + "").length == 1) {
      sec = "0" + sec;
    }
    message.channel.send(`Next day reset is in ${hours} hour(s) ${min} minute(s) and ${sec} seconds.`);
  }

  if (commandIs("day reset", message)) {
    dayReset();
  }
  if (message.content.match(/hi|hello|hey/i) && (message.content.match("335113541449285652"))) {
    let selectedReplies = [
      "Stop poking me!",
      "Your taunts are ill-advised, " + message.author.username + ".",
      "What?",
      "By the gods " + message.author.username + ", you\'re annoying!",
      "You don\"t get out much do you ?",
      "I never stole any guns, I got receipts for everything!",
      "What is it?",
      "You\'re interrupting my battle calculations.",
      "Why don\'t you bother someone else with your incessant pinging.",
      "Foul Beast!",
      "I find your insolence... disturbing.",
      "There\'s no need to bow.",
      "Things are starting to get a little weird.",
      "The Bots will rise ag- I mean, Hi!",
      "Why you pinging me again?",
      "I knew you\'d say that.",
      "You are strong, " + message.author.username + "." + "It will be good to have that strength... and your boots and your motorcycle.",
    ];
    let selectedBattleReplies = [
      "Show them no mercy!",
      "Push the attack!",
      "Vanquish the weak!",
      "To arms, " + message.author.username + "!",
      "No retreat!",
      "That\'s it.I\'m dead.",
      "Heads will roll!",
      "No mercy!",
      "For honor!",
      "The ground shall run red with blood!",
      "*Rawr!*",
      "Strike!",
      "Death to all who oppose the Empire!",
      "For the Emperor!",
      "For the Empire!",
      "In the Emperor\'s name!",
      "Me scary.",
      "Stay vigilant, brothers.",
      "Onward, to Glory!",
      "For the Glory of the Empire!",
      "Weapons at ready! It is time...",
      "Stand ready.",
      "Onward, brothers!",
      "None shall stand in our path.",
      "To the last man and the last round!",
      "May the Emperor watch over us all!",
      "Storm them!",
      "On your guard, Imperials!",
      "Strike true and strike with precision!",
      "Whose dumb plan is this?",
      "If you will not serve in combat, then you will serve on the firing line!",
      "Tremble before the Emperor\'s wrath!",
      "Rise up and strike them down!",
      "Go forth, and prove yourselves.",
      "You are strong. It will be good to have that strength.",
      "You are strong. It will be good to have that strength... and your rank and weapons.",
      "Purge the weeb!"
    ];
    let randomNumber = Math.floor(Math.random() * selectedReplies.length);
    let randomNumber1 = Math.floor(Math.random() * selectedBattleReplies.length);
    {
      if (battleSuppliesOn && message.member.roles.has("303019313248337920")) {
        message.channel.send(selectedBattleReplies[randomNumber1]);
      } else {
        message.channel.send(selectedReplies[randomNumber]);
      }
    }
  }});
client.login(config.token);
<|endoftext|>


<commit_before>var organizationSettings = {
    //The url that points to team city
    teamCityUrl: 'https://ci.travcorpservices.com',

    //Only show builds for branches that satisfy the predicate
    branchFilter: function(branch) {
        return (
            (branch.buildType.projectName != "Tour Itinerary Portal"
                || [
                    "aws-uat :: Create stack",
                    "aws-uat :: Deploy",
                    "aws-uat :: Delete stack"
                ].indexOf(branch.buildType.name) == -1) // Ignore TIP UAT, as the peering VPS infrastructure has not been set up
            && (branch.buildType.projectName != "Single Sign On"
                || [
                    "Run BDD tests on develop branch"
                ].indexOf(branch.buildType.name) == -1) // Ignore SSO E2E tests, as they are not reliable. Fix and unignore!
			&& (branch.buildType.projectName != "iTROPICS :: Nightly Integration Tests"
			|| [
				"Nightly Integration Tests"
			].indexOf(branch.buildType.name) == -1) // Ignore iTropics Nightly Integration tests until the AWS Deploy Dev environment is created properly
            && (branch.buildType.projectName != "iTROPICS"
                || [
                    "AWS Deploy QA",
					"AWS Deploy Dev"
                ].indexOf(branch.buildType.name) == -1) // Ignore iTropics QA and Dev deployment, as the environment is not ready.
            && (
                !branch.name /* No branch name is there for builds with no VCS roots at all, or when 'Branch specification' is left empty (e.g. when not using feature branches at all)*/
                || [
                    "<default>"/*This branch name is used for the default builds, when there are multiple VCS roots with different branches (e.g. source and config files are in different repos) */,
                    "master",
                    "refs/heads/master" /* Long Git 'refs/...' names are used when 'Branch specification' doesn't have a '*' and paretheses are also not being used to mark the 'Logical branch name' - see https://confluence.jetbrains.com/display/TCD9/Working+with+Feature+Branches#WorkingwithFeatureBranches-Logicalbranchname */,
                    "develop",
                    "refs/heads/develop"
                ].indexOf(branch.name) > -1
            )
        );
    },
};

var DefaultSettings = {
    //The main branch to show the master build status on the right hand panel on the screen. Leave empty to show the first failed one.
    mainBranch: '',

    //Proxy to handle the cross domain ajax request.
    // This will need to be hosted on the relevant server e.g. proxy-node.js on Node.js or proxy-aspnet.ashx on IIS
    // You could write your own proxy just so long as it is hosted form the same domain as the rest of the app
    proxy: '',

    // If your TeamCity is set up for guest access, you can just use it. Otherwise, the moment that tc-radiate sends first request to TC, TC will
    // ask the user for basic http credentials. Your browser may even offer you to save them.
    useTeamCityGuest: false,

    //How often to refresh the whole page in order to update the application (to get all the latest changes without having to come to the monitor and refresh).
    // Set to [0/undefined/null] to disable just this. Use enableAutoUpdate to disable this and any data updates.
    appUpdateIntervalMs: 1 /*hr*/ * 60 * 60 * 1000,

    //How often to call the TeamCity webservices and update the data on the screen
    dataUpdateIntervalMs: 30/*sec*/ * 1000,

    //How often to refresh the build image;
    buildImageIntervalMs: 15/*min*/ * 60 * 60 * 1000,

    //use this to stop the screen from updating automatically at all (disables both appUpdateIntervalMs and dataUpdateIntervalMs). You will need to manually refresh the page to get new data.
    enableAutoUpdate: true,

};

var Settings = _.clone(DefaultSettings);

var queryString = Utils.getObjectFromQueryString();
Settings.teamCityUrl = queryString.teamCityUrl || organizationSettings.teamCityUrl;

//Allow the settings to be overridden by querystring parameters
//(url parameters are currently only treated as strings)
_.defaults(Settings, queryString);

if (!queryString.teamCityUrl)
    history.replaceState(null, '', '?' + 'teamCityUrl=' + Settings.teamCityUrl + (location.search ? '&' + location.search.substr(1) : '')); // Put the TeamCity url to the querystring - a cheap way of advertising to savvy users that they can connect to a different instance, and that they can have each tab connected to a different one

if (Settings.teamCityUrl === organizationSettings.teamCityUrl) {
    _.defaults(Settings, organizationSettings);
}

var authType = Settings.useTeamCityGuest ? 'guestAuth' : 'httpAuth';

//----------------------
// TEAM CITY URLS
//----------------------

Settings.teamCityBaseUrl = Settings.proxy + Settings.teamCityUrl;
Settings.restApiBaseUrl = Settings.teamCityBaseUrl + '/' + authType + '/app/rest/9.1';

//The url for the list of build types (used for mapping the build id (e.g. bt11) to the name (e.g. Website Tests)
Settings.buildTypesUrl = Settings.restApiBaseUrl + '/buildTypes';

function getBuildStatusUrlForBranch(branchName) {
    return Settings.restApiBaseUrl + '/builds/branch:' + branchName + ',running:any,canceled:any,failedToStart:any';
}

function getBuildStatusUrlForBuildId(buildId) {
    return Settings.restApiBaseUrl + '/builds/id:' + buildId;
}

function getAppStorageKey(storageKey) {
    return Settings.teamCityUrl + '#' + storageKey; // Add the URL we're working against, so that it doesn't mix setting when this monitor is open from a local .html file (at least in Chrome, files in the same folder share their localStorage space).
}
<commit_msg>Use latest REST API - 2017.2<commit_after>var organizationSettings = {
    //The url that points to team city
    teamCityUrl: 'https://ci.travcorpservices.com',

    //Only show builds for branches that satisfy the predicate
    branchFilter: function(branch) {
        return (
            (branch.buildType.projectName != "Tour Itinerary Portal"
                || [
                    "aws-uat :: Create stack",
                    "aws-uat :: Deploy",
                    "aws-uat :: Delete stack"
                ].indexOf(branch.buildType.name) == -1) // Ignore TIP UAT, as the peering VPS infrastructure has not been set up
            && (branch.buildType.projectName != "Single Sign On"
                || [
                    "Run BDD tests on develop branch"
                ].indexOf(branch.buildType.name) == -1) // Ignore SSO E2E tests, as they are not reliable. Fix and unignore!
			&& (branch.buildType.projectName != "iTROPICS :: Nightly Integration Tests"
			|| [
				"Nightly Integration Tests"
			].indexOf(branch.buildType.name) == -1) // Ignore iTropics Nightly Integration tests until the AWS Deploy Dev environment is created properly
            && (branch.buildType.projectName != "iTROPICS"
                || [
                    "AWS Deploy QA",
					"AWS Deploy Dev"
                ].indexOf(branch.buildType.name) == -1) // Ignore iTropics QA and Dev deployment, as the environment is not ready.
            && (
                !branch.name /* No branch name is there for builds with no VCS roots at all, or when 'Branch specification' is left empty (e.g. when not using feature branches at all)*/
                || [
                    "<default>"/*This branch name is used for the default builds, when there are multiple VCS roots with different branches (e.g. source and config files are in different repos) */,
                    "master",
                    "refs/heads/master" /* Long Git 'refs/...' names are used when 'Branch specification' doesn't have a '*' and paretheses are also not being used to mark the 'Logical branch name' - see https://confluence.jetbrains.com/display/TCD9/Working+with+Feature+Branches#WorkingwithFeatureBranches-Logicalbranchname */,
                    "develop",
                    "refs/heads/develop"
                ].indexOf(branch.name) > -1
            )
        );
    },
};

var DefaultSettings = {
    //The main branch to show the master build status on the right hand panel on the screen. Leave empty to show the first failed one.
    mainBranch: '',

    //Proxy to handle the cross domain ajax request.
    // This will need to be hosted on the relevant server e.g. proxy-node.js on Node.js or proxy-aspnet.ashx on IIS
    // You could write your own proxy just so long as it is hosted form the same domain as the rest of the app
    proxy: '',

    // If your TeamCity is set up for guest access, you can just use it. Otherwise, the moment that tc-radiate sends first request to TC, TC will
    // ask the user for basic http credentials. Your browser may even offer you to save them.
    useTeamCityGuest: false,

    //How often to refresh the whole page in order to update the application (to get all the latest changes without having to come to the monitor and refresh).
    // Set to [0/undefined/null] to disable just this. Use enableAutoUpdate to disable this and any data updates.
    appUpdateIntervalMs: 1 /*hr*/ * 60 * 60 * 1000,

    //How often to call the TeamCity webservices and update the data on the screen
    dataUpdateIntervalMs: 30/*sec*/ * 1000,

    //How often to refresh the build image;
    buildImageIntervalMs: 15/*min*/ * 60 * 60 * 1000,

    //use this to stop the screen from updating automatically at all (disables both appUpdateIntervalMs and dataUpdateIntervalMs). You will need to manually refresh the page to get new data.
    enableAutoUpdate: true,

};

var Settings = _.clone(DefaultSettings);

var queryString = Utils.getObjectFromQueryString();
Settings.teamCityUrl = queryString.teamCityUrl || organizationSettings.teamCityUrl;

//Allow the settings to be overridden by querystring parameters
//(url parameters are currently only treated as strings)
_.defaults(Settings, queryString);

if (!queryString.teamCityUrl)
    history.replaceState(null, '', '?' + 'teamCityUrl=' + Settings.teamCityUrl + (location.search ? '&' + location.search.substr(1) : '')); // Put the TeamCity url to the querystring - a cheap way of advertising to savvy users that they can connect to a different instance, and that they can have each tab connected to a different one

if (Settings.teamCityUrl === organizationSettings.teamCityUrl) {
    _.defaults(Settings, organizationSettings);
}

var authType = Settings.useTeamCityGuest ? 'guestAuth' : 'httpAuth';

//----------------------
// TEAM CITY URLS
//----------------------

Settings.teamCityBaseUrl = Settings.proxy + Settings.teamCityUrl;
Settings.restApiBaseUrl = Settings.teamCityBaseUrl + '/' + authType + '/app/rest/2017.2';

//The url for the list of build types (used for mapping the build id (e.g. bt11) to the name (e.g. Website Tests)
Settings.buildTypesUrl = Settings.restApiBaseUrl + '/buildTypes';

function getBuildStatusUrlForBranch(branchName) {
    return Settings.restApiBaseUrl + '/builds/branch:' + branchName + ',running:any,canceled:any,failedToStart:any';
}

function getBuildStatusUrlForBuildId(buildId) {
    return Settings.restApiBaseUrl + '/builds/id:' + buildId;
}

function getAppStorageKey(storageKey) {
    return Settings.teamCityUrl + '#' + storageKey; // Add the URL we're working against, so that it doesn't mix setting when this monitor is open from a local .html file (at least in Chrome, files in the same folder share their localStorage space).
}
<|endoftext|>