<commit_before>var gitAccountsAppConfig = {
	'form': {
		'login': {
			'entries': [
				{
					'name': 'provider',
					'label': translation.accountProvider[LANG],
					'type': 'select',
					'value': [{'v': 'bitbucket', 'l': 'Bitbucket'},  {'v': 'github', 'l': 'GitHub'}],
					'tooltip': translation.chooseAccountProvider[LANG],
					'required': true,
					'onAction': function (id, selected, form) {
						if (selected === 'bitbucket') {
							form.entries[1].value = 'api.bitbucket.org';
							if (form.entries[1].type !== 'text') {
								form.entries[1].type = 'text';
							}
						}
						else if (selected === 'github') {
							form.entries[1].value = 'github.com';
							form.entries[1].type = 'readonly';
						}
						form.refresh();
					}
				},
				{
					'name': 'providerDomain',
					'label': 'Provider Domain',
					'type': 'text',
					'value': '',
					'required': true
				},
				{
					'name': 'label',
					'label': translation.accountName[LANG],
					'type': 'text',
					'value': '',
					'tooltip': translation.chooseAccountName[LANG],
					'placeholder': translation.exampleMyAccount[LANG],
					'required': true
				},
				{
					'name': 'username',
					'label': translation.username[LANG],
					'type': 'text',
					'value': '',
					'placeholder': translation.yourUsername[LANG],
					'required': true
				},
				{
					"name": "tokenMessage",
					"type": "html",
					"value": "
" + translation.loginMessagePermissionsPartOne[LANG] + "

" + translation.loginMessagePermissionsPartTwo[LANG] + "

" + translation.loginMessagePermissionsPartThree[LANG] + "

" + translation.loginMessagePermissionsPartFour[LANG] + "
"
				}
			]
		},
		'logout': {
			'entries': [
				{
					'name': 'password',
					'label': translation.pleaseProvidePassword[LANG],
					'type': 'password',
					'value': '',
					'placeholder': translation.gitPassword[LANG],
					'required': true
				}
			]
		},
		'selectConfigBranch': {
			'entries': [
				{
					'name': 'branch',
					'label': translation.pleaseSpecifyConfigBranch[LANG],
					'type': 'select',
					'value': [],
					'required': true
				}
			]
		}
	},
	'permissions': {
		listAccounts: ['dashboard', '/gitAccounts/accounts/list'],
		login: ['dashboard', '/gitAccounts/login'],
		logout: ['dashboard', '/gitAccounts/logout'],
		activateRepo: ['dashboard', '/gitAccounts/repo/activate'],
		deactivateRepo: ['dashboard', '/gitAccounts/repo/deactivate'],
		syncRepo: ['dashboard', '/gitAccounts/repo/sync'],
		getRepos: ['dashboard', '/gitAccounts/getRepos'],
		getBranches: ['dashboard', '/gitAccounts/getBranches']
	},

	"blacklistedRepos": [
		'soajs/connect-mongo-soajs',
		'soajs/soajs',
		'soajs/soajs.agent',
		'soajs/soajs.composer',
		'soajs/soajs.dash.example',
		'soajs/soajs.gcs',
		'soajs/soajs.mongodb.data',
		'soajs/soajs.utilities',
		'soajs/soajs.website.contactus',
		'soajs/soajs.jsconfbeirut'
	]
};
<commit_msg>SOAJ-255: updated UI to support new git driver<commit_after>var gitAccountsAppConfig = {
	'form': {
		'login': {
			'entries': [
				{
					'name': 'provider',
					'label': translation.accountProvider[LANG],
					'type': 'select',
					'value': [{'v': 'github', 'l': 'GitHub'}, {'v': 'bitbucketorg', 'l': 'Bitbucket'}, {'v': 'bitbucket', 'l': 'Bitbucket Enterprise'}],
					'tooltip': translation.chooseAccountProvider[LANG],
					'required': true,
					'onAction': function (id, selected, form) {
						if (selected === 'github') {
							form.entries[1].value = 'github.com';
							form.entries[1].type = 'readonly';
						}
						else if (selected === 'bitbucketorg') {
							form.entries[1].value = 'bitbucket.org';
							form.entries[1].type = 'readonly';
						}
						else {
							form.entries[1].value = '';
							form.entries[1].type = 'text';
						}

						form.refresh();
					}
				},
				{
					'name': 'providerDomain',
					'label': 'Provider Domain',
					'type': 'text',
					'value': '',
					'required': true
				},
				{
					'name': 'label',
					'label': translation.accountName[LANG],
					'type': 'text',
					'value': '',
					'tooltip': translation.chooseAccountName[LANG],
					'placeholder': translation.exampleMyAccount[LANG],
					'required': true
				},
				{
					'name': 'username',
					'label': translation.username[LANG],
					'type': 'text',
					'value': '',
					'placeholder': translation.yourUsername[LANG],
					'required': true
				},
				{
					"name": "tokenMessage",
					"type": "html",
					"value": "
" + translation.loginMessagePermissionsPartOne[LANG] + "

" + translation.loginMessagePermissionsPartTwo[LANG] + "

" + translation.loginMessagePermissionsPartThree[LANG] + "

" + translation.loginMessagePermissionsPartFour[LANG] + "
"
				}
			]
		},
		'logout': {
			'entries': [
				{
					'name': 'password',
					'label': translation.pleaseProvidePassword[LANG],
					'type': 'password',
					'value': '',
					'placeholder': translation.gitPassword[LANG],
					'required': true
				}
			]
		},
		'selectConfigBranch': {
			'entries': [
				{
					'name': 'branch',
					'label': translation.pleaseSpecifyConfigBranch[LANG],
					'type': 'select',
					'value': [],
					'required': true
				}
			]
		}
	},
	'permissions': {
		listAccounts: ['dashboard', '/gitAccounts/accounts/list'],
		login: ['dashboard', '/gitAccounts/login'],
		logout: ['dashboard', '/gitAccounts/logout'],
		activateRepo: ['dashboard', '/gitAccounts/repo/activate'],
		deactivateRepo: ['dashboard', '/gitAccounts/repo/deactivate'],
		syncRepo: ['dashboard', '/gitAccounts/repo/sync'],
		getRepos: ['dashboard', '/gitAccounts/getRepos'],
		getBranches: ['dashboard', '/gitAccounts/getBranches']
	},

	"blacklistedRepos": [
		'soajs/connect-mongo-soajs',
		'soajs/soajs',
		'soajs/soajs.agent',
		'soajs/soajs.composer',
		'soajs/soajs.dash.example',
		'soajs/soajs.gcs',
		'soajs/soajs.mongodb.data',
		'soajs/soajs.utilities',
		'soajs/soajs.website.contactus',
		'soajs/soajs.jsconfbeirut'
	]
};
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import Dropdown from 'shared/components/Dropdown';
import ReactTooltip from 'react-tooltip';
import {RULE_MESSAGE_TEMPLATES as templates} from '../constants/index.js';

const {
  arrayOf,
  func,
  shape,
  string,
} = PropTypes;

export const RuleMessage = React.createClass({
  propTypes: {
    rule: shape({}).isRequired,
    actions: shape({
      updateMessage: func.isRequired,
    }).isRequired,
    enabledAlerts: arrayOf(string.isRequired).isRequired,
  },

  handleChangeMessage() {
    const {actions, rule} = this.props;
    actions.updateMessage(rule.id, this.message.value);
  },

  handleChooseAlert(item) {
    const {actions} = this.props;
    actions.updateAlerts(item.ruleID, [item.text]);
  },

  render() {
    const {rule, actions} = this.props;
    const alerts = this.props.enabledAlerts.map((text) => {
      return {text, ruleID: rule.id};
    });

    return (

Alert Message

          <textarea
            className="alert-message"
            ref={(r) => this.message = r}
            onChange={() => actions.updateMessage(rule.id, this.message.value)}
            placeholder='Example: {{ .ID }} is {{ .Level }} value: {{ index .Fields "value" }}'
            value={rule.message}
          />

Templates:

            {
              Object.keys(templates).map(t => {
                return (
                <CodeData
                  key={t}
                  template={templates[t]}
                  onClickTemplate={() => actions.updateMessage(rule.id, `${this.message.value} ${templates[t].label}`)}
                />
                );
              })
            }
            <ReactTooltip effect="solid" html={true} offset={{top: -4}} class="influx-tooltip kapacitor-tooltip" />

Send this Alert to:

            <Dropdown className="size-256 dropdown-kapacitor" selected={rule.alerts[0] || 'Choose an output'} items={alerts} onChoose={this.handleChooseAlert} />

    );
  },
});

const CodeData = React.createClass({
  propTypes: {
    onClickTemplate: func,
    template: shape({
      label: string,
      text: string,
    }),
  },

  render() {
    const {onClickTemplate, template} = this.props;
    const {label, text} = template;

    return (
      {label}
    );
  },
});

export default RuleMessage;
<commit_msg>Add foundation UI for http/tcp alerts<commit_after>import React, {PropTypes} from 'react';
import Dropdown from 'shared/components/Dropdown';
import ReactTooltip from 'react-tooltip';
import {RULE_MESSAGE_TEMPLATES as templates} from '../constants/index.js';

const DEFAULT_ALERTS = ['http', 'tcp'];

const {
  arrayOf,
  func,
  shape,
  string,
} = PropTypes;

export const RuleMessage = React.createClass({
  propTypes: {
    rule: shape({}).isRequired,
    actions: shape({
      updateMessage: func.isRequired,
    }).isRequired,
    enabledAlerts: arrayOf(string.isRequired).isRequired,
  },

  getInitialState() {
    return {
      selectedAlert: null,
    };
  },

  handleChangeMessage() {
    const {actions, rule} = this.props;
    actions.updateMessage(rule.id, this.message.value);
  },

  handleChooseAlert(item) {
    const {actions} = this.props;
    actions.updateAlerts(item.ruleID, [item.text]);
    this.setState({selectedAlert: item.text});
  },

  render() {
    const {rule, actions, enabledAlerts} = this.props;
    const defaultAlertEndpoints = DEFAULT_ALERTS.map((text) => {
      return {text, ruleID: rule.id};
    });
    const alerts = enabledAlerts.map((text) => {
      return {text, ruleID: rule.id};
    }).concat(defaultAlertEndpoints);

    return (

Alert Message

          <textarea
            className="alert-message"
            ref={(r) => this.message = r}
            onChange={() => actions.updateMessage(rule.id, this.message.value)}
            placeholder='Example: {{ .ID }} is {{ .Level }} value: {{ index .Fields "value" }}'
            value={rule.message}
          />

Templates:

            {
              Object.keys(templates).map(t => {
                return (
                <CodeData
                  key={t}
                  template={templates[t]}
                  onClickTemplate={() => actions.updateMessage(rule.id, `${this.message.value} ${templates[t].label}`)}
                />
                );
              })
            }
            <ReactTooltip effect="solid" html={true} offset={{top: -4}} class="influx-tooltip kapacitor-tooltip" />

Send this Alert to:

            <Dropdown className="size-256 dropdown-kapacitor" selected={rule.alerts[0] || 'Choose an output'} items={alerts} onChoose={this.handleChooseAlert} />
            {this.renderInput(this.state.selectedAlert)}

    );
  },

  renderInput(alert) {
    if (!DEFAULT_ALERTS.find((a) => a === alert)) {
      return null;
    }

    return <input className="form-control col-xs-6" type="text" ref={(r) => this.selectedAlert = r} />;
  },
});

const CodeData = React.createClass({
  propTypes: {
    onClickTemplate: func,
    template: shape({
      label: string,
      text: string,
    }),
  },

  render() {
    const {onClickTemplate, template} = this.props;
    const {label, text} = template;

    return (
      {label}
    );
  },
});

export default RuleMessage;
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import AutoRefresh from 'shared/components/AutoRefresh'
import LineGraph from 'shared/components/LineGraph'
import SingleStat from 'shared/components/SingleStat'
import NameableGraph from 'shared/components/NameableGraph'
import ReactGridLayout, {WidthProvider} from 'react-grid-layout'

import timeRanges from 'hson!../data/timeRanges.hson'
import buildInfluxQLQuery from 'utils/influxql'

const GridLayout = WidthProvider(ReactGridLayout)

const RefreshingLineGraph = AutoRefresh(LineGraph)
const RefreshingSingleStat = AutoRefresh(SingleStat)

const {
  arrayOf,
  bool,
  func,
  number,
  shape,
  string,
} = PropTypes

export const LayoutRenderer = React.createClass({
  propTypes: {
    autoRefresh: number.isRequired,
    timeRange: shape({
      lower: string.isRequired,
    }).isRequired,
    cells: arrayOf(
      shape({
        queries: arrayOf(
          shape({
            label: string,
            text: string,
            query: string,
          }).isRequired
        ).isRequired,
        x: number.isRequired,
        y: number.isRequired,
        w: number.isRequired,
        h: number.isRequired,
        i: string.isRequired,
        name: string.isRequired,
        type: string.isRequired,
      }).isRequired
    ),
    host: string,
    source: string,
    onPositionChange: func,
    onEditCell: func,
    onRenameCell: func,
    onUpdateCell: func,
    onDeleteCell: func,
    onSummonOverlayTechnologies: func,
    shouldNotBeEditable: bool,
  },

  buildQueryForOldQuerySchema(q) {
    const {timeRange: {lower}, host} = this.props
    const {defaultGroupBy} = timeRanges.find((range) => range.lower === lower)
    const {wheres, groupbys} = q

    let text = q.text

    text += ` where time > ${lower}`

    if (host) {
      text += ` and \"host\" = '${host}'`
    }

    if (wheres && wheres.length > 0) {
      text += ` and ${wheres.join(' and ')}`
    }

    if (groupbys) {
      if (groupbys.find((g) => g.includes("time"))) {
        text += ` group by ${groupbys.join(',')}`
      } else if (groupbys.length > 0) {
        text += ` group by time(${defaultGroupBy}),${groupbys.join(',')}`
      } else {
        text += ` group by time(${defaultGroupBy})`
      }
    } else {
      text += ` group by time(${defaultGroupBy})`
    }

    return text
  },

  generateVisualizations() {
    const {autoRefresh, timeRange, source, cells, onEditCell, onRenameCell, onUpdateCell, onDeleteCell, onSummonOverlayTechnologies, shouldNotBeEditable} = this.props

    return cells.map((cell) => {
      const qs = cell.queries.map((query) => {
        // TODO: Canned dashboards (and possibly Kubernetes dashboard) use an old query schema,
        // which does not have enough information for the new `buildInfluxQLQuery` function
        // to operate on. We will use `buildQueryForOldQuerySchema` until we conform
        // on a stable query representation.
        let queryText
        if (query.queryConfig) {
          queryText = buildInfluxQLQuery(timeRange, query.queryConfig)
        } else {
          queryText = this.buildQueryForOldQuerySchema(query)
        }

        return Object.assign({}, query, {
          host: source,
          text: queryText,
        })
      })

      if (cell.type === 'single-stat') {
        return (

            <NameableGraph
              onEditCell={onEditCell}
              onRenameCell={onRenameCell}
              onUpdateCell={onUpdateCell}
              onDeleteCell={onDeleteCell}
              onSummonOverlayTechnologies={onSummonOverlayTechnologies}
              shouldNotBeEditable={shouldNotBeEditable}
              cell={cell}
            >
              <RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefresh} />
            </NameableGraph>

        )
      }

      const displayOptions = {
        stepPlot: cell.type === 'line-stepplot',
        stackedGraph: cell.type === 'line-stacked',
      }

      return (

          <NameableGraph
            onEditCell={onEditCell}
            onRenameCell={onRenameCell}
            onUpdateCell={onUpdateCell}
            onDeleteCell={onDeleteCell}
            onSummonOverlayTechnologies={onSummonOverlayTechnologies}
            shouldNotBeEditable={shouldNotBeEditable}
            cell={cell}
          >
            <RefreshingLineGraph
              queries={qs}
              autoRefresh={autoRefresh}
              showSingleStat={cell.type === 'line-plus-single-stat'}
              displayOptions={displayOptions}
            />
          </NameableGraph>

      )
    })
  },

  handleLayoutChange(layout) {
    this.triggerWindowResize()

    if (!this.props.onPositionChange) {
      return
    }

    const newCells = this.props.cells.map((cell) => {
      const l = layout.find((ly) => ly.i === cell.i)
      const newLayout = {x: l.x, y: l.y, h: l.h, w: l.w}
      return {...cell, ...newLayout}
    })

    this.props.onPositionChange(newCells)
  },

  render() {
    const layoutMargin = 4
    const isDashboard = !!this.props.onPositionChange

    return (
      <GridLayout
        layout={this.props.cells}
        cols={12}
        rowHeight={83.5}
        margin={[layoutMargin, layoutMargin]}
        containerPadding={[0, 0]}
        useCSSTransforms={false}
        onResize={this.triggerWindowResize}
        onLayoutChange={this.handleLayoutChange}
        draggableHandle={'.dash-graph--drag-handle'}
        isDraggable={isDashboard}
        isResizable={isDashboard}
      >
        {this.generateVisualizations()}
      </GridLayout>
    )
  },

  triggerWindowResize() {
    // Hack to get dygraphs to fit properly during and after resize (dispatchEvent is a global method on window).
    const evt = document.createEvent('CustomEvent')  // MUST be 'CustomEvent'
    evt.initCustomEvent('resize', false, false, null)
    dispatchEvent(evt)
  },
})

export default LayoutRenderer
<commit_msg>No need to build a query if rawText exists<commit_after>import React, {PropTypes} from 'react'
import AutoRefresh from 'shared/components/AutoRefresh'
import LineGraph from 'shared/components/LineGraph'
import SingleStat from 'shared/components/SingleStat'
import NameableGraph from 'shared/components/NameableGraph'
import ReactGridLayout, {WidthProvider} from 'react-grid-layout'

import timeRanges from 'hson!../data/timeRanges.hson'
import buildInfluxQLQuery from 'utils/influxql'

const GridLayout = WidthProvider(ReactGridLayout)

const RefreshingLineGraph = AutoRefresh(LineGraph)
const RefreshingSingleStat = AutoRefresh(SingleStat)

const {
  arrayOf,
  bool,
  func,
  number,
  shape,
  string,
} = PropTypes

export const LayoutRenderer = React.createClass({
  propTypes: {
    autoRefresh: number.isRequired,
    timeRange: shape({
      lower: string.isRequired,
    }).isRequired,
    cells: arrayOf(
      shape({
        queries: arrayOf(
          shape({
            label: string,
            text: string,
            query: string,
          }).isRequired
        ).isRequired,
        x: number.isRequired,
        y: number.isRequired,
        w: number.isRequired,
        h: number.isRequired,
        i: string.isRequired,
        name: string.isRequired,
        type: string.isRequired,
      }).isRequired
    ),
    host: string,
    source: string,
    onPositionChange: func,
    onEditCell: func,
    onRenameCell: func,
    onUpdateCell: func,
    onDeleteCell: func,
    onSummonOverlayTechnologies: func,
    shouldNotBeEditable: bool,
  },

  buildQueryForOldQuerySchema(q) {
    const {timeRange: {lower}, host} = this.props
    const {defaultGroupBy} = timeRanges.find((range) => range.lower === lower)
    const {wheres, groupbys} = q

    let text = q.text

    text += ` where time > ${lower}`

    if (host) {
      text += ` and \"host\" = '${host}'`
    }

    if (wheres && wheres.length > 0) {
      text += ` and ${wheres.join(' and ')}`
    }

    if (groupbys) {
      if (groupbys.find((g) => g.includes("time"))) {
        text += ` group by ${groupbys.join(',')}`
      } else if (groupbys.length > 0) {
        text += ` group by time(${defaultGroupBy}),${groupbys.join(',')}`
      } else {
        text += ` group by time(${defaultGroupBy})`
      }
    } else {
      text += ` group by time(${defaultGroupBy})`
    }

    return text
  },

  generateVisualizations() {
    const {autoRefresh, timeRange, source, cells, onEditCell, onRenameCell, onUpdateCell, onDeleteCell, onSummonOverlayTechnologies, shouldNotBeEditable} = this.props

    return cells.map((cell) => {
      const qs = cell.queries.map((query) => {
        // TODO: Canned dashboards (and possibly Kubernetes dashboard) use an old query schema,
        // which does not have enough information for the new `buildInfluxQLQuery` function
        // to operate on. We will use `buildQueryForOldQuerySchema` until we conform
        // on a stable query representation.
        let queryText
        if (query.queryConfig) {
          const {queryConfig: {rawText}} = query
          queryText = rawText || buildInfluxQLQuery(timeRange, query.queryConfig)
        } else {
          queryText = this.buildQueryForOldQuerySchema(query)
        }

        return Object.assign({}, query, {
          host: source,
          text: queryText,
        })
      })

      if (cell.type === 'single-stat') {
        return (

            <NameableGraph
              onEditCell={onEditCell}
              onRenameCell={onRenameCell}
              onUpdateCell={onUpdateCell}
              onDeleteCell={onDeleteCell}
              onSummonOverlayTechnologies={onSummonOverlayTechnologies}
              shouldNotBeEditable={shouldNotBeEditable}
              cell={cell}
            >
              <RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefresh} />
            </NameableGraph>

        )
      }

      const displayOptions = {
        stepPlot: cell.type === 'line-stepplot',
        stackedGraph: cell.type === 'line-stacked',
      }

      return (

          <NameableGraph
            onEditCell={onEditCell}
            onRenameCell={onRenameCell}
            onUpdateCell={onUpdateCell}
            onDeleteCell={onDeleteCell}
            onSummonOverlayTechnologies={onSummonOverlayTechnologies}
            shouldNotBeEditable={shouldNotBeEditable}
            cell={cell}
          >
            <RefreshingLineGraph
              queries={qs}
              autoRefresh={autoRefresh}
              showSingleStat={cell.type === 'line-plus-single-stat'}
              displayOptions={displayOptions}
            />
          </NameableGraph>

      )
    })
  },

  handleLayoutChange(layout) {
    this.triggerWindowResize()

    if (!this.props.onPositionChange) {
      return
    }

    const newCells = this.props.cells.map((cell) => {
      const l = layout.find((ly) => ly.i === cell.i)
      const newLayout = {x: l.x, y: l.y, h: l.h, w: l.w}
      return {...cell, ...newLayout}
    })

    this.props.onPositionChange(newCells)
  },

  render() {
    const layoutMargin = 4
    const isDashboard = !!this.props.onPositionChange

    return (
      <GridLayout
        layout={this.props.cells}
        cols={12}
        rowHeight={83.5}
        margin={[layoutMargin, layoutMargin]}
        containerPadding={[0, 0]}
        useCSSTransforms={false}
        onResize={this.triggerWindowResize}
        onLayoutChange={this.handleLayoutChange}
        draggableHandle={'.dash-graph--drag-handle'}
        isDraggable={isDashboard}
        isResizable={isDashboard}
      >
        {this.generateVisualizations()}
      </GridLayout>
    )
  },

  triggerWindowResize() {
    // Hack to get dygraphs to fit properly during and after resize (dispatchEvent is a global method on window).
    const evt = document.createEvent('CustomEvent')  // MUST be 'CustomEvent'
    evt.initCustomEvent('resize', false, false, null)
    dispatchEvent(evt)
  },
})

export default LayoutRenderer
<|endoftext|>


<commit_before>// ==UserScript==
// @name            Enter Selects
// @author          xiaoxiaoflood
// @include         main
// @startup         UC.enterSelects.exec(win);
// @shutdown        UC.enterSelects.destroy();
// @onlyonce
// ==/UserScript==

// original: https://addons.mozilla.org/firefox/addon/enter-selects/

UC.enterSelects = {
  init: function () {
    this.orig_receiveResults = this.controller.receiveResults;
    this.controller.receiveResults = (function () {
      return function () {
        let gURLBar = this.browserWindow.gURLBar;
        if (UC.enterSelects.shouldSelect(gURLBar, arguments[0]))
          gURLBar.view._selectItem(gURLBar.view._rows.children[1], { updateInput: false});

        let  result =  UC.enterSelects.orig_receiveResults.apply(this, arguments);
        return result;
      };
    })();

    xPref.lock('browser.urlbar.autoFill', false);
    xPref.set('browser.urlbar.matchBuckets', 'general:1', true);
  },

  exec: function (win) {
    gURLBar.textbox.addEventListener('keydown', this.keyD, true);
  },

  controller: ChromeUtils.import('resource:///modules/UrlbarController.jsm').UrlbarController.prototype,

  shouldSelect: function (gURLBar, queryContext) {
    if (queryContext.lastResultCount < 1 || gURLBar.view.selectedIndex > 0)
      return false;

    let {value} = gURLBar;
    if (gURLBar.selectionEnd == value.length)
      value = value.slice(0, gURLBar.selectionStart);
    let search = value.trim();

    try {
      // Test if is URL
      return !Services.eTLD.getBaseDomainFromHost(search);
    } catch (ex) {}

    // Test about:about, chrome://blabla ...
    if (/[a-zA-Z][\w-]*:(\/\/)?[\w-]+/.test(search))
      return false;

    // Check if the first word is a keyword (search or bookmark) or search suggestion (if enabled and there is no result)
    if (!!queryContext.results[0].payload.keyword || !queryContext.results[1].payload.displayUrl)
      return false;

    return true;
  },
  keyD: (e) => {
    let gURLBar = this.gURLBar;
    if (e.keyCode == e.DOM_VK_TAB) {
      let url = gURLBar.view._queryContext.results[1].payload.url;
      if (gURLBar.view.selectedIndex == 1 && gURLBar.value != url && new RegExp(/^(https?:\/\/(www\.)?)?/.source + gURLBar.value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).test(url) && gURLBar.value != url.match(/(\w*:\/\/)?.+\..+?\//)[0]) {
        gURLBar.inputField.value = gURLBar._untrimmedValue = gURLBar.trimValue(url.match(/(\w*:\/\/)?.+\..+?\//)[0] + '/').slice(0, -1);
        /* quando browser.urlbar.trimURLs = true, trimValue() em url terminada em '.tld/' remove o '/', o que não é desejado porque a ideia deste "atalho" tab é facilitar o preenchimento de algo depois da barra. Eu não poderia adicionar um '/' depois do trimValue() porque em caso de trim desabilitado ficaria com duas barras. A solução mais prática é esta, incluir um caractere antes de aplicar o trimValue() para que a barra não seja removida, aí depois só remove este caractere adicionado. */
        gURLBar.view.close();
        e.preventDefault();
        e.stopPropagation();
      } else if (gURLBar.view.selectedIndex == -1) {
        gURLBar.view.selectedIndex = 1;
        gURLBar.value = url;
        e.preventDefault();
        e.stopPropagation();
      } else if (gURLBar.view.selectedIndex == 1 && gURLBar.value != url) {
        gURLBar.value = url;
        e.preventDefault();
        e.stopPropagation();
      }
    }
  },

  destroy: function () {
    xPref.unlock('browser.urlbar.autoFill');
    _uc.windows((doc, win) => {
      let gURLBar = win.gURLBar;
      this.controller.receiveResults = this.orig_receiveResults;
      gURLBar.textbox.removeEventListener('keydown', this.keyD, true);
    });
    delete UC.enterSelects;
  }
}

UC.enterSelects.init();
<commit_msg>Enter Selects fx71<commit_after>// ==UserScript==
// @name            Enter Selects
// @author          xiaoxiaoflood
// @include         main
// @startup         UC.enterSelects.exec(win);
// @shutdown        UC.enterSelects.destroy();
// @onlyonce
// ==/UserScript==

// original: https://addons.mozilla.org/firefox/addon/enter-selects/

UC.enterSelects = {
  init: function () {
    this.orig_receiveResults = this.controller.receiveResults;
    this.controller.receiveResults = (function () {
      return function () {
        let gURLBar = this.browserWindow.gURLBar;
        if (UC.enterSelects.shouldSelect(gURLBar, arguments[0]))
          gURLBar.view._selectElement(gURLBar.view._rows.children[1], { updateInput: false });

        return UC.enterSelects.orig_receiveResults.apply(this, arguments);
      };
    })();

    xPref.lock('browser.urlbar.autoFill', false);
    xPref.set('browser.urlbar.matchBuckets', 'general:1', true);
  },

  exec: function (win) {
    gURLBar.textbox.addEventListener('keydown', this.keyD, true);
  },

  controller: ChromeUtils.import('resource:///modules/UrlbarController.jsm').UrlbarController.prototype,

  shouldSelect: function (gURLBar, queryContext) {
    if (queryContext.lastResultCount < 1 || gURLBar.view.selectedIndex > 0)
      return false;

    let {value} = gURLBar;
    if (gURLBar.selectionEnd == value.length)
      value = value.slice(0, gURLBar.selectionStart);
    let search = value.trim();

    try {
      // Test if is URL
      return !Services.eTLD.getBaseDomainFromHost(search);
    } catch (ex) {}

    // Test about:about, chrome://blabla ...
    if (/[a-zA-Z][\w-]*:(\/\/)?[\w-]+/.test(search))
      return false;

    // Check if the first word is a keyword (search or bookmark) or search suggestion (if enabled and there is no result)
    if (!!queryContext.results[0].payload.keyword || !queryContext.results[1].payload.displayUrl)
      return false;

    return true;
  },
  keyD: (e) => {
    let gURLBar = this.gURLBar;
    if (e.keyCode == e.DOM_VK_TAB) {
      let url = gURLBar.view._queryContext.results[1].payload.url;
      if (gURLBar.view.selectedIndex == 1 && gURLBar.value != url && new RegExp(/^(https?:\/\/(www\.)?)?/.source + gURLBar.value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).test(url) && gURLBar.value != url.match(/(\w*:\/\/)?.+\..+?\//)[0]) {
        gURLBar.inputField.value = gURLBar._untrimmedValue = gURLBar.trimValue(url.match(/(\w*:\/\/)?.+\..+?\//)[0] + '/').slice(0, -1);
        /* quando browser.urlbar.trimURLs = true, trimValue() em url terminada em '.tld/' remove o '/', o que não é desejado porque a ideia deste "atalho" tab é facilitar o preenchimento de algo depois da barra. Eu não poderia adicionar um '/' depois do trimValue() porque em caso de trim desabilitado ficaria com duas barras. A solução mais prática é esta, incluir um caractere antes de aplicar o trimValue() para que a barra não seja removida, aí depois só remove este caractere adicionado. */
        gURLBar.view.close();
        e.preventDefault();
        e.stopPropagation();
      } else if (gURLBar.view.selectedIndex == -1) {
        gURLBar.view.selectedIndex = 1;
        gURLBar.value = url;
        e.preventDefault();
        e.stopPropagation();
      } else if (gURLBar.view.selectedIndex == 1 && gURLBar.value != url) {
        gURLBar.value = url;
        e.preventDefault();
        e.stopPropagation();
      }
    }
  },

  destroy: function () {
    xPref.unlock('browser.urlbar.autoFill');
    _uc.windows((doc, win) => {
      this.controller.receiveResults = this.orig_receiveResults;
      win.gURLBar.textbox.removeEventListener('keydown', this.keyD, true);
    });
    delete UC.enterSelects;
  }
}

UC.enterSelects.init();
<|endoftext|>


<commit_before>var LEELA;

if (LEELA === undefined) {
    LEELA = {};
}

LEELA.widget = function (root, opts) {
    var options = opts || {};

    var cspline_i = function (x, xk_1, yk_1, xk, yk, xk1, yk1, xk2, yk2) {
      var t   = (x-xk) / (xk1 - xk);
      var t2  = t*t;
      var t3  = t2*t;
      var h00 = 2*t3 - 3*t2 + 1;
      var h10 = t3 - 2*t2 + t;
      var h01 = -2*t3 + 3*t2;
      var h11 = t3 - t2;
      var m0  = (yk1-yk)/(2*(xk1 - xk)) + (yk-yk_1)/(2*(xk-xk_1));
      var m1  = (yk2-yk1)/(2*(xk2 - xk1)) + (yk1-yk)/(2*(xk1-xk));
      return([x, h00*yk + h10*(xk1-xk)*m0 + h01*yk1 + h11*(xk1-xk)*m1]);
    };

    var cspline = function (data) {
      var ndata = [];
      var len   = data.length;
      var res   = 50;

      for (var k=0; k<len-1; k+=1) {
        for (var u=1; u<res; u+=1) {
          var x = k + u/res;
          ndata.push(cspline_i(x,
                               k-1,
                               (data[k-1] || [0,0])[1],
                               k,
                               data[k][1],
                               k+1,
                               data[k+1][1],
                               k+2,
                               (data[k+2] || [0,0])[1]));
        }
      }

      return(ndata);
    };

    var format = function (json) {
      var series = [];
      for (var k in json) {
        if (k!=="source" && json.hasOwnProperty(k)) {
          series.push({ label: k,
                        data: cspline(json[k])
                      });
        }
      }
      console.log(series);
      return(series);
    };

    var install = function (json) {
        var series    = format(json);
        var container = document.getElementById(root);
        var resetZoom = function () {
            // delete options.xaxis.min; delete options.xaxis.max;
            // delete options.yaxis.min; delete options.yaxis.max;
        };

        Flotr.draw(container, series, {xaxis: { mode: "normal",
                                              },
                                       title: options.title || (json.source.hostname + " - " + json.source.service),
                                       subtitle: options.subtitle || "Powered by locaweb"
                                      });

        // Flotr.EventAdapter.observe(container, 'flotr:select', function (area) {
        //     options.xaxis.min = area.x1; options.xaxis.max = area.x2;
        //     options.yaxis.min = area.y1; options.yaxis.max = area.y2;
        //     Flotr.draw(container, series, options);
        // });

        // Flotr.EventAdapter.observe(container, 'flotr:click', function () { resetZoom(); Flotr.draw(container, series, options); });
    };

    return({"install": install});
}
<commit_msg>zoom in/out is back on<commit_after>var LEELA;

if (LEELA === undefined) {
    LEELA = {};
}

LEELA.widget = function (root, opts) {
    var options = opts || {};

    var cspline_i = function (x, xk_1, yk_1, xk, yk, xk1, yk1, xk2, yk2) {
      var t   = (x-xk) / (xk1 - xk);
      var t2  = t*t;
      var t3  = t2*t;
      var h00 = 2*t3 - 3*t2 + 1;
      var h10 = t3 - 2*t2 + t;
      var h01 = -2*t3 + 3*t2;
      var h11 = t3 - t2;
      var m0  = (yk1-yk)/(2*(xk1 - xk)) + (yk-yk_1)/(2*(xk-xk_1));
      var m1  = (yk2-yk1)/(2*(xk2 - xk1)) + (yk1-yk)/(2*(xk1-xk));
      return([x, h00*yk + h10*(xk1-xk)*m0 + h01*yk1 + h11*(xk1-xk)*m1]);
    };

    var cspline = function (data) {
      var ndata = [];
      var len   = data.length;
      var res   = 50;

      for (var k=0; k<len-1; k+=1) {
        for (var u=1; u<res; u+=1) {
          var x = k + u/res;
          ndata.push(cspline_i(x,
                               k-1,
                               (data[k-1] || [0,0])[1],
                               k,
                               data[k][1],
                               k+1,
                               data[k+1][1],
                               k+2,
                               (data[k+2] || [0,0])[1]));
        }
      }

      return(ndata);
    };

    var format = function (json) {
      var series = [];
      for (var k in json) {
        if (k!=="source" && json.hasOwnProperty(k)) {
          series.push({ label: k,
                        data: cspline(json[k])
                      });
        }
      }
      console.log(series);
      return(series);
    };

    var install = function (json) {
        var series    = format(json);
        var container = document.getElementById(root);
        var myopts    = { xaxis: {mode: "normal"},
                          yaxis: {},
                          title: options.title || (json.source.hostname + " - " + json.source.service),
                          subtitle: options.subtitle || "Powered by locaweb",
                          selection: {mode: "x"}
                        };
        var resetZoom = function () {
            delete myopts.xaxis.min; delete myopts.xaxis.max;
            delete myopts.yaxis.min; delete myopts.yaxis.max;
        };

        Flotr.draw(container, series, myopts);

        Flotr.EventAdapter.observe(container, 'flotr:select', function (area) {
          myopts.xaxis.min = area.x1; myopts.xaxis.max = area.x2;
          myopts.yaxis.min = area.y1; myopts.yaxis.max = area.y2;
          Flotr.draw(container, series, myopts);
        });

        Flotr.EventAdapter.observe(container, 'flotr:click', function () { resetZoom(); Flotr.draw(container, series, myopts); });
    };

    return({"install": install});
}
<|endoftext|>


<commit_before>/**
 * Created by liangkuaisheng on 16/6/12.
 */
var path = require('path');
var fs = require('fs-extra');
var _ = require('lodash');
var colors = require('colors');
var requestSyncWin = require('request-sync-win');
var cwd = process.cwd();

var defaultDep = {
    "resource": [
        {
            "name": "angular"
        },
        {
            "name": "angular-resource"
        }
    ],
    "ng-http": []
};
var defaultConfig = {
    "file": "./swagger.json",
    "outPath": "./",
    "apiName": "ApiService",
    "type": "ng-http"
};

module.exports = function (config) {
    defaultConfig.dependence = defaultDep[config.type || defaultConfig.type];
    config = _.defaultsDeep(config, defaultConfig);

    var swagger;
    var fileName = config.file;
    try {
        if (/^(http|https):\/\/.+/gi.test(fileName)) {
            var httpRes = requestSyncWin(fileName);
            if (httpRes.statusCode === 200) {
                swagger = JSON.parse(httpRes.body);
            } else {
                throw new Error('http code=' + httpRes.statusCode);
            }
        } else {
            swagger = require(path.join(cwd, fileName));
        }
    } catch (err) {
        console.log('没有swagger文件或文件不是合法json格式'.red);
        throw err;
    }

    // 依赖注入
    var dependenceArr = [];
    var requireArr = [];
    var rootArr = [];
    var paramsArr = [];
    _.forEach(config.dependence, function (value, key) {
        value.exports = value.exports || _.camelCase(value.name);
        dependenceArr.push("'" + value.name + "'");
        requireArr.push("require('" + value.name + "')");
        rootArr.push('root.' + value.exports);
        paramsArr.push(value.exports);
    });

    config.dependenceObj = {
        dependence: dependenceArr.join(',\n            '),
        require: requireArr.join(',\n            '),
        root: rootArr.join(',\n            '),
        params: paramsArr.join(',\n    ')
    };
    var nowDate = new Date();
    config.createTime = nowDate.toLocaleString();

    swagger.apiName = config.apiName;
    swagger.dependence = config.dependence;
    swagger.pathsUrl = {};
    _.forEach(swagger.paths, function (value, key) {
        _.forEach(value, function (item, index) {
            // 方法名
            item.fnName = _.camelCase(index + key);
            // 处理restful风格url
            swagger.pathsUrl[key] = key.replace(/\{([^\{\}]+)\}/gi, function (s1, s2) {
                return ':' + s2;
            });
            if (_.findLastKey(swagger.paths) === key && _.findLastKey(value) === index) {
                // 最后一个方法没有逗号
                item.lastOneReq = true;
            }
            // 处理header
            if (needSetFormData(item.consumes)) {
                item.transformRequestAsForm = true;
                item.transformRequestFormData = true;
            }
            _.forEach(item.parameters, function (param, pKey) {
                if (param.in === 'formData') {
                    item.transformRequestAsForm = true;
                    if (param.type === 'file') {
                        item.transformRequestFormData = true;
                    }
                }
                if (param.in === 'header') {
                    item.hasInHeader = true;
                }
                if (param.in === 'body') {
                    item.hasInBody = true;
                }
            });
            item.headerStr = getHeader(item);
        });
    });

    // 处理basePath
    var schemes = swagger.schemes;
    var schemesStr = 'http';
    if (schemes && schemes.length > 0) {
        schemesStr = schemes[0];
    }
    var urlPre = ((schemesStr + '://' + swagger.host) || '') + (swagger.basePath || '');
    if (urlPre && /^.*\/$/.test(urlPre)) {
        urlPre = urlPre.replace(/(^.*)(\/)$/, function (s1, s2) {
            return s2;
        })
    }
    swagger.urlPre = urlPre;
    return {
        config: config,
        swagger: swagger
    }
};

/*
* 判断头部是否含有 consumes:["multipart/form-data"]
* */
function needSetFormData(consumes) {
    if (!consumes) {
        return false;
    }
    var res = false;
    consumes.forEach(function (item, index) {
        if (item === 'multipart/form-data') {
            res = true;
        }
    });
    return res;
}

/*
* 设置头部
* */
function getHeader(req) {
    var res = '';
    var headerArr = [];
    var headerObj = {};
    if (req.produces) {
        headerObj['Accept'] = "'" + req.produces.join(', ') + "'";
    }
    if (req.consumes) {
        headerObj['Content-Type'] = "'" + req.consumes.join(', ') + "'";
    }
    if (req.transformRequestAsForm) {
        headerObj['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
    }
    if (req.transformRequestFormData) {
        headerObj['Content-Type'] = undefined;
    }
    Object.keys(headerObj).forEach(function (key, index) {
        var item = headerObj[key];
        headerArr.push("'" + key + "': " + item);
    });
    if (headerArr.length > 0) {
        headerArr = [headerArr.join(',')];
        headerArr.unshift('\n            headers: {');
        headerArr.push('},');
        res = headerArr.join('');
    }
    return res;
}<commit_msg>优化时间展示<commit_after>/**
 * Created by liangkuaisheng on 16/6/12.
 */
var path = require('path');
var fs = require('fs-extra');
var _ = require('lodash');
var colors = require('colors');
var requestSyncWin = require('request-sync-win');
var cwd = process.cwd();

var defaultDep = {
    "resource": [
        {
            "name": "angular"
        },
        {
            "name": "angular-resource"
        }
    ],
    "ng-http": []
};
var defaultConfig = {
    "file": "./swagger.json",
    "outPath": "./",
    "apiName": "ApiService",
    "type": "ng-http"
};

module.exports = function (config) {
    defaultConfig.dependence = defaultDep[config.type || defaultConfig.type];
    config = _.defaultsDeep(config, defaultConfig);

    var swagger;
    var fileName = config.file;
    try {
        if (/^(http|https):\/\/.+/gi.test(fileName)) {
            var httpRes = requestSyncWin(fileName);
            if (httpRes.statusCode === 200) {
                swagger = JSON.parse(httpRes.body);
            } else {
                throw new Error('http code=' + httpRes.statusCode);
            }
        } else {
            swagger = require(path.join(cwd, fileName));
        }
    } catch (err) {
        console.log('没有swagger文件或文件不是合法json格式'.red);
        throw err;
    }

    // 依赖注入
    var dependenceArr = [];
    var requireArr = [];
    var rootArr = [];
    var paramsArr = [];
    _.forEach(config.dependence, function (value, key) {
        value.exports = value.exports || _.camelCase(value.name);
        dependenceArr.push("'" + value.name + "'");
        requireArr.push("require('" + value.name + "')");
        rootArr.push('root.' + value.exports);
        paramsArr.push(value.exports);
    });

    config.dependenceObj = {
        dependence: dependenceArr.join(',\n            '),
        require: requireArr.join(',\n            '),
        root: rootArr.join(',\n            '),
        params: paramsArr.join(',\n    ')
    };
    var nowDate = new Date();
    config.createTime = nowDate.toLocaleString('zh-cn', {
        hour12: false
    });

    swagger.apiName = config.apiName;
    swagger.dependence = config.dependence;
    swagger.pathsUrl = {};
    _.forEach(swagger.paths, function (value, key) {
        _.forEach(value, function (item, index) {
            // 方法名
            item.fnName = _.camelCase(index + key);
            // 处理restful风格url
            swagger.pathsUrl[key] = key.replace(/\{([^\{\}]+)\}/gi, function (s1, s2) {
                return ':' + s2;
            });
            if (_.findLastKey(swagger.paths) === key && _.findLastKey(value) === index) {
                // 最后一个方法没有逗号
                item.lastOneReq = true;
            }
            // 处理header
            if (needSetFormData(item.consumes)) {
                item.transformRequestAsForm = true;
                item.transformRequestFormData = true;
            }
            _.forEach(item.parameters, function (param, pKey) {
                if (param.in === 'formData') {
                    item.transformRequestAsForm = true;
                    if (param.type === 'file') {
                        item.transformRequestFormData = true;
                    }
                }
                if (param.in === 'header') {
                    item.hasInHeader = true;
                }
                if (param.in === 'body') {
                    item.hasInBody = true;
                }
            });
            item.headerStr = getHeader(item);
        });
    });

    // 处理basePath
    var schemes = swagger.schemes;
    var schemesStr = 'http';
    if (schemes && schemes.length > 0) {
        schemesStr = schemes[0];
    }
    var urlPre = ((schemesStr + '://' + swagger.host) || '') + (swagger.basePath || '');
    if (urlPre && /^.*\/$/.test(urlPre)) {
        urlPre = urlPre.replace(/(^.*)(\/)$/, function (s1, s2) {
            return s2;
        })
    }
    swagger.urlPre = urlPre;
    return {
        config: config,
        swagger: swagger
    }
};

/*
* 判断头部是否含有 consumes:["multipart/form-data"]
* */
function needSetFormData(consumes) {
    if (!consumes) {
        return false;
    }
    var res = false;
    consumes.forEach(function (item, index) {
        if (item === 'multipart/form-data') {
            res = true;
        }
    });
    return res;
}

/*
* 设置头部
* */
function getHeader(req) {
    var res = '';
    var headerArr = [];
    var headerObj = {};
    if (req.produces) {
        headerObj['Accept'] = "'" + req.produces.join(', ') + "'";
    }
    if (req.consumes) {
        headerObj['Content-Type'] = "'" + req.consumes.join(', ') + "'";
    }
    if (req.transformRequestAsForm) {
        headerObj['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
    }
    if (req.transformRequestFormData) {
        headerObj['Content-Type'] = undefined;
    }
    Object.keys(headerObj).forEach(function (key, index) {
        var item = headerObj[key];
        headerArr.push("'" + key + "': " + item);
    });
    if (headerArr.length > 0) {
        headerArr = [headerArr.join(',')];
        headerArr.unshift('\n            headers: {');
        headerArr.push('},');
        res = headerArr.join('');
    }
    return res;
}<|endoftext|>


<commit_before>/**
 * The global client-side alchemy object
 *
 * @type   {Object}
 */
window.alchemy = {};

(function() {

var sent_subscriptions = [];

// Create the sceneid
hawkejs.scene.data();

// The last update is when this scene was made
alchemy.last_update = Date.now();

alchemy.server = new __Protoblast.Classes.ClientSocket();

/**
 * Automatically add json-dry decoding to jQuery libraries
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.2.0
 *
 * @param     {String}   name
 * @param     {String}   path
 */
hawkejs.scene.on('script', function newScriptLoaded(name, path) {

	// Make sure it's jQuery
	if (!window.jQuery || (name.toLowerCase() != 'jquery' && !path.match(/jquery-\d/i))) {
		return;
	}

	// Add the json-dry ajax setup
	jQuery.ajaxSetup({
		accepts: {
			jsondry: 'text/json-dry, application/json-dry'
		},
		contents: {
			// Make sure the regular json interpreter ignores it
			json: /(json)(?!.*dry.*)/,
			jsondry: /json-dry/
		},
		converters: {
			"text jsondry": function jsonDryParser(val) {
				return JSON.undry(val);
			}
		}
	});
});

/**
 * Mark links as active using breadcrumbs
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.3.0
 * @version   0.3.1
 *
 * @param     {Object}   variables
 * @param     {Object}   render_data
 */
hawkejs.scene.on('rendered', function markLinks(variables, render_data) {

	var page_breadcrumb,
	    el_breadcrumb,
	    placeholder,
	    elements,
	    element,
	    temp,
	    i;

	// Get the newly set breadcrumb
	page_breadcrumb = variables.__breadcrumb;

	// Get all the elements with a breadcrumb set
	elements = document.querySelectorAll('[data-breadcrumb]');

	for (i = 0; i < elements.length; i++) {
		element = elements[i];

		// Get the elemen's set breadcrumb
		el_breadcrumb = element.getAttribute('data-breadcrumb');

		if (el_breadcrumb == page_breadcrumb) {
			markLinkElement(element, 1);
		} else if (page_breadcrumb && page_breadcrumb.indexOf(el_breadcrumb) === 0) {
			markLinkElement(element, 2);
		} else {
			markLinkElement(element, false);
		}
	}

	// Update breadcrumbs in case of ajax
	if (render_data.request && render_data.request.ajax && variables.__breadcrumb_entries) {

		// Get all the breadcrumb elements
		elements = document.querySelectorAll('[data-template="breadcrumb/wrapper"]');

		if (elements.length) {

			// Use the original view renderer to render an extra element
			placeholder = render_data.print_element('breadcrumb/wrapper', null, {wrap: false});

			// We're kind of hacking hawkejs by doing a print_element after it's done,
			// this way we prevent a warning log
			placeholder.done = true;

			placeholder.getContent(function gotContent(err, html) {

				if (err) {
					return console.error('Error updating breadcrumb:', err);
				}

				for (i = 0; i < elements.length; i++) {
					element = elements[i];
					element.innerHTML = html;
				}
			});
		}
	}
});

/**
 * Mark element as active or not
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.3.0
 * @version   0.3.0
 *
 * @param     {Element}   element
 * @param     {Number}    active_nr
 */
function markLinkElement(element, active_nr) {

	var mark_wrapper;

	// Always remove the current classes
	element.classList.remove('active-link');
	element.classList.remove('active-sublink');

	if (element.parentElement && element.parentElement.classList.contains('js-he-link-wrapper')) {
		markLinkElement(element.parentElement, active_nr);
	}

	if (!active_nr) {
		return;
	}

	if (active_nr == 1) {
		element.classList.add('active-link');
	} else if (active_nr == 2) {
		element.classList.add('active-sublink');
	}
}

/**
 * Create a socket.io connection to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.2.0
 *
 * @param     {Function}   callback
 */
alchemy.connect = function connect(callback) {

	if (typeof window.io === 'undefined') {
		hawkejs.require(['socket.io.js', 'socket.io-stream'], function() {
			alchemy.server.connect(callback);
		});
	} else {
		alchemy.server.connect(callback);
	}
};

/**
 * Submit a message to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.0.1
 *
 * @param    {String}   type
 * @param    {Object}   data
 * @param    {Function} callback
 */
alchemy.submit = function submit(type, data, callback) {
	alchemy.server.submit(type, data, callback);
};

/**
 * Create a namespace and inform the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.2.0
 *
 * @param    {String}   type    The typename of link to create
 * @param    {Object}   data    The initial data to submit
 *
 * @return   {Linkup}
 */
alchemy.linkup = function linkup(type, data) {
	return alchemy.server.linkup(type, data);
};

/**
 * Listen for server messages
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.0.1
 *
 * @param    {String}   type
 * @param    {Function} callback
 */
alchemy.listen = alchemy.on = function listen(type, callback) {
	return alchemy.server.on(type, callback);
};

/**
 * Send binding data to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.3.0
 */
alchemy.sendBindingRequests = function sendBindingRequests() {

	var subscriptions = [],
	    elements,
	    data_id,
	    element,
	    i;

	// Look for all the non-bound elements that require an update event
	elements = document.querySelectorAll('[data-update-event]');

	// Iterate over them in order to register them
	for (i = 0; i < elements.length; i++) {
		element = elements[i];
		data_id = element.getAttribute('data-update-event');

		if (~sent_subscriptions.indexOf(data_id)) {
			continue;
		}

		sent_subscriptions.push(data_id);
		subscriptions.push(data_id);
	}

	for (data_id in hawkejs.scene.live_bindings) {

		if (~sent_subscriptions.indexOf(data_id)) {
			continue;
		}

		sent_subscriptions.push(data_id);
		subscriptions.push(data_id);
	}

	// Send data id subscriptions
	if (subscriptions.length) {
		alchemy.submit('subscribe-data', subscriptions);
	}
};

// Make the connection only if websockets are enabled
if (hawkejs.scene.exposed.enable_websockets) {

	// Connect to the server
	alchemy.connect(function onConnect() {
		alchemy.sendBindingRequests();
	});

	// Send binding requests again after each render
	hawkejs.scene.on('rendered', function onRendered(){
		alchemy.sendBindingRequests();
	});

	// Bind to elements with the data-server-event attribute
	hawkejs.constructor.onAttribute('data-server-event', function serverEvent(element, value, old_value, created) {

		var event_type;

		if (value == old_value || !value) {
			return;
		}

		event_type = element.getAttribute('data-listen-type');

		if (!event_type) {
			if (element.nodeName == 'A' || element.nodeName == 'BUTTON') {
				event_type = 'click';
			} else {
				event_type = 'change';
			}
		}

		// And the change event
		element.addEventListener(event_type, function sendToServer(e) {
			var get_form,
			    elements,
			    element,
			    e_val,
			    value,
			    data,
			    i;

			console.log('Sending to server...', e);

			if (this.hasAttribute('data-server-event-form')) {
				get_form = this.getAttribute('data-server-event-form');

				if (get_form) {
					get_form = document.querySelector(get_form);
				} else {
					get_form = this.closest('form');
				}

				if (get_form) {
					data = {};

					elements = get_form.querySelectorAll('[data-name]');

					for (i = 0; i < elements.length; i++) {
						element = elements[i];
						e_val = element.value;

						switch (element.getAttribute('type')) {
							case 'number':
								e_val = Number(e_val);
								break;
						}

						data[element.getAttribute('data-name')] = e_val;
					}
				}
			}

			// Get the event string
			value = this.getAttribute('data-server-event').split('|').map(function eachEntry(str) {
				var result = str.trim();

				return result;
			});

			if (this.getAttribute('data-send-value')) {

				if (!data) {
					data = {};
				}

				data.value = this.value;
			}

			if (data) {
				value.push(data);
			}

			alchemy.submit('data-server-event', value);
			e.preventDefault();
		});
	});

	// Listen to data updates
	alchemy.on('data-update', function gotDataUpdate(packet) {

		var data = packet.data,
		    id = packet.id;

		alchemy.last_update = Date.now();
		hawkejs.scene.updateData(id, data);
	});
}

__Protoblast.emit('alchemy-loaded');
}());<commit_msg>Add client-side alchemy.fetch method<commit_after>/**
 * The global client-side alchemy object
 *
 * @type   {Object}
 */
window.alchemy = {};

(function() {

var sent_subscriptions = [];

// Create the sceneid
hawkejs.scene.data();

// The last update is when this scene was made
alchemy.last_update = Date.now();

alchemy.server = new __Protoblast.Classes.ClientSocket();

/**
 * Automatically add json-dry decoding to jQuery libraries
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.2.0
 *
 * @param     {String}   name
 * @param     {String}   path
 */
hawkejs.scene.on('script', function newScriptLoaded(name, path) {

	// Make sure it's jQuery
	if (!window.jQuery || (name.toLowerCase() != 'jquery' && !path.match(/jquery-\d/i))) {
		return;
	}

	// Add the json-dry ajax setup
	jQuery.ajaxSetup({
		accepts: {
			jsondry: 'text/json-dry, application/json-dry'
		},
		contents: {
			// Make sure the regular json interpreter ignores it
			json: /(json)(?!.*dry.*)/,
			jsondry: /json-dry/
		},
		converters: {
			"text jsondry": function jsonDryParser(val) {
				return JSON.undry(val);
			}
		}
	});
});

/**
 * Mark links as active using breadcrumbs
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.3.0
 * @version   0.3.1
 *
 * @param     {Object}   variables
 * @param     {Object}   render_data
 */
hawkejs.scene.on('rendered', function markLinks(variables, render_data) {

	var page_breadcrumb,
	    el_breadcrumb,
	    placeholder,
	    elements,
	    element,
	    temp,
	    i;

	// Get the newly set breadcrumb
	page_breadcrumb = variables.__breadcrumb;

	// Get all the elements with a breadcrumb set
	elements = document.querySelectorAll('[data-breadcrumb]');

	for (i = 0; i < elements.length; i++) {
		element = elements[i];

		// Get the elemen's set breadcrumb
		el_breadcrumb = element.getAttribute('data-breadcrumb');

		if (el_breadcrumb == page_breadcrumb) {
			markLinkElement(element, 1);
		} else if (page_breadcrumb && page_breadcrumb.indexOf(el_breadcrumb) === 0) {
			markLinkElement(element, 2);
		} else {
			markLinkElement(element, false);
		}
	}

	// Update breadcrumbs in case of ajax
	if (render_data.request && render_data.request.ajax && variables.__breadcrumb_entries) {

		// Get all the breadcrumb elements
		elements = document.querySelectorAll('[data-template="breadcrumb/wrapper"]');

		if (elements.length) {

			// Use the original view renderer to render an extra element
			placeholder = render_data.print_element('breadcrumb/wrapper', null, {wrap: false});

			// We're kind of hacking hawkejs by doing a print_element after it's done,
			// this way we prevent a warning log
			placeholder.done = true;

			placeholder.getContent(function gotContent(err, html) {

				if (err) {
					return console.error('Error updating breadcrumb:', err);
				}

				for (i = 0; i < elements.length; i++) {
					element = elements[i];
					element.innerHTML = html;
				}
			});
		}
	}
});

/**
 * Mark element as active or not
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.3.0
 * @version   0.3.0
 *
 * @param     {Element}   element
 * @param     {Number}    active_nr
 */
function markLinkElement(element, active_nr) {

	var mark_wrapper;

	// Always remove the current classes
	element.classList.remove('active-link');
	element.classList.remove('active-sublink');

	if (element.parentElement && element.parentElement.classList.contains('js-he-link-wrapper')) {
		markLinkElement(element.parentElement, active_nr);
	}

	if (!active_nr) {
		return;
	}

	if (active_nr == 1) {
		element.classList.add('active-link');
	} else if (active_nr == 2) {
		element.classList.add('active-sublink');
	}
}

/**
 * Create a socket.io connection to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.2.0
 *
 * @param     {Function}   callback
 */
alchemy.connect = function connect(callback) {

	if (typeof window.io === 'undefined') {
		hawkejs.require(['socket.io.js', 'socket.io-stream'], function() {
			alchemy.server.connect(callback);
		});
	} else {
		alchemy.server.connect(callback);
	}
};

/**
 * Submit a message to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.0.1
 *
 * @param    {String}   type
 * @param    {Object}   data
 * @param    {Function} callback
 */
alchemy.submit = function submit(type, data, callback) {
	alchemy.server.submit(type, data, callback);
};

/**
 * Create a namespace and inform the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.2.0
 *
 * @param    {String}   type    The typename of link to create
 * @param    {Object}   data    The initial data to submit
 *
 * @return   {Linkup}
 */
alchemy.linkup = function linkup(type, data) {
	return alchemy.server.linkup(type, data);
};

/**
 * Listen for server messages
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.0.1
 * @version   0.0.1
 *
 * @param    {String}   type
 * @param    {Function} callback
 */
alchemy.listen = alchemy.on = function listen(type, callback) {
	return alchemy.server.on(type, callback);
};

/**
 * Send binding data to the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.2.0
 * @version   0.3.0
 */
alchemy.sendBindingRequests = function sendBindingRequests() {

	var subscriptions = [],
	    elements,
	    data_id,
	    element,
	    i;

	// Look for all the non-bound elements that require an update event
	elements = document.querySelectorAll('[data-update-event]');

	// Iterate over them in order to register them
	for (i = 0; i < elements.length; i++) {
		element = elements[i];
		data_id = element.getAttribute('data-update-event');

		if (~sent_subscriptions.indexOf(data_id)) {
			continue;
		}

		sent_subscriptions.push(data_id);
		subscriptions.push(data_id);
	}

	for (data_id in hawkejs.scene.live_bindings) {

		if (~sent_subscriptions.indexOf(data_id)) {
			continue;
		}

		sent_subscriptions.push(data_id);
		subscriptions.push(data_id);
	}

	// Send data id subscriptions
	if (subscriptions.length) {
		alchemy.submit('subscribe-data', subscriptions);
	}
};

// Make the connection only if websockets are enabled
if (hawkejs.scene.exposed.enable_websockets) {

	// Connect to the server
	alchemy.connect(function onConnect() {
		alchemy.sendBindingRequests();
	});

	// Send binding requests again after each render
	hawkejs.scene.on('rendered', function onRendered(){
		alchemy.sendBindingRequests();
	});

	// Bind to elements with the data-server-event attribute
	hawkejs.constructor.onAttribute('data-server-event', function serverEvent(element, value, old_value, created) {

		var event_type;

		if (value == old_value || !value) {
			return;
		}

		event_type = element.getAttribute('data-listen-type');

		if (!event_type) {
			if (element.nodeName == 'A' || element.nodeName == 'BUTTON') {
				event_type = 'click';
			} else {
				event_type = 'change';
			}
		}

		// And the change event
		element.addEventListener(event_type, function sendToServer(e) {
			var get_form,
			    elements,
			    element,
			    e_val,
			    value,
			    data,
			    i;

			console.log('Sending to server...', e);

			if (this.hasAttribute('data-server-event-form')) {
				get_form = this.getAttribute('data-server-event-form');

				if (get_form) {
					get_form = document.querySelector(get_form);
				} else {
					get_form = this.closest('form');
				}

				if (get_form) {
					data = {};

					elements = get_form.querySelectorAll('[data-name]');

					for (i = 0; i < elements.length; i++) {
						element = elements[i];
						e_val = element.value;

						switch (element.getAttribute('type')) {
							case 'number':
								e_val = Number(e_val);
								break;
						}

						data[element.getAttribute('data-name')] = e_val;
					}
				}
			}

			// Get the event string
			value = this.getAttribute('data-server-event').split('|').map(function eachEntry(str) {
				var result = str.trim();

				return result;
			});

			if (this.getAttribute('data-send-value')) {

				if (!data) {
					data = {};
				}

				data.value = this.value;
			}

			if (data) {
				value.push(data);
			}

			alchemy.submit('data-server-event', value);
			e.preventDefault();
		});
	});

	// Listen to data updates
	alchemy.on('data-update', function gotDataUpdate(packet) {

		var data = packet.data,
		    id = packet.id;

		alchemy.last_update = Date.now();
		hawkejs.scene.updateData(id, data);
	});
}

/**
 * Fetch date from the server
 *
 * @author    Jelle De Loecker   <jelle@develry.be>
 * @since     0.4.0
 * @version   0.4.0
 */
alchemy.fetch = function fetch(href, options, callback) {

	var temp;

	if (typeof href == 'object' && !(href instanceof Blast.Classes.URL)) {
		callback = options;
		options = href;
		href = options.href;
	}

	// The href could be a resource name, try getting the url
	temp = hawkejs.scene.helpers.Router.routeUrl(href);

	if (temp) {
		href = temp;
	}

	return hawkejs.scene.fetch(href, options, callback);
};

__Protoblast.emit('alchemy-loaded');
}());<|endoftext|>


<commit_before>describe('Navy.WebInstaller installs web resource to WebSQL:', function(){

  it('updates local resources by using manifest.', function(done){
    Navy.WebInstaller.initialize('/base/fixture/manifest1.json');

    var totalUpdatingCount;
    var updatingCount = 0;
    var options = {
      forceUpdate: true,
      onProgress: function(count, total) {
        updatingCount++;
        totalUpdatingCount = total;
      },
      onComplete: function() {
        expect(updatingCount).toBe(5);
        expect(updatingCount).toBe(totalUpdatingCount);
        done();
      },
      onError: function(path) {
        throw new Error('fail updating path. ' + path);
      }
    };

    Navy.WebInstaller.update(options);
  });

  it('only update invalid resources.', function(done){
    Navy.WebInstaller.setManifestURL('/base/fixture/manifest2.json');

    var totalUpdatingCount;
    var updatingCount = 0;
    var options = {
      onProgress: function(count, total) {
        updatingCount++;
        totalUpdatingCount = total;
      },
      onComplete: function() {
        expect(updatingCount).toBe(2);
        expect(updatingCount).toBe(totalUpdatingCount);
        done();
      },
      onError: function(path) {
        throw new Error('fail updating path. ' + path);
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('do not update when not changed manifest', function(done){
    var options = {
      onProgress: function() {
        throw new Error('onProgress should not be called.');
      },
      onComplete: function() {
        expect(true).toBeTruthy();
        done();
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('call onError when remote file is not exists.', function(done){
    Navy.WebInstaller.setManifestURL('/base/fixture/manifest3_error.json');

    var options = {
      onError: function(path) {
        expect(path).toBe('/not_exists.js');
        done();
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('can load javascript.', function(done){
    var scriptElement = document.createElement('script');
    Navy.WebInstaller.loadJavaScript('/base/fixture/code/code1.js', scriptElement, function(scriptElement){
      expect(scriptElement.textContent).toBe('// dummy code1\n');
      done();
    });
  });

  it('can load json.', function(done){
    Navy.WebInstaller.loadJSON('/base/fixture/layout/layout1.json', function(obj){
      expect(obj).toEqual({prop1: 'dummy layout1'});
      done();
    });
  });

  it('can load image.', function(done){
    var imageElement = new Image();
    Navy.WebInstaller.loadImage('/base/fixture/image/image1.png', imageElement, function(imageElement){
      var src = imageElement.src;
      expect(src).toContain('/base/fixture/image/image1.png');
      expect(imageElement.complete).toBeTruthy();
      done();
    });
  });

  it('can load css.', function(done){
    var styleElement = document.createElement('style');
    Navy.WebInstaller.loadCSS('/base/fixture/css/style1.css', styleElement, function(styleElement){
      expect(styleElement.textContent).toBe('/* dummy style1 */\n');
      done();
    })
  });

  it('can be updated if disabled database.', function(done){
    Navy.WebInstaller.setEnableDatabase(false);

    Navy.WebInstaller.update({
      onProgress: function(){
        throw new Error('onProgress should not be called');
      },
      onComplete: function(){
        expect(true).toBeTruthy();
        done();
      }
    });
  });

  it('can load remote resource.', function(done){
    Navy.WebInstaller.setEnableDatabase(false);
    expect(Navy.WebInstaller._loadResource).toBe(Navy.WebInstaller._loadRemoteResource);

    Navy.WebInstaller.loadJSON('/base/fixture/config/config1.json', function(obj){
      expect(obj).toEqual({prop1: 'dummy config1'});
      Navy.WebInstaller.setEnableDatabase(true);
      done();
    });
  });

  describe('exceptions', function(){
    it('throws not javascript exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not javascript');
        expect(errorMsg).toContain('config1.json');
        done();
      };
      var scriptElement = document.createElement('script');
      Navy.WebInstaller.loadJavaScript('/base/fixture/config/config1.json', scriptElement, function(scriptElement){});
    });

    it('throws not json exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not json');
        expect(errorMsg).toContain('code1.js');
        done();
      };
      Navy.WebInstaller.loadJSON('/base/fixture/code/code1.js', function(obj){});
    });

    it('throws not css exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not css');
        expect(errorMsg).toContain('code1.js');
        done();
      };

      var styleElement = document.createElement('style');
      Navy.WebInstaller.loadCSS('/base/fixture/code/code1.js', styleElement, function(styleElement){});
    });

    it('throws not image exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not image');
        expect(errorMsg).toContain('code1.js');
        done();
      };

      var imageElement = new Image();
      Navy.WebInstaller.loadImage('/base/fixture/code/code1.js', imageElement, function(){});
    });

    it('throws not exists image.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('fail loading image');
        expect(errorMsg).toContain('not_exists_image.png');
        done();
      };

      var imageElement = new Image();
      Navy.WebInstaller.loadImage('/not_exists_image.png', imageElement, function(){});
    });

    it('throws not found path in DB exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('not found the path in DB');
        expect(errorMsg).toContain('not_exists_json.json');
        done();
      };

      Navy.WebInstaller.loadJSON('/not_exists_json.json', function(){});
    });

    it('throws not found path in remote exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('not found the path in remote');
        expect(errorMsg).toContain('not_exists_json.json');
        done();
      };

      Navy.WebInstaller.setEnableDatabase(false);
      Navy.WebInstaller.loadJSON('/not_exists_json.json', function(){});
      Navy.WebInstaller.setEnableDatabase(true);
    });

    it('throws unknown file extension exception.', function(){
      var exception = null;
      try {
        Navy.WebInstaller._getContentType('foo.invalid');
      } catch(e) {
        exception = e;
      }

      expect(exception.message).toContain('unknown file extension');
      expect(exception.message).toContain('.invalid');
    });
  });
});
<commit_msg>Loaderの例外spec追加.<commit_after>describe('Navy.WebInstaller installs web resource to WebSQL:', function(){

  it('updates local resources by using manifest.', function(done){
    Navy.WebInstaller.initialize('/base/fixture/manifest1.json');

    var totalUpdatingCount;
    var updatingCount = 0;
    var options = {
      forceUpdate: true,
      onProgress: function(count, total) {
        updatingCount++;
        totalUpdatingCount = total;
      },
      onComplete: function() {
        expect(updatingCount).toBe(5);
        expect(updatingCount).toBe(totalUpdatingCount);
        done();
      },
      onError: function(path) {
        throw new Error('fail updating path. ' + path);
      }
    };

    Navy.WebInstaller.update(options);
  });

  it('only update invalid resources.', function(done){
    Navy.WebInstaller.setManifestURL('/base/fixture/manifest2.json');

    var totalUpdatingCount;
    var updatingCount = 0;
    var options = {
      onProgress: function(count, total) {
        updatingCount++;
        totalUpdatingCount = total;
      },
      onComplete: function() {
        expect(updatingCount).toBe(2);
        expect(updatingCount).toBe(totalUpdatingCount);
        done();
      },
      onError: function(path) {
        throw new Error('fail updating path. ' + path);
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('do not update when not changed manifest', function(done){
    var options = {
      onProgress: function() {
        throw new Error('onProgress should not be called.');
      },
      onComplete: function() {
        expect(true).toBeTruthy();
        done();
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('call onError when remote file is not exists.', function(done){
    Navy.WebInstaller.setManifestURL('/base/fixture/manifest3_error.json');

    var options = {
      onError: function(path) {
        expect(path).toBe('/not_exists.js');
        done();
      }
    };
    Navy.WebInstaller.update(options);
  });

  it('can load javascript.', function(done){
    var scriptElement = document.createElement('script');
    Navy.WebInstaller.loadJavaScript('/base/fixture/code/code1.js', scriptElement, function(scriptElement){
      expect(scriptElement.textContent).toBe('// dummy code1\n');
      done();
    });
  });

  it('can load json.', function(done){
    Navy.WebInstaller.loadJSON('/base/fixture/layout/layout1.json', function(obj){
      expect(obj).toEqual({prop1: 'dummy layout1'});
      done();
    });
  });

  it('can load image.', function(done){
    var imageElement = new Image();
    Navy.WebInstaller.loadImage('/base/fixture/image/image1.png', imageElement, function(imageElement){
      var src = imageElement.src;
      expect(src).toContain('/base/fixture/image/image1.png');
      expect(imageElement.complete).toBeTruthy();
      done();
    });
  });

  it('can load css.', function(done){
    var styleElement = document.createElement('style');
    Navy.WebInstaller.loadCSS('/base/fixture/css/style1.css', styleElement, function(styleElement){
      expect(styleElement.textContent).toBe('/* dummy style1 */\n');
      done();
    })
  });

  it('can be updated if disabled database.', function(done){
    Navy.WebInstaller.setEnableDatabase(false);

    Navy.WebInstaller.update({
      onProgress: function(){
        throw new Error('onProgress should not be called');
      },
      onComplete: function(){
        expect(true).toBeTruthy();
        done();
      }
    });
  });

  it('can load remote resource.', function(done){
    Navy.WebInstaller.setEnableDatabase(false);
    expect(Navy.WebInstaller._loadResource).toBe(Navy.WebInstaller._loadRemoteResource);

    Navy.WebInstaller.loadJSON('/base/fixture/config/config1.json', function(obj){
      expect(obj).toEqual({prop1: 'dummy config1'});
      Navy.WebInstaller.setEnableDatabase(true);
      done();
    });
  });

  describe('exceptions', function(){
    it('throws not javascript exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not javascript');
        expect(errorMsg).toContain('config1.json');
        done();
      };
      var scriptElement = document.createElement('script');
      Navy.WebInstaller.loadJavaScript('/base/fixture/config/config1.json', scriptElement, function(scriptElement){});
    });

    it('throws not json exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not json');
        expect(errorMsg).toContain('code1.js');
        done();
      };
      Navy.WebInstaller.loadJSON('/base/fixture/code/code1.js', function(obj){});
    });

    it('throws not css exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not css');
        expect(errorMsg).toContain('code1.js');
        done();
      };

      var styleElement = document.createElement('style');
      Navy.WebInstaller.loadCSS('/base/fixture/code/code1.js', styleElement, function(styleElement){});
    });

    it('throws not image exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('the path is not image');
        expect(errorMsg).toContain('code1.js');
        done();
      };

      var imageElement = new Image();
      Navy.WebInstaller.loadImage('/base/fixture/code/code1.js', imageElement, function(){});
    });

    it('throws not exists image.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('fail loading image');
        expect(errorMsg).toContain('not_exists_image.png');
        done();
      };

      var imageElement = new Image();
      Navy.WebInstaller.loadImage('/not_exists_image.png', imageElement, function(){});
    });

    it('throws not found path in DB exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('not found the path in DB');
        expect(errorMsg).toContain('not_exists_json.json');
        done();
      };

      Navy.WebInstaller.loadJSON('/not_exists_json.json', function(){});
    });

    it('throws not found path in remote exception.', function(done){
      window.onerror = function(errorMsg){
        window.onerror = null;
        expect(errorMsg).toContain('not found the path in remote');
        expect(errorMsg).toContain('not_exists_json.json');
        done();
      };

      Navy.WebInstaller.setEnableDatabase(false);
      Navy.WebInstaller.loadJSON('/not_exists_json.json', function(){});
      Navy.WebInstaller.setEnableDatabase(true);
    });

    it('throws unknown file extension exception.', function(){
      var exception = null;
      try {
        Navy.WebInstaller._getContentType('foo.invalid');
      } catch(e) {
        exception = e;
      }

      expect(exception.message).toContain('unknown file extension');
      expect(exception.message).toContain('.invalid');
    });
  });

  describe('Navy.WebInstaller.Loader exception:', function(){
    var loader = new Navy.WebInstaller.Loader();

    it('throws unknown content type exception.', function(){
      var exception = null;
      try {
        loader.load({contentType: 'invalid/*'});
      } catch(e) {
        exception = e;
      }

      expect(exception.message).toContain('unknown content type');
      expect(exception.message).toContain('invalid/*');
    });

    it('does not throw exception when onload/onerror is null.', function(){
      loader.onload = null;
      loader.onerror = null;

      var exception = null;
      try {
        loader._onLoad();
        loader._onError();
      } catch(e) {
        exception = e;
      }

      expect(exception).toBeNull();
    });

  });
});
<|endoftext|>


<commit_before>// This script takes the DHL country.txt file, only retains the used columns and then
// stores the JSON document in MongoDB
// See developer documentation here: http://www.dhl.co.uk/content/gb/en/express/resource_centre/integrated_shipping_solutions/developer_download_centre1.html

/*
TODO:
- remove doubles/triples
- compare nr of postcodes here: http://www.goeievraag.nl/vraag/maatschappij/samenleving/verschillende-postcodes-inclusief-letters-nederland.118761
- get new relic working
*/

"use strict";
require('newrelic');

// start timer
var start = process.hrtime();

// MongoDB configuration
var db = require("mongojs").connect("test"); // "username:password@example.com/mydb"
var mycollection = db.collection('test_ESD_1');

var Transform = require('stream').Transform,
    csv = require('csv-streamify'),
    JSONStream = require('JSONStream'),
    _ = require('lodash');

var nrOfRecords = 0;

// see parser options defined here: https://github.com/klaemo/csv-stream
var csvToJson = csv({objectMode: true, delimiter: '|' });

var parser = new Transform({objectMode: true});
parser._transform = function (data, encoding, done) {
    var countryCode = data[0];
    var cityName = data[4];
    var postcodeFrom = data[6];
    var postcodeTo = data[7];
    var result;
    var from;
    var to;
    // get rid of first title record
    if (countryCode == "NL") {
        if (postcodeFrom != "" && postcodeTo != "") {
            // postcode available
            if (postcodeFrom === postcodeTo) {
                // no postcode ranges so move on
                result = _.zipObject(
                    ['a', 'b', 'c'],
                    [countryCode, cityName, String(postcodeFrom)]
                );
                this.push(result);
                nrOfRecords++;
            } else {
                // postcode ranges
                from = parseInt(postcodeFrom);
                to = parseInt(postcodeTo);
                if (postcodeFrom == "8041") console.log("From: " + from + ", To: " + to);
                for (var i = from; i <= to; i++) {
                    result = _.zipObject(
                        ['a', 'b', 'c'],
                        [countryCode, cityName, String(i)]
                    );
                    this.push(result);
                    if (postcodeFrom == "8041") console.log("Nr: " + nrOfRecords + ", Counter: " + i);
                    if (postcodeFrom == "8041") console.log(result);
                    nrOfRecords++;
                }
            }
        } else {
            // No postcode, just city
            result = _.zipObject(
                ['a', 'b', 'c'],
                [countryCode, cityName, ""]
            );
            this.push(result);
            nrOfRecords++;
        }
    }
    done();
};
parser.on("end", function (done) {
    console.log("Nr of records processed: " + nrOfRecords);
    var precision = 3; // 3 decimal places
    var elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
    console.log("Processing time: " + process.hrtime(start)[0] + " s, " + elapsed.toFixed(precision) + " ms"); // print message + time
});

process.stdin
.pipe(csvToJson)
.pipe(parser)
.pipe(process.stdout);

<commit_msg>got deduplication of entries working now<commit_after>// This script takes the DHL country.txt file, only retains the used columns and then
// stores the JSON document in MongoDB
// See developer documentation here: http://www.dhl.co.uk/content/gb/en/express/resource_centre/integrated_shipping_solutions/developer_download_centre1.html

/*
TODO:
- get new relic working
*/

"use strict";

// start timer
var start = process.hrtime();

var Transform = require('stream').Transform,
    csv = require('csv-streamify'),
    JSONStream = require('JSONStream'),
    _ = require('lodash');

var nrOfRecords = 0;
var nrOfReducedRecords = 0;
var cityArray = [];

// see parser options defined here: https://github.com/klaemo/csv-stream
var csvToJson = csv({objectMode: true, delimiter: '|' });

var parser = new Transform({objectMode: true});
parser._transform = function (data, encoding, done) {
    var countryCode = data[0];
    var cityName = data[4];
    var postcodeFrom = data[6];
    var postcodeTo = data[7];
    var from;
    var to;
    var cityArray; // intermediate object for storing record
    // get rid of first title record
    if (countryCode == "NL") {
        if (postcodeFrom != "" && postcodeTo != "") {
            // postcode available
            if (postcodeFrom === postcodeTo) {
                // no postcode ranges so move on
                cityArray = [countryCode, cityName, String(postcodeFrom)];
                this.push(_.zipObject(['a', 'b', 'c'], cityArray));
                nrOfRecords++;
            } else {
                // unpack postcode ranges
                from = parseInt(postcodeFrom);
                to = parseInt(postcodeTo);
                for (var i = from; i <= to; i++) {
                    cityArray = [countryCode, cityName, String(i)];
                    this.push(_.zipObject(['a', 'b', 'c'], cityArray));
                    nrOfRecords++;
                }
            }
        } else {
            // No postcode, just city
            cityArray = [countryCode, cityName, ""];
            this.push(_.zipObject(['a', 'b', 'c'], cityArray));
            nrOfRecords++;
        }

    }
    done();
};
parser.on("end", function (done) {
    console.log("\nNr of records processed: " + nrOfRecords);
    console.log("Nr of final records: " + nrOfReducedRecords);
    var precision = 3; // 3 decimal places
    var elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
    console.log("Processing time: " + process.hrtime(start)[0] + " s, " + elapsed.toFixed(precision) + " ms"); // print message + time
});

var reducer = new Transform({objectMode: true});
reducer._transform = function (data, encoding, done) {
    var record = JSON.stringify(data);
    if (cityArray.indexOf(record) === -1) {
        cityArray.push(record);
        nrOfReducedRecords++;
        this.push(data);
    }
    done();
};

process.stdin
.pipe(csvToJson)
.pipe(parser)
.pipe(reducer)
.pipe(JSONStream.stringify(false))
.pipe(process.stdout);

<|endoftext|>


<commit_before>/**
 *
 * WoT.City Open Source Project
 *
 * Copyright 2015 WoT.City Open Source Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

 "use strict";

var bl = require('bl');
var WebSocketClient = require('websocket').client;

if (typeof(Handlers) == "undefined") {
    var Handlers = {};
}

/**
 * The sending observer.
 */
Handlers.send = function(pathname, connection, clients) {
  var stream = bl();

  // the server of this connection
  var server = connection.server;
  var req = connection.request;

  /*
   * convert sender pathname to viewer pathname
   * eg. '/object/testman/send' to '/object/testman/viewer'
   */
  var paths = pathname.split('/');

  // remove the rear string 'send'
  var viewer = paths.slice(0, -1).join('/');

  connection.viewer = viewer + '/viewer';

  var done = function(data) {
    // emit 'onData'
    server.emit('data', {
      data: data,
      pathname: pathname
    });

    // dispatch this data
    for (var path in clients) {
        if (path === connection.viewer)
            return server.dispatchData(path, data);
    }
  };

  req.on('data', function(chunk) {
    stream.append(chunk);
  });

  req.on('end', function() {
    var data = stream.toString('ascii');
    done(data);
  });
}

/**
 * The viewer observer.
 */
Handlers.viewer = function(pathname, connection, clients) {
  console.log("Viewer Routed: " + pathname);

  // write back the original sender pathname
  connection.pathname = pathname;

  // Save viewer clients (unlimited clients)
  for (var path in clients) {
      if (path === pathname) {
          return clients[path].push(connection.responsive);
      }
  }

  /*
   * Not found. There is not a existing sender.
   */
  clients[pathname] = [];
  clients[pathname].push(connection.responsive);
}

/**
 * The CoAP Proxy - HTTP
 */
Handlers.proxyingHTTP = function(pathname, connection, clients) {
  var http = require('http');
  var options = {
    host: 'wot.city',
    path: pathname
  };

  callback = function(response) {
    var str = '';

    // chunk of data
    response.on('data', function (chunk) {
      str += chunk;
    });

    response.on('end', function () {
    });
  }

  // Proxying this CoAP request
  http.request(options, callback).end();

  // write back the original sender pathname
  connection.pathname = pathname;
}

/**
 * The CoAP Proxy to WebSocket Endpoint
 */
var webSocketConnections = [];

Handlers.proxyingWebSocket = function(pathname, connection, clients) {
  var request = connection.request;
  var wsConn = webSocketConnections[pathname];

  // The instance of CoapServer
  var server = connection.server;
  var endpoint = server.endpoint;

  if (!/^(ws|wss):\/\//.test(endpoint)) {
    endpoint = 'ws://' + endpoint;
  }

  if (typeof(wsConn) === 'undefined') {
    var wsClient = new WebSocketClient();

    wsClient.on('connectFailed', function(error) {
      console.log('Connect Error: ' + error.toString());
    });

    wsClient.on('connect', function(conn) {
      conn.on('error', function(error) {
      });
      conn.on('close', function() {
        delete webSocketConnections[pathname];
      });
      conn.on('message', function(message) {
      });

      webSocketConnections[pathname] = conn;
    });

    var uri = endpoint + pathname;
    console.log('Connect to endpoint ' + uri);

    // initial websocket connection
    return wsClient.connect(uri, '');
  }

  // there is an normal websocket client of this client connection
  // start dispatch coap message
  var stream = bl();

  request.on('data', function(chunk) {
    stream.append(chunk);
  });

  // websocket sender
  request.on('end', function() {
    var data = stream.toString('ascii');
    wsConn.sendUTF(data);

    // emit 'onData'
    server.emit('data', {
      data: data
    });
  });

  // write back the original sender pathname
  connection.pathname = pathname;
}

if (typeof(module) != "undefined" && typeof(exports) != "undefined")
  module.exports = Handlers;
<commit_msg>Enhanced: payload of data event, #18<commit_after>/**
 *
 * WoT.City Open Source Project
 *
 * Copyright 2015 WoT.City Open Source Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

 "use strict";

var bl = require('bl');
var WebSocketClient = require('websocket').client;

if (typeof(Handlers) == "undefined") {
    var Handlers = {};
}

/**
 * The sending observer.
 */
Handlers.send = function(pathname, connection, clients) {
  var stream = bl();

  // the server of this connection
  var server = connection.server;
  var req = connection.request;

  /*
   * convert sender pathname to viewer pathname
   * eg. '/object/testman/send' to '/object/testman/viewer'
   */
  var paths = pathname.split('/');

  // remove the rear string 'send'
  var viewer = paths.slice(0, -1).join('/');

  connection.viewer = viewer + '/viewer';

  var done = function(data) {
    // emit 'onData'
    server.emit('data', {
      data: data,
      pathname: pathname
    });

    // dispatch this data
    for (var path in clients) {
        if (path === connection.viewer)
            return server.dispatchData(path, data);
    }
  };

  req.on('data', function(chunk) {
    stream.append(chunk);
  });

  req.on('end', function() {
    var data = stream.toString('ascii');
    done(data);
  });
}

/**
 * The viewer observer.
 */
Handlers.viewer = function(pathname, connection, clients) {
  console.log("Viewer Routed: " + pathname);

  // write back the original sender pathname
  connection.pathname = pathname;

  // Save viewer clients (unlimited clients)
  for (var path in clients) {
      if (path === pathname) {
          return clients[path].push(connection.responsive);
      }
  }

  /*
   * Not found. There is not a existing sender.
   */
  clients[pathname] = [];
  clients[pathname].push(connection.responsive);
}

/**
 * The CoAP Proxy - HTTP
 */
Handlers.proxyingHTTP = function(pathname, connection, clients) {
  var http = require('http');
  var options = {
    host: 'wot.city',
    path: pathname
  };

  callback = function(response) {
    var str = '';

    // chunk of data
    response.on('data', function (chunk) {
      str += chunk;
    });

    response.on('end', function () {
    });
  }

  // Proxying this CoAP request
  http.request(options, callback).end();

  // write back the original sender pathname
  connection.pathname = pathname;
}

/**
 * The CoAP Proxy to WebSocket Endpoint
 */
var webSocketConnections = [];

Handlers.proxyingWebSocket = function(pathname, connection, clients) {
  var request = connection.request;
  var wsConn = webSocketConnections[pathname];

  // The instance of CoapServer
  var server = connection.server;
  var endpoint = server.endpoint;

  if (!/^(ws|wss):\/\//.test(endpoint)) {
    endpoint = 'ws://' + endpoint;
  }

  if (typeof(wsConn) === 'undefined') {
    var wsClient = new WebSocketClient();

    wsClient.on('connectFailed', function(error) {
      console.log('Connect Error: ' + error.toString());
    });

    wsClient.on('connect', function(conn) {
      conn.on('error', function(error) {
      });
      conn.on('close', function() {
        delete webSocketConnections[pathname];
      });
      conn.on('message', function(message) {
      });

      webSocketConnections[pathname] = conn;
    });

    var uri = endpoint + pathname;
    console.log('Connect to endpoint ' + uri);

    // initial websocket connection
    return wsClient.connect(uri, '');
  }

  // there is an normal websocket client of this client connection
  // start dispatch coap message
  var stream = bl();

  request.on('data', function(chunk) {
    stream.append(chunk);
  });

  // websocket sender
  request.on('end', function() {
    var data = stream.toString('ascii');
    wsConn.sendUTF(data);

    // emit 'onData'
    server.emit('data', {
      data: data,
      pathname: pathname
    });
  });

  // write back the original sender pathname
  connection.pathname = pathname;
}

if (typeof(module) != "undefined" && typeof(exports) != "undefined")
  module.exports = Handlers;
<|endoftext|>