<commit_before>import { useState } from 'react';
import Popover from '@material-ui/core/Popover';
import { makeStyles } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
import cx from 'clsx';
import BaseFilterOption from './BaseFilterOption';

const useStyles = makeStyles(theme => ({
  title: {
    fontSize: 12,
    lineHeight: '20px',
    color: theme.palette.secondary[300],
    padding: `${theme.spacing(1)}px 18px 0`,

    [theme.breakpoints.up('md')]: {
      fontSize: 14,
      paddingTop: theme.spacing(1.5),
      borderBottom: `1px solid ${theme.palette.secondary[100]}`,
    },
    '&:last-of-type': {
      borderBottom: 0,
    },
  },
  expandable: {
    cursor: 'pointer',
    '&:hover': {
      color: theme.palette.secondary[500],
    },
    '& > svg': {
      verticalAlign: 'middle',
    },
  },
  active: {
    color: theme.palette.primary[500],
  },
  body: {
    margin: 0 /* override dd defaults */,
    borderBottom: `1px solid ${theme.palette.secondary[100]}`,
    '&:last-child': {
      borderBottom: 0,
    },

    padding: theme.spacing(0.5),
    '& > *': {
      margin: theme.spacing(0.5),
    },
  },
  dropdown: {
    maxWidth: 400,
    padding: '14px 20px',
    '& > *': {
      margin: '6px 4px',
    },
  },
  placeholder: {
    padding: '4px 10px',
    margin: 4,
  },
}));

/**
 * One row of filter in <Filters>.
 * Designed to add 2 grid cells in <Filters>'s grid.
 *
 * @param {string} props.title
 * @param {string?} props.placeholder - Shown when no options are selected
 * @param {boolean?} props.expandable - Makes options collapsible on desktop.
 *   Turning this on also hides filters not selected on desktop.
 * @param {Array<string>} props.selected - Selected option values
 * @param {Array<{value: string, label:string}>} props.options
 * @param {(selected: string[]) => void} props.onChange
 */
function BaseFilter({
  title,
  onChange = () => null,
  placeholder,
  expandable,
  selected = [],
  options = [],
}) {
  const classes = useStyles();
  const [expandEl, setExpandEl] = useState(null);

  // Note: this is implemented using JS, don't use it on places
  // that is going to cause flicker on page load!
  const isDesktop = useMediaQuery(theme => theme.breakpoints.up('md'));

  const isValueSelected = Object.fromEntries(
    selected.map(value => [value, true])
  );
  const isExpandable = expandable && isDesktop;

  const handleOptionClicked = value => {
    if (isValueSelected[value]) {
      onChange(selected.filter(v => v !== value));
    } else {
      onChange(selected.concat(value));
    }
  };

  const handleExpand = e => {
    setExpandEl(e.currentTarget);
  };

  const handleCollapse = () => {
    setExpandEl(null);
  };

  const isExpanded = !!expandEl;
  const dtProps = isExpandable
    ? {
        onClick: isExpanded ? handleCollapse : handleExpand,
        'data-ga': 'FilterExpandButton',
      }
    : {};

  return (
    <>

        {title}
        {isExpandable && (isExpanded ? <ExpandLessIcon /> : <ExpandMoreIcon />)}

      <Popover
        open={isExpanded}
        anchorEl={expandEl}
        onClose={handleCollapse}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
        transformOrigin={{
          vertical: -4,
          horizontal: 'left',
        }}
        elevation={1}
      >

          {options.map(option => (
            <BaseFilterOption
              key={option.value}
              selected={isValueSelected[option.value]}
              label={option.label}
              value={option.value}
              onClick={handleOptionClicked}
              chip
            />
          ))}

      </Popover>

        {placeholder && selected.length === 0 ? (

{placeholder}

        ) : (
          options
            .filter(option =>
              // Only show selected items when BaseFilter is expandable
              isExpandable ? isValueSelected[option.value] : true
            )
            .map(option => (
              <BaseFilterOption
                key={option.value}
                label={option.label}
                value={option.value}
                selected={isValueSelected[option.value]}
                onClick={handleOptionClicked}
              />
            ))
        )}

    </>
  );
}

export default BaseFilter;
<commit_msg>[ListPage] reduce the need to include 2 icons and also add transition animation<commit_after>import { useState } from 'react';
import Popover from '@material-ui/core/Popover';
import { makeStyles } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import cx from 'clsx';
import BaseFilterOption from './BaseFilterOption';

const useStyles = makeStyles(theme => ({
  title: {
    fontSize: 12,
    lineHeight: '20px',
    color: theme.palette.secondary[300],
    padding: `${theme.spacing(1)}px 18px 0`,

    [theme.breakpoints.up('md')]: {
      fontSize: 14,
      paddingTop: theme.spacing(1.5),
      borderBottom: `1px solid ${theme.palette.secondary[100]}`,
    },
    '&:last-of-type': {
      borderBottom: 0,
    },
  },
  expandable: {
    cursor: 'pointer',
    '&:hover': {
      color: theme.palette.secondary[500],
    },
    '& > svg': {
      verticalAlign: 'middle',
    },
  },
  active: {
    color: theme.palette.primary[500],
  },
  icon: {
    transition: 'transform .2s',
  },
  activeIcon: {
    transform: 'rotateX(180deg)',
  },
  body: {
    margin: 0 /* override dd defaults */,
    borderBottom: `1px solid ${theme.palette.secondary[100]}`,
    '&:last-child': {
      borderBottom: 0,
    },

    padding: theme.spacing(0.5),
    '& > *': {
      margin: theme.spacing(0.5),
    },
  },
  dropdown: {
    maxWidth: 400,
    padding: '14px 20px',
    '& > *': {
      margin: '6px 4px',
    },
  },
  placeholder: {
    padding: '4px 10px',
    margin: 4,
  },
}));

/**
 * One row of filter in <Filters>.
 * Designed to add 2 grid cells in <Filters>'s grid.
 *
 * @param {string} props.title
 * @param {string?} props.placeholder - Shown when no options are selected
 * @param {boolean?} props.expandable - Makes options collapsible on desktop.
 *   Turning this on also hides filters not selected on desktop.
 * @param {Array<string>} props.selected - Selected option values
 * @param {Array<{value: string, label:string}>} props.options
 * @param {(selected: string[]) => void} props.onChange
 */
function BaseFilter({
  title,
  onChange = () => null,
  placeholder,
  expandable,
  selected = [],
  options = [],
}) {
  const classes = useStyles();
  const [expandEl, setExpandEl] = useState(null);

  // Note: this is implemented using JS, don't use it on places
  // that is going to cause flicker on page load!
  const isDesktop = useMediaQuery(theme => theme.breakpoints.up('md'));

  const isValueSelected = Object.fromEntries(
    selected.map(value => [value, true])
  );
  const isExpandable = expandable && isDesktop;

  const handleOptionClicked = value => {
    if (isValueSelected[value]) {
      onChange(selected.filter(v => v !== value));
    } else {
      onChange(selected.concat(value));
    }
  };

  const handleExpand = e => {
    setExpandEl(e.currentTarget);
  };

  const handleCollapse = () => {
    setExpandEl(null);
  };

  const isExpanded = !!expandEl;
  const dtProps = isExpandable
    ? {
        onClick: isExpanded ? handleCollapse : handleExpand,
        'data-ga': 'FilterExpandButton',
      }
    : {};

  return (
    <>

        {title}
        {isExpandable && (
          <ExpandMoreIcon
            className={cx(classes.icon, { [classes.activeIcon]: isExpanded })}
          />
        )}

      <Popover
        open={isExpanded}
        anchorEl={expandEl}
        onClose={handleCollapse}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
        transformOrigin={{
          vertical: -4,
          horizontal: 'left',
        }}
        elevation={1}
      >

          {options.map(option => (
            <BaseFilterOption
              key={option.value}
              selected={isValueSelected[option.value]}
              label={option.label}
              value={option.value}
              onClick={handleOptionClicked}
              chip
            />
          ))}

      </Popover>

        {placeholder && selected.length === 0 ? (

{placeholder}

        ) : (
          options
            .filter(option =>
              // Only show selected items when BaseFilter is expandable
              isExpandable ? isValueSelected[option.value] : true
            )
            .map(option => (
              <BaseFilterOption
                key={option.value}
                label={option.label}
                value={option.value}
                selected={isValueSelected[option.value]}
                onClick={handleOptionClicked}
              />
            ))
        )}

    </>
  );
}

export default BaseFilter;
<|endoftext|>


<commit_before>'use strict';

var gulpConfig = require(__dirname + '/../gulpfile').config;

var sessionPages = require(__dirname + '/e2e/pages/session'),
    communityPages = require(__dirname + '/e2e/pages/community'),
    projectPages = require(__dirname + '/e2e/pages/project');

exports.config = {
  allScriptsTimeout: 90000,

  // Sometimes Selenium Webdriver gets stuck, and directly connecting to browsers work
  //directConnect: true,

  specs: [
    'e2e/**/*.js'
  ],

  multiCapabilities: [
    {
      'browserName': 'chrome',
      'chromeOptions' : {
        args: [
          '--lang=en',
          '--window-size=1024,800'
        ]
      },
    },
    {
      'browserName': 'chrome',
      'chromeOptions' : {
        args: [
          '--lang=en',
          '--window-size=350,650'
        ]
      },
    }
  ],

  baseUrl: 'http://' + gulpConfig.serverTest.host + ':' + gulpConfig.serverTest.port + '/',

  framework: 'jasmine2',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 90000
  },

  suites: {
    session: 'e2e/session.js',
    frontpage: 'e2e/frontpage.js',
    core: 'e2e/core/*.js',
    participant: 'e2e/participant/*.js',
    guest: 'e2e/guest/*.js'
  },

  onPrepare: function() {
    var registerPage = new sessionPages.Register(),
        loginPage = new sessionPages.Login(),
        newCommunityPage = new communityPages.NewCommunityPage(),
        projectsPage = new projectPages.ProjectsPage(),
        newProjectPage = new projectPages.NewProjectPage();

    // Disable animations to improve tests performance
    // Source http://stackoverflow.com/a/32611061/4928558

    var disableNgAnimate = function() {
        angular
            .module('disableNgAnimate', [])
            .run(['$animate', function($animate) {
                $animate.enabled(false);
            }]);
    };

    var disableCssAnimate = function() {
        angular
            .module('disableCssAnimate', [])
            .run(function() {
                var style = document.createElement('style');
                style.type = 'text/css';
                style.innerHTML = '* {' +
                    '-webkit-transition: none !important;' +
                    '-moz-transition: none !important' +
                    '-o-transition: none !important' +
                    '-ms-transition: none !important' +
                    'transition: none !important' +
                    '}';
                document.getElementsByTagName('head')[0].appendChild(style);
            });
    };

    // Decrease Notifications delay
    var shortNotifications = function(){
      angular.module('shortNotifications', ['ui-notification'])
        .config(function(NotificationProvider) {
          NotificationProvider.setOptions({
            delay: 1000
        });
    });
    };

    browser.addMockModule('disableNgAnimate', disableNgAnimate);
    browser.addMockModule('disableCssAnimate', disableCssAnimate);
    browser.addMockModule('shortNotifications', shortNotifications);

    return browser.driver.executeScript('return window.innerWidth >= 992;').then((desktop) => {
      global.isDesktop = desktop;
    }).then(() => {
      // isDesktop global variable is needed for some of these:

      // Register default user
      registerPage.get();
      registerPage.register();

      registerPage.get();
      registerPage.register(registerPage.participant);

      loginPage.get();
      loginPage.login(loginPage.default);

      // Create default community
      newCommunityPage.get();
      newCommunityPage.create();

      browser.getCurrentUrl().then((url) => {
        global.defaultCommunity = newCommunityPage;
        global.defaultCommunity.url = url;
      });

      // Create default teem
      projectsPage.goToNew();
      newProjectPage.create();

      return browser.getCurrentUrl().then((url) => {
        global.defaultProject = newProjectPage;
        global.defaultProject.url = url;
      });
    });
  }
};
<commit_msg>Decrease wait timeout so it does not crashes with Jasmine's<commit_after>'use strict';

var gulpConfig = require(__dirname + '/../gulpfile').config;

var sessionPages = require(__dirname + '/e2e/pages/session'),
    communityPages = require(__dirname + '/e2e/pages/community'),
    projectPages = require(__dirname + '/e2e/pages/project');

exports.config = {
  allScriptsTimeout: 30000,

  // Sometimes Selenium Webdriver gets stuck, and directly connecting to browsers work
  //directConnect: true,

  specs: [
    'e2e/**/*.js'
  ],

  multiCapabilities: [
    {
      'browserName': 'chrome',
      'chromeOptions' : {
        args: [
          '--lang=en',
          '--window-size=1024,800'
        ]
      },
    },
    {
      'browserName': 'chrome',
      'chromeOptions' : {
        args: [
          '--lang=en',
          '--window-size=350,650'
        ]
      },
    }
  ],

  baseUrl: 'http://' + gulpConfig.serverTest.host + ':' + gulpConfig.serverTest.port + '/',

  framework: 'jasmine2',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 90000
  },

  suites: {
    session: 'e2e/session.js',
    frontpage: 'e2e/frontpage.js',
    core: 'e2e/core/*.js',
    participant: 'e2e/participant/*.js',
    guest: 'e2e/guest/*.js'
  },

  onPrepare: function() {
    var registerPage = new sessionPages.Register(),
        loginPage = new sessionPages.Login(),
        newCommunityPage = new communityPages.NewCommunityPage(),
        projectsPage = new projectPages.ProjectsPage(),
        newProjectPage = new projectPages.NewProjectPage();

    // Disable animations to improve tests performance
    // Source http://stackoverflow.com/a/32611061/4928558

    var disableNgAnimate = function() {
        angular
            .module('disableNgAnimate', [])
            .run(['$animate', function($animate) {
                $animate.enabled(false);
            }]);
    };

    var disableCssAnimate = function() {
        angular
            .module('disableCssAnimate', [])
            .run(function() {
                var style = document.createElement('style');
                style.type = 'text/css';
                style.innerHTML = '* {' +
                    '-webkit-transition: none !important;' +
                    '-moz-transition: none !important' +
                    '-o-transition: none !important' +
                    '-ms-transition: none !important' +
                    'transition: none !important' +
                    '}';
                document.getElementsByTagName('head')[0].appendChild(style);
            });
    };

    // Decrease Notifications delay
    var shortNotifications = function(){
      angular.module('shortNotifications', ['ui-notification'])
        .config(function(NotificationProvider) {
          NotificationProvider.setOptions({
            delay: 1000
        });
    });
    };

    browser.addMockModule('disableNgAnimate', disableNgAnimate);
    browser.addMockModule('disableCssAnimate', disableCssAnimate);
    browser.addMockModule('shortNotifications', shortNotifications);

    return browser.driver.executeScript('return window.innerWidth >= 992;').then((desktop) => {
      global.isDesktop = desktop;
    }).then(() => {
      // isDesktop global variable is needed for some of these:

      // Register default user
      registerPage.get();
      registerPage.register();

      registerPage.get();
      registerPage.register(registerPage.participant);

      loginPage.get();
      loginPage.login(loginPage.default);

      // Create default community
      newCommunityPage.get();
      newCommunityPage.create();

      browser.getCurrentUrl().then((url) => {
        global.defaultCommunity = newCommunityPage;
        global.defaultCommunity.url = url;
      });

      // Create default teem
      projectsPage.goToNew();
      newProjectPage.create();

      return browser.getCurrentUrl().then((url) => {
        global.defaultProject = newProjectPage;
        global.defaultProject.url = url;
      });
    });
  }
};
<|endoftext|>


<commit_before>// Main JS File<% if (projectjquery === true) { %>
import $ from 'jquery'<% } %><% if ( projectJSFramework === 'React' ) { %>
import React from 'react'
import ReactDOM from 'react-dom'<% } %>
import eq from 'eqcss'<% if ( projectJSFramework === 'Vue.js' ) { %>
import Vue from 'vue'<% } %><% if ( projectvueplugins === true)  { %>
import { sync } from 'vuex-router-sync'
import axios from 'axios'
import VueAxios from 'vue-axios'
import router from './router/router'
import store from './store/store'<% }  if (projectcraftbp === true || projectwordpressbp === true) { %>
import progressLoader from './partial/progressloader'
import initPhotoSwipeFromDOM from './partial/init-photoswipe' // eslint-disable-line
import './partial/init-heighttransition'
import './partial/init-autoscroll'
import 'flickity'
import 'flickity-imagesloaded'<% } %>
import lazySizes from 'lazysizes'
import lazybgset from 'lazysizes/plugins/bgset/ls.bgset'
import 'babel-polyfill'
import 'svgxuse' // eslint-disable-line
import './partial/kittnad' // Small Advertising for Kittn :)
import './partial/modernizer-loader'
import './partial/conditionizr-init'
import './partial/disable-pointerevents'<% if ( projectJSFramework === 'Vue.js') { %>
import App from './app.vue'<%}%><% if (projectvueplugins === true)  { %>

// keep vue-router and vuex store in sync
    sync(store, router)

// Adding Vue Plugins
Vue.use(VueAxios, axios)<% } %>

<% if ( projectJSFramework === 'Vue.js' && projectvueplugins === false) { %>
// Vue App
/* eslint-disable no-new */
new Vue({
    el: '#app',
    render: h => h(App)
})<% } %><% if ( projectJSFramework === 'Vue.js' && projectvueplugins === true) { %>
// Vue App
/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App)
})<% } %><% if ( projectJSFramework === 'React') { %>
ReactDOM.render(

Hello, world! from React
,
  document.getElementById('app')
)<% } %>

// Lasysizes Lazyload Config
window.lazySizesConfig = window.lazySizesConfig || {}
window.lazySizesConfig.expand = 130
lazySizesConfig.expFactor = 1.3

// Lazy Sizes Init
lazySizes.init()<% if (projectcraftbp === true || projectwordpressbp === true) { %>

// Init Photoswipe
initPhotoSwipeFromDOM('.is-photoswipped')

// Activate Progressloader
progressLoader()<% } %>
<commit_msg>ESLint ignore<commit_after>// Main JS File<% if (projectjquery === true) { %>
import $ from 'jquery'<% } %><% if ( projectJSFramework === 'React' ) { %>
import React from 'react'
import ReactDOM from 'react-dom'<% } %>
import eq from 'eqcss' // eslint-disable-line<% if ( projectJSFramework === 'Vue.js' ) { %>
import Vue from 'vue'<% } %><% if ( projectvueplugins === true)  { %>
import { sync } from 'vuex-router-sync'
import axios from 'axios'
import VueAxios from 'vue-axios'
import router from './router/router'
import store from './store/store'<% }  if (projectcraftbp === true || projectwordpressbp === true) { %>
import progressLoader from './partial/progressloader'
import initPhotoSwipeFromDOM from './partial/init-photoswipe' // eslint-disable-line
import './partial/init-heighttransition'
import './partial/init-autoscroll'
import 'flickity'
import 'flickity-imagesloaded'<% } %>
import lazySizes from 'lazysizes'
import lazybgset from 'lazysizes/plugins/bgset/ls.bgset' // eslint-disable-line
import 'babel-polyfill'
import 'svgxuse' // eslint-disable-line
import './partial/kittnad' // Small Advertising for Kittn :)
import './partial/modernizer-loader'
import './partial/conditionizr-init'
import './partial/disable-pointerevents'<% if ( projectJSFramework === 'Vue.js') { %>
import App from './app.vue'<%}%><% if (projectvueplugins === true)  { %>

// keep vue-router and vuex store in sync
    sync(store, router)

// Adding Vue Plugins
Vue.use(VueAxios, axios)<% } %>

<% if ( projectJSFramework === 'Vue.js' && projectvueplugins === false) { %>
// Vue App
/* eslint-disable no-new */
new Vue({
    el: '#app',
    render: h => h(App)
})<% } %><% if ( projectJSFramework === 'Vue.js' && projectvueplugins === true) { %>
// Vue App
/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App)
})<% } %><% if ( projectJSFramework === 'React') { %>
ReactDOM.render(

Hello, world! from React
,
  document.getElementById('app')
)<% } %>

// Lasysizes Lazyload Config
window.lazySizesConfig = window.lazySizesConfig || {}
window.lazySizesConfig.expand = 130
lazySizesConfig.expFactor = 1.3

// Lazy Sizes Init
lazySizes.init()<% if (projectcraftbp === true || projectwordpressbp === true) { %>

// Init Photoswipe
initPhotoSwipeFromDOM('.is-photoswipped')

// Activate Progressloader
progressLoader()<% } %>
<|endoftext|>


<commit_before>import { TimeoutError, isEventExpired } from './utils';
import ga from 'src/lib/ga';
import rollbar from 'src/lib/rollbar';
import lineClient from 'src/webhook/lineClient';
import groupMessage from './groupMessage';

export default async function processGroupEvent({
  type,
  replyToken,
  groupId,
  otherFields,
}) {
  // await new Promise(resolve => setTimeout(resolve, 2000));

  // Set default result
  //
  let result = {
    context: { data: {} },
    replies: undefined,
  };

  // Handle join/leave event
  // To calculate total group the bot joined, we set ga event value 1 as join, -1 as leave
  // Details see Implicit Count in https://support.google.com/analytics/answer/1033068?hl=en
  if (type === 'join') {
    // https://developers.line.biz/en/reference/messaging-api/#get-members-group-count
    // Note: leave group cannot get the number
    const { count: numberOfGroupMembers } = await lineClient.get(
      `/group/${groupId}/members/count`
    );
    console.log(
      'Joined group, numberOfGroupMembers: ' +
        JSON.stringify(numberOfGroupMembers)
    );

    const visitor = ga(groupId, 'N/A', '', otherFields.source.type);

    visitor.event({
      ec: 'Group',
      ea: 'Join',
      ev: 1,
    });
    visitor.set('cd2', numberOfGroupMembers);
    visitor.send();
  } else if (type === 'leave') {
    const visitor = ga(groupId, 'N/A', '', otherFields.source.type);
    visitor.event({
      ec: 'Group',
      ea: 'Leave',
      ev: -1,
    });
    visitor.send();
  }

  // React to certain type of events
  //
  if (type === 'message' && otherFields.message.type === 'text') {
    const input = otherFields.message.text;

    try {
      result = await groupMessage({ type, input, ...otherFields }, groupId);
    } catch (e) {
      console.error(e);
      rollbar.error(e, { type, input, ...otherFields });
    }
  }
  // else if (type === 'message' && otherFields.message.type === 'image') {
  //   // skip
  // } else if (type === 'message' && otherFields.message.type === 'video') {
  //   // skip
  // }
  if (isEventExpired(otherFields.timestamp)) {
    return Promise.reject(new TimeoutError('Event expired'));
  }

  return Promise.resolve({ result, replyToken });
}
<commit_msg>[GA] Use custom metrics to record groupMembersCount<commit_after>import { TimeoutError, isEventExpired } from './utils';
import ga from 'src/lib/ga';
import rollbar from 'src/lib/rollbar';
import lineClient from 'src/webhook/lineClient';
import groupMessage from './groupMessage';

export default async function processGroupEvent({
  type,
  replyToken,
  groupId,
  otherFields,
}) {
  // await new Promise(resolve => setTimeout(resolve, 2000));

  // Set default result
  //
  let result = {
    context: { data: {} },
    replies: undefined,
  };

  // Handle join/leave event
  // To calculate total group the bot joined, we set ga event value 1 as join, -1 as leave
  // Details see Implicit Count in https://support.google.com/analytics/answer/1033068?hl=en
  if (type === 'join') {
    // https://developers.line.biz/en/reference/messaging-api/#get-members-group-count
    // Note: leave group cannot get the number
    const { count: groupMembersCount } = await lineClient.get(
      `/${otherFields.source.type}/${groupId}/members/count`
    );

    const visitor = ga(groupId, 'N/A', '', otherFields.source.type);
    visitor.set('cm1', groupMembersCount);
    visitor.event({
      ec: 'Group',
      ea: 'Join',
      ev: 1,
    });
    visitor.send();
  } else if (type === 'leave') {
    const visitor = ga(groupId, 'N/A', '', otherFields.source.type);
    visitor.event({
      ec: 'Group',
      ea: 'Leave',
      ev: -1,
    });
    visitor.send();
  }

  // React to certain type of events
  //
  if (type === 'message' && otherFields.message.type === 'text') {
    const input = otherFields.message.text;

    try {
      result = await groupMessage({ type, input, ...otherFields }, groupId);
    } catch (e) {
      console.error(e);
      rollbar.error(e, { type, input, ...otherFields });
    }
  }
  // else if (type === 'message' && otherFields.message.type === 'image') {
  //   // skip
  // } else if (type === 'message' && otherFields.message.type === 'video') {
  //   // skip
  // }
  if (isEventExpired(otherFields.timestamp)) {
    return Promise.reject(new TimeoutError('Event expired'));
  }

  return Promise.resolve({ result, replyToken });
}
<|endoftext|>


<commit_before>import {
  plusReady
} from 'uni-shared'

function hideKeyboard () {
  document.activeElement.blur()
}
/**
 * 保证iOS点击输入框外隐藏键盘
 */
function iosHideKeyboard () { }

export default {
  name: 'Keyboard',
  props: {
    cursorSpacing: {
      type: [Number, String],
      default: 0
    },
    showConfirmBar: {
      type: [Boolean, String],
      default: 'auto'
    },
    adjustPosition: {
      type: Boolean,
      default: true
    }
  },
  watch: {
    focus (val) {
      if (val) {
        this.showSoftKeybord()
      }
    }
  },
  mounted () {
    if (this.autoFocus || this.focus) {
      this.showSoftKeybord()
    }
  },
  beforeDestroy () {
    this.onKeyboardHide()
  },
  methods: {
    initKeyboard (el) {
      el.addEventListener('focus', () => {
        this.hideKeyboardTemp = function () {
          hideKeyboard()
        }
        UniViewJSBridge.subscribe('hideKeyboard', this.hideKeyboardTemp)
        document.addEventListener('click', iosHideKeyboard, false)
        this.setSoftinputNavBar()
        this.setSoftinputTemporary()
      })
      el.addEventListener('blur', this.onKeyboardHide.bind(this))
    },
    showSoftKeybord () {
      plusReady(() => {
        plus.key.showSoftKeybord()
      })
    },
    setSoftinputTemporary () {
      plusReady(() => {
        const currentWebview = plus.webview.currentWebview()
        const style = currentWebview.getStyle() || {}
        const rect = this.$el.getBoundingClientRect()
        currentWebview.setSoftinputTemporary && currentWebview.setSoftinputTemporary({
          mode: style.softinputMode === 'adjustResize' ? 'adjustResize' : (this.adjustPosition ? 'adjustPan' : 'nothing'),
          position: {
            top: rect.top,
            height: rect.height + (Number(this.cursorSpacing) || 0)
          }
        })
      })
    },
    setSoftinputNavBar () {
      if (this.showConfirmBar === 'auto') {
        delete this.__softinputNavBar
        return
      }
      plusReady(() => {
        const currentWebview = plus.webview.currentWebview()
        const { softinputNavBar } = currentWebview.getStyle() || {}
        const showConfirmBar = softinputNavBar !== 'none'
        if (showConfirmBar !== this.showConfirmBar) {
          this.__softinputNavBar = softinputNavBar || 'auto'
          currentWebview.setStyle({
            softinputNavBar: this.showConfirmBar ? 'auto' : 'none'
          })
        } else {
          delete this.__softinputNavBar
        }
      })
    },
    resetSoftinputNavBar () {
      const softinputNavBar = this.__softinputNavBar
      if (softinputNavBar) {
        plusReady(() => {
          const currentWebview = plus.webview.currentWebview()
          currentWebview.setStyle({
            softinputNavBar
          })
        })
      }
    },
    onKeyboardHide () {
      UniViewJSBridge.unsubscribe('hideKeyboard', this.hideKeyboardTemp)
      document.removeEventListener('click', iosHideKeyboard, false)
      this.resetSoftinputNavBar()
      // 修复ios端显示与点击位置错位的Bug by:wyq
      if (document.body.scrollIntoView) {
        document.body.scrollIntoView()
      }
    }
  }
}
<commit_msg>fix: 2.6.14-alpha引起的输入框失焦页面滚动到顶部的Bug askId: 94065<commit_after>import {
  plusReady
} from 'uni-shared'

function hideKeyboard () {
  document.activeElement.blur()
}
/**
 * 保证iOS点击输入框外隐藏键盘
 */
function iosHideKeyboard () { }

export default {
  name: 'Keyboard',
  props: {
    cursorSpacing: {
      type: [Number, String],
      default: 0
    },
    showConfirmBar: {
      type: [Boolean, String],
      default: 'auto'
    },
    adjustPosition: {
      type: Boolean,
      default: true
    }
  },
  watch: {
    focus (val) {
      if (val) {
        this.showSoftKeybord()
      }
    }
  },
  mounted () {
    if (this.autoFocus || this.focus) {
      this.showSoftKeybord()
    }
  },
  beforeDestroy () {
    this.onKeyboardHide()
  },
  methods: {
    initKeyboard (el) {
      el.addEventListener('focus', () => {
        this.hideKeyboardTemp = function () {
          hideKeyboard()
        }
        UniViewJSBridge.subscribe('hideKeyboard', this.hideKeyboardTemp)
        document.addEventListener('click', iosHideKeyboard, false)
        this.setSoftinputNavBar()
        this.setSoftinputTemporary()
      })
      el.addEventListener('blur', this.onKeyboardHide.bind(this))
    },
    showSoftKeybord () {
      plusReady(() => {
        plus.key.showSoftKeybord()
      })
    },
    setSoftinputTemporary () {
      plusReady(() => {
        const currentWebview = plus.webview.currentWebview()
        const style = currentWebview.getStyle() || {}
        const rect = this.$el.getBoundingClientRect()
        currentWebview.setSoftinputTemporary && currentWebview.setSoftinputTemporary({
          mode: style.softinputMode === 'adjustResize' ? 'adjustResize' : (this.adjustPosition ? 'adjustPan' : 'nothing'),
          position: {
            top: rect.top,
            height: rect.height + (Number(this.cursorSpacing) || 0)
          }
        })
      })
    },
    setSoftinputNavBar () {
      if (this.showConfirmBar === 'auto') {
        delete this.__softinputNavBar
        return
      }
      plusReady(() => {
        const currentWebview = plus.webview.currentWebview()
        const { softinputNavBar } = currentWebview.getStyle() || {}
        const showConfirmBar = softinputNavBar !== 'none'
        if (showConfirmBar !== this.showConfirmBar) {
          this.__softinputNavBar = softinputNavBar || 'auto'
          currentWebview.setStyle({
            softinputNavBar: this.showConfirmBar ? 'auto' : 'none'
          })
        } else {
          delete this.__softinputNavBar
        }
      })
    },
    resetSoftinputNavBar () {
      const softinputNavBar = this.__softinputNavBar
      if (softinputNavBar) {
        plusReady(() => {
          const currentWebview = plus.webview.currentWebview()
          currentWebview.setStyle({
            softinputNavBar
          })
        })
      }
    },
    onKeyboardHide () {
      UniViewJSBridge.unsubscribe('hideKeyboard', this.hideKeyboardTemp)
      document.removeEventListener('click', iosHideKeyboard, false)
      this.resetSoftinputNavBar()
      // 修复ios端显示与点击位置错位的Bug by:wyq
      if (String(navigator.vendor).indexOf('Apple') === 0) {
        document.documentElement.scrollTo(document.documentElement.scrollLeft, document.documentElement.scrollTop)
      }
    }
  }
}
<|endoftext|>


<commit_before>include('helma/unittest');
include('helma/skin');

exports.testBasic = function() {
    var skin = createSkin('simple');
    assertEqual('simple', render(skin));
    assertEqual('simple', render(skin, {}));
};

exports.testValue = function() {
    var skin = createSkin('before <% value %> after');
    var context = {value: 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testMacro = function() {
    var skin = createSkin('before <% macro %> after');
    var context = {macro_macro: function () 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testFilter = function() {
    var skin = createSkin('before <% x | filter %> after');
    var context = {filter_filter: function (str) 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testSubskin = function() {
    var skin;
    var context;

    skin = createSkin('a<% subskin sub %>b');
    assertEqual('a', render(skin));

    skin = createSkin('a<% render sub %><% subskin sub %>b');
    assertEqual('ab', render(skin));

    skin = createSkin('a<% s %><% subskin sub %>b');
    context = {s_macro: function(macro, context, skin) skin.renderSubskin('sub')}
    assertEqual('ab', render(skin, context));
};

exports.testSubskinWhitespace = function() {
    var skin;

    skin = createSkin('a\n<% subskin sub %>\nb\n');
    assertEqual('a\n', render(skin));

    skin = createSkin('a\n<% render sub %>\n<% subskin sub %>\nb\n');
    assertEqual('a\n\nb\n', render(skin));
};
<commit_msg>Add skin truncate filter test.<commit_after>include('helma/unittest');
include('helma/skin');

exports.testBasic = function() {
    var skin = createSkin('simple');
    assertEqual('simple', render(skin));
    assertEqual('simple', render(skin, {}));
};

exports.testValue = function() {
    var skin = createSkin('before <% value %> after');
    var context = {value: 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testMacro = function() {
    var skin = createSkin('before <% macro %> after');
    var context = {macro_macro: function () 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testFilter = function() {
    var skin = createSkin('before <% x | filter %> after');
    var context = {filter_filter: function (str) 'HERE'};
    assertEqual('before HERE after', render(skin, context));
};

exports.testSubskin = function() {
    var skin;
    var context;

    skin = createSkin('a<% subskin sub %>b');
    assertEqual('a', render(skin));

    skin = createSkin('a<% render sub %><% subskin sub %>b');
    assertEqual('ab', render(skin));

    skin = createSkin('a<% s %><% subskin sub %>b');
    context = {s_macro: function(macro, context, skin) skin.renderSubskin('sub')}
    assertEqual('ab', render(skin, context));
};

exports.testSubskinWhitespace = function() {
    var skin;

    skin = createSkin('a\n<% subskin sub %>\nb\n');
    assertEqual('a\n', render(skin));

    skin = createSkin('a\n<% render sub %>\n<% subskin sub %>\nb\n');
    assertEqual('a\n\nb\n', render(skin));
};

exports.testTruncateFilter = function() {
    var string = 'foobarbaz';
    var skin = createSkin('<% value | truncate limit="10" %>');
    var context = {value: string};
    assertEqual(string, render(skin, context));
}
<|endoftext|>


<commit_before>/**
@module ember
@submodule ember-handlebars-compiler
*/

// Eliminate dependency on any Ember to simplify precompilation workflow
var objectCreate = Object.create || function(parent) {
  function F() {}
  F.prototype = parent;
  return new F();
};

var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
if(!Handlebars && typeof require === 'function') {
  Handlebars = require('handlebars');
}

Ember.assert("Ember Handlebars requires Handlebars version 1.0.0. Include a SCRIPT tag in the HTML HEAD linking to the Handlebars file before you link to Ember.", Handlebars)
Ember.assert("Ember Handlebars requires Handlebars version 1.0.0, COMPILER_REVISION expected: 4, got: " +  Handlebars.COMPILER_REVISION + " – Please note: Builds of master may have other COMPILER_REVISION values.", Handlebars.COMPILER_REVISION === 4);

/**
  Prepares the Handlebars templating library for use inside Ember's view
  system.

  The `Ember.Handlebars` object is the standard Handlebars library, extended to
  use Ember's `get()` method instead of direct property access, which allows
  computed properties to be used inside templates.

  To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`.
  This will return a function that can be used by `Ember.View` for rendering.

  @class Handlebars
  @namespace Ember
*/
Ember.Handlebars = objectCreate(Handlebars);

function makeBindings(options) {
  var hash = options.hash,
      hashType = options.hashTypes;

  for (var prop in hash) {
    if (hashType[prop] === 'ID') {
      hash[prop + 'Binding'] = hash[prop];
      hashType[prop + 'Binding'] = 'STRING';
      delete hash[prop];
      delete hashType[prop];
    }
  }
}

/**
  Register a bound helper or custom view helper.

  ## Simple bound helper example

  ```javascript
  Ember.Handlebars.helper('capitalize', function(value) {
    return value.toUpperCase();
  });
  ```

  The above bound helper can be used inside of templates as follows:

  ```handlebars
  {{capitalize name}}
  ```

  In this case, when the `name` property of the template's context changes,
  the rendered value of the helper will update to reflect this change.

  For more examples of bound helpers, see documentation for
  `Ember.Handlebars.registerBoundHelper`.

  ## Custom view helper example

  Assuming a view subclass named `App.CalenderView` were defined, a helper
  for rendering instances of this view could be registered as follows:

  ```javascript
  Ember.Handlebars.helper('calendar', App.CalendarView):
  ```

  The above bound helper can be used inside of templates as follows:

  ```handlebars
  {{calendar}}
  ```

  Which is functionally equivalent to:

  ```handlebars
  {{view App.CalendarView}}
  ```

  Options in the helper will be passed to the view in exactly the same
  manner as with the `view` helper.

  @method helper
  @for Ember.Handlebars
  @param {String} name
  @param {Function|Ember.View} function or view class constructor
  @param {String} dependentKeys*
*/
Ember.Handlebars.helper = function(name, value) {
  if (Ember.Component.detect(value)) {
    Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", name.match(/-/));

    var proto = value.proto();
    if (!proto.layoutName && !proto.templateName) {
      value.reopen({
        layoutName: 'components/' + name
      });
    }
  }

  if (Ember.View.detect(value)) {
    Ember.Handlebars.registerHelper(name, function(options) {
      Ember.assert("You can only pass attributes as parameters (not values) to a application-defined helper", arguments.length < 2);
      makeBindings(options);
      return Ember.Handlebars.helpers.view.call(this, value, options);
    });
  } else {
    Ember.Handlebars.registerBoundHelper.apply(null, arguments);
  }
}

/**
@class helpers
@namespace Ember.Handlebars
*/
Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);

/**
  Override the the opcode compiler and JavaScript compiler for Handlebars.

  @class Compiler
  @namespace Ember.Handlebars
  @private
  @constructor
*/
Ember.Handlebars.Compiler = function() {};

// Handlebars.Compiler doesn't exist in runtime-only
if (Handlebars.Compiler) {
  Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
}

Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;

/**
  @class JavaScriptCompiler
  @namespace Ember.Handlebars
  @private
  @constructor
*/
Ember.Handlebars.JavaScriptCompiler = function() {};

// Handlebars.JavaScriptCompiler doesn't exist in runtime-only
if (Handlebars.JavaScriptCompiler) {
  Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
  Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
}

Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";

Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
  return "''";
};

/**
  @private

  Override the default buffer for Ember Handlebars. By default, Handlebars
  creates an empty String at the beginning of each invocation and appends to
  it. Ember's Handlebars overrides this to append to a single shared buffer.

  @method appendToBuffer
  @param string {String}
*/
Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
  return "data.buffer.push("+string+");";
};

var prefix = "ember" + (+new Date()), incr = 1;

/**
  @private

  Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that
  all simple mustaches in Ember's Handlebars will also set up an observer to
  keep the DOM up to date when the underlying property changes.

  @method mustache
  @for Ember.Handlebars.Compiler
  @param mustache
*/
Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
  if (mustache.isHelper && mustache.id.string === 'control') {
    mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
    mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
  } else if (mustache.params.length || mustache.hash) {
    // no changes required
  } else {
    var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]);

    // Update the mustache node to include a hash value indicating whether the original node
    // was escaped. This will allow us to properly escape values when the underlying value
    // changes and we need to re-render the value.
    if(!mustache.escaped) {
      mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
      mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
    }
    mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
  }

  return Handlebars.Compiler.prototype.mustache.call(this, mustache);
};

/**
  Used for precompilation of Ember Handlebars templates. This will not be used
  during normal app execution.

  @method precompile
  @for Ember.Handlebars
  @static
  @param {String} string The template to precompile
*/
Ember.Handlebars.precompile = function(string) {
  var ast = Handlebars.parse(string);

  var options = {
    knownHelpers: {
      action: true,
      unbound: true,
      bindAttr: true,
      template: true,
      view: true,
      _triageMustache: true
    },
    data: true,
    stringParams: true
  };

  var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
};

// We don't support this for Handlebars runtime-only
if (Handlebars.compile) {
  /**
    The entry point for Ember Handlebars. This replaces the default
    `Handlebars.compile` and turns on template-local data and String
    parameters.

    @method compile
    @for Ember.Handlebars
    @static
    @param {String} string The template to compile
    @return {Function}
  */
  Ember.Handlebars.compile = function(string) {
    var ast = Handlebars.parse(string);
    var options = { data: true, stringParams: true };
    var environment = new Ember.Handlebars.Compiler().compile(ast, options);
    var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);

    return Ember.Handlebars.template(templateSpec);
  };
}

<commit_msg>Remove non ASCII character in handlebars assertion error message<commit_after>/**
@module ember
@submodule ember-handlebars-compiler
*/

// Eliminate dependency on any Ember to simplify precompilation workflow
var objectCreate = Object.create || function(parent) {
  function F() {}
  F.prototype = parent;
  return new F();
};

var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
if(!Handlebars && typeof require === 'function') {
  Handlebars = require('handlebars');
}

Ember.assert("Ember Handlebars requires Handlebars version 1.0.0. Include a SCRIPT tag in the HTML HEAD linking to the Handlebars file before you link to Ember.", Handlebars)
Ember.assert("Ember Handlebars requires Handlebars version 1.0.0, COMPILER_REVISION expected: 4, got: " +  Handlebars.COMPILER_REVISION + " - Please note: Builds of master may have other COMPILER_REVISION values.", Handlebars.COMPILER_REVISION === 4);

/**
  Prepares the Handlebars templating library for use inside Ember's view
  system.

  The `Ember.Handlebars` object is the standard Handlebars library, extended to
  use Ember's `get()` method instead of direct property access, which allows
  computed properties to be used inside templates.

  To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`.
  This will return a function that can be used by `Ember.View` for rendering.

  @class Handlebars
  @namespace Ember
*/
Ember.Handlebars = objectCreate(Handlebars);

function makeBindings(options) {
  var hash = options.hash,
      hashType = options.hashTypes;

  for (var prop in hash) {
    if (hashType[prop] === 'ID') {
      hash[prop + 'Binding'] = hash[prop];
      hashType[prop + 'Binding'] = 'STRING';
      delete hash[prop];
      delete hashType[prop];
    }
  }
}

/**
  Register a bound helper or custom view helper.

  ## Simple bound helper example

  ```javascript
  Ember.Handlebars.helper('capitalize', function(value) {
    return value.toUpperCase();
  });
  ```

  The above bound helper can be used inside of templates as follows:

  ```handlebars
  {{capitalize name}}
  ```

  In this case, when the `name` property of the template's context changes,
  the rendered value of the helper will update to reflect this change.

  For more examples of bound helpers, see documentation for
  `Ember.Handlebars.registerBoundHelper`.

  ## Custom view helper example

  Assuming a view subclass named `App.CalenderView` were defined, a helper
  for rendering instances of this view could be registered as follows:

  ```javascript
  Ember.Handlebars.helper('calendar', App.CalendarView):
  ```

  The above bound helper can be used inside of templates as follows:

  ```handlebars
  {{calendar}}
  ```

  Which is functionally equivalent to:

  ```handlebars
  {{view App.CalendarView}}
  ```

  Options in the helper will be passed to the view in exactly the same
  manner as with the `view` helper.

  @method helper
  @for Ember.Handlebars
  @param {String} name
  @param {Function|Ember.View} function or view class constructor
  @param {String} dependentKeys*
*/
Ember.Handlebars.helper = function(name, value) {
  if (Ember.Component.detect(value)) {
    Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", name.match(/-/));

    var proto = value.proto();
    if (!proto.layoutName && !proto.templateName) {
      value.reopen({
        layoutName: 'components/' + name
      });
    }
  }

  if (Ember.View.detect(value)) {
    Ember.Handlebars.registerHelper(name, function(options) {
      Ember.assert("You can only pass attributes as parameters (not values) to a application-defined helper", arguments.length < 2);
      makeBindings(options);
      return Ember.Handlebars.helpers.view.call(this, value, options);
    });
  } else {
    Ember.Handlebars.registerBoundHelper.apply(null, arguments);
  }
}

/**
@class helpers
@namespace Ember.Handlebars
*/
Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);

/**
  Override the the opcode compiler and JavaScript compiler for Handlebars.

  @class Compiler
  @namespace Ember.Handlebars
  @private
  @constructor
*/
Ember.Handlebars.Compiler = function() {};

// Handlebars.Compiler doesn't exist in runtime-only
if (Handlebars.Compiler) {
  Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
}

Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;

/**
  @class JavaScriptCompiler
  @namespace Ember.Handlebars
  @private
  @constructor
*/
Ember.Handlebars.JavaScriptCompiler = function() {};

// Handlebars.JavaScriptCompiler doesn't exist in runtime-only
if (Handlebars.JavaScriptCompiler) {
  Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
  Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
}

Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";

Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
  return "''";
};

/**
  @private

  Override the default buffer for Ember Handlebars. By default, Handlebars
  creates an empty String at the beginning of each invocation and appends to
  it. Ember's Handlebars overrides this to append to a single shared buffer.

  @method appendToBuffer
  @param string {String}
*/
Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
  return "data.buffer.push("+string+");";
};

var prefix = "ember" + (+new Date()), incr = 1;

/**
  @private

  Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that
  all simple mustaches in Ember's Handlebars will also set up an observer to
  keep the DOM up to date when the underlying property changes.

  @method mustache
  @for Ember.Handlebars.Compiler
  @param mustache
*/
Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
  if (mustache.isHelper && mustache.id.string === 'control') {
    mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
    mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
  } else if (mustache.params.length || mustache.hash) {
    // no changes required
  } else {
    var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]);

    // Update the mustache node to include a hash value indicating whether the original node
    // was escaped. This will allow us to properly escape values when the underlying value
    // changes and we need to re-render the value.
    if(!mustache.escaped) {
      mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
      mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
    }
    mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
  }

  return Handlebars.Compiler.prototype.mustache.call(this, mustache);
};

/**
  Used for precompilation of Ember Handlebars templates. This will not be used
  during normal app execution.

  @method precompile
  @for Ember.Handlebars
  @static
  @param {String} string The template to precompile
*/
Ember.Handlebars.precompile = function(string) {
  var ast = Handlebars.parse(string);

  var options = {
    knownHelpers: {
      action: true,
      unbound: true,
      bindAttr: true,
      template: true,
      view: true,
      _triageMustache: true
    },
    data: true,
    stringParams: true
  };

  var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
};

// We don't support this for Handlebars runtime-only
if (Handlebars.compile) {
  /**
    The entry point for Ember Handlebars. This replaces the default
    `Handlebars.compile` and turns on template-local data and String
    parameters.

    @method compile
    @for Ember.Handlebars
    @static
    @param {String} string The template to compile
    @return {Function}
  */
  Ember.Handlebars.compile = function(string) {
    var ast = Handlebars.parse(string);
    var options = { data: true, stringParams: true };
    var environment = new Ember.Handlebars.Compiler().compile(ast, options);
    var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);

    return Ember.Handlebars.template(templateSpec);
  };
}

<|endoftext|>


<commit_before>(function() {
	window.taskBoxes = {
		assembleBoxHTML: function(boxName) {
			return '

' + boxName + '

';
		},

		countBoxes: 0,

		// Maps task boxes to their endpoints
		taskBoxesToEndpoints: {},

		storeEndpoint: function(boxId, isInput, epoint) {
			var points = window.taskBoxes.taskBoxesToEndpoints[boxId];
			if (!points) {
				window.taskBoxes.taskBoxesToEndpoints[boxId] = {};
				window.taskBoxes.taskBoxesToEndpoints[boxId]["ipoints"] = [];
				window.taskBoxes.taskBoxesToEndpoints[boxId]["opoints"] = [];
			}
			window.taskBoxes.taskBoxesToEndpoints[boxId][isInput ? "ipoints": "opoints"].push(epoint);
		},

		// remove all endpoints of a task box
		removeEndpoints: function(taskBoxId) {
			var epoints = window.taskBoxes.taskBoxesToEndpoints[taskBoxId];
			if (epoints) {
				if (epoints.ipoints) { // remove input endpoints
					$.each(epoints.ipoints, function(idx, e) {
						jsPlumb.deleteEndpoint(e);
					});
				}
				if (epoints.opoints) { // remove output endpoints
					$.each(epoints.opoints, function(idx, e) {
						jsPlumb.deleteEndpoint(e);
					});
				}
				delete window.taskBoxes.taskBoxesToEndpoints[taskBoxId];
			}
		},

		// Right-click on task box
		taskBoxRightClick: function(ev) {
			if (ev.button == 2) {
				var taskBox = $(ev.target).hasClass("task-box") ? $(ev.target) : $(ev.target).closest(".task-box");
				window.taskBoxes.removeTaskBox(taskBox);
			}
		},

		removeTaskBox: function(taskBox) {
			var formWindow = $("#" + window.taskBoxes.getFormWindowId(taskBox));
			formWindow.find(".delete-row").click(); // remove task form
			formWindow.remove(); // remove the window
			// all connections are automatically detached
			// so this box outgoing connections input parameters are
			// reset by "connectionDetached" event handler
			window.taskBoxes.removeEndpoints(taskBox.attr("id"));
			taskBox.remove(); // remove task box
		},

		// modify box name according to algorithm selection
		setBoxName: function(taskBoxId) {
			var formWindow = $("#" + window.taskBoxes.getFormWindowId(taskBoxId));
			var nameContainer= $("#" + taskBoxId).find(".desc div");
            nameContainer.html(formWindow.find(".task-form select[id$='-algorithm']").find("option:selected").text());
		},

		// delete existing endpoints and create new ones to reflect the
		// selected algorithm
		recreateEndpoints: function(taskBoxId, formWindow) {
			// Remove old endpoints
			window.taskBoxes.removeEndpoints(taskBoxId);
			// Add new endpoints for input/output parameters
			var parameters = formWindow.find('.parameter-values');

			var outAnchors = ["RightMiddle", [1, 0, 1, 1], [1, 1, 1, 1]];
			var oIdx = 0;
			var inAnchors = ["LeftMiddle", [0, 0, - 1, - 1], [0, 1, - 1, - 1]];
			var iIdx = 0;

			var ipoints = []
			var opoints = []

			var taskBox = $("#" + taskBoxId);

			// inspect each parameter form
			// each form has one "value" field and
			// indicator fields: "is_input", "is_output"
			$.each(parameters.find('div'), function(idx) {
				var isIn = $(this).find("input[id$='is_input']").val();
				var isOut = $(this).find("input[id$='is_output']").val();
				var paramName = "" + $(this).find("span").text() + "";

				if (isIn === "True") {
					//add input endpoint
					var x = jsPlumb.addEndpoint(taskBox, window.experimentCanvas.getTargetEndpoint(), {
						anchor: inAnchors[iIdx],
						parameters: {
							iParamNo: idx,
							// parameter form idx
							iTaskBoxId: taskBoxId
						},
					});
					ipoints.push(x);
					iIdx++;
				} else if (isOut === "True") {
					//add output endpoint
					var y = jsPlumb.addEndpoint(taskBox, window.experimentCanvas.getSourceEndpoint(), {
						anchor: outAnchors[oIdx],
						parameters: {
							oParamNo: idx,
							// parameter form idx
							oTaskBoxId: taskBoxId
						}
					});
					opoints.push(y);
					oIdx++;
				}
			});
			window.taskBoxes.taskBoxesToEndpoints[taskBoxId] = {
				"ipoints": ipoints,
				"opoints": opoints
			}
		},

		// Loads parameters for the selected algorithm
		loadAlgorithmParameters: function() {
			$.ajax({
				url: parametersUrl,
				data: {
					algorithm_id: $(this).val(),
					prefix: $(this).attr('name')
				},
				context: $(this)
			}).done(function(resp) {
				// replace old parameter formset with a new one
				var formWindow = $(this).closest('.task').parent();
				formWindow.find(".parameter-values").html(resp);

				// rename the box
				var taskBoxId = window.taskBoxes.getBoxId(formWindow);
				window.taskBoxes.setBoxName(taskBoxId);
				window.taskBoxes.recreateEndpoints(taskBoxId, formWindow);
			});
		},

		// create modal window and assign algorithm change handler
		createTaskFormDialog: function(taskForm, existingParameters, formWindowId) {
			var taskFormContainer = $("

");
			taskFormContainer.attr("id", formWindowId);
			taskFormContainer.addClass("task-window");
			taskFormContainer.append(taskForm);
			if (existingParameters) {
				taskFormContainer.append(existingParameters);
			} else {
				taskFormContainer.append("

");
			}
			taskFormContainer.dialog({
				autoOpen: false,
				appendTo: "#task-forms",
				modal: true,
				// Cancel button should return the box to a previous state, but
				// that is too complicated for now, so no Cancel button
				buttons: [{
					text: "Close",
					click: function(ev) {
						$(this).dialog("close");
					}
				}]
			});
			taskForm.find(".algorithm-selection select").change(window.taskBoxes.loadAlgorithmParameters);
		},

		// create a new task box and modal window, assign event handlers
		createTaskBox: function(ev, ui, taskContainer) {
			// drop the task where it was dragged
			var currentName = ui.draggable.text();
			var taskBox = $(window.taskBoxes.assembleBoxHTML(currentName));
			taskBox.appendTo(taskContainer);
			taskBox.css("left", ui.position.left + "px");
			taskBox.css("top", ui.position.top + "px");

			//assign id and class
			count = window.taskBoxes.countBoxes;
			window.taskBoxes.countBoxes++;
			taskBox.attr("id", "task-box-" + count);
			taskBox.addClass("task-box");

			// create a form for this box
			var addTaskBtn = $("a.add-row")
			addTaskBtn.click();
			var taskForm = addTaskBtn.prev();

			// create modal window for the form
			window.taskBoxes.createTaskFormDialog(taskForm, null, window.taskBoxes.getFormWindowId(taskBox));

			this.addTaskBoxEventHandlers(taskBox);
		},

		//adds task box event handlers: dbclick, mousedown, and makes it
		//draggable
		addTaskBoxEventHandlers: function(taskBox) {

			// delete task box on right-click
			taskBox.off("mousedown");
			taskBox.on("mousedown", this.taskBoxRightClick);

			// open dialog on dbclick
			taskBox.off("dbclick");
			taskBox.on("dblclick", function(ev) {
				var formWindowId = window.taskBoxes.getFormWindowId($(ev.currentTarget));
				$("#" + formWindowId).dialog('open');
			});

			//make the box draggable
			jsPlumb.draggable(taskBox, {
				grid: [20, 20],
				containment: "parent"
			});
		},

		//generates task box id from the provided task form
		getBoxId: function(formWindow) {
			return formWindow.attr("id").replace("-form", "");
		},

		// generates task form id from the provided task box
		getFormWindowId: function(taskBox) {
			return taskBox instanceof $ ? taskBox.attr("id") + "-form": taskBox + "-form";
		},

	}

})();

<commit_msg>Changed endpoint location to top corners.<commit_after>(function() {
	window.taskBoxes = {
		assembleBoxHTML: function(boxName) {
			return '

' + boxName + '

';
		},

		countBoxes: 0,

		// Maps task boxes to their endpoints
		taskBoxesToEndpoints: {},

		storeEndpoint: function(boxId, isInput, epoint) {
			var points = window.taskBoxes.taskBoxesToEndpoints[boxId];
			if (!points) {
				window.taskBoxes.taskBoxesToEndpoints[boxId] = {};
				window.taskBoxes.taskBoxesToEndpoints[boxId]["ipoints"] = [];
				window.taskBoxes.taskBoxesToEndpoints[boxId]["opoints"] = [];
			}
			window.taskBoxes.taskBoxesToEndpoints[boxId][isInput ? "ipoints": "opoints"].push(epoint);
		},

		// remove all endpoints of a task box
		removeEndpoints: function(taskBoxId) {
			var epoints = window.taskBoxes.taskBoxesToEndpoints[taskBoxId];
			if (epoints) {
				if (epoints.ipoints) { // remove input endpoints
					$.each(epoints.ipoints, function(idx, e) {
						jsPlumb.deleteEndpoint(e);
					});
				}
				if (epoints.opoints) { // remove output endpoints
					$.each(epoints.opoints, function(idx, e) {
						jsPlumb.deleteEndpoint(e);
					});
				}
				delete window.taskBoxes.taskBoxesToEndpoints[taskBoxId];
			}
		},

		// Right-click on task box
		taskBoxRightClick: function(ev) {
			if (ev.button == 2) {
				var taskBox = $(ev.target).hasClass("task-box") ? $(ev.target) : $(ev.target).closest(".task-box");
				window.taskBoxes.removeTaskBox(taskBox);
			}
		},

		removeTaskBox: function(taskBox) {
			var formWindow = $("#" + window.taskBoxes.getFormWindowId(taskBox));
			formWindow.find(".delete-row").click(); // remove task form
			formWindow.remove(); // remove the window
			// all connections are automatically detached
			// so this box outgoing connections input parameters are
			// reset by "connectionDetached" event handler
			window.taskBoxes.removeEndpoints(taskBox.attr("id"));
			taskBox.remove(); // remove task box
		},

		// modify box name according to algorithm selection
		setBoxName: function(taskBoxId) {
			var formWindow = $("#" + window.taskBoxes.getFormWindowId(taskBoxId));
			var nameContainer= $("#" + taskBoxId).find(".desc div");
            nameContainer.html(formWindow.find(".task-form select[id$='-algorithm']").find("option:selected").text());
		},

		// delete existing endpoints and create new ones to reflect the
		// selected algorithm
		recreateEndpoints: function(taskBoxId, formWindow) {
			// Remove old endpoints
			window.taskBoxes.removeEndpoints(taskBoxId);
			// Add new endpoints for input/output parameters
			var parameters = formWindow.find('.parameter-values');

			var outAnchors = ["TopRight", [1, 0, 1, 1], [1, 1, 1, 1]];
			var oIdx = 0;
			var inAnchors = ["TopLeft", [0, 0, - 1, - 1], [0, 1, - 1, - 1]];
			var iIdx = 0;

			var ipoints = []
			var opoints = []

			var taskBox = $("#" + taskBoxId);

			// inspect each parameter form
			// each form has one "value" field and
			// indicator fields: "is_input", "is_output"
			$.each(parameters.find('div'), function(idx) {
				var isIn = $(this).find("input[id$='is_input']").val();
				var isOut = $(this).find("input[id$='is_output']").val();
				var paramName = "" + $(this).find("span").text() + "";

				if (isIn === "True") {
					//add input endpoint
					var x = jsPlumb.addEndpoint(taskBox, window.experimentCanvas.getTargetEndpoint(), {
						anchor: inAnchors[iIdx],
						parameters: {
							iParamNo: idx,
							// parameter form idx
							iTaskBoxId: taskBoxId
						},
					});
					ipoints.push(x);
					iIdx++;
				} else if (isOut === "True") {
					//add output endpoint
					var y = jsPlumb.addEndpoint(taskBox, window.experimentCanvas.getSourceEndpoint(), {
						anchor: outAnchors[oIdx],
						parameters: {
							oParamNo: idx,
							// parameter form idx
							oTaskBoxId: taskBoxId
						}
					});
					opoints.push(y);
					oIdx++;
				}
			});
			window.taskBoxes.taskBoxesToEndpoints[taskBoxId] = {
				"ipoints": ipoints,
				"opoints": opoints
			}
		},

		// Loads parameters for the selected algorithm
		loadAlgorithmParameters: function() {
			$.ajax({
				url: parametersUrl,
				data: {
					algorithm_id: $(this).val(),
					prefix: $(this).attr('name')
				},
				context: $(this)
			}).done(function(resp) {
				// replace old parameter formset with a new one
				var formWindow = $(this).closest('.task').parent();
				formWindow.find(".parameter-values").html(resp);

				// rename the box
				var taskBoxId = window.taskBoxes.getBoxId(formWindow);
				window.taskBoxes.setBoxName(taskBoxId);
				window.taskBoxes.recreateEndpoints(taskBoxId, formWindow);
			});
		},

		// create modal window and assign algorithm change handler
		createTaskFormDialog: function(taskForm, existingParameters, formWindowId) {
			var taskFormContainer = $("

");
			taskFormContainer.attr("id", formWindowId);
			taskFormContainer.addClass("task-window");
			taskFormContainer.append(taskForm);
			if (existingParameters) {
				taskFormContainer.append(existingParameters);
			} else {
				taskFormContainer.append("

");
			}
			taskFormContainer.dialog({
				autoOpen: false,
				appendTo: "#task-forms",
				modal: true,
				// Cancel button should return the box to a previous state, but
				// that is too complicated for now, so no Cancel button
				buttons: [{
					text: "Close",
					click: function(ev) {
						$(this).dialog("close");
					}
				}]
			});
			taskForm.find(".algorithm-selection select").change(window.taskBoxes.loadAlgorithmParameters);
		},

		// create a new task box and modal window, assign event handlers
		createTaskBox: function(ev, ui, taskContainer) {
			// drop the task where it was dragged
			var currentName = ui.draggable.text();
			var taskBox = $(window.taskBoxes.assembleBoxHTML(currentName));
			taskBox.appendTo(taskContainer);
			taskBox.css("left", ui.position.left + "px");
			taskBox.css("top", ui.position.top + "px");

			//assign id and class
			count = window.taskBoxes.countBoxes;
			window.taskBoxes.countBoxes++;
			taskBox.attr("id", "task-box-" + count);
			taskBox.addClass("task-box");

			// create a form for this box
			var addTaskBtn = $("a.add-row")
			addTaskBtn.click();
			var taskForm = addTaskBtn.prev();

			// create modal window for the form
			window.taskBoxes.createTaskFormDialog(taskForm, null, window.taskBoxes.getFormWindowId(taskBox));

			this.addTaskBoxEventHandlers(taskBox);
		},

		//adds task box event handlers: dbclick, mousedown, and makes it
		//draggable
		addTaskBoxEventHandlers: function(taskBox) {

			// delete task box on right-click
			taskBox.off("mousedown");
			taskBox.on("mousedown", this.taskBoxRightClick);

			// open dialog on dbclick
			taskBox.off("dbclick");
			taskBox.on("dblclick", function(ev) {
				var formWindowId = window.taskBoxes.getFormWindowId($(ev.currentTarget));
				$("#" + formWindowId).dialog('open');
			});

			//make the box draggable
			jsPlumb.draggable(taskBox, {
				grid: [20, 20],
				containment: "parent"
			});
		},

		//generates task box id from the provided task form
		getBoxId: function(formWindow) {
			return formWindow.attr("id").replace("-form", "");
		},

		// generates task form id from the provided task box
		getFormWindowId: function(taskBox) {
			return taskBox instanceof $ ? taskBox.attr("id") + "-form": taskBox + "-form";
		},

	}

})();

<|endoftext|>


<commit_before>/**
 * Prepros
 * (c) Subash Pathak
 * sbshpthk@gmail.com
 * License: MIT
 */

/*jshint browser: true, node: true*/
/*global prepros, angular, _, $*/

prepros.factory('config',[

    function () {

        'use strict';

        var fs = require('fs-extra'),
            path = require('path'),
            os = require('os');

        //Base path
        var basePath = path.join(process.cwd(), 'app');

        //Package.json file url
        var packageFileUrl = path.join(basePath, '../package.json');

        //Read package.json file and get data of app in prepros object
        var packageData = angular.fromJson(fs.readFileSync(packageFileUrl).toString());

        //We need package path because everything is relative to this file
        var packagePath = path.join(basePath, '..');

        //CachePath
        var cachePath = path.join(os.tmpdir(), 'PreprosCache');

        //Node modules required by the app
        var node_modules = packageData.dependencies;

        //Ruby Gems
        var ruby_gems = packageData.ruby.gems;

        //App version
        var version = packageData.version;

        //App urls
        var online = {
            url: 'http://alphapixels.com/prepros',
            helpUrl: 'http://alphapixels.com/prepros/docs/',
            loveUrl: 'http://alphapixels.com/prepros#love',
            updateFileUrl: 'http://prepros.alphapixels.com/update.json',
            githubUrl: 'http://github.com/sbspk/prepros',
            authorTwitter: 'http://twitter.com/sbspk',
            authorUrl: 'http://alphapixels.com'
        };

        //Older projects and files are not compatible with this version
        if('PreprosProjects' in localStorage) {
            localStorage.removeItem('PreprosProjects');
            localStorage.removeItem('PreprosFiles');
            localStorage.removeItem('PreprosImports');
        }

        //Read user config
        var userConfig = {};
        try {

            userConfig = $.parseJSON(localStorage.PreprosConfig || '{}');

        } catch (e) {

            window.alert('Error Reading Configurations ! Reverting to defaults.');

            saveUserOptions(userConfig);
        }

        var defaultConfig = {
            cssPath: 'css',
            jsPath: 'js',
            htmlPath: 'html',
            jsMinPath: 'min',
            htmlExtension: '.html',
            enableSuccessNotifications: true,
            enableErrorNotifications: true,
            filterPatterns: 'node_modules', //Filter node modules folder by default
            autoprefixerBrowsers: '',
            liveRefreshDelay: 0,
            notificationTime: 3000,
            notificationDetails: false,
            experimental : {
                fileWatcher: false,
                autoAddRemoveFile: true
            },

            customRuby: {
                use: false,
                path: '',
                sass: false,
                slim: false,
                haml: false
            },

            //Default Less Options
            less: {
                autoCompile: true,
                compress: false,
                lineNumbers: false,
                strictMath: false,
                strictUnits: false,
                autoprefixer: false
            },

            //Default Sass options
            sass: {
                autoCompile: true,
                lineNumbers: false,
                unixNewlines: false,
                debug: false,
                compass: false,
                fullCompass: false,
                compassConfigRb: false,
                outputStyle: 'expanded', //compressed, nested, expanded, compact
                autoprefixer: false
            },

            //Default Stylus Options
            stylus: {
                autoCompile: true,
                lineNumbers: false,
                nib: false,
                compress: false,
                autoprefixer: false
            },

            //Default Markdown Options
            markdown: {
                autoCompile: true,
                sanitize: false,
                gfm: true
            },

            //Default Coffeescript Options
            coffee: {
                autoCompile: true,
                bare: false,
                uglify: false,
                mangle: true
            },

            //Default Livescript Options
            livescript: {
                autoCompile: true,
                bare: false,
                uglify: false,
                mangle: true
            },

            //Default javascript options
            javascript: {
                autoCompile: true,
                uglify: true,
                mangle: true
            },

            //Default Jade  Options
            jade: {
                autoCompile: true,
                pretty: true
            },

            //Default Haml Options
            haml: {
                autoCompile: true,
                format: 'html5', //xhtml, html5
                outputStyle: 'indented', //indented, ugly
                doubleQuotes: false
            },

            //Default Slim  Options
            slim: {
                autoCompile: true,
                pretty: true,
                indent: 'default', //default, four, tab
                fourSpaceIndent: true,
                format: ':html5' //:xhtml, :html4, :html5, :html
            }
        };

        //Fill in the undefined values from default configurations
        userConfig = _.defaults(userConfig, defaultConfig);

        for (var configKey in userConfig) {

            if (userConfig.hasOwnProperty(configKey) && typeof userConfig[configKey] === 'object') {

                userConfig[configKey] = _.defaults(userConfig[configKey], defaultConfig[configKey]);
            }
        }

        //Wrap user options in a function to prevent angular data sharing between services
        //If user config data is shared between files changing configuration of one file will affect another file
        function getUserOptions() {

            return $.parseJSON(angular.toJson(userConfig, false));

        }

        function saveUserOptions(options) {

            localStorage.setItem('PreprosConfig', angular.toJson(options));

            userConfig = $.parseJSON(angular.toJson(options));
        }

        //Ruby Executable
        var ruby = {
            version: packageData.ruby.version,
            bourbon: path.join(packagePath, packageData.ruby.bourbon),
            neat: path.join(packagePath, packageData.ruby.neat),
            getExec: function (fileType) {

                if (userConfig.customRuby.use && userConfig.customRuby.path !== '' && userConfig.customRuby[fileType]) {

                    return path.normalize(userConfig.customRuby.path);
                }

                return path.join(packagePath, packageData.ruby.path);

            },
            getGem: function (fileType) {

                var ft = (fileType === 'compass') ? 'sass' : fileType;

                var loader = path.join(basePath, '../bin/gems.rb');

                var gemPath = path.join(packagePath, packageData.ruby.gemPath);

                if (userConfig.customRuby.use && userConfig.customRuby.path !== '' && userConfig.customRuby[ft]) {

                    return [loader, 'custom', fileType];

                } else {

                    return [loader, gemPath, fileType];

                }
            }
        };

        return {
            cachePath: cachePath,
            basePath: basePath,
            ruby: ruby,
            node_modules: node_modules,
            ruby_gems: ruby_gems,
            online: online,
            version: version,
            getUserOptions: getUserOptions,
            saveUserOptions: saveUserOptions
        };

    }
]);
<commit_msg>cleanup<commit_after>/**
 * Prepros
 * (c) Subash Pathak
 * sbshpthk@gmail.com
 * License: MIT
 */

/*jshint browser: true, node: true*/
/*global prepros, angular, _, $*/

prepros.factory('config',[

    function () {

        'use strict';

        var fs = require('fs-extra'),
            path = require('path'),
            os = require('os');

        //Base path
        var basePath = path.join(process.cwd(), 'app');

        //Package.json file url
        var packageFileUrl = path.join(basePath, '../package.json');

        //Read package.json file and get data of app in prepros object
        var packageData = angular.fromJson(fs.readFileSync(packageFileUrl).toString());

        //We need package path because everything is relative to this file
        var packagePath = path.join(basePath, '..');

        //CachePath
        var cachePath = path.join(os.tmpdir(), 'PreprosCache');

        //Node modules required by the app
        var node_modules = packageData.dependencies;

        //Ruby Gems
        var ruby_gems = packageData.ruby.gems;

        //App version
        var version = packageData.version;

        //App urls
        var online = {
            url: 'http://alphapixels.com/prepros',
            helpUrl: 'http://alphapixels.com/prepros/docs/',
            loveUrl: 'http://alphapixels.com/prepros#love',
            updateFileUrl: 'http://prepros.alphapixels.com/update.json',
            githubUrl: 'http://github.com/sbspk/prepros',
            authorTwitter: 'http://twitter.com/sbspk',
            authorUrl: 'http://alphapixels.com'
        };

        //Older projects and files are not compatible with this version
        if('PreprosProjects' in localStorage) {
            localStorage.removeItem('PreprosProjects');
            localStorage.removeItem('PreprosFiles');
            localStorage.removeItem('PreprosImports');
        }

        //Read user config
        var userConfig = {};
        try {

            userConfig = $.parseJSON(localStorage.PreprosConfig || '{}');

        } catch (e) {

            window.alert('Error Reading Configurations ! Reverting to defaults.');

            saveUserOptions(userConfig);
        }

        var defaultConfig = {
            cssPath: 'css',
            jsPath: 'js',
            htmlPath: 'html',
            jsMinPath: 'min',
            htmlExtension: '.html',
            enableSuccessNotifications: true,
            enableErrorNotifications: true,
            filterPatterns: 'node_modules', //Filter node modules folder by default
            autoprefixerBrowsers: '',
            liveRefreshDelay: 0,
            notificationTime: 3000,
            notificationDetails: false,
            experimental : {
                fileWatcher: false
            },

            customRuby: {
                use: false,
                path: '',
                sass: false,
                slim: false,
                haml: false
            },

            //Default Less Options
            less: {
                autoCompile: true,
                compress: false,
                lineNumbers: false,
                strictMath: false,
                strictUnits: false,
                autoprefixer: false
            },

            //Default Sass options
            sass: {
                autoCompile: true,
                lineNumbers: false,
                unixNewlines: false,
                debug: false,
                compass: false,
                fullCompass: false,
                compassConfigRb: false,
                outputStyle: 'expanded', //compressed, nested, expanded, compact
                autoprefixer: false
            },

            //Default Stylus Options
            stylus: {
                autoCompile: true,
                lineNumbers: false,
                nib: false,
                compress: false,
                autoprefixer: false
            },

            //Default Markdown Options
            markdown: {
                autoCompile: true,
                sanitize: false,
                gfm: true
            },

            //Default Coffeescript Options
            coffee: {
                autoCompile: true,
                bare: false,
                uglify: false,
                mangle: true
            },

            //Default Livescript Options
            livescript: {
                autoCompile: true,
                bare: false,
                uglify: false,
                mangle: true
            },

            //Default javascript options
            javascript: {
                autoCompile: true,
                uglify: true,
                mangle: true
            },

            //Default Jade  Options
            jade: {
                autoCompile: true,
                pretty: true
            },

            //Default Haml Options
            haml: {
                autoCompile: true,
                format: 'html5', //xhtml, html5
                outputStyle: 'indented', //indented, ugly
                doubleQuotes: false
            },

            //Default Slim  Options
            slim: {
                autoCompile: true,
                pretty: true,
                indent: 'default', //default, four, tab
                fourSpaceIndent: true,
                format: ':html5' //:xhtml, :html4, :html5, :html
            }
        };

        //Fill in the undefined values from default configurations
        userConfig = _.defaults(userConfig, defaultConfig);

        for (var configKey in userConfig) {

            if (userConfig.hasOwnProperty(configKey) && typeof userConfig[configKey] === 'object') {

                userConfig[configKey] = _.defaults(userConfig[configKey], defaultConfig[configKey]);
            }
        }

        //Wrap user options in a function to prevent angular data sharing between services
        //If user config data is shared between files changing configuration of one file will affect another file
        function getUserOptions() {

            return $.parseJSON(angular.toJson(userConfig, false));

        }

        function saveUserOptions(options) {

            localStorage.setItem('PreprosConfig', angular.toJson(options));

            userConfig = $.parseJSON(angular.toJson(options));
        }

        //Ruby Executable
        var ruby = {
            version: packageData.ruby.version,
            bourbon: path.join(packagePath, packageData.ruby.bourbon),
            neat: path.join(packagePath, packageData.ruby.neat),
            getExec: function (fileType) {

                if (userConfig.customRuby.use && userConfig.customRuby.path !== '' && userConfig.customRuby[fileType]) {

                    return path.normalize(userConfig.customRuby.path);
                }

                return path.join(packagePath, packageData.ruby.path);

            },
            getGem: function (fileType) {

                var ft = (fileType === 'compass') ? 'sass' : fileType;

                var loader = path.join(basePath, '../bin/gems.rb');

                var gemPath = path.join(packagePath, packageData.ruby.gemPath);

                if (userConfig.customRuby.use && userConfig.customRuby.path !== '' && userConfig.customRuby[ft]) {

                    return [loader, 'custom', fileType];

                } else {

                    return [loader, gemPath, fileType];

                }
            }
        };

        return {
            cachePath: cachePath,
            basePath: basePath,
            ruby: ruby,
            node_modules: node_modules,
            ruby_gems: ruby_gems,
            online: online,
            version: version,
            getUserOptions: getUserOptions,
            saveUserOptions: saveUserOptions
        };

    }
]);
<|endoftext|>


<commit_before>

define('kbaseExpressionSampleTable',
    [
        'jquery',
        'kbwidget',
        'kbaseAuthenticatedWidget',
        'kbase-client-api',
        'kbaseTable',
    ], function( $, colorbrewer ) {

    'use strict';

    $.KBWidget({

	    name: "kbaseExpressionSampleTable",
	    parent : "kbaseAuthenticatedWidget",

        version: "1.0.0",
        options: {

        },

        authToken : function() {
            return "un=thomasoniii|tokenid=9dd17a66-8c78-11e5-942b-22000ab4b42b|expiry=1479224537|client_id=thomasoniii|token_type=Bearer|SigningSubject=https://nexus.api.globusonline.org/goauth/keys/5c2ed44a-8a30-11e5-b9f9-22000aef184d|sig=520590a675d6e9579b0dd4739fff40ea71ffd5e7e5bd950f691535a1bd19a2fef131ea94b88862fb430c8b7c73bb3f741eeb6bd02c74d4f74068db7f51e2f2b7664b43758ad23486264821bab3c7985614ee6f24b1a0428453e978551d0424902a2d9bc604483c85e4d2cbcd02a868e9d010aee3a75de2df7c9f8f1453453282";
        },

        _accessors : [
            {name: 'dataset', setter: 'setDataset'},
        ],

        setDataset : function setDataset(newDataset) {

            var rows = [];

            $.each(
                Object.keys(newDataset.expression_levels).sort(),
                function (i,k) {
                    rows.push({gene_id : k, feature_value : newDataset.expression_levels[k]});
                }
            );

            this.data('tableElem').kbaseTable(
                {
                    sortable : true,
                    striped : true,
                    navControls : true,
                    maxVisibleRowIndex : 10,
                    structure : {
                        header : [{value : 'gene_id', label : 'Gene ID'}, {value : 'feature_value', label : 'Feature Value'} ],
                        rows : rows,
                    }
                }
            );

            this.data('loader').hide();
            this.data('tableElem').show();

        },

        init : function init(options) {
            this._super(options);

            var $self = this;

            var ws = new Workspace(window.kbconfig.urls.workspace, {token : $self.authToken()});
            //var ws = new Workspace('https://ci.kbase.us/services/ws', {token : $self.authToken()});

            var ws_params = {
                workspace : this.options.workspace,
                wsid : this.options.wsid,
                name : this.options.output
            };

            ws.get_objects([ws_params]).then(function (d) {
                $self.setDataset(d[0].data);
            }).fail(function(d) {

                $self.$elem.empty();
                $self.$elem
                    .addClass('alert alert-danger')
                    .html("Could not load object : " + d.error.message);
            })

            this.appendUI(this.$elem);

            return this;
        },

        appendUI : function appendUI($elem) {

            $elem
                .append(
                    $.jqElem('div')
                        .attr('id', 'tableElem')
                        .css('display', 'none')
                )
                .append(
                    $.jqElem('div')
                        .attr('id', 'loader')
                        .append('
 Loading data...
 please wait...')
                        .append($.jqElem('br'))
                        .append(
                            $.jqElem('div')
                                .attr('align', 'center')
                                .append($.jqElem('i').addClass('fa fa-spinner').addClass('fa fa-spin fa fa-4x'))
                        )
                )
            ;

            this._rewireIds($elem, this);

        },

    });

} );
<commit_msg>updated to use dataTables; I hope<commit_after>

define('kbaseExpressionSampleTable',
    [
        'jquery',
        'kbwidget',
        'kbaseAuthenticatedWidget',
        'kbase-client-api',
        'kbaseTable',
        'dataTables',
    ], function( $, colorbrewer ) {

    'use strict';

    $.KBWidget({

	    name: "kbaseExpressionSampleTable",
	    parent : "kbaseAuthenticatedWidget",

        version: "1.0.0",
        options: {

        },

        _accessors : [
            {name: 'dataset', setter: 'setDataset'},
        ],

        setDataset : function setDataset(newDataset) {

            var rows = [];

            $.each(
                Object.keys(newDataset.expression_levels).sort(),
                function (i,k) {
                    rows.push([k,newDataset.expression_levels[k]]);
                }
            );

            var $dt = this.data('tableElem').DataTable({
                aoColumns : [
                    { title : 'Gene ID'},
                    { title : 'Feature Value'}
                ]
            });
            $dt.fnAddData(rows);

            /*this.data('tableElem').kbaseTable(
                {
                    sortable : true,
                    striped : true,
                    navControls : true,
                    maxVisibleRowIndex : 10,
                    structure : {
                        header : [{value : 'gene_id', label : 'Gene ID'}, {value : 'feature_value', label : 'Feature Value'} ],
                        rows : rows,
                    }
                }
            );*/

            this.data('loader').hide();
            this.data('tableElem').show();

        },

        init : function init(options) {
            this._super(options);

            var $self = this;

            var ws = new Workspace(window.kbconfig.urls.workspace, {token : $self.authToken()});
            //var ws = new Workspace('https://ci.kbase.us/services/ws', {token : $self.authToken()});

            var ws_params = {
                workspace : this.options.workspace,
                wsid : this.options.wsid,
                name : this.options.output
            };

            ws.get_objects([ws_params]).then(function (d) {
                $self.setDataset(d[0].data);
            }).fail(function(d) {

                $self.$elem.empty();
                $self.$elem
                    .addClass('alert alert-danger')
                    .html("Could not load object : " + d.error.message);
            })

            this.appendUI(this.$elem);

            return this;
        },

        appendUI : function appendUI($elem) {

            $elem
                .append(
                    $.jqElem('table')
                        .attr('id', 'tableElem')
                        .addClass('display')
                        .css('display', 'none')
                            .append(
                                $.jqElem('thead')
                                    .append(
                                        $.jqElem('tr')
                                            .append($.jqElem('th').append('Gene ID'))
                                            .append($.jqElem('th').append('Feature Value'))
                                    )
                            )

                )
                .append(
                    $.jqElem('div')
                        .attr('id', 'loader')
                        .append('
 Loading data...
 please wait...')
                        .append($.jqElem('br'))
                        .append(
                            $.jqElem('div')
                                .attr('align', 'center')
                                .append($.jqElem('i').addClass('fa fa-spinner').addClass('fa fa-spin fa fa-4x'))
                        )
                )
            ;

            this._rewireIds($elem, this);

        },

    });

} );
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
var serializeModule = require('./serialize'),
    promises = require('../../utilities/promises'),
    schemaModule = require('./schema'),
    errorTypes = require('./errorTypes');

module.exports = function (connection, table, serialize) {
    var schema = schemaModule(connection, serialize);

    var api = {
        execute: function (statements, item, attempt) {
            attempt = attempt || 1;

            return serialize(statements)
                .catch(function (err) {
                    return handleError(err).then(function () {
                        return api.execute(statements, item, attempt + 1);
                    });
                });

            function handleError(err) {
                if (attempt >= 3)
                    return promises.rejected(err);

                if(errorTypes.isMissingTable(err))
                    return schema.createTable(table, item);
                if(errorTypes.isMissingColumn(err))
                    return schema.updateSchema(table, item);

                return promises.rejected(err);
            }
        },
        read: function (statement) {
            return serialize(statement)
                .catch(function (err) {
                    // if dynamic schema is enabled and the error is invalid column, it is likely that the schema has not been
                    // updated to include the column. V1 behavior is to return an empty array, maintain this behavior.
                    if(errorTypes.isMissingTable(err) || errorTypes.isMissingColumn(err)) {
                        var result = [];
                        return result;
                    }
                    throw err;
                });
        }
    };

    return api;
};
<commit_msg>Fixed lint issue<commit_after>// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
var promises = require('../../utilities/promises'),
    schemaModule = require('./schema'),
    errorTypes = require('./errorTypes');

module.exports = function (connection, table, serialize) {
    var schema = schemaModule(connection, serialize);

    var api = {
        execute: function (statements, item, attempt) {
            attempt = attempt || 1;

            return serialize(statements)
                .catch(function (err) {
                    return handleError(err).then(function () {
                        return api.execute(statements, item, attempt + 1);
                    });
                });

            function handleError(err) {
                if (attempt >= 3)
                    return promises.rejected(err);

                if(errorTypes.isMissingTable(err))
                    return schema.createTable(table, item);
                if(errorTypes.isMissingColumn(err))
                    return schema.updateSchema(table, item);

                return promises.rejected(err);
            }
        },
        read: function (statement) {
            return serialize(statement)
                .catch(function (err) {
                    // if dynamic schema is enabled and the error is invalid column, it is likely that the schema has not been
                    // updated to include the column. V1 behavior is to return an empty array, maintain this behavior.
                    if(errorTypes.isMissingTable(err) || errorTypes.isMissingColumn(err)) {
                        var result = [];
                        return result;
                    }
                    throw err;
                });
        }
    };

    return api;
};
<|endoftext|>


<commit_before>import Scrollbar from '../../src/';

const DPR = window.devicePixelRatio;

const size = {
    width: 250,
    height: 150
};

const canvas = document.getElementById('preview');
const scrollbar = Scrollbar.get(document.getElementById('content'));
const ctx = canvas.getContext('2d');
const options = Object.assign({}, scrollbar.options);

canvas.width = size.width * DPR;
canvas.height = size.height * DPR;
ctx.scale(DPR, DPR);

ctx.strokeStyle = '#94a6b7';
ctx.fillStyle = '#abc';

let shouldUpdate = true;

function render() {
    if (!shouldUpdate) {
        return requestAnimationFrame(render);
    }

    let dots = calcDots();

    ctx.clearRect(0, 0, size.width, size.height);
    ctx.save();
    ctx.transform(1, 0, 0, -1, 0, size.height);
    ctx.beginPath();
    ctx.moveTo(0, 0);

    let scaleX = (size.width / dots.length) * (options.speed / 20 + 0.5);
    dots.forEach(([x, y]) => {
        ctx.lineTo(x * scaleX, y);
    });

    ctx.stroke();

    let [x, y] = dots[dots.length - 1];
    ctx.lineTo(x * scaleX, y);
    ctx.fill();
    ctx.closePath();
    ctx.restore();

    shouldUpdate = false;

    requestAnimationFrame(render);
};

render();

function calcDots() {
    let {
        speed,
        friction
    } = options;

    let dots = [];

    let x = 0;
    let y = (speed / 20 + 0.5) * size.height;

    while(y > 0.1) {
        dots.push([x, y]);

        y *= (1 - friction / 100);
        x++;
    }

    return dots;
};

document.querySelector('#version').textContent = `v${Scrollbar.version}`;

[...document.querySelectorAll('.options')].forEach((el) => {
    const prop = el.name;
    const label = document.querySelector(`.option-${prop}`);

    el.addEventListener('input', () => {
        label.textContent = options[prop] = parseFloat(el.value);
        scrollbar.setOptions(options);
        shouldUpdate = true;
    });
});

const innerScrollbar = Scrollbar.get(document.querySelector('.inner-scrollbar'));

document.querySelector('#continuous').addEventListener('change', ({ target }) => {
    innerScrollbar.setOptions({
        continuousScrolling: target.checked
    });
});

render();
<commit_msg>update demo<commit_after>import Scrollbar from '../../src/';

const DPR = window.devicePixelRatio;

const size = {
    width: 250,
    height: 150
};

const canvas = document.getElementById('preview');
const scrollbar = Scrollbar.get(document.getElementById('content'));
const ctx = canvas.getContext('2d');
const options = Object.assign({}, scrollbar.options);

canvas.width = size.width * DPR;
canvas.height = size.height * DPR;
ctx.scale(DPR, DPR);

ctx.strokeStyle = '#94a6b7';
ctx.fillStyle = '#abc';

let shouldUpdate = true;

function render() {
    if (!shouldUpdate) {
        return requestAnimationFrame(render);
    }

    let dots = calcDots();

    ctx.clearRect(0, 0, size.width, size.height);
    ctx.save();
    ctx.transform(1, 0, 0, -1, 0, size.height);
    ctx.beginPath();
    ctx.moveTo(0, 0);

    let scaleX = (size.width / dots.length) * (options.speed / 20 + 0.5);
    dots.forEach(([x, y]) => {
        ctx.lineTo(x * scaleX, y);
    });

    ctx.stroke();

    let [x, y] = dots[dots.length - 1];
    ctx.lineTo(x * scaleX, y);
    ctx.fill();
    ctx.closePath();
    ctx.restore();

    shouldUpdate = false;

    requestAnimationFrame(render);
};

render();

function calcDots() {
    let {
        speed,
        friction
    } = options;

    let dots = [];

    let x = 0;
    let y = (speed / 20 + 0.5) * size.height;

    while(y > 0.1) {
        dots.push([x, y]);

        y *= (1 - friction / 100);
        x++;
    }

    dots.push([x, 0]);

    return dots;
};

document.querySelector('#version').textContent = `v${Scrollbar.version}`;

[...document.querySelectorAll('.options')].forEach((el) => {
    const prop = el.name;
    const label = document.querySelector(`.option-${prop}`);

    el.addEventListener('input', () => {
        label.textContent = options[prop] = parseFloat(el.value);
        scrollbar.setOptions(options);
        shouldUpdate = true;
    });
});

const innerScrollbar = Scrollbar.get(document.querySelector('.inner-scrollbar'));

document.querySelector('#continuous').addEventListener('change', ({ target }) => {
    innerScrollbar.setOptions({
        continuousScrolling: target.checked
    });
});

render();
<|endoftext|>