<commit_before>import React, { Fragment } from 'react'
import {
  BackgroundImage,
  Box,
  Container,
  Flex,
  Heading,
  Link as A,
  Section,
  Text
} from '@hackclub/design-system'
import styled, { css } from 'styled-components'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Module from 'components/Module'
import Framed from 'components/Framed'
import Start from 'components/Start'
import Footer from 'components/Footer'

const shadows = `
  h1,
  h2 {
    color: #fff;
    text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75);
  }
`
const PhotoSection = styled(Section)`
  position: relative;
  background: linear-gradient(rgba(0, 0, 0, 0.325), rgba(0, 0, 0, 0.125)),
    url(${props => props.src});
  background-position: center;
  background-size: cover;
  ${shadows};
`
PhotoSection.defaultProps = {
  py: 4
}

const Modules = styled(Box)`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: repeat(3, 1fr);
  }
  > div {
    align-items: flex-start;
    padding: 0;
    text-align: left;
    width: 100% !important;
  }
  p {
    color: ${({ theme }) => theme.colors.slate};
    line-height: 1.375;
  }
`

const Notification = styled(Flex)`
  border-radius: ${({ theme }) => theme.radius};
  background-color: rgba(255, 255, 255, 0.9375);
  strong {
    font-weight: bold;
  }
`
Notification.defaultProps = {
  py: 3,
  px: 4,
  mb: 3,
  mt: 5,
  mx: 2,
  align: 'center',
  justify: 'center',
  color: 'gray.9',
  flexDirection: 'column'
}

const Row = Container.extend.attrs({ color: 'black', px: 3, py: [3, 4] })`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  text-align: left;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: ${props => props.cols || '2fr 3fr'};
    grid-gap: ${({ theme }) => theme.space[4]}px;
  }
`

const styles = {
  ultraline: { f: [6, 7], style: { lineHeight: '1.0625' } },
  headline: { f: [5, 6], style: { lineHeight: '1.125' } },
  subhline: {
    f: [3, 4],
    color: 'black',
    regular: true,
    style: { lineHeight: '1.375' }
  },
  contentContainer: {
    maxWidth: 64,
    w: 1,
    p: [3, 2]
  }
}

const title = 'Start Your Hack Club | Hack Club'
const description =
  'Learn how to start a coding club at your high school through Hack Club. Get programming club ideas, curriculum, activities, and more.'

export default () => (
  <Fragment>
    <Helmet
      title={title}
      meta={[
        { name: 'twitter:title', content: title },
        { name: 'description', content: description },
        { name: 'twitter:description', content: description },
        { property: 'og:title', content: title },
        { property: 'og:description', content: description },
        { property: 'og:url', content: 'https://hackclub.com/start' }
      ]}
    />

    <PhotoSection src="/lah_2.jpg">
      <Notification>
        <Text f={3} bold>
          Fall 2018 applications due by September 30th
        </Text>
        <Text f={2}>
          Applications are open and accepted on a rolling basis.
        </Text>
      </Notification>
      <Container maxWidth={56} p={[2, 3]} mb={[5, 6]}>
        <Heading.h1 {...styles.ultraline} color="white">
          Let’s get started.
        </Heading.h1>
        <Heading.h2 {...styles.subhline} color="white" f={[4, 5]} mt={3}>
          Whether you're interested in starting a new chapter or joining Hack
          Club with an existing CS club, we should talk.
        </Heading.h2>
      </Container>
    </PhotoSection>
    <Row my={[3, 4]}>
      <Box color="black">
        <Heading.h2 {...styles.headline} mb={3}>
          HQ provides the support to get you started
        </Heading.h2>
        <Text {...styles.subhline}>
          Get your club started with our resources used by 200+ Hack Clubs.
        </Text>
      </Box>
      <Modules>
        <Module
          icon="forum"
          heading="Community"
          body="Join our Slack and meet hundreds of other club leaders and members around the world."
          color="red.5"
        />
        <Module
          icon="pages"
          heading="Curriculum"
          body="Give your members dozens of free tutorials for making websites, apps, and games."
          color="orange.5"
        />
        <Module
          icon="voice_chat"
          heading="Mentorship"
          body="Talk to our team over a call or on Slack for guidance and assistance whenever you need help."
          color="yellow.7"
        />
        <Module
          icon="chrome_reader_mode"
          heading="Guidelines"
          body="Learn from hundreds of other clubs—we’ve got information, advice, and experience."
          color="teal.7"
        />
        <Module
          icon="local_activity"
          heading="Local events"
          body="Attend hackathons, workshops, and other events from Hack Clubs near yours."
          color="blue.5"
        />
        <Module
          icon="wallpaper"
          heading="Marketing"
          body="Get stickers, posters, and ideas for spreading the word about your amazing club meetings."
          color="indigo.5"
        />
      </Modules>
    </Row>
    <Container px={3} mt={[0, 0, -75]} mb={[3, 5]}>
      <Box color="black">
        <Heading.h3 f={[4, 5]} mt={4}>
          Already have a club?
        </Heading.h3>
        <Text f={[3, 4]} my={3}>
          Great! When established CS clubs join, they get the full benefits of
          the network. Hack Club is currently optimized for new chapters, but
          we're increasing the benefits for existing clubs every day with
          launches like{' '}

            hackathons
          {' '}
          and{' '}

            bank
          .
        </Text>
      </Box>
    </Container>
    <Container px={3} my={[3, 5]}>
      <Box color="black">
        <Heading.h2 f={[5, 6]} mt={5} mb={4}>
          What do meetings look like?
        </Heading.h2>
        <Container maxWidth={48} mx={0}>
          <Text f={[3, 4]}>
            Hack Clubs meet weekly, typically for 1.5 hours. Meetings resemble
            mini-hackathons, where members learn to code through building
            projects like{' '}

              websites
            {' '}
            and{' '}

              games
            .
          </Text>
          <Text f={[3, 4]} my={3}>
            Clubs are led by teams of 2-3 students (sorry, no parents or
            teachers). We ask that at least 1 leader be technically adept enough
            to write and customize{' '}

              workshops
            .
          </Text>
          <Heading.h3 f={[4, 5]} mt={4}>
            What happens outside of club meetings?
          </Heading.h3>
          <Text f={[3, 4]} my={3}>
            After Hack Clubs establish a dedicated base of members, they begin
            to attend{' '}

              nearby hackathons
            {' '}
            and eventually host their own (sometimes with{' '}

              Hack Club Bank
            ).
          </Text>
          <Heading.h3 f={[4, 5]} mt={4}>
            Will you provide everything to make my club successful?
          </Heading.h3>
          <Text f={[3, 4]} my={3}>
            No. Every school is different and you're going to need to heavily
            customize our advice and resources. We try our best, but you know
            your school better than we do.
          </Text>
        </Container>
      </Box>
    </Container>
    <Row my={[4, 5]}>
      <Box mt={-4}>
        <Text color="accent" f={4} bold caps>
          here's the process
        </Text>
        <Heading.h2 {...styles.headline}>Apply and start your club.</Heading.h2>
      </Box>
      <Modules w={1}>
        <Module
          icon="assignment"
          heading="1. Apply"
          body="Submit your information to start—totally free."
          color="primary"
        />
        <Module
          icon="ring_volume"
          heading="2. Training call"
          body="We’ll chat and begin a plan for your club."
          color="teal.7"
        />
        <Module
          icon="event_available"
          heading="3. Lead your club!"
          body="Schedule your first meeting and get ready!"
          color="info"
        />
      </Modules>
    </Row>
    <Start
      mt={4}
      buttonProps={{ children: 'Begin Your Application', to: '/apply' }}
    />
    <PhotoSection
      src="/lah_1.jpg"
      aria-label="Students stacking cups together"
      py={[0, 250, 350]}
      my={[0, -50]}
      style={{ zIndex: -1 }}
    />

  </Fragment>
)
<commit_msg>Edit Start content<commit_after>import React, { Fragment } from 'react'
import styled, { css } from 'styled-components'
import {
  BackgroundImage,
  Box,
  Container,
  Flex,
  Heading,
  Link as A,
  Section,
  Text
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import Link from 'gatsby-link'
import Nav from 'components/Nav'
import Module from 'components/Module'
import Framed from 'components/Framed'
import Start from 'components/Start'
import Footer from 'components/Footer'

const shadows = css`
  h1,
<<<<<< theme.colors.white};
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
>>>>>>> Edit Start content
  }
`
const PhotoSection = styled(Section)`
  position: relative;
  background: linear-gradient(rgba(0, 0, 0, 0.325), rgba(0, 0, 0, 0.125)),
    url(${props => props.src});
  background-position: center;
  background-size: cover;
  ${shadows};
`
PhotoSection.defaultProps = {
  py: 4
}

const Modules = styled(Box)`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: repeat(3, 1fr);
  }
  > div {
    align-items: flex-start;
    padding: 0;
    text-align: left;
    width: 100% !important;
  }
  p {
    color: ${({ theme }) => theme.colors.slate};
    line-height: 1.375;
  }
`

const Notification = styled(Flex)`
  border-radius: ${({ theme }) => theme.radius};
  background-color: rgba(255, 255, 255, 0.9375);
  strong {
    font-weight: bold;
  }
`
Notification.defaultProps = {
  py: 3,
  px: 4,
  mb: 3,
  mt: 5,
  mx: 2,
  align: 'center',
  justify: 'center',
  color: 'gray.9',
  flexDirection: 'column'
}

const Row = Container.extend.attrs({ color: 'black', px: 3, py: [3, 4] })`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  text-align: left;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: ${props => props.cols || '2fr 3fr'};
    grid-gap: ${({ theme }) => theme.space[4]}px;
  }
`

const styles = {
  ultraline: { f: [6, 7], style: { lineHeight: '1.0625' } },
  headline: { f: [5, 6], style: { lineHeight: '1.125' } },
  subhline: {
    f: [3, 4],
    color: 'black',
    regular: true,
    style: { lineHeight: '1.375' }
  },
  contentContainer: {
    maxWidth: 64,
    w: 1,
    p: [3, 2]
  }
}

const title = 'Start Your Hack Club | Hack Club'
const description =
  'Learn how to start a coding club at your high school through Hack Club. Get programming club ideas, curriculum, activities, and more.'

export default () => (
  <Fragment>
    <Helmet
      title={title}
      meta={[
        { name: 'twitter:title', content: title },
        { name: 'description', content: description },
        { name: 'twitter:description', content: description },
        { property: 'og:title', content: title },
        { property: 'og:description', content: description },
        { property: 'og:url', content: 'https://hackclub.com/start' }
      ]}
    />

    <PhotoSection src="/lah_2.jpg">
      <Notification>
        <Text f={3} bold>
          Fall 2018 applications due by September 30th
        </Text>
        <Text f={2}>
          Applications are open and accepted on a rolling basis.
        </Text>
      </Notification>
      <Container maxWidth={56} p={[2, 3]} mb={[5, 6]}>
        <Heading.h1 {...styles.ultraline} color="white">
          Let’s get started.
        </Heading.h1>
        <Heading.h2 {...styles.subhline} color="white" f={[4, 5]} mt={3}>
          Whether you’re interested in starting a new chapter or joining Hack
          Club’s network with an existing CS club, we should talk.
        </Heading.h2>
      </Container>
    </PhotoSection>
    <Row my={[3, 4]}>
      <Box color="black">
        <Heading.h2 {...styles.headline} mb={3}>
          HQ provides the support to get you growing.
        </Heading.h2>
        <Text {...styles.subhline}>
          Get your club started with our resources used by 200+ Hack Clubs.
        </Text>
      </Box>
      <Modules>
        <Module
          icon="forum"
          heading="Community"
          body="Join our Slack and meet hundreds of other club leaders and members around the world."
          color="red.5"
        />
        <Module
          icon="pages"
          heading="Curriculum"
          body="Give your members dozens of free tutorials for making websites, apps, and games."
          color="orange.5"
        />
        <Module
          icon="voice_chat"
          heading="Mentorship"
          body="Talk to our team over a call or on Slack for guidance and assistance whenever you need help."
          color="yellow.7"
        />
        <Module
          icon="chrome_reader_mode"
          heading="Guidelines"
          body="Learn from hundreds of other clubs—we’ve got information, advice, and experience."
          color="teal.7"
        />
        <Module
          icon="local_activity"
          heading="Local events"
          body="Attend hackathons, workshops, and other events from Hack Clubs near yours."
          color="blue.5"
        />
        <Module
          icon="wallpaper"
          heading="Marketing"
          body="Get stickers, posters, and ideas for spreading the word about your amazing club meetings."
          color="indigo.5"
        />
      </Modules>
    </Row>
    <Container px={3} my={[3, 5]}>
      <Box color="black">
        <Heading.h3 f={[4, 5]} mt={4}>
          Already have a club?
        </Heading.h3>
        <Text f={[3, 4]} my={3}>
          Great! When established CS clubs join, they get the full benefits of
          the network. Hack Club is currently optimized for new chapters, but
          we’re increasing the benefits for existing clubs every day with new
          products like{' '}

            Hackathons
          {' '}
          and{' '}

            Bank

          .
        </Text>
        <Heading.h2 f={[5, 6]} mt={4} mb={3}>
          What do meetings look like?
        </Heading.h2>
        <Container maxWidth={48} mx={0}>
          <Text f={[3, 4]}>
            Hack Clubs meet weekly, typically for 1.5 hours. Meetings resemble
            mini-hackathons, where members learn to code through building
            projects like{' '}

              websites
            {' '}
            and{' '}

              games

            .
          </Text>
          <Text f={[3, 4]} my={3}>
            Clubs are led by teams of 2-3 students (sorry, no parents or
            teachers). We ask that at least 1 leader be technically adept enough
            to write and customize{' '}

              workshops

            .
          </Text>
          <Heading.h3 f={[4, 5]} mt={4}>
            What happens outside of club meetings?
          </Heading.h3>
          <Text f={[3, 4]} my={3}>
            After Hack Clubs establish a dedicated base of members, they begin
            to attend{' '}

              nearby hackathons
            {' '}
            and eventually host their own (sometimes with{' '}

              Hack Club Bank

            ).
          </Text>
          <Heading.h3 f={[4, 5]} mt={4}>
            Will you provide everything to make my club successful?
          </Heading.h3>
          <Text f={[3, 4]} my={3}>
            No. Every school is different and you’re going to need to heavily
            customize our advice and resources. We try our best, but you know
            your school better than we do.
          </Text>
        </Container>
      </Box>
    </Container>
    <Row my={[4, 5]}>
      <Box mt={-4}>
        <Text color="accent" f={4} bold caps>
          Here’s the process
        </Text>
        <Heading.h2 {...styles.headline}>Apply and start your club.</Heading.h2>
      </Box>
      <Modules w={1}>
        <Module
          icon="assignment"
          heading="1. Apply"
          body="Submit your information to start—totally free."
          color="primary"
        />
        <Module
          icon="ring_volume"
          heading="2. Training call"
          body="We’ll chat and begin a plan for your club."
          color="teal.7"
        />
        <Module
          icon="event_available"
          heading="3. Lead your club!"
          body="Schedule your first meeting and get ready!"
          color="info"
        />
      </Modules>
    </Row>
    <Start
      mt={4}
      buttonProps={{ children: 'Apply to Hack Club', to: '/apply' }}
    />
    <PhotoSection
      src="/lah_1.jpg"
      aria-label="Students stacking cups together"
      py={[0, 250, 350]}
      my={[0, -50]}
      style={{ zIndex: -1 }}
    />

  </Fragment>
)
<|endoftext|>


<commit_before>"use strict";
(function (SegmentScore) {
    SegmentScore[SegmentScore["NotVis"] = -1] = "NotVis";
    SegmentScore[SegmentScore["Dis_Scar"] = 6] = "Dis_Scar";
    SegmentScore[SegmentScore["Ak_Scar"] = 7] = "Ak_Scar";
    SegmentScore[SegmentScore["Aneurysm"] = 5] = "Aneurysm";
    SegmentScore[SegmentScore["Dyskin"] = 4] = "Dyskin";
    SegmentScore[SegmentScore["Akinetic"] = 3] = "Akinetic";
    SegmentScore[SegmentScore["Hypokin"] = 2] = "Hypokin";
    SegmentScore[SegmentScore["Normal"] = 1] = "Normal";
    SegmentScore[SegmentScore["UnableEv"] = 0] = "UnableEv";
    SegmentScore[SegmentScore["Hyperkin"] = 8] = "Hyperkin";
    SegmentScore[SegmentScore["H_Score"] = -2] = "H_Score";
    //extended scores
    SegmentScore[SegmentScore["Min"] = 100] = "Min";
    SegmentScore[SegmentScore["Max"] = 101] = "Max";
})(exports.SegmentScore || (exports.SegmentScore = {}));
var SegmentScore = exports.SegmentScore;
//# sourceMappingURL=segment-score.js.map<commit_msg>Delete segment-score.js<commit_after><|endoftext|>


<commit_before>$(function () {
  $('.datepicker').datetimepicker({
    format: 'YYYY-MM-DD'
  });

  $('.datetimepicker').datetimepicker({
    format: 'YYYY-MM-DD HH:mm'
  });
});
<commit_msg>datetimepicker に、datetime, time を修正・追加<commit_after>$(function () {
  $('.datepicker').datetimepicker({
    format: 'YYYY-MM-DD'
  });

  $('.timepicker').datetimepicker({
    format: 'HH:mm:ss'
  });

  $('.datetimepicker').datetimepicker({
    format: 'YYYY-MM-DD HH:mm:ss'
  });
});
<|endoftext|>


<commit_before>import { Observable } from 'rx';
// import debug from 'debug';
import dedent from 'dedent';
import { isEmail } from 'validator';

import { observeMethod, observeQuery } from '../../server/utils/rx';
import { wrapHandledError } from '../../server/utils/create-handled-error.js';

// const log = debug('fcc:models:userIdent');

export default function(UserIdent) {
  UserIdent.on('dataSourceAttached', () => {
    UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
  });

  UserIdent.login = function(
    _provider,
    authScheme,
    profile,
    credentials,
    options,
    cb
  ) {
    const User = UserIdent.app.models.User;
    const AccessToken = UserIdent.app.models.AccessToken;
    options = options || {};
    if (typeof options === 'function' && !cb) {
      cb = options;
      options = {};
    }

    // get the social provider data and the external id from auth0
    profile.id = profile.id || profile.openid;
    const auth0IdString = '' + profile.id;
    const [provider, socialExtId] = auth0IdString.split('|');
    const query = {
      where: {
        provider: provider,
        externalId: socialExtId
      },
      include: 'user'
    };
    // get the email from the auth0 (its expected from social providers)
    const email =
      profile && profile.emails && profile.emails[0]
        ? profile.emails[0].value
        : '';
    if (!isEmail('' + email)) {
      throw wrapHandledError(
        new Error('invalid or empty email received from auth0'),
        {
          message: dedent`
    ${provider} did not return a valid email address.
    Please try again with a different account that has an
    email associated with it your update your settings on ${provider}, for us to be able to retrieve your email.
          `,
          type: 'info',
          redirectTo: '/'
        }
      );
    }

    if (provider === 'email') {
      return User.findOne$({
        where: { email: new RegExp(email.replace('.', '\\.'), 'i') }
      })
        .flatMap(user => {
          return user
            ? Observable.of(user)
            : User.create$({ email }).toPromise();
        })
        .flatMap(user => {
          if (!user) {
            throw wrapHandledError(
              new Error('could not find or create a user'),
              {
                message: dedent`
    We could not find or create a user with that email address.
                `,
                type: 'info',
                redirectTo: '/'
              }
            );
          }
          const createToken = observeQuery(AccessToken, 'create', {
            userId: user.id,
            created: new Date(),
            ttl: user.constructor.settings.ttl
          });
          const updateUserPromise = new Promise((resolve, reject) =>
            user.updateAttributes(
              {
                emailVerified: true,
                emailAuthLinkTTL: null,
                emailVerifyTTL: null
              },
              err => {
                if (err) {
                  return reject(err);
                }
                return resolve();
              }
            )
          );
          return Observable.combineLatest(
            Observable.of(user),
            createToken,
            Observable.fromPromise(updateUserPromise),
            (user, token) => ({ user, token })
          );
        })
        .subscribe(({ user, token }) => cb(null, user, null, token), cb);
    } else {
      return UserIdent.findOne$(query)
        .flatMap(identity => {
          return identity
            ? Observable.of(identity.user())
            : User.findOne$({ where: { email } }).flatMap(user => {
                return user
                  ? Observable.of(user)
                  : User.create$({ email }).toPromise();
              });
        })
        .flatMap(user => {
          const createToken = observeQuery(AccessToken, 'create', {
            userId: user.id,
            created: new Date(),
            ttl: user.constructor.settings.ttl
          });
          const updateUser = new Promise((resolve, reject) =>
            user.updateAttributes(
              {
                email: email,
                emailVerified: true,
                emailAuthLinkTTL: null,
                emailVerifyTTL: null
              },
              err => {
                if (err) {
                  return reject(err);
                }
                return resolve();
              }
            )
          );
          return Observable.combineLatest(
            Observable.of(user),
            createToken,
            Observable.fromPromise(updateUser),
            (user, token) => ({ user, token })
          );
        })
        .subscribe(({ user, token }) => cb(null, user, null, token), cb);
    }
  };
}
<commit_msg>fix(api): revert regex based email query (#37393)<commit_after>import { Observable } from 'rx';
// import debug from 'debug';
import dedent from 'dedent';
import { isEmail } from 'validator';

import { observeMethod, observeQuery } from '../../server/utils/rx';
import { wrapHandledError } from '../../server/utils/create-handled-error.js';

// const log = debug('fcc:models:userIdent');

export default function(UserIdent) {
  UserIdent.on('dataSourceAttached', () => {
    UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
  });

  UserIdent.login = function(
    _provider,
    authScheme,
    profile,
    credentials,
    options,
    cb
  ) {
    const User = UserIdent.app.models.User;
    const AccessToken = UserIdent.app.models.AccessToken;
    options = options || {};
    if (typeof options === 'function' && !cb) {
      cb = options;
      options = {};
    }

    // get the social provider data and the external id from auth0
    profile.id = profile.id || profile.openid;
    const auth0IdString = '' + profile.id;
    const [provider, socialExtId] = auth0IdString.split('|');
    const query = {
      where: {
        provider: provider,
        externalId: socialExtId
      },
      include: 'user'
    };
    // get the email from the auth0 (its expected from social providers)
    const email =
      profile && profile.emails && profile.emails[0]
        ? profile.emails[0].value
        : '';
    if (!isEmail('' + email)) {
      throw wrapHandledError(
        new Error('invalid or empty email received from auth0'),
        {
          message: dedent`
    ${provider} did not return a valid email address.
    Please try again with a different account that has an
    email associated with it your update your settings on ${provider}, for us to be able to retrieve your email.
          `,
          type: 'info',
          redirectTo: '/'
        }
      );
    }

    if (provider === 'email') {
      return User.findOne$({ where: { email } })
        .flatMap(user => {
          return user
            ? Observable.of(user)
            : User.create$({ email }).toPromise();
        })
        .flatMap(user => {
          if (!user) {
            throw wrapHandledError(
              new Error('could not find or create a user'),
              {
                message: dedent`
    We could not find or create a user with that email address.
                `,
                type: 'info',
                redirectTo: '/'
              }
            );
          }
          const createToken = observeQuery(AccessToken, 'create', {
            userId: user.id,
            created: new Date(),
            ttl: user.constructor.settings.ttl
          });
          const updateUserPromise = new Promise((resolve, reject) =>
            user.updateAttributes(
              {
                emailVerified: true,
                emailAuthLinkTTL: null,
                emailVerifyTTL: null
              },
              err => {
                if (err) {
                  return reject(err);
                }
                return resolve();
              }
            )
          );
          return Observable.combineLatest(
            Observable.of(user),
            createToken,
            Observable.fromPromise(updateUserPromise),
            (user, token) => ({ user, token })
          );
        })
        .subscribe(({ user, token }) => cb(null, user, null, token), cb);
    } else {
      return UserIdent.findOne$(query)
        .flatMap(identity => {
          return identity
            ? Observable.of(identity.user())
            : User.findOne$({ where: { email } }).flatMap(user => {
                return user
                  ? Observable.of(user)
                  : User.create$({ email }).toPromise();
              });
        })
        .flatMap(user => {
          const createToken = observeQuery(AccessToken, 'create', {
            userId: user.id,
            created: new Date(),
            ttl: user.constructor.settings.ttl
          });
          const updateUser = new Promise((resolve, reject) =>
            user.updateAttributes(
              {
                email: email,
                emailVerified: true,
                emailAuthLinkTTL: null,
                emailVerifyTTL: null
              },
              err => {
                if (err) {
                  return reject(err);
                }
                return resolve();
              }
            )
          );
          return Observable.combineLatest(
            Observable.of(user),
            createToken,
            Observable.fromPromise(updateUser),
            (user, token) => ({ user, token })
          );
        })
        .subscribe(({ user, token }) => cb(null, user, null, token), cb);
    }
  };
}
<|endoftext|>


<commit_before>/**
 * ImportExportController
 *
 * @description :: Handle importing of seed data and exporting of ruleset data.
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */
var waterfall = require('async'), exec = require('child_process').exec, fs = require('fs');
var pathToMathMaps = "node_modules/speech-rule-engine/lib/";
var pathToSpellRules = "lib/";
module.exports = {

    /** Read json rulesets from the speech-rule-engine and import as default rulesets. */
    import: function(req, res) {
        //before we do anything, create the default rulesets.
        RuleSetImportExporter.createDefaultRulesets(function() {
            var mathmaps = RuleSetImportExporter.getMathMapDirectories(pathToMathMaps) +
		RuleSetImportExporter.getMathMapDirectories(pathToSpellRules);
            for (var m = 0; m < mathmaps.length; m++) {
                MathMap.findOrCreate({name: mathmaps[m]}).then(function(mathmap) {
                    RuleSetImportExporter.importMathMap(pathToMathMaps + mathmap.name, mathmap);
                });
            }
        });

        return res.json("Importing...");
    },

    previewExport: function(req, res) {
        MathMap.find().then(function(mathmaps) {
            async.map(mathmaps,
                function(mathmap, callback) {
                    MathMapCategory.find({mathMap: mathmap.id}).populate("rules").then(function(categories) {
                        mathmap.categories = categories;
                        return callback(null, mathmap);
                    });
                },
                function(err, results){
                    return res.json(results);
                }
            );
        }).catch(function(err) {
            return res.badRequest(err);
        });
    },

    export: function(req, res) {
        RuleSetImportExporter.exportMathMaps(pathToMathMaps);
        //Pretty hoopty, but I don't want to deal with reconfiguring
        //the export with callbacks.
        setTimeout(function() {
            //Restart server.
            console.log("Restarting Server.");
            var forever_restart = exec('forever restartall', {cwd: '/vagrant'});
        }, 60000);
        return res.json("Exporting. Please wait while the rulesets are exported. The server will restart in 1 minute.");
    },

    seedStatesAndCountries: function(req, res) {
        var states = JSON.parse(fs.readFileSync("states.json", 'utf8'));
        for ( code in states ) {
            State.findOrCreate({code: code, name: states[code]}).then(function(states) {
                //Do nothing.
            }).catch(function(err) {
                console.log(err);
            });
        }
        var countries = JSON.parse(fs.readFileSync("countries.json", 'utf8'));
        for (var i = 0; i < countries.length; i++) {
            var country = countries[i];
            Country.findOrCreate({code: country.code, name: country.name}).then(function(countries) {
                //Do nothing.
            }).catch(function(err) {
                console.log(err);
            });
        }
        return res.json("Seeding states and countries.");
    }
};

<commit_msg>Fixed list concatenation.<commit_after>/**
 * ImportExportController
 *
 * @description :: Handle importing of seed data and exporting of ruleset data.
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */
var waterfall = require('async'), exec = require('child_process').exec, fs = require('fs');
var pathToMathMaps = "node_modules/speech-rule-engine/lib/";
var pathToSpellRules = "lib/";
module.exports = {

    /** Read json rulesets from the speech-rule-engine and import as default rulesets. */
    import: function(req, res) {
        //before we do anything, create the default rulesets.
        RuleSetImportExporter.createDefaultRulesets(function() {
          var mathmaps = RuleSetImportExporter.getMathMapDirectories(pathToMathMaps).concat(
	    RuleSetImportExporter.getMathMapDirectories(pathToSpellRules));
            for (var m = 0; m < mathmaps.length; m++) {
                MathMap.findOrCreate({name: mathmaps[m]}).then(function(mathmap) {
                    RuleSetImportExporter.importMathMap(pathToMathMaps + mathmap.name, mathmap);
                });
            }
        });

        return res.json("Importing...");
    },

    previewExport: function(req, res) {
        MathMap.find().then(function(mathmaps) {
            async.map(mathmaps,
                function(mathmap, callback) {
                    MathMapCategory.find({mathMap: mathmap.id}).populate("rules").then(function(categories) {
                        mathmap.categories = categories;
                        return callback(null, mathmap);
                    });
                },
                function(err, results){
                    return res.json(results);
                }
            );
        }).catch(function(err) {
            return res.badRequest(err);
        });
    },

    export: function(req, res) {
        RuleSetImportExporter.exportMathMaps(pathToMathMaps);
        //Pretty hoopty, but I don't want to deal with reconfiguring
        //the export with callbacks.
        setTimeout(function() {
            //Restart server.
            console.log("Restarting Server.");
            var forever_restart = exec('forever restartall', {cwd: '/vagrant'});
        }, 60000);
        return res.json("Exporting. Please wait while the rulesets are exported. The server will restart in 1 minute.");
    },

    seedStatesAndCountries: function(req, res) {
        var states = JSON.parse(fs.readFileSync("states.json", 'utf8'));
        for ( code in states ) {
            State.findOrCreate({code: code, name: states[code]}).then(function(states) {
                //Do nothing.
            }).catch(function(err) {
                console.log(err);
            });
        }
        var countries = JSON.parse(fs.readFileSync("countries.json", 'utf8'));
        for (var i = 0; i < countries.length; i++) {
            var country = countries[i];
            Country.findOrCreate({code: country.code, name: country.name}).then(function(countries) {
                //Do nothing.
            }).catch(function(err) {
                console.log(err);
            });
        }
        return res.json("Seeding states and countries.");
    }
};

<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

/**
 * IOET's code start here
 * packet frame format <STX> FN text <ETX> C1 C2 <CR> <LF>
 * */
var _ = require('lodash');
var async = require('async');
var sundial = require('sundial');
var crcCalculator = require('../crc.js');
var struct = require('../struct.js')();
var annotate = require('../eventAnnotations');

var isBrowser = typeof window !== 'undefined';
var debug = isBrowser ? require('../bows')('BCNextDriver') : debug;

module.exports = function (config) {
  var cfg = _.clone(config);
  var hidDevice = config.deviceComms;
  var HID_PACKET_SIZE = 64;

  /*
   * TODO This info should be collected in the initial phase cause we can't assert if
   *      it is the same for all contour devices
   * */
  var REPORT_BYTES = {
    reportID: 0x41, // A
    //checksum: 0x00, // Checksum is not been used by bayer contour device
    hostID  : 0x42, // B
    deviceID: 0x43  // C
  };

  /* end */

  var ASCII_CONTROL = {
    ACK : 0x06,
    NAK : 0x15,
    ENQ : 0x05,
    STX : 0x02,
    ETB : 0x17,
    ETX : 0x03,
    EOT : 0x04,
    TER : 0x4c
  };

  var probe = function(cb){
    debug('attempting probe of Bayer Contour Next');
  };

  var bcnPacketHandler = function (buffer) {
    var discardCount = _.keys(REPORT_BYTES).length;
    buffer.discard(discardCount);

    if (buffer.len() === 0) { //empty buffer finish the data gathering
      return false;
    }

    var packet = extractPacket(buffer.bytes());
    if (packet.packet_len !== 0) {
      // cleanup the buffer data
      buffer.discard(HID_PACKET_SIZE - discardCount);
    }

    if (packet.valid) {
      return packet;
    } else {
      return null;
    }
  };

  var buildPacket = function (command, cmdlength) {
    var datalen = cmdlength + 4; // We need just 5 bytes for now
    var buf = new ArrayBuffer(datalen);
    var bytes = new Uint8Array(buf);
    var ctr = struct.pack(bytes, 0, 'bbb', REPORT_BYTES.reportID,
                          REPORT_BYTES.hostID, REPORT_BYTES.deviceID);
    if (cmdlength) {
      ctr += struct.pack(bytes, ctr, 'bb', cmdlength, command);
    }
    return buf;
  };

  var packetParser = function(result){
    var tostr = _.map(result.bytes,
                      function(e){
                        return String.fromCharCode(e);
                      }).join('');
    result.payload = tostr;
    return tostr;
  };

  var buildAckPacket = function() {
    return buildPacket(ASCII_CONTROL.ACK, 1);
  };

  var extractPacket = function (bytes) {
    var packet = {
      bytes: bytes,
      valid: false,
      packet_len: 0,
      payload: null
    };

    var plen = bytes.length;
    var packet_len = struct.extractByte(bytes, 0);

    if (packet_len > plen) {
      return packet;
    }

    //discard the length byte from the begining
    var tmpbuff = new ArrayBuffer(packet_len);
    struct.copyBytes(tmpbuff, 0, bytes, packet_len, 1);
    packet.bytes = tmpbuff;
    packet.packet_len = packet_len;
    packet.valid = true;

    return packet;
  };

  var buildHeaderCmd = function() {
    return {
      packet: buildAckPacket(),
      parser: packetParser
    };
  };

    //header data looks like
  /*
  <STX>1H|\^&||qvqOi8|Bayer7350^01.14\01.03\04.18^7358-1611135^0000-
  |A=1^C=00^G=es,en\es\it\de\fr\hr\da\nl\fi\el\no\pt\sl\sv^I=0200^R=
  0^S=01^U=0^V=20600^X=070070070180130180070130^Y=120054252099^Z=1|4
  |||||P|1|201505291248<ETB>01<CR><LF>
  */

  var parseHeader = function (s){
    var data = s.split('\n').filter(function(e){ return e !== '';});
    var header = data.shift();

    if(verifyChecksum(header)){
      var patient = data.shift();
      var lineFeed = data.pop();
      var pString = header.split('|');
      var pInfo = pString[4].split('^');
      var sNum = pInfo[2].match(/^\d+\-\s*(\w+)/);
      var records = data;
      var threshold = pString[5].split('^')[7].match(/^.+\=(\d{2})(\d{3})/);

      var devInfo = {
        model: pInfo[0],
        serialNumber: sNum[1],
        nrecs: pString[6],
        rawrecords: records,
        lowT: parseInt(threshold[1]),
        hiT: parseInt(threshold[2])
      };

      return devInfo;
    }else{
      return null;
    }
  };

  function verifyChecksum(record){
      var str = record.trim();
      var data = str.split(String.fromCharCode(ASCII_CONTROL.ETB));
      var check = data[1];
      var sum = 0;
      var n = record.slice(0, record.length - 3);

      _.map(n, function(e){
          if(e.charCodeAt(0) !== ASCII_CONTROL.STX){
              sum += e.charCodeAt(0);
          }
      });

      if((sum % 256) !== parseInt(check, 16)){
          return null;
      }else{
          return data[0];
      }
  }

  /* Record data looks like
  <STX>5R|3|^^^Glucose|93|mg/dL^P||A/M0/T1||201505261150<CR><ETB>74<CR><LF>
  */
  var parseDataRecord = function (str, callback){
    var data = verifyChecksum(str);
    if(data){
      var result = data.trim().match(/^.*\d+R\|(\d+).*Glucose\|(\d+)\|(\w+\/\w+).*\|{2}(.*)\|{2}(\d{12})$/).slice(1,6);
      callback(null, result);
    }else{
      throw( new Error('Invalid record data') );
    }

  };

  var getAnnotations = function (annotation, data){
    if (annotation.indexOf('>') !== -1) {
      return [{
        code: 'bg/out-of-range',
        threshold: data.hiT,
        value: 'high'
      }];
    } else if (annotation.indexOf('<') !== -1) {
      return [{
        code: 'bg/out-of-range',
        threshold: data.lowT,
        value: 'low'
      }];
    } else {
      return null;
    }
  };

  var getOneRecord = function (record, data, callback) {
    parseDataRecord(record,function(err,r){
      var robj = {};
      if (err) {
          debug('Failure trying to read record', record);
          debug(err);
          return callback(err, null);
      } else {
          robj.timestamp = parseInt(r[4]);
          robj.annotations = getAnnotations(r[3], data);
          robj.units = r[2];
          robj.glucose = parseInt(r[1]);
          robj.nrec = parseInt(r[0]);
          return callback(null, robj);
      }
    });
  };

  var bcnCommandResponse = function (commandpacket, callback) {

    hidDevice.send(commandpacket.packet, function () {
        receivePacket(5000, commandpacket.parser, function(err, packet) {
            var rawtext = '';
            while(hidDevice.hasAvailablePacket()){
                var pkt = hidDevice.nextPacket();
                pkt.parsed_payload = commandpacket.parser(pkt);
                rawtext += pkt.parsed_payload;
            }

            if (err !== 'TIMEOUT') {
              callback(err, rawtext);
            }else{
              debug('receivePacket timed out');
              callback(err, null);
            }
        });
    });
  };

  var receivePacket = function (timeout, parser, callback) {
    var abortTimer = setTimeout(function () {
      clearInterval(listenTimer);
      debug('TIMEOUT');
      callback('TIMEOUT', null);
    }, timeout);

    var listenTimer = setInterval(function () {
      hidDevice.receive(function(raw) {
          var r = new Uint8Array(raw);
          var startIndex = 0;
          var rec = struct.unpack(r, 6, 'b', ['TYPE']);
          var hasETB = _.indexOf(r, ASCII_CONTROL.ETB, startIndex);
          debug(rec);
          if(hasETB !== -1){
              // send a new ACK
              var cmd = buildAckPacket();
              hidDevice.send(cmd, function () {
                  debug('New ACK SENT');
              });

          }else if(rec.TYPE == ASCII_CONTROL.TER){
              clearTimeout(abortTimer);
              clearInterval(listenTimer);
              callback(null, '');
          }
        });
      }, 200);
  };

  var getDeviceInfo = function (obj, cb) {
      debug('DEBUG: on getDeviceInfo');
      var cmd = buildHeaderCmd();
      bcnCommandResponse(cmd, function (err, datatxt) {
          if (err) {
              debug('Failure trying to talk to device.');
              debug(err);
              debug(datatxt);
              cb(null, null);
          } else {
              obj.header = datatxt;
              if(parseHeader(datatxt)){
                _.assign(obj, parseHeader(datatxt));
                cb(null, obj);
              }else{
                debug('Invalid header data');
                throw(new Error('Invalid header data'));
              }
          }
      });
  };

  var processReadings = function(readings) {
    _.each(readings, function(reading, index) {
      var dateTime = sundial.parseFromFormat(reading.timestamp, 'YYYYMMDD HHmm');
      readings[index].displayTime = sundial.formatDeviceTime(new Date(dateTime).toISOString());
      readings[index].displayUtc = sundial.applyTimezone(readings[index].displayTime, cfg.timezone).toISOString();
      readings[index].displayOffset = sundial.getOffsetFromZone(readings[index].displayUtc, cfg.timezone);
    });
  };

  var prepBGData = function (progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        var smbg = cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.displayOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    }else{
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };

  return {
    detect: function(deviceInfo, cb){
      debug('no detect function needed', arguments);
      cb(null, deviceInfo);
    },

    setup: function (deviceInfo, progress, cb) {
      console.log('in setup!');
      progress(100);
      cb(null, {deviceInfo: deviceInfo});
    },

    connect: function (progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, bcnPacketHandler, probe, function(err) {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        cb(null, data);

      });
    },

    getConfigInfo: function (progress, data, cb) {
      debug('in getConfigInfo', data);

      getDeviceInfo({}, function (err, result) {
          progress(100);

          if(!err){
              data.connect = true;
              _.assign(data, result);

              cb(null, data);
          }else{
              cb(err,result);
          }
      });
    },

    fetchData: function (progress, data, cb) {
      debug('in fetchData', data);

      function getOneRecordWithProgress(recnum, cb) {
        var rec = data.rawrecords.shift();
        progress(100.0 * recnum / data.nrecs);
        setTimeout(function() {
          getOneRecord(rec, data, cb);
        }, 20);
      }

      async.timesSeries(data.nrecs, getOneRecordWithProgress, function(err, result) {
        if (err) {
          debug('fetchData failed');
          debug(err);
          debug(result);
        } else {
          debug('fetchData', result);
        }
        data.fetchData = true;
        data.bgmReadings = result;
        progress(100);
        cb(err, data);
      });
    },

    processData: function (progress, data, cb) {
        progress(0);
        data.bg_data = processReadings(data.bgmReadings);
        data.post_records = prepBGData(progress, data);
        var ids = {};
        for (var i = 0; i < data.post_records.length; ++i) {
            var id = data.post_records[i].time + '|' + data.post_records[i].deviceId;
            if (ids[id]) {
                debug('duplicate! %s @ %d == %d', id, i, ids[id] - 1);
                debug(data.post_records[ids[id] - 1]);
                debug(data.post_records[i]);
            } else {
                ids[id] = i + 1;
            }
        }
        progress(100);
        data.processData = true;
        cb(null, data);
    },

    uploadData: function (progress, data, cb) {
      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: 'Contour Next',
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo, progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });

    },

    disconnect: function (progress, data, cb) {
      debug('in disconnect');
      progress(100);
      cb(null, data);
    },

    cleanup: function (progress, data, cb) {
      debug('in cleanup');
      if(!data.disconnect){
          cfg.deviceComms.disconnect(data, function() {
              progress(100);
              data.cleanup = true;
              data.disconnect = true;
              cb(null, data);
          });
      }else{
        progress(100);
      }
    }
  };
};
<commit_msg>Deleted index from object so it only appears in logIndices<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

/**
 * IOET's code start here
 * packet frame format <STX> FN text <ETX> C1 C2 <CR> <LF>
 * */
var _ = require('lodash');
var async = require('async');
var sundial = require('sundial');
var crcCalculator = require('../crc.js');
var struct = require('../struct.js')();
var annotate = require('../eventAnnotations');

var isBrowser = typeof window !== 'undefined';
var debug = isBrowser ? require('../bows')('BCNextDriver') : debug;

module.exports = function (config) {
  var cfg = _.clone(config);
  var hidDevice = config.deviceComms;
  var HID_PACKET_SIZE = 64;

  /*
   * TODO This info should be collected in the initial phase cause we can't assert if
   *      it is the same for all contour devices
   * */
  var REPORT_BYTES = {
    reportID: 0x41, // A
    //checksum: 0x00, // Checksum is not been used by bayer contour device
    hostID  : 0x42, // B
    deviceID: 0x43  // C
  };

  /* end */

  var ASCII_CONTROL = {
    ACK : 0x06,
    NAK : 0x15,
    ENQ : 0x05,
    STX : 0x02,
    ETB : 0x17,
    ETX : 0x03,
    EOT : 0x04,
    TER : 0x4c
  };

  var probe = function(cb){
    debug('attempting probe of Bayer Contour Next');
  };

  var bcnPacketHandler = function (buffer) {
    var discardCount = _.keys(REPORT_BYTES).length;
    buffer.discard(discardCount);

    if (buffer.len() === 0) { //empty buffer finish the data gathering
      return false;
    }

    var packet = extractPacket(buffer.bytes());
    if (packet.packet_len !== 0) {
      // cleanup the buffer data
      buffer.discard(HID_PACKET_SIZE - discardCount);
    }

    if (packet.valid) {
      return packet;
    } else {
      return null;
    }
  };

  var buildPacket = function (command, cmdlength) {
    var datalen = cmdlength + 4; // We need just 5 bytes for now
    var buf = new ArrayBuffer(datalen);
    var bytes = new Uint8Array(buf);
    var ctr = struct.pack(bytes, 0, 'bbb', REPORT_BYTES.reportID,
                          REPORT_BYTES.hostID, REPORT_BYTES.deviceID);
    if (cmdlength) {
      ctr += struct.pack(bytes, ctr, 'bb', cmdlength, command);
    }
    return buf;
  };

  var packetParser = function(result){
    var tostr = _.map(result.bytes,
                      function(e){
                        return String.fromCharCode(e);
                      }).join('');
    result.payload = tostr;
    return tostr;
  };

  var buildAckPacket = function() {
    return buildPacket(ASCII_CONTROL.ACK, 1);
  };

  var extractPacket = function (bytes) {
    var packet = {
      bytes: bytes,
      valid: false,
      packet_len: 0,
      payload: null
    };

    var plen = bytes.length;
    var packet_len = struct.extractByte(bytes, 0);

    if (packet_len > plen) {
      return packet;
    }

    //discard the length byte from the begining
    var tmpbuff = new ArrayBuffer(packet_len);
    struct.copyBytes(tmpbuff, 0, bytes, packet_len, 1);
    packet.bytes = tmpbuff;
    packet.packet_len = packet_len;
    packet.valid = true;

    return packet;
  };

  var buildHeaderCmd = function() {
    return {
      packet: buildAckPacket(),
      parser: packetParser
    };
  };

    //header data looks like
  /*
  <STX>1H|\^&||qvqOi8|Bayer7350^01.14\01.03\04.18^7358-1611135^0000-
  |A=1^C=00^G=es,en\es\it\de\fr\hr\da\nl\fi\el\no\pt\sl\sv^I=0200^R=
  0^S=01^U=0^V=20600^X=070070070180130180070130^Y=120054252099^Z=1|4
  |||||P|1|201505291248<ETB>01<CR><LF>
  */

  var parseHeader = function (s){
    var data = s.split('\n').filter(function(e){ return e !== '';});
    var header = data.shift();

    if(verifyChecksum(header)){
      var patient = data.shift();
      var lineFeed = data.pop();
      var pString = header.split('|');
      var pInfo = pString[4].split('^');
      var sNum = pInfo[2].match(/^\d+\-\s*(\w+)/);
      var records = data;
      var threshold = pString[5].split('^')[7].match(/^.+\=(\d{2})(\d{3})/);

      var devInfo = {
        model: pInfo[0],
        serialNumber: sNum[1],
        nrecs: pString[6],
        rawrecords: records,
        lowT: parseInt(threshold[1]),
        hiT: parseInt(threshold[2])
      };

      return devInfo;
    }else{
      return null;
    }
  };

  function verifyChecksum(record){
      var str = record.trim();
      var data = str.split(String.fromCharCode(ASCII_CONTROL.ETB));
      var check = data[1];
      var sum = 0;
      var n = record.slice(0, record.length - 3);

      _.map(n, function(e){
          if(e.charCodeAt(0) !== ASCII_CONTROL.STX){
              sum += e.charCodeAt(0);
          }
      });

      if((sum % 256) !== parseInt(check, 16)){
          return null;
      }else{
          return data[0];
      }
  }

  /* Record data looks like
  <STX>5R|3|^^^Glucose|93|mg/dL^P||A/M0/T1||201505261150<CR><ETB>74<CR><LF>
  */
  var parseDataRecord = function (str, callback){
    var data = verifyChecksum(str);
    if(data){
      var result = data.trim().match(/^.*\d+R\|(\d+).*Glucose\|(\d+)\|(\w+\/\w+).*\|{2}(.*)\|{2}(\d{12})$/).slice(1,6);
      callback(null, result);
    }else{
      throw( new Error('Invalid record data') );
    }

  };

  var getAnnotations = function (annotation, data){
    if (annotation.indexOf('>') !== -1) {
      return [{
        code: 'bg/out-of-range',
        threshold: data.hiT,
        value: 'high'
      }];
    } else if (annotation.indexOf('<') !== -1) {
      return [{
        code: 'bg/out-of-range',
        threshold: data.lowT,
        value: 'low'
      }];
    } else {
      return null;
    }
  };

  var getOneRecord = function (record, data, callback) {
    parseDataRecord(record,function(err,r){
      var robj = {};
      if (err) {
          debug('Failure trying to read record', record);
          debug(err);
          return callback(err, null);
      } else {
          robj.timestamp = parseInt(r[4]);
          robj.annotations = getAnnotations(r[3], data);
          robj.units = r[2];
          robj.glucose = parseInt(r[1]);
          robj.nrec = parseInt(r[0]);
          return callback(null, robj);
      }
    });
  };

  var bcnCommandResponse = function (commandpacket, callback) {

    hidDevice.send(commandpacket.packet, function () {
        receivePacket(5000, commandpacket.parser, function(err, packet) {
            var rawtext = '';
            while(hidDevice.hasAvailablePacket()){
                var pkt = hidDevice.nextPacket();
                pkt.parsed_payload = commandpacket.parser(pkt);
                rawtext += pkt.parsed_payload;
            }

            if (err !== 'TIMEOUT') {
              callback(err, rawtext);
            }else{
              debug('receivePacket timed out');
              callback(err, null);
            }
        });
    });
  };

  var receivePacket = function (timeout, parser, callback) {
    var abortTimer = setTimeout(function () {
      clearInterval(listenTimer);
      debug('TIMEOUT');
      callback('TIMEOUT', null);
    }, timeout);

    var listenTimer = setInterval(function () {
      hidDevice.receive(function(raw) {
          var r = new Uint8Array(raw);
          var startIndex = 0;
          var rec = struct.unpack(r, 6, 'b', ['TYPE']);
          var hasETB = _.indexOf(r, ASCII_CONTROL.ETB, startIndex);
          debug(rec);
          if(hasETB !== -1){
              // send a new ACK
              var cmd = buildAckPacket();
              hidDevice.send(cmd, function () {
                  debug('New ACK SENT');
              });

          }else if(rec.TYPE == ASCII_CONTROL.TER){
              clearTimeout(abortTimer);
              clearInterval(listenTimer);
              callback(null, '');
          }
        });
      }, 200);
  };

  var getDeviceInfo = function (obj, cb) {
      debug('DEBUG: on getDeviceInfo');
      var cmd = buildHeaderCmd();
      bcnCommandResponse(cmd, function (err, datatxt) {
          if (err) {
              debug('Failure trying to talk to device.');
              debug(err);
              debug(datatxt);
              cb(null, null);
          } else {
              obj.header = datatxt;
              if(parseHeader(datatxt)){
                _.assign(obj, parseHeader(datatxt));
                cb(null, obj);
              }else{
                debug('Invalid header data');
                throw(new Error('Invalid header data'));
              }
          }
      });
  };

  var processReadings = function(readings) {
    _.each(readings, function(reading, index) {
      var dateTime = sundial.parseFromFormat(reading.timestamp, 'YYYYMMDD HHmm');
      readings[index].displayTime = sundial.formatDeviceTime(new Date(dateTime).toISOString());
      readings[index].displayUtc = sundial.applyTimezone(readings[index].displayTime, cfg.timezone).toISOString();
      readings[index].displayOffset = sundial.getOffsetFromZone(readings[index].displayUtc, cfg.timezone);
    });
  };

  var prepBGData = function (progress, data) {
    //build missing data.id
    data.id = data.model + '-' + data.serialNumber;
    cfg.builder.setDefaults({ deviceId: data.id});
    var dataToPost = [];
    if (data.bgmReadings.length > 0) {
      for (var i = 0; i < data.bgmReadings.length; ++i) {
        var datum = data.bgmReadings[i];
        var smbg = cfg.builder.makeSMBG()
          .with_value(datum.glucose)
          .with_deviceTime(datum.displayTime)
          .with_timezoneOffset(datum.displayOffset)
          .with_time(datum.displayUtc)
          .with_units(datum.units)
          .set('index', datum.nrec)
          .done();
          if (datum.annotations) {
            _.each(datum.annotations, function(ann) {
              annotate.annotateEvent(smbg, ann);
            });
          }
        dataToPost.push(smbg);
      }
    }else{
      debug('Device has no records to upload');
      throw(new Error('Device has no records to upload'));
    }

    return dataToPost;
  };

  return {
    detect: function(deviceInfo, cb){
      debug('no detect function needed', arguments);
      cb(null, deviceInfo);
    },

    setup: function (deviceInfo, progress, cb) {
      console.log('in setup!');
      progress(100);
      cb(null, {deviceInfo: deviceInfo});
    },

    connect: function (progress, data, cb) {
      debug('in connect!');

      cfg.deviceComms.connect(data.deviceInfo, bcnPacketHandler, probe, function(err) {
        if (err) {
          return cb(err);
        }
        data.disconnect = false;
        progress(100);
        cb(null, data);

      });
    },

    getConfigInfo: function (progress, data, cb) {
      debug('in getConfigInfo', data);

      getDeviceInfo({}, function (err, result) {
          progress(100);

          if(!err){
              data.connect = true;
              _.assign(data, result);

              cb(null, data);
          }else{
              cb(err,result);
          }
      });
    },

    fetchData: function (progress, data, cb) {
      debug('in fetchData', data);

      function getOneRecordWithProgress(recnum, cb) {
        var rec = data.rawrecords.shift();
        progress(100.0 * recnum / data.nrecs);
        setTimeout(function() {
          getOneRecord(rec, data, cb);
        }, 20);
      }

      async.timesSeries(data.nrecs, getOneRecordWithProgress, function(err, result) {
        if (err) {
          debug('fetchData failed');
          debug(err);
          debug(result);
        } else {
          debug('fetchData', result);
        }
        data.fetchData = true;
        data.bgmReadings = result;
        progress(100);
        cb(err, data);
      });
    },

    processData: function (progress, data, cb) {
        progress(0);
        data.bg_data = processReadings(data.bgmReadings);
        data.post_records = prepBGData(progress, data);
        var ids = {};
        for (var i = 0; i < data.post_records.length; ++i) {
            delete data.post_records[i].index; //Remove index as Jaeb study uses logIndices instead
            var id = data.post_records[i].time + '|' + data.post_records[i].deviceId;
            if (ids[id]) {
                debug('duplicate! %s @ %d == %d', id, i, ids[id] - 1);
                debug(data.post_records[ids[id] - 1]);
                debug(data.post_records[i]);
            } else {
                ids[id] = i + 1;
            }
        }
        progress(100);
        data.processData = true;
        cb(null, data);
    },

    uploadData: function (progress, data, cb) {
      progress(0);
      var sessionInfo = {
        deviceTags: ['bgm'],
        deviceManufacturers: ['Bayer'],
        deviceModel: 'Contour Next',
        deviceSerialNumber: data.serialNumber,
        deviceId: data.id,
        start: sundial.utcDateString(),
        tzName : cfg.timezone,
        version: cfg.version
      };

      cfg.api.upload.toPlatform(data.post_records, sessionInfo, progress, cfg.groupId, function (err, result) {
        progress(100);

        if (err) {
          debug(err);
          debug(result);
          return cb(err, data);
        } else {
          data.cleanup = true;
          return cb(null, data);
        }
      });

    },

    disconnect: function (progress, data, cb) {
      debug('in disconnect');
      progress(100);
      cb(null, data);
    },

    cleanup: function (progress, data, cb) {
      debug('in cleanup');
      if(!data.disconnect){
          cfg.deviceComms.disconnect(data, function() {
              progress(100);
              data.cleanup = true;
              data.disconnect = true;
              cb(null, data);
          });
      }else{
        progress(100);
      }
    }
  };
};
<|endoftext|>


<commit_before>var moment = require("moment");
var blogs = require("./src/blogs.json");

var authors = {
    niall: "@niall.crosby",
    john: "@john.masterson",
    sean: "@sean_35243",
    amit: "@amitmoryossef",
    sophia: "!!!sophia"
};

for (var blog of blogs) {
    if (!blog.medium) {
        continue;
    }
    var url = blog.medium.replace(/\?.+$/, "");
    console.log(url + ",", authors[blog.author]);
}
<commit_msg>Add Sophia as author<commit_after>var moment = require("moment");
var blogs = require("./src/blogs.json");

var authors = {
    niall: "@niall.crosby",
    john: "@john.masterson",
    sean: "@sean_35243",
    amit: "@amitmoryossef",
    sophia: "@sophialazarova"
};

for (var blog of blogs) {
    if (!blog.medium) {
        continue;
    }
    var url = blog.medium.replace(/\?.+$/, "");
    console.log(url + ",", authors[blog.author]);
}
<|endoftext|>


<commit_before>// reference: http://www.programminginkorean.com/programming/hangul-in-unicode/composing-syllables-in-unicode/
// input: hangul character
// output: returns an array of components that make up the given hangul
const breakdown = (input) => {
  const hex = '\\u'+(input.charCodeAt(0)+0x10000).toString(16).slice(1);
  const numHex = hex.substring(2);
  total = parseInt(numHex, 16);

  let letterArray = [];
  total = total - 44032;
  let initialValue = Math.floor(total/588);
  letterArray.push(initialValue);
  total = total - (588*initialValue);
  let medialValue = Math.floor(total/28);
  letterArray.push(medialValue);
  let finalValue = total - (28*medialValue);
  if (finalValue > 0) {
    letterArray.push(finalValue);
  }
  return letterArray;
}

<commit_msg>simplify code for calculating total unicode<commit_after>// reference: http://www.programminginkorean.com/programming/hangul-in-unicode/composing-syllables-in-unicode/
// input: hangul character
// output: returns an array of components that make up the given hangul
// ex: breakdown('린') outputs [5,20,4]
const breakdown = (input) => {
  let total = parseInt(input.charCodeAt(0).toString(16), 16);

  let letterArray = [];
  total = total - 44032;
  let initialValue = Math.floor(total/588);
  letterArray.push(initialValue);
  total = total - (588*initialValue);
  let medialValue = Math.floor(total/28);
  letterArray.push(medialValue);
  let finalValue = total - (28*medialValue);
  if (finalValue > 0) {
    letterArray.push(finalValue);
  }
  return letterArray;
}
<|endoftext|>


<commit_before>import {config} from '../config';

export class DashboardController {
  constructor ($http, $log, $scope, $rootScope, $timeout, toasty) {
    'ngInject';

    $rootScope.hasChanges = function() {
      return ahud.isChanged($rootScope.backup, $rootScope.current());
    };

    $rootScope.$watch('loaded', function() {
      if ($rootScope.loaded === true) {
        if (angular.isUndefined($rootScope.backup)) {
          $rootScope.backup = angular.copy($rootScope.current());
        }
        ahud.settings = $rootScope.settings;

        $scope.refresh(() => {
          $rootScope.loading = false;
        });
      }
    });

    $rootScope.current = function() {
      return {
        crosshairs: $rootScope.crosshairs,
        colors: $rootScope.colors,
        styles: $rootScope.styles
      };
    };

    $scope.version = {
      current: 'not installed!',
      latest: ''
    };

    $scope.refresh = function(cb) {
      var r = function() {
        ahud.latestVersion(() => {
          $scope.version.latest = ahud.latest.string();

          ahud.currentVersion(() => {
            $scope.version.current = ahud.current.string();
            $scope.state = ahud.state($rootScope.backup, $rootScope.current());
            console.log('CURRENT STATE -> ' + $scope.state);
            console.log('IS CHANGED ' + ahud.isChanged($rootScope.backup, $rootScope.current()));

            if (angular.isFunction(cb)) {
              cb();
            }
          });
        });
      };

      if (angular.isUndefined(ahud.steamPath)) {
        $scope.state = ahud.state($rootScope.backup, $rootScope.current());
        r();
      } else {
        $scope.state = ahud.state($rootScope.backup, $rootScope.current());
        r();
      }
    };

    var doneInstall = () => {
        console.log('installed');
        $timeout(function() {
          $rootScope.backup = angular.copy($rootScope.current());
          $scope.refresh(() => {
            $rootScope.loading = false;
          });

          toasty.success({
            title: "Dashboard",
            msg: "ahud is installed and up to date!",
            showClose: true,
            clickToClose: false,
            timeout: 5000,
            sound: false,
            html: false,
            shake: false,
            theme: "default"
          });
        }, 1000);
      };

    //$scope.state = ahud.state($rootScope.backup, $rootScope.current());
    $scope.changeState = function() {
      $rootScope.loading = true;

      if ($scope.state === 'INSTALLED') {
        ahud.remove(() => {
          console.log('removed');
          $timeout(function() {
            $scope.refresh(() => {
              $rootScope.loading = false;
            });

            toasty.warning({
              title: "Dashboard",
              msg: "ahud was removed from your tf2 directory!",
              showClose: true,
              clickToClose: false,
              timeout: 5000,
              sound: false,
              html: false,
              shake: false,
              theme: "default"
            });
          }, 1000);
        });

      } else if ($scope.state === 'CHANGED') {
        ahud.remove(() => {
          console.log('removed');
          ahud.install($rootScope.current(), doneInstall);
        })
      } else if ($scope.state === 'NOT_INSTALLED') {
        ahud.install($rootScope.current(), doneInstall);

      } else if ($scope.state === 'UPDATE_AVAILABLE') {
        alert('update available');
      }
    };

    if ($rootScope.loaded === true) {
      $scope.refresh(() => {
        $rootScope.loading = false;
      });
    }

    this.$http = $http;
    this.$log = $log;
    this.getNews();
  }

  getNews() {
    return;
    var self = this;
    let newsURL = 'http://steamcommunity.com/groups/ahud/rss';
    this.$http.get(newsURL).then(function(response) {
      //console.log(response.data);
      //self.onGetNews(response, self);
    }, this.onErr);

    //this.$http.get(config.API_URL + '/api/news').then(function(response) {
    //  self.onGetNews(response, self);
    //}, this.onErr);
  }

  onGetNews(response, self) {
    self.news = response.data;
    self.$log.debug(response.data);
  }

  onErr() {
    alert('Error: News can\'t be loaded, try again.');
  }
}
<commit_msg>Add default<commit_after>import {config} from '../config';
const storage = require('electron-json-storage');
var updaterAutoLauncher = require('../../startup');

export class DashboardController {
  constructor ($http, $log, $scope, $rootScope, $timeout, toasty) {
    'ngInject';

    $rootScope.hasChanges = function() {
      return ahud.isChanged($rootScope.backup, $rootScope.current());
    };

    $rootScope.$watch('loaded', function() {
      if ($rootScope.loaded === true) {
        if (angular.isUndefined($rootScope.backup)) {
          $rootScope.backup = angular.copy($rootScope.current());
        }
        ahud.settings = $rootScope.settings;

        $scope.refresh(() => {
          $rootScope.loading = false;

          if (angular.isUndefined($rootScope.settings['auto_updater'])) {
            $rootScope.settings['auto_updater'] = true;
            updaterAutoLauncher.enable();

            storage.set('settings', $rootScope.settings, function(error) {
              if (error) throw error;
            });
          }
        });
      }
    });

    $rootScope.current = function() {
      return {
        crosshairs: $rootScope.crosshairs,
        colors: $rootScope.colors,
        styles: $rootScope.styles
      };
    };

    $scope.version = {
      current: 'not installed!',
      latest: ''
    };

    $scope.refresh = function(cb) {
      var r = function() {
        ahud.latestVersion(() => {
          $scope.version.latest = ahud.latest.string();

          ahud.currentVersion(() => {
            $scope.version.current = ahud.current.string();
            $scope.state = ahud.state($rootScope.backup, $rootScope.current());
            console.log('CURRENT STATE -> ' + $scope.state);
            console.log('IS CHANGED ' + ahud.isChanged($rootScope.backup, $rootScope.current()));

            if (angular.isFunction(cb)) {
              cb();
            }
          });
        });
      };

      if (angular.isUndefined(ahud.steamPath)) {
        $scope.state = ahud.state($rootScope.backup, $rootScope.current());
        r();
      } else {
        $scope.state = ahud.state($rootScope.backup, $rootScope.current());
        r();
      }
    };

    var doneInstall = () => {
        console.log('installed');
        $timeout(function() {
          $rootScope.backup = angular.copy($rootScope.current());
          $scope.refresh(() => {
            $rootScope.loading = false;
          });

          toasty.success({
            title: "Dashboard",
            msg: "ahud is installed and up to date!",
            showClose: true,
            clickToClose: false,
            timeout: 5000,
            sound: false,
            html: false,
            shake: false,
            theme: "default"
          });
        }, 1000);
      };

    //$scope.state = ahud.state($rootScope.backup, $rootScope.current());
    $scope.changeState = function() {
      $rootScope.loading = true;

      if ($scope.state === 'INSTALLED') {
        ahud.remove(() => {
          console.log('removed');
          $timeout(function() {
            $scope.refresh(() => {
              $rootScope.loading = false;
            });

            toasty.warning({
              title: "Dashboard",
              msg: "ahud was removed from your tf2 directory!",
              showClose: true,
              clickToClose: false,
              timeout: 5000,
              sound: false,
              html: false,
              shake: false,
              theme: "default"
            });
          }, 1000);
        });

      } else if ($scope.state === 'CHANGED') {
        ahud.remove(() => {
          console.log('removed');
          ahud.install($rootScope.current(), doneInstall);
        })
      } else if ($scope.state === 'NOT_INSTALLED') {
        ahud.install($rootScope.current(), doneInstall);

      } else if ($scope.state === 'UPDATE_AVAILABLE') {
        alert('update available');
      }
    };

    if ($rootScope.loaded === true) {
      $scope.refresh(() => {
        $rootScope.loading = false;
      });
    }

    this.$http = $http;
    this.$log = $log;
    this.getNews();
  }

  getNews() {
    return;
    var self = this;
    let newsURL = 'http://steamcommunity.com/groups/ahud/rss';
    this.$http.get(newsURL).then(function(response) {
      //console.log(response.data);
      //self.onGetNews(response, self);
    }, this.onErr);

    //this.$http.get(config.API_URL + '/api/news').then(function(response) {
    //  self.onGetNews(response, self);
    //}, this.onErr);
  }

  onGetNews(response, self) {
    self.news = response.data;
    self.$log.debug(response.data);
  }

  onErr() {
    alert('Error: News can\'t be loaded, try again.');
  }
}
<|endoftext|>


<commit_before>'use strict'

const debug = require('debug')('skiff.peer-leader')
const timers = require('timers')
const EventEmitter = require('events')

const BatchTransformStream = require('./lib/batch-transform-stream')

class PeerLeader extends EventEmitter {

  constructor (address, node, options) {
    if (typeof address !== 'string') {
      throw new Error('need address to be a string')
    }

    super()

    this._address = address
    this._node = node
    this._options = options
    this._nextIndex = this._node.log._lastLogIndex + 1
    this._matchIndex = 0
    this._needsIndex = 0
    this._installingSnapshot = false
    this._lastSent = 0
    this._stopped = false

    this._appendEntries()
  }

  stop () {
    this._stopped = true
    this._clearAppendEntriesTimeout()
  }

  needsIndex (index) {
    if (index > this._needsIndex) {
      this._needsIndex = index
    }
    if (this._needsMore) {
      timers.setImmediate(this._appendEntries.bind(this))
    }
  }

  _needsMore () {
    return this._nextIndex <= this._needsIndex
  }

  _appendEntries () {
    debug('sending AppendEntries to %s', this._address)

    if (this._stopped) {
      return
    }

    if (this._installingSnapshot) {
      this._resetAppendEntriesTimeout()
      return
    }

    const log = this._node.log
    const currentTerm = this._node.state.term()

    const entriesReply = this._entries()
    const entries = entriesReply.entries
    const capped = entriesReply.capped
    if (entries) {
      debug('%s: entries for %s are: %j', this._node.state.id, this._address, entries)

      const previousEntry = this._previousEntry()
      const lastEntry = entries[entries.length - 1]
      const leaderCommit = log._commitIndex

      const appendEntriesArgs = {
        term: currentTerm,
        leaderId: this._node.state.id,
        prevLogIndex: previousEntry && previousEntry.i || 0,
        prevLogTerm: previousEntry && previousEntry.t || 0,
        entries,
        leaderCommit
      }

      this._lastSent = Date.now()

      this._resetAppendEntriesTimeout()

      this._node.network.rpc(
        {
          to: this._address,
          action: 'AppendEntries',
          params: appendEntriesArgs
        },
        (err, reply) => { // callback
          debug('%s: got reply to AppendEntries from %s: %j', this._node.state.id, this._address, reply)
          if (err) {
            debug('%s: error on AppendEntries reply:\n%s', this._node.state.id, err.stack)
          } else if (reply && reply.params) {
            if (reply.params.success) {
              this._matchIndex = leaderCommit
              if (lastEntry) {
                this._nextIndex = lastEntry.i + 1
              }
              if (capped) {
                this._needsMore = true
              }
              const commitedEntry = lastEntry || previousEntry
              const commitedIndex = commitedEntry && commitedEntry.i || 0
              this.emit('committed', this, commitedIndex)
            } else {
              if (reply.params.lastIndexForTerm !== undefined) {
                this._nextIndex = reply.params.lastIndexForTerm + 1
              } else {
                this._nextIndex --
              }
            }

            if (this._needsMore()) {
              timers.setImmediate(this._appendEntries.bind(this))
            }
          }
        }
      )
    } else {
      // no log entries for peer that's lagging behind
      debug('%s: peer %s is lagging behind (next index is %d), going to install snapshot',
        this._node.state.id, this._address, this._nextIndex)

      this._resetAppendEntriesTimeout()
      return this._installSnapshot()
    }
  }

  _clearAppendEntriesTimeout () {
    if (this._appendEntriesTimeout) {
      timers.clearTimeout(this._appendEntriesTimeout)
    }
    this._appendEntriesTimeout = null
  }

  _setAppendEntriesTimeout () {
    debug('%s: setting the append entries timeout to %d ms',
      this._node.state.id, this._options.appendEntriesIntervalMS)

    this._appendEntriesTimeout = timers.setTimeout(
      this._onAppendEntriesTimeout.bind(this),
      this._options.appendEntriesIntervalMS)
  }

  _resetAppendEntriesTimeout () {
    this._clearAppendEntriesTimeout()
    this._setAppendEntriesTimeout()
  }

  _onAppendEntriesTimeout () {
    debug('%s: AppendEntries timedout', this._node.state.id)
    this._appendEntries()
  }

  _entries () {
    debug('follower %s next index is %d', this._address, this._nextIndex)
    const start = this._nextIndex
    let entries = this._node.log.entriesFrom(start)
    const cap = entries && (entries.length > this._options.batchEntriesLimit)
    if (cap) {
      entries = entries.slice(0, this._options.batchEntriesLimit)
    }
    return { capped: cap, entries }
  }

  _previousEntry () {
    return this._node.log.atLogIndex(this._nextIndex - 1)
  }

  // Install snapshot

  _installSnapshot () {
    debug('%s: _installSnapshot on %s', this._node.state.id, this._address)

    if (this._stopped) {
      return
    }

    const self = this
    const log = this._node.state.log

    this._clearAppendEntriesTimeout()
    let finished = false
    let offset = 0

    this._installingSnapshot = true

    const lastIncludedIndex = log._lastApplied
    const lastIncludedTerm = log._lastAppliedTerm

    const rs = this._node.state.db.state.createReadStream()
    const stream = rs.pipe(
      new BatchTransformStream({
        batchSize: this._options.installSnapshotChunkSize
      })
    )

    stream.on('data', installSnapshot)

    function installSnapshot (data) {
      debug('%s: have chunks %j, finished = %j', self._node.state.id, data.chunks, data.finished)
      debug('%s: installSnapshot on leader: have chunks %j, finished = %j', self._node.state.id, data.chunks, data.finished)
      stream.pause()

      const installSnapshotArgs = {
        term: self._node.state.term(),
        leaderId: self._node.id,
        lastIncludedIndex,
        lastIncludedTerm,
        offset,
        data: data.chunks,
        done: data.finished
      }

      offset += data.chunks.length

      self._node.network.rpc(
        {
          to: self._address,
          action: 'InstallSnapshot',
          params: installSnapshotArgs
        },
        (err, reply) => { // callback
          debug('%s: got InstallSnapshot reply', self._node.state.id, err, reply)
          if (err) {
            cleanup()
          } else {
            if (data.finished) {
              debug('%s: data finished, setting next index of %j to %d',
                self._node.state.id, self._address, lastIncludedIndex)
              self._nextIndex = self._matchIndex = lastIncludedIndex
              cleanup()
              this.emit('committed', self, lastIncludedIndex)
            } else {
              debug('resuming stream...')
              stream.resume()
            }
          }
        }
      )

      debug('%s: sent InstallSnapshot', self._node.state.id)
    }

    function cleanup () {
      if (!finished) {
        finished = true
        self._installingSnapshot = false
        self._resetAppendEntriesTimeout()
        rs.destroy()
      }
    }
  }

  state () {
    return {
      address: this._address,
      stopped: this._stopped,
      nextIndex: this._nextIndex,
      matchIndex: this._matchIndex,
      installingSnapshot: this._installingSnapshot,
      sentAppendEntriesAgoMS: Date.now() - this._lastSent
    }
  }
}

module.exports = PeerLeader
<commit_msg>corrected peer leader needsMore()<commit_after>'use strict'

const debug = require('debug')('skiff.peer-leader')
const timers = require('timers')
const EventEmitter = require('events')

const BatchTransformStream = require('./lib/batch-transform-stream')

class PeerLeader extends EventEmitter {

  constructor (address, node, options) {
    if (typeof address !== 'string') {
      throw new Error('need address to be a string')
    }

    super()

    this._address = address
    this._node = node
    this._options = options
    this._nextIndex = this._node.log._lastLogIndex + 1
    this._matchIndex = 0
    this._needsIndex = 0
    this._installingSnapshot = false
    this._lastSent = 0
    this._stopped = false

    this._appendEntries()
  }

  stop () {
    this._stopped = true
    this._clearAppendEntriesTimeout()
  }

  needsIndex (index) {
    if (index > this._needsIndex) {
      this._needsIndex = index
    }
    if (this._needsMore()) {
      timers.setImmediate(this._appendEntries.bind(this))
    }
  }

  _needsMore () {
    return this._nextIndex <= this._needsIndex
  }

  _appendEntries () {
    debug('sending AppendEntries to %s', this._address)

    if (this._stopped) {
      return
    }

    if (this._installingSnapshot) {
      this._resetAppendEntriesTimeout()
      return
    }

    const log = this._node.log
    const currentTerm = this._node.state.term()

    const entriesReply = this._entries()
    const entries = entriesReply.entries
    const capped = entriesReply.capped
    if (entries) {
      debug('%s: entries for %s are: %j', this._node.state.id, this._address, entries)

      const previousEntry = this._previousEntry()
      const lastEntry = entries[entries.length - 1]
      const leaderCommit = log._commitIndex

      const appendEntriesArgs = {
        term: currentTerm,
        leaderId: this._node.state.id,
        prevLogIndex: previousEntry && previousEntry.i || 0,
        prevLogTerm: previousEntry && previousEntry.t || 0,
        entries,
        leaderCommit
      }

      this._lastSent = Date.now()

      this._resetAppendEntriesTimeout()

      this._node.network.rpc(
        {
          to: this._address,
          action: 'AppendEntries',
          params: appendEntriesArgs
        },
        (err, reply) => { // callback
          debug('%s: got reply to AppendEntries from %s: %j', this._node.state.id, this._address, reply)
          if (err) {
            debug('%s: error on AppendEntries reply:\n%s', this._node.state.id, err.stack)
          } else if (reply && reply.params) {
            if (reply.params.success) {
              this._matchIndex = leaderCommit
              if (lastEntry) {
                this._nextIndex = lastEntry.i + 1
              }
              const commitedEntry = lastEntry || previousEntry
              const commitedIndex = commitedEntry && commitedEntry.i || 0
              this.emit('committed', this, commitedIndex)
            } else {
              if (reply.params.lastIndexForTerm !== undefined) {
                this._nextIndex = reply.params.lastIndexForTerm + 1
              } else {
                this._nextIndex --
              }
            }

            if (this._needsMore()) {
              timers.setImmediate(this._appendEntries.bind(this))
            }
          }
        }
      )
    } else {
      // no log entries for peer that's lagging behind
      debug('%s: peer %s is lagging behind (next index is %d), going to install snapshot',
        this._node.state.id, this._address, this._nextIndex)

      this._resetAppendEntriesTimeout()
      return this._installSnapshot()
    }
  }

  _clearAppendEntriesTimeout () {
    if (this._appendEntriesTimeout) {
      timers.clearTimeout(this._appendEntriesTimeout)
    }
    this._appendEntriesTimeout = null
  }

  _setAppendEntriesTimeout () {
    debug('%s: setting the append entries timeout to %d ms',
      this._node.state.id, this._options.appendEntriesIntervalMS)

    this._appendEntriesTimeout = timers.setTimeout(
      this._onAppendEntriesTimeout.bind(this),
      this._options.appendEntriesIntervalMS)
  }

  _resetAppendEntriesTimeout () {
    this._clearAppendEntriesTimeout()
    this._setAppendEntriesTimeout()
  }

  _onAppendEntriesTimeout () {
    debug('%s: AppendEntries timedout', this._node.state.id)
    this._appendEntries()
  }

  _entries () {
    debug('follower %s next index is %d', this._address, this._nextIndex)
    const start = this._nextIndex
    let entries = this._node.log.entriesFrom(start)
    const cap = entries && (entries.length > this._options.batchEntriesLimit)
    if (cap) {
      entries = entries.slice(0, this._options.batchEntriesLimit)
    }
    return { capped: cap, entries }
  }

  _previousEntry () {
    return this._node.log.atLogIndex(this._nextIndex - 1)
  }

  // Install snapshot

  _installSnapshot () {
    debug('%s: _installSnapshot on %s', this._node.state.id, this._address)

    if (this._stopped) {
      return
    }

    const self = this
    const log = this._node.state.log

    this._clearAppendEntriesTimeout()
    let finished = false
    let offset = 0

    this._installingSnapshot = true

    const lastIncludedIndex = log._lastApplied
    const lastIncludedTerm = log._lastAppliedTerm

    const rs = this._node.state.db.state.createReadStream()
    const stream = rs.pipe(
      new BatchTransformStream({
        batchSize: this._options.installSnapshotChunkSize
      })
    )

    stream.on('data', installSnapshot)

    function installSnapshot (data) {
      debug('%s: have chunks %j, finished = %j', self._node.state.id, data.chunks, data.finished)
      debug('%s: installSnapshot on leader: have chunks %j, finished = %j', self._node.state.id, data.chunks, data.finished)
      stream.pause()

      const installSnapshotArgs = {
        term: self._node.state.term(),
        leaderId: self._node.id,
        lastIncludedIndex,
        lastIncludedTerm,
        offset,
        data: data.chunks,
        done: data.finished
      }

      offset += data.chunks.length

      self._node.network.rpc(
        {
          to: self._address,
          action: 'InstallSnapshot',
          params: installSnapshotArgs
        },
        (err, reply) => { // callback
          debug('%s: got InstallSnapshot reply', self._node.state.id, err, reply)
          if (err) {
            cleanup()
          } else {
            if (data.finished) {
              debug('%s: data finished, setting next index of %j to %d',
                self._node.state.id, self._address, lastIncludedIndex)
              self._nextIndex = self._matchIndex = lastIncludedIndex
              cleanup()
              this.emit('committed', self, lastIncludedIndex)
            } else {
              debug('resuming stream...')
              stream.resume()
            }
          }
        }
      )

      debug('%s: sent InstallSnapshot', self._node.state.id)
    }

    function cleanup () {
      if (!finished) {
        finished = true
        self._installingSnapshot = false
        self._resetAppendEntriesTimeout()
        rs.destroy()
      }
    }
  }

  state () {
    return {
      address: this._address,
      stopped: this._stopped,
      nextIndex: this._nextIndex,
      matchIndex: this._matchIndex,
      installingSnapshot: this._installingSnapshot,
      sentAppendEntriesAgoMS: Date.now() - this._lastSent
    }
  }
}

module.exports = PeerLeader
<|endoftext|>


<commit_before>function attach_drag_functor() {
  $('.skill-draggable').draggable({
    drag: function(event, ui) {},
    start: function(event, ui) {},
    stop: function(event, ui) {},
  });

  $('.skill-draggable').on('dragstart', function(event, ui) {
    //$(this).css('z-index', 100);
    if ($(this).hasClass('faded')) {
      return false;
    }

    $('.popover').hide();

    $('.skill-draggable')
      .css('z-index', -10);

    $('.skill-droppable')
      .css('border', '1px solid #388038')
      .css('background-color', '#ddffdd')
      .css('z-index', -10);

    $(this).css('z-index', 1000);
  })

  $('.skill-draggable').on('dragstop', function(event, ui) {
    $(this).css('left', '')
           .css('top', '');

    $('.skill-draggable')
      .css('z-index', '');

    $('.skill-droppable')
      .css('border', '1px solid #ddd')
      .css('background-color', '')
      .css('z-index', '');

    $('.popover').hide();
  })
}

function attach_drop_functor(_element_id) {
  var element_id = '#' + _element_id;
  var list_id = element_id + '-list';

  var target_size = $(list_id).css('width');
  $(element_id).droppable({
    drop: function(event, ui) {
      event.preventDefault();
      var dragged_object = ui.draggable;

      //$(list_id).append(dragged_object);
      if (_element_id  == 'graphical') {
        append_lexicographically(list_id, dragged_object);
      } else {
        $(list_id).append(dragged_object);
        //resize_height();

      }

      dragged_object
        .css('width', target_size)
        .css('z-index', '');

      $('.popover').hide();
    }
  })
}

function append_lexicographically(list_id, dragged_object) {
  var seek_skill_name = dragged_object.attr('skill-name');
  var appended = false;
  //console.log(seek_skill_name);
  $(list_id).children('li').each(function() {
    var iterated_skill_name = $(this).attr('skill-name');
    var s_compare = seek_skill_name.localeCompare(iterated_skill_name);

    //console.log('comparing ' + seek_skill_name + ' | ' + iterated_skill_name + ' = ' + s_compare);

    if (s_compare == -1) {
      dragged_object.insertBefore($(this));
      appended = true;
      return false;
    }
    // console.log($(this).attr('skill-name'));
  })

  if (!appended) {
    $(list_id).append(dragged_object);
  }
}

function replan() {
  replan_list('#acquired-list');
  replan_list('#planned-list');
}

function replan_list(target_id) {
  $(target_id).children('li').each(function() {
    var that = $(this);
    var skill_label = that.attr('skill-name');

    //console.log(that.attr('skill-name') + ' | ' + that.hasClass('faded'));
    if (that.hasClass('faded')) {
      var cloned = that.clone();
      append_lexicographically('#graphical-list', cloned);
      cloned.css('width', $('#graphical-list').css('width'));

      that.addClass('invalid');
      that.find('.skill-label')
            .addClass('text-danger')
            .css('text-decoration', 'line-through');
    }

    if (that.hasClass('invalid')) {
      if (is_valid_skill(skill_label)) {
        that.find('.skill-label')
              .removeClass('text-danger')
              .css('text-decoration', 'none');
        $('#graphical-list').find('[skill-name="' + skill_label + '"]').remove();
      }
    }
  })
}

function is_valid_skill(skill_name) {
  return !$('[skill-name="' + skill_name + '"]').hasClass('faded');
}

$(function() {
  //$('#acquired').resizable();
  //$('#planned').resizable();

  $('#acquired').css('marginTop', ($(window).scrollTop() + 96) + 'px');

  $(window).scroll(function() {
    $('#acquired')
      .stop()
      .animate({'marginTop': ($(window).scrollTop() + 96) + 'px'}, 0);
  });

  attach_drop_functor('acquired');
  attach_drop_functor('planned');
  attach_drop_functor('graphical');
});<commit_msg>Drag-and-drop in between planned/acquired no longer obstructs dragged element.<commit_after>function attach_drag_functor() {
  $('.skill-draggable').draggable({
    drag: function(event, ui) {},
    start: function(event, ui) {},
    stop: function(event, ui) {},
  });

  $('.skill-draggable').on('dragstart', function(event, ui) {
    //$(this).css('z-index', 100);
    if ($(this).hasClass('faded')) {
      return false;
    }

    $('.popover').hide();

    $('.skill-draggable')
      .css('z-index', -10);

    $('.skill-droppable')
      .css('border', '1px solid #388038')
      //.css('background-color', '#ddffdd')
      .css('overflow-y', 'visible')
      .css('z-index', -10);

    $(this).css('z-index', 1000);
  })

  $('.skill-draggable').on('dragstop', function(event, ui) {
    $(this).css('left', '')
           .css('top', '');

    $('.skill-draggable')
      .css('z-index', '');

    $('.skill-droppable')
      .css('border', '1px solid #ddd')
      .css('background-color', '')
      .css('z-index', '');

    $('.popover').hide();
  })
}

function attach_drop_functor(_element_id) {
  var element_id = '#' + _element_id;
  var list_id = element_id + '-list';

  var target_size = $(list_id).css('width');
  $(element_id).droppable({
    drop: function(event, ui) {
      event.preventDefault();
      var dragged_object = ui.draggable;

      append_lexicographically(list_id, dragged_object);

      dragged_object
        .css('width', target_size)
        .css('z-index', '');

      $('.skill-droppable')
        .css('overflow-y', 'auto');

      $('.popover').hide();
    }
  })
}

function append_lexicographically(list_id, dragged_object) {
  var seek_skill_name = dragged_object.attr('skill-name');
  var appended = false;
  //console.log(seek_skill_name);
  $(list_id).children('li').each(function() {
    var iterated_skill_name = $(this).attr('skill-name');
    var s_compare = seek_skill_name.localeCompare(iterated_skill_name);

    //console.log('comparing ' + seek_skill_name + ' | ' + iterated_skill_name + ' = ' + s_compare);

    if (s_compare == -1) {
      dragged_object.insertBefore($(this));
      appended = true;
      return false;
    }
    // console.log($(this).attr('skill-name'));
  })

  if (!appended) {
    $(list_id).append(dragged_object);
  }
}

function replan() {
  replan_list('#acquired-list');
  replan_list('#planned-list');
}

function replan_list(target_id) {
  $(target_id).children('li').each(function() {
    var that = $(this);
    var skill_label = that.attr('skill-name');

    //console.log(that.attr('skill-name') + ' | ' + that.hasClass('faded'));
    if (that.hasClass('faded')) {
      var cloned = that.clone();
      append_lexicographically('#graphical-list', cloned);
      cloned.css('width', $('#graphical-list').css('width'));

      that.addClass('invalid');
      that.find('.skill-label')
            .addClass('text-danger')
            .css('text-decoration', 'line-through');
    }

    if (that.hasClass('invalid')) {
      if (is_valid_skill(skill_label)) {
        that.find('.skill-label')
              .removeClass('text-danger')
              .css('text-decoration', 'none');
        $('#graphical-list').find('[skill-name="' + skill_label + '"]').remove();
      }
    }
  })
}

function is_valid_skill(skill_name) {
  return !$('[skill-name="' + skill_name + '"]').hasClass('faded');
}

$(function() {
  //$('#acquired').resizable();
  //$('#planned').resizable();

  $('#acquired').css('marginTop', ($(window).scrollTop() + 96) + 'px');

  $(window).scroll(function() {
    $('#acquired')
      .stop()
      .animate({'marginTop': ($(window).scrollTop() + 96) + 'px'}, 0);
  });

  attach_drop_functor('acquired');
  attach_drop_functor('planned');
  attach_drop_functor('graphical');
});<|endoftext|>