<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var React = require('react');
var sdk = require('../../index');
var dis = require("../../dispatcher");
var WhoIsTyping = require("../../WhoIsTyping");
var MatrixClientPeg = require("../../MatrixClientPeg");

module.exports = React.createClass({
    displayName: 'RoomStatusBar',

    propTypes: {
        // the room this statusbar is representing.
        room: React.PropTypes.object.isRequired,

        // a list of TabCompleteEntries.Entry objects
        tabCompleteEntries: React.PropTypes.array,

        // the number of messages which have arrived since we've been scrolled up
        numUnreadMessages: React.PropTypes.number,

        // true if there are messages in the room which had errors on send
        hasUnsentMessages: React.PropTypes.bool,

        // this is true if we are fully scrolled-down, and are looking at
        // the end of the live timeline.
        atEndOfLiveTimeline: React.PropTypes.bool,

        // true if there is an active call in this room (means we show
        // the 'Active Call' text in the status bar if there is nothing
        // more interesting)
        hasActiveCall: React.PropTypes.bool,

        // callback for when the user clicks on the 'resend all' button in the
        // 'unsent messages' bar
        onResendAllClick: React.PropTypes.func,

        // callback for when the user clicks on the 'scroll to bottom' button
        onScrollToBottomClick: React.PropTypes.func,
    },

    getInitialState: function() {
        return {
            syncState: MatrixClientPeg.get().getSyncState(),
        };
    },

    componentWillMount: function() {
        MatrixClientPeg.get().on("sync", this.onSyncStateChange);
    },

    componentWillUnmount: function() {
        MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange);
    },

    onSyncStateChange: function(state, prevState) {
        if (state === "SYNCING" && prevState === "SYNCING") {
            return;
        }
        this.setState({
            syncState: state
        });
    },

    render: function() {
        var TabCompleteBar = sdk.getComponent('rooms.TabCompleteBar');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");

        // no conn bar trumps unread count since you can't get unread messages
        // without a connection! (technically may already have some but meh)
        // It also trumps the "some not sent" msg since you can't resend without
        // a connection!
        if (this.state.syncState === "ERROR") {
            return (

                            Connectivity to the server has been lost.

                            Sent messages will be stored until your connection has returned.

            );
        }

        if (this.props.tabCompleteEntries) {
            return (

...

                        <TabCompleteBar entries={this.props.tabCompleteEntries} />

|">
                            <TintableSvg src="img/eol.svg" width="22" height="16"/>
                            Auto-complete

            );
        }

        if (this.props.hasUnsentMessages) {
            return (

                            Some of your messages have not been sent.

                            Resend all now
                             or select individual messages to re-send.

            );
        }

        // unread count trumps who is typing since the unread count is only
        // set when you've scrolled up
        if (this.props.numUnreadMessages) {
            var unreadMsgs = this.props.numUnreadMessages + " new message" +
                (this.props.numUnreadMessages > 1 ? "s" : "");

            return (

                    {unreadMsgs}

            );
        }

        var typingString = WhoIsTyping.whoIsTypingString(this.props.room);
        if (typingString) {
            return (

...

                    {typingString}

            );
        }

        if (!this.props.atEndOfLiveTimeline) {
            return (

            );
        }

        if (this.props.hasActiveCall) {
            return (

                    Active call

            );
        }

        return
;
    },
});
<commit_msg>Show jump-to-bottom icon even when there is other stuff in the status bar<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var React = require('react');
var sdk = require('../../index');
var dis = require("../../dispatcher");
var WhoIsTyping = require("../../WhoIsTyping");
var MatrixClientPeg = require("../../MatrixClientPeg");

module.exports = React.createClass({
    displayName: 'RoomStatusBar',

    propTypes: {
        // the room this statusbar is representing.
        room: React.PropTypes.object.isRequired,

        // a list of TabCompleteEntries.Entry objects
        tabCompleteEntries: React.PropTypes.array,

        // the number of messages which have arrived since we've been scrolled up
        numUnreadMessages: React.PropTypes.number,

        // true if there are messages in the room which had errors on send
        hasUnsentMessages: React.PropTypes.bool,

        // this is true if we are fully scrolled-down, and are looking at
        // the end of the live timeline.
        atEndOfLiveTimeline: React.PropTypes.bool,

        // true if there is an active call in this room (means we show
        // the 'Active Call' text in the status bar if there is nothing
        // more interesting)
        hasActiveCall: React.PropTypes.bool,

        // callback for when the user clicks on the 'resend all' button in the
        // 'unsent messages' bar
        onResendAllClick: React.PropTypes.func,

        // callback for when the user clicks on the 'scroll to bottom' button
        onScrollToBottomClick: React.PropTypes.func,
    },

    getInitialState: function() {
        return {
            syncState: MatrixClientPeg.get().getSyncState(),
        };
    },

    componentWillMount: function() {
        MatrixClientPeg.get().on("sync", this.onSyncStateChange);
    },

    componentWillUnmount: function() {
        MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange);
    },

    onSyncStateChange: function(state, prevState) {
        if (state === "SYNCING" && prevState === "SYNCING") {
            return;
        }
        this.setState({
            syncState: state
        });
    },

    // return suitable content for the image on the left of the status bar.
    //
    // if wantPlaceholder is true, we include a "..." placeholder if
    // there is nothing better to put in.
    _getIndicator: function(wantPlaceholder) {
        if (this.props.numUnreadMessages) {
            return (

            );
        }

        if (!this.props.atEndOfLiveTimeline) {
            return (

            );
        }

        if (this.props.hasActiveCall) {
            return (

            );
        }

        if (wantPlaceholder) {
            return (

...

            );
        }

        return null;
    },

    // return suitable content for the main (text) part of the status bar.
    _getContent: function() {
        var TabCompleteBar = sdk.getComponent('rooms.TabCompleteBar');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");

        // no conn bar trumps unread count since you can't get unread messages
        // without a connection! (technically may already have some but meh)
        // It also trumps the "some not sent" msg since you can't resend without
        // a connection!
        if (this.state.syncState === "ERROR") {
            return (

                        Connectivity to the server has been lost.

                        Sent messages will be stored until your connection has returned.

            );
        }

        if (this.props.tabCompleteEntries) {
            return (

                        <TabCompleteBar entries={this.props.tabCompleteEntries} />

|">
                            <TintableSvg src="img/eol.svg" width="22" height="16"/>
                            Auto-complete

            );
        }

        if (this.props.hasUnsentMessages) {
            return (

                        Some of your messages have not been sent.

                        Resend all now
                         or select individual messages to re-send.

            );
        }

        // unread count trumps who is typing since the unread count is only
        // set when you've scrolled up
        if (this.props.numUnreadMessages) {
            var unreadMsgs = this.props.numUnreadMessages + " new message" +
                (this.props.numUnreadMessages > 1 ? "s" : "");

            return (

                    {unreadMsgs}

            );
        }

        var typingString = WhoIsTyping.whoIsTypingString(this.props.room);
        if (typingString) {
            return (

                    {typingString}

            );
        }

        if (this.props.hasActiveCall) {
            return (

                    Active call

            );
        }

        return null;
    },

    render: function() {
        var content = this._getContent();
        var indicator = this._getIndicator(content !== null);

        return (

                    {indicator}

                {content}

        );
    },
});
<|endoftext|>


<commit_before>import React, { Component } from "react";
import gql from "graphql-tag";
import { graphql, withApollo } from "react-apollo";
import { Label, Row, Col, Input, Button, ButtonGroup } from "reactstrap";
import Preview, { Viewscreen } from "./index";
import * as ViewscreenCards from "../../viewscreens";
import Layouts from "../../layouts";

import "./style.css";

const CardPreview = Viewscreen;

const VIEWSCREEN_SUB = gql`
  subscription ViewscreenSub($simulatorId: ID) {
    viewscreensUpdate(simulatorId: $simulatorId) {
      id
      name
      component
      data
      auto
    }
  }
`;

class ViewscreenCore extends Component {
  sub = null;
  cards = Object.keys(ViewscreenCards)
    .filter(c => c.indexOf("Config") === -1)
    .sort();
  configs = Object.keys(ViewscreenCards)
    .filter(c => c.indexOf("Config") > -1)
    .sort();
  state = {
    selectedViewscreen: null,
    preview: true,
    configData: "{}"
  };
  componentWillUnmount() {
    this.sub && this.sub();
  }
  componentWillReceiveProps(nextProps) {
    if (!this.sub && !nextProps.data.loading) {
      this.sub = nextProps.data.subscribeToMore({
        document: VIEWSCREEN_SUB,
        variables: {
          simulatorId: nextProps.simulator.id
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          return Object.assign({}, previousResult, {
            viewscreens: subscriptionData.viewscreensUpdate
          });
        }
      });
    }
    if (!nextProps.data.loading) {
      const { viewscreens } = nextProps.data;
      if (viewscreens.length === 1) {
        this.setState({
          selectedViewscreen: viewscreens[0].id
        });
      }
    }
  }
  updateCard = component => {
    const { previewComponent, configData } = this.state;

    const mutation = gql`
      mutation UpdateViewscreen($id: ID!, $component: String!, $data: String) {
        updateViewscreenComponent(id: $id, component: $component, data: $data)
      }
    `;
    const variables = {
      id: this.state.selectedViewscreen,
      component
    };
    if (component === previewComponent) {
      // If the component we are switching to is the same as the preview component
      // Apply the preview data to the new component
      variables.data = configData;
    }
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  updateData = data => {
    const mutation = gql`
      mutation UpdateViewscreenData($id: ID!, $data: String!) {
        updateViewscreenData(id: $id, data: $data)
      }
    `;
    const variables = {
      id: this.state.selectedViewscreen,
      data
    };
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  toggleAuto = () => {
    const { viewscreens } = this.props.data;
    const { selectedViewscreen } = this.state;
    const auto = !(
      viewscreens.find(v => v.id === selectedViewscreen) &&
      viewscreens.find(v => v.id === selectedViewscreen).auto
    );
    const id = selectedViewscreen;
    const mutation = gql`
      mutation UpdateViewscreenAuto($id: ID!, $auto: Boolean!) {
        updateViewscreenAuto(id: $id, auto: $auto)
      }
    `;
    const variables = {
      id,
      auto
    };
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  render() {
    if (this.props.data.loading || !this.props.data.viewscreens) return null;
    const { viewscreens } = this.props.data;
    const {
      selectedViewscreen = null,
      preview,
      previewComponent,
      configData
    } = this.state;
    const LayoutComponent =
      Layouts[this.props.simulator.layout + "Viewscreen"] ||
      Layouts[this.props.simulator.layout] ||
      (({ children }) =>
{children}
);
    if (!viewscreens) return
No Viewscreens
;
    return (

          {selectedViewscreen && (
            <LayoutComponent
              clientObj={{}}
              flight={{}}
              simulator={this.props.simulator}
              station={{}}
              cardName={"Viewscreen"}
            >
              <Preview
                simulator={this.props.simulator}
                flightId={this.props.flightId}
                clientObj={{ id: selectedViewscreen }}
              />
            </LayoutComponent>
          )}

          {previewComponent && (
            <LayoutComponent
              clientObj={{}}
              flight={{}}
              simulator={this.props.simulator}
              station={{}}
              cardName={"Viewscreen"}
            >
              <CardPreview
                simulator={this.props.simulator}
                component={previewComponent}
                flightId={this.props.flightId}
                viewscreen={{ data: configData }}
              />
            </LayoutComponent>
          )}

            <Row>
              <Col sm={6}>
                Viewscreen
                <Input
                  type="select"
                  size="sm"
                  value={selectedViewscreen || "select"}
                  onChange={evt => {
                    this.setState({ selectedViewscreen: evt.target.value });
                  }}
                >
                  <option value="select">Select a viewscreen</option>
                  {viewscreens.map(v => (
                    <option key={v.id} value={v.id}>
                      {v.name}
                    </option>
                  ))}
                </Input>

                  <input
                    type="checkbox"
                    checked={
                      selectedViewscreen &&
                      viewscreens.length &&
                      viewscreens.find(v => v.id === selectedViewscreen).auto
                    }
                    onChange={this.toggleAuto}
                  />{" "}
                  Auto-switch generic tactical cards

              </Col>
              <Col sm={6}>
                Cards

                  {this.cards.map(c => (

 v.id === selectedViewscreen)
                        .component === c
                        ? "previewing"
                        : ""} ${previewComponent === c ? "selected" : ""}`}
                      onClick={() =>
                        preview
                          ? this.setState({ previewComponent: c })
                          : this.updateCard(c)}
                    >
                      {c}

                  ))}

                <ButtonGroup>
                  <Button
                    color="primary"
                    className={preview ? "active" : ""}
                    onClick={() => this.setState({ preview: true })}
                  >
                    Preview
                  </Button>
                  <Button
                    color="info"
                    onClick={() => this.updateCard(previewComponent)}
                  >
                    Go
                  </Button>
                  <Button
                    color="success"
                    className={!preview ? "active" : ""}
                    onClick={() => this.setState({ preview: false })}
                  >
                    Change
                  </Button>
                </ButtonGroup>
              </Col>
            </Row>

            Config
            <Row>
              <Col sm={6}>
                Current Viewscreen
                {(() => {
                  const viewscreen =
                    selectedViewscreen &&
                    viewscreens.find(v => v.id === selectedViewscreen);
                  const currentComponent = viewscreen && viewscreen.component;
                  const currentData = viewscreen && viewscreen.data;
                  if (this.configs.indexOf(`${currentComponent}Config`) > -1) {
                    const ConfigComponent =
                      ViewscreenCards[`${currentComponent}Config`];
                    return (
                      <ConfigComponent
                        simulator={this.props.simulator}
                        flightId={this.props.flightId}
                        data={currentData}
                        updateData={this.updateData}
                      />
                    );
                  }
                  return
No config for this component
;
                })()}
              </Col>
              <Col sm={6}>
                Preview Viewscreen
                {(() => {
                  if (this.configs.indexOf(`${previewComponent}Config`) > -1) {
                    const ConfigComponent =
                      ViewscreenCards[`${previewComponent}Config`];
                    return (
                      <ConfigComponent
                        simulator={this.props.simulator}
                        flightId={this.props.flightId}
                        data={configData}
                        updateData={data => this.setState({ configData: data })}
                        selectedClient={selectedViewscreen}
                      />
                    );
                  }
                  return
No config for this component
;
                })()}
              </Col>
            </Row>

    );
  }
}

const VIEWSCREEN_QUERY = gql`
  query Viewscreens($simulatorId: ID) {
    viewscreens(simulatorId: $simulatorId) {
      id
      name
      component
      data
      auto
    }
  }
`;
export default graphql(VIEWSCREEN_QUERY, {
  options: ownProps => ({
    variables: {
      simulatorId: ownProps.simulator.id
    }
  })
})(withApollo(ViewscreenCore));
<commit_msg>Fix for viewscreen breaking<commit_after>import React, { Component } from "react";
import gql from "graphql-tag";
import { graphql, withApollo } from "react-apollo";
import { Label, Row, Col, Input, Button, ButtonGroup } from "reactstrap";
import Preview, { Viewscreen } from "./index";
import * as ViewscreenCards from "../../viewscreens";
import Layouts from "../../layouts";

import "./style.css";

const CardPreview = Viewscreen;

const VIEWSCREEN_SUB = gql`
  subscription ViewscreenSub($simulatorId: ID) {
    viewscreensUpdate(simulatorId: $simulatorId) {
      id
      name
      component
      data
      auto
    }
  }
`;

class ViewscreenCore extends Component {
  sub = null;
  cards = Object.keys(ViewscreenCards)
    .filter(c => c.indexOf("Config") === -1)
    .sort();
  configs = Object.keys(ViewscreenCards)
    .filter(c => c.indexOf("Config") > -1)
    .sort();
  state = {
    selectedViewscreen: null,
    preview: true,
    configData: "{}"
  };
  componentWillUnmount() {
    this.sub && this.sub();
  }
  componentWillReceiveProps(nextProps) {
    if (!this.sub && !nextProps.data.loading) {
      this.sub = nextProps.data.subscribeToMore({
        document: VIEWSCREEN_SUB,
        variables: {
          simulatorId: nextProps.simulator.id
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          return Object.assign({}, previousResult, {
            viewscreens: subscriptionData.viewscreensUpdate
          });
        }
      });
    }
    if (!nextProps.data.loading) {
      const { viewscreens } = nextProps.data;
      if (viewscreens.length === 1) {
        this.setState({
          selectedViewscreen: viewscreens[0].id
        });
      }
    }
  }
  updateCard = component => {
    const { previewComponent, configData } = this.state;

    const mutation = gql`
      mutation UpdateViewscreen($id: ID!, $component: String!, $data: String) {
        updateViewscreenComponent(id: $id, component: $component, data: $data)
      }
    `;
    const variables = {
      id: this.state.selectedViewscreen,
      component
    };
    if (component === previewComponent) {
      // If the component we are switching to is the same as the preview component
      // Apply the preview data to the new component
      variables.data = configData;
    }
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  updateData = data => {
    const mutation = gql`
      mutation UpdateViewscreenData($id: ID!, $data: String!) {
        updateViewscreenData(id: $id, data: $data)
      }
    `;
    const variables = {
      id: this.state.selectedViewscreen,
      data
    };
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  toggleAuto = () => {
    const { viewscreens } = this.props.data;
    const { selectedViewscreen } = this.state;
    const auto = !(
      viewscreens.find(v => v.id === selectedViewscreen) &&
      viewscreens.find(v => v.id === selectedViewscreen).auto
    );
    const id = selectedViewscreen;
    const mutation = gql`
      mutation UpdateViewscreenAuto($id: ID!, $auto: Boolean!) {
        updateViewscreenAuto(id: $id, auto: $auto)
      }
    `;
    const variables = {
      id,
      auto
    };
    this.props.client.mutate({
      mutation,
      variables
    });
  };
  render() {
    if (this.props.data.loading || !this.props.data.viewscreens) return null;
    const { viewscreens } = this.props.data;
    const {
      selectedViewscreen = null,
      preview,
      previewComponent,
      configData
    } = this.state;
    const LayoutComponent =
      Layouts[this.props.simulator.layout + "Viewscreen"] ||
      Layouts[this.props.simulator.layout] ||
      (({ children }) =>
{children}
);
    if (!viewscreens) return
No Viewscreens
;
    return (

          {selectedViewscreen && (
            <LayoutComponent
              clientObj={{}}
              flight={{}}
              simulator={this.props.simulator}
              station={{}}
              cardName={"Viewscreen"}
            >
              <Preview
                simulator={this.props.simulator}
                flightId={this.props.flightId}
                clientObj={{ id: selectedViewscreen }}
              />
            </LayoutComponent>
          )}

          {previewComponent && (
            <LayoutComponent
              clientObj={{}}
              flight={{}}
              simulator={this.props.simulator}
              station={{}}
              cardName={"Viewscreen"}
            >
              <CardPreview
                simulator={this.props.simulator}
                component={previewComponent}
                flightId={this.props.flightId}
                viewscreen={{ data: configData }}
              />
            </LayoutComponent>
          )}

            <Row>
              <Col sm={6}>
                Viewscreen
                <Input
                  type="select"
                  size="sm"
                  value={selectedViewscreen || "select"}
                  onChange={evt => {
                    this.setState({ selectedViewscreen: evt.target.value });
                  }}
                >
                  <option value="select">Select a viewscreen</option>
                  {viewscreens.map(v => (
                    <option key={v.id} value={v.id}>
                      {v.name}
                    </option>
                  ))}
                </Input>

                  <input
                    type="checkbox"
                    checked={
                      selectedViewscreen &&
                      viewscreens.length &&
                      viewscreens.find(v => v.id === selectedViewscreen).auto
                    }
                    onChange={this.toggleAuto}
                  />{" "}
                  Auto-switch generic tactical cards

              </Col>
              <Col sm={6}>
                Cards

                  {this.cards.map(c => (

 v.id === selectedViewscreen) &&
                      viewscreens.find(v => v.id === selectedViewscreen)
                        .component === c
                        ? "previewing"
                        : ""} ${previewComponent === c ? "selected" : ""}`}
                      onClick={() =>
                        preview
                          ? this.setState({ previewComponent: c })
                          : this.updateCard(c)}
                    >
                      {c}

                  ))}

                <ButtonGroup>
                  <Button
                    color="primary"
                    className={preview ? "active" : ""}
                    onClick={() => this.setState({ preview: true })}
                  >
                    Preview
                  </Button>
                  <Button
                    color="info"
                    onClick={() => this.updateCard(previewComponent)}
                  >
                    Go
                  </Button>
                  <Button
                    color="success"
                    className={!preview ? "active" : ""}
                    onClick={() => this.setState({ preview: false })}
                  >
                    Change
                  </Button>
                </ButtonGroup>
              </Col>
            </Row>

            Config
            <Row>
              <Col sm={6}>
                Current Viewscreen
                {(() => {
                  const viewscreen =
                    selectedViewscreen &&
                    viewscreens.find(v => v.id === selectedViewscreen);
                  const currentComponent = viewscreen && viewscreen.component;
                  const currentData = viewscreen && viewscreen.data;
                  if (this.configs.indexOf(`${currentComponent}Config`) > -1) {
                    const ConfigComponent =
                      ViewscreenCards[`${currentComponent}Config`];
                    return (
                      <ConfigComponent
                        simulator={this.props.simulator}
                        flightId={this.props.flightId}
                        data={currentData}
                        updateData={this.updateData}
                      />
                    );
                  }
                  return
No config for this component
;
                })()}
              </Col>
              <Col sm={6}>
                Preview Viewscreen
                {(() => {
                  if (this.configs.indexOf(`${previewComponent}Config`) > -1) {
                    const ConfigComponent =
                      ViewscreenCards[`${previewComponent}Config`];
                    return (
                      <ConfigComponent
                        simulator={this.props.simulator}
                        flightId={this.props.flightId}
                        data={configData}
                        updateData={data => this.setState({ configData: data })}
                        selectedClient={selectedViewscreen}
                      />
                    );
                  }
                  return
No config for this component
;
                })()}
              </Col>
            </Row>

    );
  }
}

const VIEWSCREEN_QUERY = gql`
  query Viewscreens($simulatorId: ID) {
    viewscreens(simulatorId: $simulatorId) {
      id
      name
      component
      data
      auto
    }
  }
`;
export default graphql(VIEWSCREEN_QUERY, {
  options: ownProps => ({
    variables: {
      simulatorId: ownProps.simulator.id
    }
  })
})(withApollo(ViewscreenCore));
<|endoftext|>


<commit_before>const {type} = require('message-type')
const config = require('./server/init/configuration')
const canvasApi = require('canvas-api')(config.full.canvas.apiUrl, config.secure.canvas.apiKey)
var Promise = require('bluebird')
const fs = require('fs')
const colors = require('colors')

function _handleError(err,sisCourseCode) {
    let eCode = err.statusCode
    if (eCode === 404) // The course code is not in canvas, do nothing.....
    {
      console.warn("Course does not exist in canvas, skipping, ".red + sisCourseCode.red)
      return Promise.resolve("Course does not exist in canvas")
    }

    if (eCode >= 400) // Besides course not in Canvas, Probably an other type of problem with canvas.....
    {
      console.warn("Canvas is not accessable, Invalid token or other Canvas related errors..... ".red + sisCourseCode.red)
    }
    else { //It is an error and unrelated to the Canvas HTTP requests, probably IO errors
      console.warn("Other error..... ".red + sisCourseCode.red)
    }

    return Promise.reject(err)
}

function _createCsvFile(msg,sisCourseCode) {
  let d = Date.now();
  let header = 'course_id,user_id,role,status\n'
  let msgtype = msg._desc.userType
  let fileName = 'enrollments.' + msgtype + '.' + sisCourseCode + "." + d
  let csvFileName = "./CSV/" + fileName + ".csv"
  let msgFileName = "./MSG/" + fileName + ".msg"
  let csvString = ""

if (msg.member && msg.member.length > 0)
{
let csvArray = msg.member.map(user => {
  csvObj = {}
  csvObj["course_id"] = sisCourseCode
  csvObj["user_id"] = user
  csvObj["role"] = msgtype
  csvObj["status"] =  "active"
  return csvObj
})
csvArray.forEach(csvRow=> csvString = csvString + `${csvRow.course_id},${csvRow.user_id},${csvRow.role},${csvRow.status}\n`)
}

let csvData = header + csvString
console.info('\nGoing to open file: ' + csvFileName + ' ' + msgFileName)
fs.writeFileSync(csvFileName, csvData, 'utf8') // we are in a promise chain, if error thrown it shoud be cateched in error handling funciton
fs.writeFileSync(msgFileName, msg, 'utf8')
return {"csvContent": csvData, "csvFileName": csvFileName}

}

function _process (msg) {
   let course = null
   let termin = null
   let year = null
   let ladok = null
   let sisCourseCode = null
   let myRe = null
   let myArray = []
   let msgtype = msg._desc.userType

  if (msgtype === type.students) { // ladok2.kurser.DM.2517.registrerade_20162.1
    myRe = /^(\w+).(\w+).(\w+).(\w+).(\w+)_(\d\d)(\d\d)(\d).(\d+)/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseInOne = 3
      let courseInTwo = 4
      let terminIn = 8
      let yearIn = 7
      let ladokIn = 9
      course = myArray[courseInOne] + myArray[courseInTwo]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve("Key parse error, Student")
    }
  }

  if (msgtype === type.teachers || msgtype === type.assistants) { // edu.courses.AE.AE2302.20162.1.teachers edu.courses.DD.DD1310.20162.1.assistants
    myRe = /^edu.courses.(\w+).(\w+).(\d\d)(\d\d)(\d).(\d).(\w+)$/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseIn = 2
      let terminIn = 5
      let yearIn = 4
      let ladokIn = 6
      course = myArray[courseIn]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    }
    else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve("Key parse error, Teacher or Assistant")
    }
  }

  console.info(`\nIn _process ${sisCourseCode}, processing for ${msgtype}`)

          return canvasApi.findCourse(sisCourseCode)
          .then(() => _createCsvFile(msg,sisCourseCode))
          .then(csvObject=>{console.log(csvObject.csvContent); return csvObject.csvFileName })
          .then(fileName => canvasApi.sendCsvFile(fileName))
          .then(canvasReturnValue => console.log(canvasReturnValue, null, 4))
          .catch(error => _handleError(error,sisCourseCode))
        }

module.exports = function (msg) {
  console.info('\nProcessing for msg..... ' + msg.ug1Name)
  var msgtype = msg._desc.userType
  if (msg._desc && (msgtype === type.students || msgtype === type.teachers || msgtype === type.assistants)) {
    return _process(msg)
  }
  else {
    console.warn('\nThis is something else than students, teacher, assistant, we can probably wait with this until the students is handled', JSON.stringify(msg, null, 4))
    return Promise.resolve("Unknown flag: " + msgtype)
  }
}
<commit_msg>changed a var to const on Promise library<commit_after>const {type} = require('message-type')
const config = require('./server/init/configuration')
const canvasApi = require('canvas-api')(config.full.canvas.apiUrl, config.secure.canvas.apiKey)
const Promise = require('bluebird')
const fs = require('fs')
const colors = require('colors')

function _handleError(err,sisCourseCode) {
    let eCode = err.statusCode
    if (eCode === 404) // The course code is not in canvas, do nothing.....
    {
      console.warn("Course does not exist in canvas, skipping, ".red + sisCourseCode.red)
      return Promise.resolve("Course does not exist in canvas")
    }

    if (eCode >= 400) // Besides course not in Canvas, Probably an other type of problem with canvas.....
    {
      console.warn("Canvas is not accessable, Invalid token or other Canvas related errors..... ".red + sisCourseCode.red)
    }
    else { //It is an error and unrelated to the Canvas HTTP requests, probably IO errors
      console.warn("Other error..... ".red + sisCourseCode.red)
    }

    return Promise.reject(err)
}

function _createCsvFile(msg,sisCourseCode) {
  let d = Date.now();
  let header = 'course_id,user_id,role,status\n'
  let msgtype = msg._desc.userType
  let fileName = 'enrollments.' + msgtype + '.' + sisCourseCode + "." + d
  let csvFileName = "./CSV/" + fileName + ".csv"
  let msgFileName = "./MSG/" + fileName + ".msg"
  let csvString = ""

if (msg.member && msg.member.length > 0)
{
let csvArray = msg.member.map(user => {
  csvObj = {}
  csvObj["course_id"] = sisCourseCode
  csvObj["user_id"] = user
  csvObj["role"] = msgtype
  csvObj["status"] =  "active"
  return csvObj
})
csvArray.forEach(csvRow=> csvString = csvString + `${csvRow.course_id},${csvRow.user_id},${csvRow.role},${csvRow.status}\n`)
}

let csvData = header + csvString
console.info('\nGoing to open file: ' + csvFileName + ' ' + msgFileName)
fs.writeFileSync(csvFileName, csvData, 'utf8') // we are in a promise chain, if error thrown it shoud be cateched in error handling funciton
fs.writeFileSync(msgFileName, msg, 'utf8')
return {"csvContent": csvData, "csvFileName": csvFileName}

}

function _process (msg) {
   let course = null
   let termin = null
   let year = null
   let ladok = null
   let sisCourseCode = null
   let myRe = null
   let myArray = []
   let msgtype = msg._desc.userType

  if (msgtype === type.students) { // ladok2.kurser.DM.2517.registrerade_20162.1
    myRe = /^(\w+).(\w+).(\w+).(\w+).(\w+)_(\d\d)(\d\d)(\d).(\d+)/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseInOne = 3
      let courseInTwo = 4
      let terminIn = 8
      let yearIn = 7
      let ladokIn = 9
      course = myArray[courseInOne] + myArray[courseInTwo]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    } else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve("Key parse error, Student")
    }
  }

  if (msgtype === type.teachers || msgtype === type.assistants) { // edu.courses.AE.AE2302.20162.1.teachers edu.courses.DD.DD1310.20162.1.assistants
    myRe = /^edu.courses.(\w+).(\w+).(\d\d)(\d\d)(\d).(\d).(\w+)$/g
    myArray = myRe.exec(msg.ug1Name)
    if (myArray != null) {
      let courseIn = 2
      let terminIn = 5
      let yearIn = 4
      let ladokIn = 6
      course = myArray[courseIn]
      termin = myArray[terminIn] === 1 ? 'HT' : 'VT'
      year = myArray[yearIn]
      ladok = myArray[ladokIn]
      sisCourseCode = course + termin + year + ladok
    }
    else { // failed to parse course
      console.warn('\nCourse code not parsable from ug1Name structure: ' + msg.ug1Name)
      return Promise.resolve("Key parse error, Teacher or Assistant")
    }
  }

  console.info(`\nIn _process ${sisCourseCode}, processing for ${msgtype}`)

          return canvasApi.findCourse(sisCourseCode)
          .then(() => _createCsvFile(msg,sisCourseCode))
          .then(csvObject=>{console.log(csvObject.csvContent); return csvObject.csvFileName })
          .then(fileName => canvasApi.sendCsvFile(fileName))
          .then(canvasReturnValue => console.log(canvasReturnValue, null, 4))
          .catch(error => _handleError(error,sisCourseCode))
        }

module.exports = function (msg) {
  console.info('\nProcessing for msg..... ' + msg.ug1Name)
  var msgtype = msg._desc.userType
  if (msg._desc && (msgtype === type.students || msgtype === type.teachers || msgtype === type.assistants)) {
    return _process(msg)
  }
  else {
    console.warn('\nThis is something else than students, teacher, assistant, we can probably wait with this until the students is handled', JSON.stringify(msg, null, 4))
    return Promise.resolve("Unknown flag: " + msgtype)
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name openshiftConsole.controller:PodsController
 * @description
 * # ProjectController
 * Controller of the openshiftConsole
 */
angular.module('openshiftConsole')
  .controller('CatalogImagesController', function ($scope, DataService, $filter, LabelFilter, imageEnvFilter, $routeParams, Logger) {
    $scope.builders = [];
    $scope.nonBuilders = [];
    $scope.sourceURL = $routeParams.builderfor;
    $scope.loaded = false;

    // Image repositories for this project.
    var projectImageRepos;

    // Image repositories in the openshift namespace.
    var openshiftImageRepos;

    var isBuilder = function(imageRepo, tag) {
      if (!imageRepo.spec || !imageRepo.spec.tags) {
        return false;
      }

      var i, imageTagSpec, categoryTags;
      for (i = 0; i < imageRepo.spec.tags.length; i++) {
        imageTagSpec = imageRepo.spec.tags[i];
        if (imageTagSpec.name === tag && imageTagSpec.annotations && imageTagSpec.annotations.tags) {
          categoryTags = imageTagSpec.annotations.tags.split(/\s*,\s*/);
          if (categoryTags.indexOf("builder") >= 0) {
            return true;
          }
        }
      }
    };

    var imagesForRepos = function(imageRepos, scope) {
      var tagAnnotationFilter = $filter('imageStreamTagAnnotation');
      angular.forEach(imageRepos, function(imageRepo) {
        if (imageRepo.status) {
          angular.forEach(imageRepo.status.tags, function(tag) {
            var imageRepoTag = tag.tag;
            var image = {
              imageRepo: imageRepo,
              imageRepoTag: imageRepoTag,
              name: imageRepo.metadata.name + ":" + imageRepoTag,
              version: tagAnnotationFilter(imageRepo, 'version', imageRepoTag)
            };

            if (isBuilder(imageRepo, imageRepoTag)) {
              $scope.builders.push(image);
            } else {
              $scope.nonBuilders.push(image);
            }
          });
        }
      });
      Logger.info("builders", $scope.builders);
    };

    var checkIfLoaded = function() {
      // Set loaded to true only if both openshift image repos and project
      // image repos have been loaded.
      $scope.loaded = openshiftImageRepos && projectImageRepos;
    };

    DataService.list("imagestreams", $scope, function(imageRepos) {
      projectImageRepos = imageRepos.by("metadata.name");
      imagesForRepos(projectImageRepos, $scope);
      checkIfLoaded();

      Logger.info("project image repos", projectImageRepos);
    });

    DataService.list("imagestreams", {namespace: "openshift"}, function(imageRepos) {
      openshiftImageRepos = imageRepos.by("metadata.name");
      imagesForRepos(openshiftImageRepos, {namespace: "openshift"});
      checkIfLoaded();

      Logger.info("openshift image repos", openshiftImageRepos);
    });

    var templatesByTag = function() {
      $scope.templatesByTag = {};
      angular.forEach($scope.templates, function(template) {
        if (template.metadata.annotations && template.metadata.annotations.tags) {
          var tags = template.metadata.annotations.tags.split(",");
          angular.forEach(tags, function(tag){
            tag = $.trim(tag);
            // not doing this as a map since we are dealing with things across namespaces that could have collisions on name
            $scope.templatesByTag[tag] = $scope.templatesByTag[tag] || [];
            $scope.templatesByTag[tag].push(template);
          });
        }
      });

      Logger.info("templatesByTag", $scope.templatesByTag);
    };
  });
<commit_msg>Remove unused function in CatalogImagesController<commit_after>'use strict';

/**
 * @ngdoc function
 * @name openshiftConsole.controller:PodsController
 * @description
 * # ProjectController
 * Controller of the openshiftConsole
 */
angular.module('openshiftConsole')
  .controller('CatalogImagesController', function ($scope, DataService, $filter, LabelFilter, imageEnvFilter, $routeParams, Logger) {
    $scope.builders = [];
    $scope.nonBuilders = [];
    $scope.sourceURL = $routeParams.builderfor;
    $scope.loaded = false;

    // Image repositories for this project.
    var projectImageRepos;

    // Image repositories in the openshift namespace.
    var openshiftImageRepos;

    var isBuilder = function(imageRepo, tag) {
      if (!imageRepo.spec || !imageRepo.spec.tags) {
        return false;
      }

      var i, imageTagSpec, categoryTags;
      for (i = 0; i < imageRepo.spec.tags.length; i++) {
        imageTagSpec = imageRepo.spec.tags[i];
        if (imageTagSpec.name === tag && imageTagSpec.annotations && imageTagSpec.annotations.tags) {
          categoryTags = imageTagSpec.annotations.tags.split(/\s*,\s*/);
          if (categoryTags.indexOf("builder") >= 0) {
            return true;
          }
        }
      }
    };

    var imagesForRepos = function(imageRepos, scope) {
      var tagAnnotationFilter = $filter('imageStreamTagAnnotation');
      angular.forEach(imageRepos, function(imageRepo) {
        if (imageRepo.status) {
          angular.forEach(imageRepo.status.tags, function(tag) {
            var imageRepoTag = tag.tag;
            var image = {
              imageRepo: imageRepo,
              imageRepoTag: imageRepoTag,
              name: imageRepo.metadata.name + ":" + imageRepoTag,
              version: tagAnnotationFilter(imageRepo, 'version', imageRepoTag)
            };

            if (isBuilder(imageRepo, imageRepoTag)) {
              $scope.builders.push(image);
            } else {
              $scope.nonBuilders.push(image);
            }
          });
        }
      });
      Logger.info("builders", $scope.builders);
    };

    var checkIfLoaded = function() {
      // Set loaded to true only if both openshift image repos and project
      // image repos have been loaded.
      $scope.loaded = openshiftImageRepos && projectImageRepos;
    };

    DataService.list("imagestreams", $scope, function(imageRepos) {
      projectImageRepos = imageRepos.by("metadata.name");
      imagesForRepos(projectImageRepos, $scope);
      checkIfLoaded();

      Logger.info("project image repos", projectImageRepos);
    });

    DataService.list("imagestreams", {namespace: "openshift"}, function(imageRepos) {
      openshiftImageRepos = imageRepos.by("metadata.name");
      imagesForRepos(openshiftImageRepos, {namespace: "openshift"});
      checkIfLoaded();

      Logger.info("openshift image repos", openshiftImageRepos);
    });
  });
<|endoftext|>


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

/**
 * External dependencies
 */
import invariant from 'invariant';
import { detectAnyAdblocker } from 'just-detect-adblock';

/**
 * WordPress dependencies
 */
import { addQueryArgs } from '@wordpress/url';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';

// Actions
const CHECK_ADBLOCKER = 'CHECK_ADBLOCKER';
const RECEIVE_IS_ADBLOCKER_ACTIVE = 'RECEIVE_IS_ADBLOCKER_ACTIVE';

export const initialState = {
	isAdBlockerActive: undefined,
};

export const actions = {
	*checkAdBlocker() {
		return yield {
			payload: {},
			type: CHECK_ADBLOCKER,
		};
	},
	receiveIsAdBlockerActive( isAdBlockerActive ) {
		invariant( 'boolean' === typeof isAdBlockerActive, 'isAdBlockerActive must be boolean.' );
		return {
			payload: { isAdBlockerActive },
			type: RECEIVE_IS_ADBLOCKER_ACTIVE,
		};
	},
};

export const controls = {
	[ CHECK_ADBLOCKER ]: async () => {
		if ( await detectAnyAdblocker() ) {
			return true;
		}
		// The above is good about detecting most adblockers.
		// For the rest, we'll make a placeholder request to the favicon with some
		// additional stuff in the query string to (hopefully) trigger a filter.
		// If this throws, then the fetch request failed completely and we'll assume it was blocked.
		try {
			await fetch(
				addQueryArgs(
					'/favicon.ico',
					{
						// The name of the parameter here doesn't really matter
						// since adblockers look at the URL as a whole.
						'google-site-kit': '/adsense/pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
						// Add a timestamp for cache-busting.
						timestamp: Date.now(),
					}
				),
				{
					credentials: 'omit',
					// Don't follow any redirects; we only care about this request being blocked or not.
					redirect: 'manual',
				}
			);
		} catch {
			return true;
		}
		return false;
	},
};

export const reducer = ( state, { payload, type } ) => {
	switch ( type ) {
		case RECEIVE_IS_ADBLOCKER_ACTIVE: {
			const { isAdBlockerActive } = payload;

			return {
				...state,
				isAdBlockerActive,
			};
		}

		default: {
			return state;
		}
	}
};

export const resolvers = {
	*isAdBlockerActive() {
		const registry = yield Data.commonActions.getRegistry();
		const isAdBlockerActive = registry.select( STORE_NAME ).isAdBlockerActive();

		// If ad blocker status was already detected, consider it fulfilled
		// and don't check the global.
		if ( undefined !== isAdBlockerActive ) {
			return;
		}

		const detected = yield actions.checkAdBlocker();

		yield actions.receiveIsAdBlockerActive( detected );
	},
};

export const selectors = {
	/**
	 * Returns whether an ad blocker is active on the client.
	 *
	 * @since 1.9.0
	 *
	 * @param {Object} state Data store's state.
	 * @return {boolean|undefined} True or false depending on whether an ad blocker is active; `undefined` if not loaded.
	 */
	isAdBlockerActive( state ) {
		const { isAdBlockerActive } = state;

		return isAdBlockerActive;
	},
};

export default {
	initialState,
	actions,
	controls,
	reducer,
	resolvers,
	selectors,
};
<commit_msg>Remove use of addQueryArgs.<commit_after>/**
 * `modules/adsense` data store: adblocker.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';
import { detectAnyAdblocker } from 'just-detect-adblock';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';

// Actions
const CHECK_ADBLOCKER = 'CHECK_ADBLOCKER';
const RECEIVE_IS_ADBLOCKER_ACTIVE = 'RECEIVE_IS_ADBLOCKER_ACTIVE';

export const initialState = {
	isAdBlockerActive: undefined,
};

export const actions = {
	*checkAdBlocker() {
		return yield {
			payload: {},
			type: CHECK_ADBLOCKER,
		};
	},
	receiveIsAdBlockerActive( isAdBlockerActive ) {
		invariant( 'boolean' === typeof isAdBlockerActive, 'isAdBlockerActive must be boolean.' );
		return {
			payload: { isAdBlockerActive },
			type: RECEIVE_IS_ADBLOCKER_ACTIVE,
		};
	},
};

export const controls = {
	[ CHECK_ADBLOCKER ]: async () => {
		if ( await detectAnyAdblocker() ) {
			return true;
		}
		// The above is good about detecting most adblockers.
		// For the rest, we'll make a placeholder request to the favicon with some
		// additional stuff in the query string to (hopefully) trigger a filter.
		// If this throws, then the fetch request failed completely and we'll assume it was blocked.
		try {
			const params = [
				// The name of the parameter here doesn't really matter
				// since adblockers look at the URL as a whole.
				// Note: this value must not be URL-encoded.
				'google-site-kit=/adsense/pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
				// Add a timestamp for cache-busting.
				`timestamp=${ Date.now() }`,
			];
			await fetch(
				`/favicon.ico?${ params.join( '&' ) }`,
				{
					credentials: 'omit',
					// Don't follow any redirects; we only care about this request being blocked or not.
					redirect: 'manual',
				}
			);
		} catch {
			return true;
		}
		return false;
	},
};

export const reducer = ( state, { payload, type } ) => {
	switch ( type ) {
		case RECEIVE_IS_ADBLOCKER_ACTIVE: {
			const { isAdBlockerActive } = payload;

			return {
				...state,
				isAdBlockerActive,
			};
		}

		default: {
			return state;
		}
	}
};

export const resolvers = {
	*isAdBlockerActive() {
		const registry = yield Data.commonActions.getRegistry();
		const isAdBlockerActive = registry.select( STORE_NAME ).isAdBlockerActive();

		// If ad blocker status was already detected, consider it fulfilled
		// and don't check the global.
		if ( undefined !== isAdBlockerActive ) {
			return;
		}

		const detected = yield actions.checkAdBlocker();

		yield actions.receiveIsAdBlockerActive( detected );
	},
};

export const selectors = {
	/**
	 * Returns whether an ad blocker is active on the client.
	 *
	 * @since 1.9.0
	 *
	 * @param {Object} state Data store's state.
	 * @return {boolean|undefined} True or false depending on whether an ad blocker is active; `undefined` if not loaded.
	 */
	isAdBlockerActive( state ) {
		const { isAdBlockerActive } = state;

		return isAdBlockerActive;
	},
};

export default {
	initialState,
	actions,
	controls,
	reducer,
	resolvers,
	selectors,
};
<|endoftext|>


<commit_before>/*
*  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
*  Use of this source code is governed by a BSD-style license
*  that can be found in the LICENSE file in the root of the source
*  tree.
*/

// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html

'use strict';

/* globals MediaRecorder */

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const recordedVideo = document.querySelector('video#recorded');
recordedVideo.addEventListener('error', function(ev) {
  console.error('MediaRecording.recordedMedia.error()');
  alert(`Your browser can not play ${recordedVideo.src} media clip. event: ${JSON.stringify(ev)}`);
}, true);

const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  // workaround for non-seekable video taken from
  // https://bugs.chromium.org/p/chromium/issues/detail?id=642012#c23
  recordedVideo.addEventListener('loadedmetadata', () => {
    if (recordedVideo.duration === Infinity) {
      recordedVideo.currentTime = 1e101;
      recordedVideo.ontimeupdate = function() {
        recordedVideo.currentTime = 0;
        recordedVideo.ontimeupdate = function() {
          delete recordedVideo.ontimeupdate;
          recordedVideo.play();
        };
      };
    }
  });
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

// window.isSecureContext could be used for Chrome
let isSecureOrigin = location.protocol === 'https:' || location.hostname === 'localhost';
if (!isSecureOrigin) {
  alert('getUserMedia() must be run from a secure origin: HTTPS or localhost.\n\nChanging protocol to HTTPS');
  location.protocol = 'HTTPS';
}

const constraints = {
  audio: true,
  video: true
};

function handleSourceOpen(event) {
  console.log('MediaSource opened');
  sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
  console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function handleStop(event) {
  console.log('Recorder stopped: ', event);
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9'};
  if (!MediaRecorder.isTypeSupported(options.mimeType)) {
    console.log(options.mimeType + ' is not Supported');
    options = {mimeType: 'video/webm;codecs=vp8'};
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.log(options.mimeType + ' is not Supported');
      options = {mimeType: 'video/webm'};
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.log(options.mimeType + ' is not Supported');
        options = {mimeType: ''};
      }
    }
  }
  try {
    mediaRecorder = new MediaRecorder(window.stream, options);
  } catch (e) {
    console.error(`Exception while creating MediaRecorder: ${e}`);
    alert(`Exception while creating MediaRecorder: ${e}. mimeType: ${options.mimeType}`);
    return;
  }
  console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
  recordButton.textContent = 'Stop Recording';
  playButton.disabled = true;
  downloadButton.disabled = true;
  mediaRecorder.onstop = handleStop;
  mediaRecorder.ondataavailable = handleDataAvailable;
  mediaRecorder.start(10); // collect 10ms of data
  console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
  mediaRecorder.stop();
  console.log('Recorded Blobs: ', recordedBlobs);
  recordedVideo.controls = true;
}

function handleSuccess(stream) {
  recordButton.disabled = false;
  console.log('getUserMedia() got stream: ', stream);
  window.stream = stream;

  const gumVideo = document.querySelector('video#gum');
  gumVideo.srcObject = stream;
}

function handleError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
<commit_msg>recording: fix demo in firefox<commit_after>/*
*  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
*  Use of this source code is governed by a BSD-style license
*  that can be found in the LICENSE file in the root of the source
*  tree.
*/

// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html

'use strict';

/* globals MediaRecorder */

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const recordedVideo = document.querySelector('video#recorded');
recordedVideo.addEventListener('error', function(ev) {
  console.error('MediaRecording.recordedMedia.error()');
  alert(`Your browser can not play ${recordedVideo.src} media clip. event: ${JSON.stringify(ev)}`);
}, true);

const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  // workaround for non-seekable video taken from
  // https://bugs.chromium.org/p/chromium/issues/detail?id=642012#c23
  recordedVideo.addEventListener('loadedmetadata', () => {
    if (recordedVideo.duration === Infinity) {
      recordedVideo.currentTime = 1e101;
      recordedVideo.ontimeupdate = function() {
        recordedVideo.currentTime = 0;
        recordedVideo.ontimeupdate = function() {
          delete recordedVideo.ontimeupdate;
          recordedVideo.play();
        };
      };
    } else {
      recordedVideo.play();
    }
  });
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

// window.isSecureContext could be used for Chrome
let isSecureOrigin = location.protocol === 'https:' || location.hostname === 'localhost';
if (!isSecureOrigin) {
  alert('getUserMedia() must be run from a secure origin: HTTPS or localhost.\n\nChanging protocol to HTTPS');
  location.protocol = 'HTTPS';
}

const constraints = {
  audio: true,
  video: true
};

function handleSourceOpen(event) {
  console.log('MediaSource opened');
  sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
  console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function handleStop(event) {
  console.log('Recorder stopped: ', event);
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9'};
  if (!MediaRecorder.isTypeSupported(options.mimeType)) {
    console.log(options.mimeType + ' is not Supported');
    options = {mimeType: 'video/webm;codecs=vp8'};
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.log(options.mimeType + ' is not Supported');
      options = {mimeType: 'video/webm'};
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.log(options.mimeType + ' is not Supported');
        options = {mimeType: ''};
      }
    }
  }
  try {
    mediaRecorder = new MediaRecorder(window.stream, options);
  } catch (e) {
    console.error(`Exception while creating MediaRecorder: ${e}`);
    alert(`Exception while creating MediaRecorder: ${e}. mimeType: ${options.mimeType}`);
    return;
  }
  console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
  recordButton.textContent = 'Stop Recording';
  playButton.disabled = true;
  downloadButton.disabled = true;
  mediaRecorder.onstop = handleStop;
  mediaRecorder.ondataavailable = handleDataAvailable;
  mediaRecorder.start(10); // collect 10ms of data
  console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
  mediaRecorder.stop();
  console.log('Recorded Blobs: ', recordedBlobs);
  recordedVideo.controls = true;
}

function handleSuccess(stream) {
  recordButton.disabled = false;
  console.log('getUserMedia() got stream: ', stream);
  window.stream = stream;

  const gumVideo = document.querySelector('video#gum');
  gumVideo.srcObject = stream;
}

function handleError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
<|endoftext|>


<commit_before>/*
*  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
*  Use of this source code is governed by a BSD-style license
*  that can be found in the LICENSE file in the root of the source
*  tree.
*/

// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html

'use strict';

/* globals MediaRecorder */

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
  recordedVideo.src = null;
  recordedVideo.srcObject = null;
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  recordedVideo.controls = true;
  recordedVideo.play();
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

function handleSourceOpen(event) {
  console.log('MediaSource opened');
  sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
  console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9'};
  if (!MediaRecorder.isTypeSupported(options.mimeType)) {
    console.error(`${options.mimeType} is not Supported`);
    errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
    options = {mimeType: 'video/webm;codecs=vp8'};
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.error(`${options.mimeType} is not Supported`);
      errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
      options = {mimeType: 'video/webm'};
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not Supported`);
        errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
        options = {mimeType: ''};
      }
    }
  }

  try {
    mediaRecorder = new MediaRecorder(window.stream, options);
  } catch (e) {
    console.error('Exception while creating MediaRecorder:', e);
    errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;
    return;
  }

  console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
  recordButton.textContent = 'Stop Recording';
  playButton.disabled = true;
  downloadButton.disabled = true;
  mediaRecorder.onstop = (event) => {
    console.log('Recorder stopped: ', event);
  };
  mediaRecorder.ondataavailable = handleDataAvailable;
  mediaRecorder.start(10); // collect 10ms of data
  console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
  mediaRecorder.stop();
  console.log('Recorded Blobs: ', recordedBlobs);
}

function handleSuccess(stream) {
  recordButton.disabled = false;
  console.log('getUserMedia() got stream:', stream);
  window.stream = stream;

  const gumVideo = document.querySelector('video#gum');
  gumVideo.srcObject = stream;
}

async function init(constraints) {
  try {
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    handleSuccess(stream);
  } catch (e) {
    console.error('navigator.getUserMedia error:', e);
    errorMsgElement.innerHTML = `navigator.getUserMedia error:${e.toString()}`;
  }
}

document.querySelector('button#start').addEventListener('click', async() => {
  const hasEchoCancellation = document.querySelector('#echoCancellation').checked;
  const constraints = {
    audio: {
      echoCancellation: {exact: hasEchoCancellation}
    },
    video: {
      width: 1280, height: 720
    }
  };
  console.log('Using media constraints:', constraints);
  await init(constraints);
});
<commit_msg>Fix lint error<commit_after>/*
*  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
*  Use of this source code is governed by a BSD-style license
*  that can be found in the LICENSE file in the root of the source
*  tree.
*/

// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html

'use strict';

/* globals MediaRecorder */

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
  recordedVideo.src = null;
  recordedVideo.srcObject = null;
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  recordedVideo.controls = true;
  recordedVideo.play();
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

function handleSourceOpen(event) {
  console.log('MediaSource opened');
  sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
  console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9'};
  if (!MediaRecorder.isTypeSupported(options.mimeType)) {
    console.error(`${options.mimeType} is not Supported`);
    errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
    options = {mimeType: 'video/webm;codecs=vp8'};
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.error(`${options.mimeType} is not Supported`);
      errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
      options = {mimeType: 'video/webm'};
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not Supported`);
        errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
        options = {mimeType: ''};
      }
    }
  }

  try {
    mediaRecorder = new MediaRecorder(window.stream, options);
  } catch (e) {
    console.error('Exception while creating MediaRecorder:', e);
    errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;
    return;
  }

  console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
  recordButton.textContent = 'Stop Recording';
  playButton.disabled = true;
  downloadButton.disabled = true;
  mediaRecorder.onstop = (event) => {
    console.log('Recorder stopped: ', event);
  };
  mediaRecorder.ondataavailable = handleDataAvailable;
  mediaRecorder.start(10); // collect 10ms of data
  console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
  mediaRecorder.stop();
  console.log('Recorded Blobs: ', recordedBlobs);
}

function handleSuccess(stream) {
  recordButton.disabled = false;
  console.log('getUserMedia() got stream:', stream);
  window.stream = stream;

  const gumVideo = document.querySelector('video#gum');
  gumVideo.srcObject = stream;
}

async function init(constraints) {
  try {
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    handleSuccess(stream);
  } catch (e) {
    console.error('navigator.getUserMedia error:', e);
    errorMsgElement.innerHTML = `navigator.getUserMedia error:${e.toString()}`;
  }
}

document.querySelector('button#start').addEventListener('click', async () => {
  const hasEchoCancellation = document.querySelector('#echoCancellation').checked;
  const constraints = {
    audio: {
      echoCancellation: {exact: hasEchoCancellation}
    },
    video: {
      width: 1280, height: 720
    }
  };
  console.log('Using media constraints:', constraints);
  await init(constraints);
});
<|endoftext|>


<commit_before>describe("Player", function() {
    it("has name", function () {
        var player = {},
            pubsubSpy = {
                on: jasmine.createSpy()
            }
            ;

        Player({
            $: $,
            pubsub: pubsubSpy
        }, player);

        player.setName("foo");
        expect(player.getName()).toEqual("foo");
    });
});

describe("OppositePlayer", function () {
    it("inherits from player (has name)", function () {
        var pubsubSpy = {
                on: jasmine.createSpy()
            },
            player = OppositePlayer({
                $: $,
                pubsub: pubsubSpy
            });
            ;

        player.setName("foo");
        expect(player.getName()).toEqual("foo");
    });
});

describe("ControlledPlayer", function () {
    it("inherits from player (has name)", function () {
        var pubsubSpy = {
                on: jasmine.createSpy()
            },
            player = ControlledPlayer({
                $: $,
                pubsub: pubsubSpy
            });
            ;

        player.setName("bar");
        expect(player.getName()).toEqual("bar");
    });
});
<commit_msg>testPlayer: pass cardBuilder spy to palyers<commit_after>describe("Player", function() {
    var pubsubSpy,
        player = {}
        ;

    beforeEach(function() {
        pubsubSpy = {
            on: jasmine.createSpy()
        };

        Player({
            $: $,
            pubsub: pubsubSpy,
            cardBuilder: {
                get: jasmine.createSpy().andReturn($('<div>')),
                getBackside: jasmine.createSpy().andReturn($('<div>')),
                getCardWidth: jasmine.createSpy().andReturn(100),
                getCardHeight: jasmine.createSpy().andReturn(200),
            }
        }, player);
    });

    it("has name", function () {
        player.setName("foo");
        expect(player.getName()).toEqual("foo");
    });
});

describe("OppositePlayer", function () {
    var pubsubSpy,
        player
        ;

    beforeEach(function() {
        pubsubSpy = {
            on: jasmine.createSpy()
        };

        player = OppositePlayer({
            $: $,
            pubsub: pubsubSpy,
            cardBuilder: {
                get: jasmine.createSpy().andReturn($('<div>')),
                getBackside: jasmine.createSpy().andReturn($('<div>')),
                getCardWidth: jasmine.createSpy().andReturn(100),
                getCardHeight: jasmine.createSpy().andReturn(200),
            }
        });
    });

    it("inherits from player (has name)", function () {
        player.setName("foo");
        expect(player.getName()).toEqual("foo");
    });
});

describe("ControlledPlayer", function () {
    var pubsubSpy,
        player
        ;

    beforeEach(function() {
        pubsubSpy = {
            on: jasmine.createSpy()
        };

        player = ControlledPlayer({
            $: $,
            pubsub: pubsubSpy,
            cardBuilder: {
                get: jasmine.createSpy().andReturn($('<div>')),
                getBackside: jasmine.createSpy().andReturn($('<div>')),
                getCardWidth: jasmine.createSpy().andReturn(100),
                getCardHeight: jasmine.createSpy().andReturn(200),
            }
        });
    });

    it("inherits from player (has name)", function () {
        player.setName("bar");
        expect(player.getName()).toEqual("bar");
    });
});
<|endoftext|>


<commit_before>(function() {
  init();

  function init() {
    var jsonTimestamp = new Promise(function(resolve, reject) {
      getLatestSHA().then(function(response) {
        var sha = JSON.parse(response)[0].sha;
        var cdn =
          "https://cdn.rawgit.com/tsitu/MH-Tools/" +
          sha +
          "/data/bookmarklet-timestamps.json";
        var xhr = new XMLHttpRequest();
        xhr.open("GET", cdn);
        xhr.onload = function() {
          resolve(xhr.responseText);
        };
        xhr.onerror = function() {
          reject(xhr.statusText);
        };
        xhr.send();
      });
    });

    jsonTimestamp.then(function(response) {
      buildUI(JSON.parse(response));
    });
  }

  function buildUI(timestamps) {
    var mainDiv = document.createElement("div");
    mainDiv.id = "mht-bookmarklet-loader";
    var loaderTimestamp = "Last updated: " + timestamps["loader"];
    var creTimestamp = "Last updated: " + timestamps["cre"];
    var mapTimestamp = "Last updated: " + timestamps["map"];
    var setupTimestamp = "Last updated: " + timestamps["setup"];
    var setupFieldsTimestamp = "Last updated: " + timestamps["setupfields"];
    var analyzerTimestamp = "Last updated: " + timestamps["analyzer"];
    var crownTimestamp = "Last updated: " + timestamps["crown"];
    var craftingTimestamp = "Last updated: " + timestamps["crafting"];

    var closeButton = document.createElement("button", { id: "close-button" });
    closeButton.textContent = "x";
    closeButton.onclick = function() {
      document.body.removeChild(mainDiv);
    };

    var titleSpan = document.createElement("span");
    titleSpan.style.fontSize = "15px";
    titleSpan.style.fontWeight = "bold";
    titleSpan.appendChild(document.createTextNode("MH Tools Bookmarklets"));

    var descriptionSpan = document.createElement("span");
    descriptionSpan.innerHTML =
      "Version 1.2.2 / Using RawGit";
    var loaderSpanTimestamp = document.createElement("span");
    loaderSpanTimestamp.style.fontSize = "10px";
    loaderSpanTimestamp.style.fontStyle = "italic";
    loaderSpanTimestamp.innerHTML = loaderTimestamp;

    var creButton = document.createElement("button", { id: "cre-button" });
    creButton.textContent = "Catch Rate Estimator";
    creButton.onclick = function() {
      loadBookmarklet("cre");
    };
    var creSpanTimestamp = document.createElement("span");
    creSpanTimestamp.style.fontSize = "10px";
    creSpanTimestamp.style.fontStyle = "italic";
    creSpanTimestamp.innerHTML = creTimestamp;

    var mapButton = document.createElement("button", { id: "map-button" });
    mapButton.textContent = "Map Solver";
    mapButton.onclick = function() {
      loadBookmarklet("map");
    };
    var mapSpanTimestamp = document.createElement("span");
    mapSpanTimestamp.style.fontSize = "10px";
    mapSpanTimestamp.style.fontStyle = "italic";
    mapSpanTimestamp.innerHTML = mapTimestamp;

    var setupButton = document.createElement("button", { id: "setup-button" });
    setupButton.textContent = "Best Setup: Load Items";
    setupButton.onclick = function() {
      loadBookmarklet("setup");
    };
    var setupSpanTimestamp = document.createElement("span");
    setupSpanTimestamp.style.fontSize = "10px";
    setupSpanTimestamp.style.fontStyle = "italic";
    setupSpanTimestamp.innerHTML = setupTimestamp;

    var setupFieldsButton = document.createElement("button", {
      id: "setup-fields-button"
    });
    setupFieldsButton.textContent = "Best Setup: Fields";
    setupFieldsButton.onclick = function() {
      loadBookmarklet("setupfields");
    };
    var setupFieldsSpanTimestamp = document.createElement("span");
    setupFieldsSpanTimestamp.style.fontSize = "10px";
    setupFieldsSpanTimestamp.style.fontStyle = "italic";
    setupFieldsSpanTimestamp.innerHTML = setupFieldsTimestamp;

    var analyzerButton = document.createElement("button", {
      id: "analyzer-button"
    });
    analyzerButton.textContent = "Marketplace Analyzer";
    analyzerButton.onclick = function() {
      loadBookmarklet("analyzer");
    };
    var analyzerSpanTimestamp = document.createElement("span");
    analyzerSpanTimestamp.style.fontSize = "10px";
    analyzerSpanTimestamp.style.fontStyle = "italic";
    analyzerSpanTimestamp.innerHTML = analyzerTimestamp;

    var crownButton = document.createElement("button", { id: "crown-button" });
    crownButton.textContent = "Silver Crown Solver";
    crownButton.onclick = function() {
      loadBookmarklet("crown");
    };
    var crownSpanTimestamp = document.createElement("span");
    crownSpanTimestamp.style.fontSize = "10px";
    crownSpanTimestamp.style.fontStyle = "italic";
    crownSpanTimestamp.innerHTML = crownTimestamp;

    var craftingButton = document.createElement("button", {
      id: "crafting-button"
    });
    craftingButton.textContent = "Crafting Wizard";
    craftingButton.onclick = function() {
      loadBookmarklet("crafting");
    };
    var craftingSpanTimestamp = document.createElement("span");
    craftingSpanTimestamp.style.fontSize = "10px";
    craftingSpanTimestamp.style.fontStyle = "italic";
    craftingSpanTimestamp.innerHTML = craftingTimestamp;

    mainDiv.appendChild(closeButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(titleSpan);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(descriptionSpan);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(loaderSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(creButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(creSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(mapButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(mapSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupFieldsButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupFieldsSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(analyzerButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(analyzerSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(crownButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(crownSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(craftingButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(craftingSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createTextNode("(Drag me around on a PC)"));

    mainDiv.style.backgroundColor = "#F5F5F5";
    mainDiv.style.position = "fixed";
    mainDiv.style.zIndex = "9999";
    // Allow customizable left position property
    mainDiv.style.left =
      typeof window.tsitu_loader_offset != "undefined"
        ? window.tsitu_loader_offset.concat("%")
        : "80%";
    mainDiv.style.top = "25px";
    mainDiv.style.border = "solid 3px #696969";
    mainDiv.style.borderRadius = "20px";
    mainDiv.style.padding = "10px";
    mainDiv.style.textAlign = "center";
    document.body.appendChild(mainDiv);
    dragElement(document.getElementById("mht-bookmarklet-loader"));
  }

  function getLatestSHA() {
    // Fetch latest gh-pages commit SHA to use with RawGit CDN since it caches URLs permanently
    return new Promise(function(resolve, reject) {
      var xhr = new XMLHttpRequest();
      xhr.open(
        "GET",
        "https://api.github.com/repos/tsitu/MH-Tools/commits?sha=gh-pages"
      );
      xhr.onload = function() {
        resolve(xhr.responseText);
      };
      xhr.onerror = function() {
        reject(xhr.statusText);
      };
      xhr.send();
    });
  }

  function loadBookmarklet(type) {
    getLatestSHA().then(function(response) {
      var sha = JSON.parse(response)[0].sha;
      var el = document.createElement("script");
      var cdn = "https://cdn.rawgit.com/tsitu/MH-Tools/";
      cdn += sha + "/src/bookmarklet/" + type + "bookmarklet.min.js";
      el.src = cdn;
      document.body.appendChild(el);
    });
  }

  function dragElement(el) {
    var pos1 = 0,
      pos2 = 0,
      pos3 = 0,
      pos4 = 0;
    if (document.getElementById(el.id + "header")) {
      document.getElementById(el.id + "header").onmousedown = dragMouseDown;
    } else {
      el.onmousedown = dragMouseDown;
    }

    function dragMouseDown(e) {
      e = e || window.event;
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
      e = e || window.event;
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      el.style.top = el.offsetTop - pos2 + "px";
      el.style.left = el.offsetLeft - pos1 + "px";
    }

    function closeDragElement() {
      document.onmouseup = null;
      document.onmousemove = null;
    }
  }
})();
<commit_msg>Bumped Auto-Loader version to 1.2.3<commit_after>(function() {
  init();

  function init() {
    var jsonTimestamp = new Promise(function(resolve, reject) {
      getLatestSHA().then(function(response) {
        var sha = JSON.parse(response)[0].sha;
        var cdn =
          "https://cdn.rawgit.com/tsitu/MH-Tools/" +
          sha +
          "/data/bookmarklet-timestamps.json";
        var xhr = new XMLHttpRequest();
        xhr.open("GET", cdn);
        xhr.onload = function() {
          resolve(xhr.responseText);
        };
        xhr.onerror = function() {
          reject(xhr.statusText);
        };
        xhr.send();
      });
    });

    jsonTimestamp.then(function(response) {
      buildUI(JSON.parse(response));
    });
  }

  function buildUI(timestamps) {
    var mainDiv = document.createElement("div");
    mainDiv.id = "mht-bookmarklet-loader";
    var loaderTimestamp = "Last updated: " + timestamps["loader"];
    var creTimestamp = "Last updated: " + timestamps["cre"];
    var mapTimestamp = "Last updated: " + timestamps["map"];
    var setupTimestamp = "Last updated: " + timestamps["setup"];
    var setupFieldsTimestamp = "Last updated: " + timestamps["setupfields"];
    var analyzerTimestamp = "Last updated: " + timestamps["analyzer"];
    var crownTimestamp = "Last updated: " + timestamps["crown"];
    var craftingTimestamp = "Last updated: " + timestamps["crafting"];

    var closeButton = document.createElement("button", { id: "close-button" });
    closeButton.textContent = "x";
    closeButton.onclick = function() {
      document.body.removeChild(mainDiv);
    };

    var titleSpan = document.createElement("span");
    titleSpan.style.fontSize = "15px";
    titleSpan.style.fontWeight = "bold";
    titleSpan.appendChild(document.createTextNode("MH Tools Bookmarklets"));

    var descriptionSpan = document.createElement("span");
    descriptionSpan.innerHTML =
      "Version 1.2.3 / Using RawGit";
    var loaderSpanTimestamp = document.createElement("span");
    loaderSpanTimestamp.style.fontSize = "10px";
    loaderSpanTimestamp.style.fontStyle = "italic";
    loaderSpanTimestamp.innerHTML = loaderTimestamp;

    var creButton = document.createElement("button", { id: "cre-button" });
    creButton.textContent = "Catch Rate Estimator";
    creButton.onclick = function() {
      loadBookmarklet("cre");
    };
    var creSpanTimestamp = document.createElement("span");
    creSpanTimestamp.style.fontSize = "10px";
    creSpanTimestamp.style.fontStyle = "italic";
    creSpanTimestamp.innerHTML = creTimestamp;

    var mapButton = document.createElement("button", { id: "map-button" });
    mapButton.textContent = "Map Solver";
    mapButton.onclick = function() {
      loadBookmarklet("map");
    };
    var mapSpanTimestamp = document.createElement("span");
    mapSpanTimestamp.style.fontSize = "10px";
    mapSpanTimestamp.style.fontStyle = "italic";
    mapSpanTimestamp.innerHTML = mapTimestamp;

    var setupButton = document.createElement("button", { id: "setup-button" });
    setupButton.textContent = "Best Setup: Load Items";
    setupButton.onclick = function() {
      loadBookmarklet("setup");
    };
    var setupSpanTimestamp = document.createElement("span");
    setupSpanTimestamp.style.fontSize = "10px";
    setupSpanTimestamp.style.fontStyle = "italic";
    setupSpanTimestamp.innerHTML = setupTimestamp;

    var setupFieldsButton = document.createElement("button", {
      id: "setup-fields-button"
    });
    setupFieldsButton.textContent = "Best Setup: Fields";
    setupFieldsButton.onclick = function() {
      loadBookmarklet("setupfields");
    };
    var setupFieldsSpanTimestamp = document.createElement("span");
    setupFieldsSpanTimestamp.style.fontSize = "10px";
    setupFieldsSpanTimestamp.style.fontStyle = "italic";
    setupFieldsSpanTimestamp.innerHTML = setupFieldsTimestamp;

    var analyzerButton = document.createElement("button", {
      id: "analyzer-button"
    });
    analyzerButton.textContent = "Marketplace Analyzer";
    analyzerButton.onclick = function() {
      loadBookmarklet("analyzer");
    };
    var analyzerSpanTimestamp = document.createElement("span");
    analyzerSpanTimestamp.style.fontSize = "10px";
    analyzerSpanTimestamp.style.fontStyle = "italic";
    analyzerSpanTimestamp.innerHTML = analyzerTimestamp;

    var crownButton = document.createElement("button", { id: "crown-button" });
    crownButton.textContent = "Silver Crown Solver";
    crownButton.onclick = function() {
      loadBookmarklet("crown");
    };
    var crownSpanTimestamp = document.createElement("span");
    crownSpanTimestamp.style.fontSize = "10px";
    crownSpanTimestamp.style.fontStyle = "italic";
    crownSpanTimestamp.innerHTML = crownTimestamp;

    var craftingButton = document.createElement("button", {
      id: "crafting-button"
    });
    craftingButton.textContent = "Crafting Wizard";
    craftingButton.onclick = function() {
      loadBookmarklet("crafting");
    };
    var craftingSpanTimestamp = document.createElement("span");
    craftingSpanTimestamp.style.fontSize = "10px";
    craftingSpanTimestamp.style.fontStyle = "italic";
    craftingSpanTimestamp.innerHTML = craftingTimestamp;

    mainDiv.appendChild(closeButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(titleSpan);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(descriptionSpan);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(loaderSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(creButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(creSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(mapButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(mapSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupFieldsButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(setupFieldsSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(analyzerButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(analyzerSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(crownButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(crownSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(craftingButton);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(craftingSpanTimestamp);
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createElement("br"));
    mainDiv.appendChild(document.createTextNode("(Drag me around on a PC)"));

    mainDiv.style.backgroundColor = "#F5F5F5";
    mainDiv.style.position = "fixed";
    mainDiv.style.zIndex = "9999";
    // Allow customizable left position property
    mainDiv.style.left =
      typeof window.tsitu_loader_offset != "undefined"
        ? window.tsitu_loader_offset.concat("%")
        : "80%";
    mainDiv.style.top = "25px";
    mainDiv.style.border = "solid 3px #696969";
    mainDiv.style.borderRadius = "20px";
    mainDiv.style.padding = "10px";
    mainDiv.style.textAlign = "center";
    document.body.appendChild(mainDiv);
    dragElement(document.getElementById("mht-bookmarklet-loader"));
  }

  function getLatestSHA() {
    // Fetch latest gh-pages commit SHA to use with RawGit CDN since it caches URLs permanently
    return new Promise(function(resolve, reject) {
      var xhr = new XMLHttpRequest();
      xhr.open(
        "GET",
        "https://api.github.com/repos/tsitu/MH-Tools/commits?sha=gh-pages"
      );
      xhr.onload = function() {
        resolve(xhr.responseText);
      };
      xhr.onerror = function() {
        reject(xhr.statusText);
      };
      xhr.send();
    });
  }

  function loadBookmarklet(type) {
    getLatestSHA().then(function(response) {
      var sha = JSON.parse(response)[0].sha;
      var el = document.createElement("script");
      var cdn = "https://cdn.rawgit.com/tsitu/MH-Tools/";
      cdn += sha + "/src/bookmarklet/" + type + "bookmarklet.min.js";
      el.src = cdn;
      document.body.appendChild(el);
    });
  }

  function dragElement(el) {
    var pos1 = 0,
      pos2 = 0,
      pos3 = 0,
      pos4 = 0;
    if (document.getElementById(el.id + "header")) {
      document.getElementById(el.id + "header").onmousedown = dragMouseDown;
    } else {
      el.onmousedown = dragMouseDown;
    }

    function dragMouseDown(e) {
      e = e || window.event;
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
      e = e || window.event;
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      el.style.top = el.offsetTop - pos2 + "px";
      el.style.left = el.offsetLeft - pos1 + "px";
    }

    function closeDragElement() {
      document.onmouseup = null;
      document.onmousemove = null;
    }
  }
})();
<|endoftext|>