<commit_before>import * as R from 'ramda'
import * as React from 'react'
import AutosizeInput from 'react-input-autosize'
import { Link } from 'react-router-dom'
import * as M from '@material-ui/core'

import * as Pagination from 'components/Pagination'
import { readableBytes } from 'utils/string'
import tagged from 'utils/tagged'
import useDebouncedInput from 'utils/useDebouncedInput'
import usePrevious from 'utils/usePrevious'

function WrappedAutosizeInput({ className, ...props }) {
  return <AutosizeInput inputClassName={className} {...props} />
}

export const ListingItem = tagged([
  'Dir', // { name, to }
  'File', // { name, to, size, modified }
])

const useItemStyles = M.makeStyles((t) => ({
  root: {
    flexWrap: 'wrap',
    fontSize: 14, // TODO: use existing definition
    justifyContent: 'space-between',
    padding: t.spacing(1),
    '&:hover': {
      background: t.palette.action.hover,
    },
  },
  name: {
    alignItems: 'center',
    display: 'flex',
  },
  info: {
    display: 'flex',
  },
  icon: {
    fontSize: 16, // TODO: use predefined font-size
    marginRight: t.spacing(0.5),
  },
}))

function Item({ name, to, icon, children, ...props }) {
  const classes = useItemStyles()
  return (
    <M.ListItem component={Link} to={to} className={classes.root} {...props}>

        {!!icon && <M.Icon className={classes.icon}>{icon}</M.Icon>}
        {name}

{children}

    </M.ListItem>
  )
}

const computeStats = R.reduce(
  ListingItem.reducer({
    File: (file) =>
      R.evolve({
        files: R.inc,
        size: R.add(file.size),
        modified: R.max(file.modified),
      }),
    Dir: ({ name }) => (name === '..' ? R.identity : R.evolve({ dirs: R.inc })),
  }),
  {
    dirs: 0,
    files: 0,
    size: 0,
    modified: 0,
  },
)

const useStatsStyles = M.makeStyles((t) => ({
  root: {
    alignItems: 'center',
    borderBottom: `1px solid ${t.palette.divider}`,
    display: 'flex',
    flexWrap: 'wrap',
    minHeight: 37,
    padding: [[2, t.spacing(1)]],
  },
  input: {
    fontSize: 14,
    height: 20,
    lineHeight: 20,
    padding: 0,
  },
  checkbox: {
    marginBottom: -9,
    marginRight: -5,
    marginTop: -9,
  },
  checkboxLabel: {
    ...t.typography.body2,
  },
  clear: {
    fontSize: 11,
    lineHeight: '22px',
    paddingBottom: 0,
    paddingTop: 2,
  },
  clearIcon: {
    fontSize: '16px !important',
    lineHeight: '15px',
    marginLeft: -4,
  },
  searchIcon: {
    fontSize: 20,
    marginLeft: -2,
    marginRight: t.spacing(0.5) - 2,
  },
  divider: {
    color: t.palette.text.hint,
    marginLeft: t.spacing(1),
    marginRight: t.spacing(1),
  },
  truncated: {
    color: t.palette.text.secondary,
    marginLeft: t.spacing(1),
  },
  spacer: {
    flexGrow: 1,
  },
}))

function Stats({ items, unfiltered, filtering, truncated, useRE, setUseRE }) {
  const classes = useStatsStyles()
  const stats = React.useMemo(() => computeStats(unfiltered), [unfiltered])
  const filteredStats = React.useMemo(() => computeStats(items), [items])
  const inputRef = React.useRef()
  const handleKeyDown = React.useCallback(
    (e) => {
      if (e.key === 'Escape') {
        filtering.set('')
        if (inputRef.current && inputRef.current.blur) inputRef.current.blur()
      }
    },
    [filtering.set, inputRef],
  )
  const handleToggleRE = React.useCallback(
    (e) => {
      setUseRE(e.target.checked)
    },
    [setUseRE],
  )

  return (

      <M.InputBase
        {...filtering.input}
        onKeyDown={handleKeyDown}
        placeholder="Filter current directory"
        classes={{ input: classes.input }}
        inputComponent={WrappedAutosizeInput}
        inputRef={inputRef}
        startAdornment={<M.Icon className={classes.searchIcon}>search</M.Icon>}
        endAdornment={
          <>
            <M.FormControlLabel
              style={{ marginLeft: 0 }}
              classes={{ label: classes.checkboxLabel }}
              control={
                <M.Checkbox
                  checked={useRE}
                  onChange={handleToggleRE}
                  color="primary"
                  size="small"
                  className={classes.checkbox}
                />
              }
              label="regex"
            />
            {!!filtering.input.value && (
              <M.Button
                className={classes.clear}
                size="small"
                variant="contained"
                color="primary"
                onClick={() => filtering.set('')}
                endIcon={<M.Icon className={classes.clearIcon}>clear</M.Icon>}
              >
                Clear filter
              </M.Button>
            )}
          </>
        }
      />

        {!!filtering.value && <>{filteredStats.dirs} / </>}
        {stats.dirs} folders

       |

        {!!filtering.value && <>{filteredStats.files} / </>}
        {stats.files} files

       |

        {!!filtering.value && <>{readableBytes(filteredStats.size)} / </>}
        {readableBytes(stats.size)}

      {truncated && (truncated)}
      {!!stats.modified && (
        <>
           |
          Last modified {stats.modified.toLocaleString()}
        </>
      )}

  )
}

const useListingStyles = M.makeStyles((t) => ({
  root: {
    minHeight: 40 + t.spacing(4), // for spinner
    padding: '0 !important',
    position: 'relative',
  },
  lock: {
    alignItems: 'center',
    background: t.palette.common.white,
    display: 'flex',
    height: '100%',
    justifyContent: 'center',
    left: 0,
    opacity: 0.5,
    padding: t.spacing(2),
    position: 'absolute',
    top: 0,
    width: '100%',
    zIndex: 1,
  },
  empty: {
    marginLeft: t.spacing(2),
    paddingTop: t.spacing(2.5),
  },
  noMatch: {
    ...t.typography.body2,
    padding: t.spacing(1),
  },
  size: {
    textAlign: 'right',
    width: '6em',
  },
  modified: {
    textAlign: 'right',
    width: '12em',
  },
}))

export default function Listing({ items, truncated = false, locked = false, loadMore }) {
  const classes = useListingStyles()

  const scrollRef = React.useRef(null)
  const scroll = React.useCallback((prev) => {
    if (prev && scrollRef.current) scrollRef.current.scrollIntoView()
  })

  const [useRE, setUseRE] = React.useState(false)
  const filtering = useDebouncedInput('', 200)
  const filtered = React.useMemo(
    R.tryCatch(
      R.pipe(
        () =>
          filtering.value
            ? items.filter(
                R.pipe(
                  ListingItem.case({
                    Dir: R.prop('name'),
                    File: R.prop('name'),
                  }),
                  R.toLower,
                  useRE
                    ? R.test(new RegExp(filtering.value, 'i'))
                    : R.includes(filtering.value.toLowerCase()),
                ),
              )
            : items,
        R.objOf('result'),
      ),
      (err) => ({ result: [], err }),
    ),
    [filtering.value, items, useRE],
  )

  const totalItems = React.useMemo(() => {
    const stats = computeStats(items)
    return stats.dirs + stats.files
  }, [items])

  usePrevious(items, (prevItems) => {
    if (R.is(Array, items) && R.is(Array, prevItems) && !R.startsWith(prevItems, items)) {
      filtering.set('')
    }
  })

  const pagination = Pagination.use(filtered.result, { perPage: 25, onChange: scroll })

  return (
    <M.Card>
      <M.CardContent className={classes.root}>
        {locked && (

            <M.CircularProgress />

        )}
        {!items.length ? (
          <M.Typography className={classes.empty} variant="h5">
            No files
          </M.Typography>
        ) : (
          <>
            <Stats
              items={filtered.result}
              unfiltered={items}
              filtering={filtering}
              truncated={truncated}
              useRE={useRE}
              setUseRE={setUseRE}
            />

            {!filtered.result.length &&
              (filtered.err ? (

{filtered.err.message}

              ) : (

                  No entries matching{' '}

                      {useRE ? `/${filtering.value}/i` : `"${filtering.value}"`}

                  {truncated && !!loadMore && (
                    <> → try loading more items (button below)</>
                  )}

              ))}
            {pagination.paginated.map(
              ListingItem.case({
                Dir: ({ name, to }) => (
                  <Item icon="folder_open" key={name} name={name} to={to} />
                ),
                File: ({ name, to, size, modified }) => (
                  <Item icon="insert_drive_file" key={name} name={name} to={to}>

{readableBytes(size)}

                    {!!modified && (

{modified.toLocaleString()}

                    )}
                  </Item>
                ),
              }),
            )}
            {(truncated || pagination.pages > 1) && (
              <M.Box>
                <M.Divider />
                <M.Box display="flex" alignItems="center" minHeight={36} px={1}>
                  {truncated && (
                    <M.Typography variant="body2" component="span" color="textSecondary">
                      <M.Icon
                        style={{
                          fontSize: 16,
                          verticalAlign: 'text-bottom',
                          marginRight: 4,
                        }}
                      >
                        warning
                      </M.Icon>
                      Results truncated to {totalItems} items
                      {!!loadMore && (
                        <>
                          <> → </>
                          <M.Link
                            onClick={loadMore}
                            component="button"
                            underline="always"
                            style={{ verticalAlign: 'baseline' }}
                          >
                            load more
                          </M.Link>
                        </>
                      )}
                    </M.Typography>
                  )}
                  <M.Box flexGrow={1} />
                  {pagination.pages > 1 && <Pagination.Controls {...pagination} />}
                </M.Box>
              </M.Box>
            )}
          </>
        )}
      </M.CardContent>
    </M.Card>
  )
}
<commit_msg>Bucket/Listing: enable regex filtering by default (#1631)<commit_after>import * as R from 'ramda'
import * as React from 'react'
import AutosizeInput from 'react-input-autosize'
import { Link } from 'react-router-dom'
import * as M from '@material-ui/core'

import * as Pagination from 'components/Pagination'
import { readableBytes } from 'utils/string'
import tagged from 'utils/tagged'
import useDebouncedInput from 'utils/useDebouncedInput'
import usePrevious from 'utils/usePrevious'

function WrappedAutosizeInput({ className, ...props }) {
  return <AutosizeInput inputClassName={className} {...props} />
}

export const ListingItem = tagged([
  'Dir', // { name, to }
  'File', // { name, to, size, modified }
])

const useItemStyles = M.makeStyles((t) => ({
  root: {
    flexWrap: 'wrap',
    fontSize: 14, // TODO: use existing definition
    justifyContent: 'space-between',
    padding: t.spacing(1),
    '&:hover': {
      background: t.palette.action.hover,
    },
  },
  name: {
    alignItems: 'center',
    display: 'flex',
  },
  info: {
    display: 'flex',
  },
  icon: {
    fontSize: 16, // TODO: use predefined font-size
    marginRight: t.spacing(0.5),
  },
}))

function Item({ name, to, icon, children, ...props }) {
  const classes = useItemStyles()
  return (
    <M.ListItem component={Link} to={to} className={classes.root} {...props}>

        {!!icon && <M.Icon className={classes.icon}>{icon}</M.Icon>}
        {name}

{children}

    </M.ListItem>
  )
}

const computeStats = R.reduce(
  ListingItem.reducer({
    File: (file) =>
      R.evolve({
        files: R.inc,
        size: R.add(file.size),
        modified: R.max(file.modified),
      }),
    Dir: ({ name }) => (name === '..' ? R.identity : R.evolve({ dirs: R.inc })),
  }),
  {
    dirs: 0,
    files: 0,
    size: 0,
    modified: 0,
  },
)

const useStatsStyles = M.makeStyles((t) => ({
  root: {
    alignItems: 'center',
    borderBottom: `1px solid ${t.palette.divider}`,
    display: 'flex',
    flexWrap: 'wrap',
    minHeight: 37,
    padding: [[2, t.spacing(1)]],
  },
  input: {
    fontSize: 14,
    height: 20,
    lineHeight: 20,
    padding: 0,
  },
  checkbox: {
    marginBottom: -9,
    marginRight: -5,
    marginTop: -9,
  },
  checkboxLabel: {
    ...t.typography.body2,
  },
  clear: {
    fontSize: 11,
    lineHeight: '22px',
    paddingBottom: 0,
    paddingTop: 2,
  },
  clearIcon: {
    fontSize: '16px !important',
    lineHeight: '15px',
    marginLeft: -4,
  },
  searchIcon: {
    fontSize: 20,
    marginLeft: -2,
    marginRight: t.spacing(0.5) - 2,
  },
  divider: {
    color: t.palette.text.hint,
    marginLeft: t.spacing(1),
    marginRight: t.spacing(1),
  },
  truncated: {
    color: t.palette.text.secondary,
    marginLeft: t.spacing(1),
  },
  spacer: {
    flexGrow: 1,
  },
}))

function Stats({ items, unfiltered, filtering, truncated, useRE, setUseRE }) {
  const classes = useStatsStyles()
  const stats = React.useMemo(() => computeStats(unfiltered), [unfiltered])
  const filteredStats = React.useMemo(() => computeStats(items), [items])
  const inputRef = React.useRef()
  const handleKeyDown = React.useCallback(
    (e) => {
      if (e.key === 'Escape') {
        filtering.set('')
        if (inputRef.current && inputRef.current.blur) inputRef.current.blur()
      }
    },
    [filtering.set, inputRef],
  )
  const handleToggleRE = React.useCallback(
    (e) => {
      setUseRE(e.target.checked)
    },
    [setUseRE],
  )

  return (

      <M.InputBase
        {...filtering.input}
        onKeyDown={handleKeyDown}
        placeholder="Filter current directory"
        classes={{ input: classes.input }}
        inputComponent={WrappedAutosizeInput}
        inputRef={inputRef}
        startAdornment={<M.Icon className={classes.searchIcon}>search</M.Icon>}
        endAdornment={
          <>
            <M.FormControlLabel
              style={{ marginLeft: 0 }}
              classes={{ label: classes.checkboxLabel }}
              control={
                <M.Checkbox
                  checked={useRE}
                  onChange={handleToggleRE}
                  color="primary"
                  size="small"
                  className={classes.checkbox}
                />
              }
              label="regex"
            />
            {!!filtering.input.value && (
              <M.Button
                className={classes.clear}
                size="small"
                variant="contained"
                color="primary"
                onClick={() => filtering.set('')}
                endIcon={<M.Icon className={classes.clearIcon}>clear</M.Icon>}
              >
                Clear filter
              </M.Button>
            )}
          </>
        }
      />

        {!!filtering.value && <>{filteredStats.dirs} / </>}
        {stats.dirs} folders

       |

        {!!filtering.value && <>{filteredStats.files} / </>}
        {stats.files} files

       |

        {!!filtering.value && <>{readableBytes(filteredStats.size)} / </>}
        {readableBytes(stats.size)}

      {truncated && (truncated)}
      {!!stats.modified && (
        <>
           |
          Last modified {stats.modified.toLocaleString()}
        </>
      )}

  )
}

const useListingStyles = M.makeStyles((t) => ({
  root: {
    minHeight: 40 + t.spacing(4), // for spinner
    padding: '0 !important',
    position: 'relative',
  },
  lock: {
    alignItems: 'center',
    background: t.palette.common.white,
    display: 'flex',
    height: '100%',
    justifyContent: 'center',
    left: 0,
    opacity: 0.5,
    padding: t.spacing(2),
    position: 'absolute',
    top: 0,
    width: '100%',
    zIndex: 1,
  },
  empty: {
    marginLeft: t.spacing(2),
    paddingTop: t.spacing(2.5),
  },
  noMatch: {
    ...t.typography.body2,
    padding: t.spacing(1),
  },
  size: {
    textAlign: 'right',
    width: '6em',
  },
  modified: {
    textAlign: 'right',
    width: '12em',
  },
}))

export default function Listing({ items, truncated = false, locked = false, loadMore }) {
  const classes = useListingStyles()

  const scrollRef = React.useRef(null)
  const scroll = React.useCallback((prev) => {
    if (prev && scrollRef.current) scrollRef.current.scrollIntoView()
  })

  const [useRE, setUseRE] = React.useState(true)
  const filtering = useDebouncedInput('', 200)
  const filtered = React.useMemo(
    R.tryCatch(
      R.pipe(
        () =>
          filtering.value
            ? items.filter(
                R.pipe(
                  ListingItem.case({
                    Dir: R.prop('name'),
                    File: R.prop('name'),
                  }),
                  R.toLower,
                  useRE
                    ? R.test(new RegExp(filtering.value, 'i'))
                    : R.includes(filtering.value.toLowerCase()),
                ),
              )
            : items,
        R.objOf('result'),
      ),
      (err) => ({ result: [], err }),
    ),
    [filtering.value, items, useRE],
  )

  const totalItems = React.useMemo(() => {
    const stats = computeStats(items)
    return stats.dirs + stats.files
  }, [items])

  usePrevious(items, (prevItems) => {
    if (R.is(Array, items) && R.is(Array, prevItems) && !R.startsWith(prevItems, items)) {
      filtering.set('')
    }
  })

  const pagination = Pagination.use(filtered.result, { perPage: 25, onChange: scroll })

  return (
    <M.Card>
      <M.CardContent className={classes.root}>
        {locked && (

            <M.CircularProgress />

        )}
        {!items.length ? (
          <M.Typography className={classes.empty} variant="h5">
            No files
          </M.Typography>
        ) : (
          <>
            <Stats
              items={filtered.result}
              unfiltered={items}
              filtering={filtering}
              truncated={truncated}
              useRE={useRE}
              setUseRE={setUseRE}
            />

            {!filtered.result.length &&
              (filtered.err ? (

{filtered.err.message}

              ) : (

                  No entries matching{' '}

                      {useRE ? `/${filtering.value}/i` : `"${filtering.value}"`}

                  {truncated && !!loadMore && (
                    <> → try loading more items (button below)</>
                  )}

              ))}
            {pagination.paginated.map(
              ListingItem.case({
                Dir: ({ name, to }) => (
                  <Item icon="folder_open" key={name} name={name} to={to} />
                ),
                File: ({ name, to, size, modified }) => (
                  <Item icon="insert_drive_file" key={name} name={name} to={to}>

{readableBytes(size)}

                    {!!modified && (

{modified.toLocaleString()}

                    )}
                  </Item>
                ),
              }),
            )}
            {(truncated || pagination.pages > 1) && (
              <M.Box>
                <M.Divider />
                <M.Box display="flex" alignItems="center" minHeight={36} px={1}>
                  {truncated && (
                    <M.Typography variant="body2" component="span" color="textSecondary">
                      <M.Icon
                        style={{
                          fontSize: 16,
                          verticalAlign: 'text-bottom',
                          marginRight: 4,
                        }}
                      >
                        warning
                      </M.Icon>
                      Results truncated to {totalItems} items
                      {!!loadMore && (
                        <>
                          <> → </>
                          <M.Link
                            onClick={loadMore}
                            component="button"
                            underline="always"
                            style={{ verticalAlign: 'baseline' }}
                          >
                            load more
                          </M.Link>
                        </>
                      )}
                    </M.Typography>
                  )}
                  <M.Box flexGrow={1} />
                  {pagination.pages > 1 && <Pagination.Controls {...pagination} />}
                </M.Box>
              </M.Box>
            )}
          </>
        )}
      </M.CardContent>
    </M.Card>
  )
}
<|endoftext|>


<commit_before>// Create the cache manager (a shared object)
var cacheManager = Ti.App.Properties.getObject("cachedXHRDocuments", {});
var storedExtraParams = Ti.App.Properties.getObject("extraXHRParams", addDefaultsToOptions({}));

XHR = function() {};

// Public functions
// ================

// GET
// @url (string) URL to fetch
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.GET = function(url, onSuccess, onError, extraParams) {
    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var cache = readCache(url);

    // If there is nothing cached, send the request
    if (cache === false || !extraParams.ttl) {

        var xhr = initXHRRequest('GET', url, extraParams);

        // When the connection was successful
        xhr.onload = function() {
            var result = handleSuccess(xhr, extraParams);
            onSuccess(result);

            // only cache if there is a ttl
            if (extraParams.ttl) {
                writeCache(result.data, url, extraParams.ttl);
            }
        };

        // When there was an error
        xhr.onerror = function(e) {
            onError(handleError(xhr, e));
        };

        xhr.send();

    } else {

        var result = {};
        result.result = "cache";
        result.status = 304;
        // not modified
        result.data = cache;

        onSuccess(result);
    }
};

// POST requests
// @url (string) URL to fetch
// @data (object)
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.POST = function(url, data, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('POST', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send(extraParams.parseJSON ? JSON.stringify(data) : data);
};

// PUT requests
// @url (string) URL to fetch
// @data (object)
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.PUT = function(url, data, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('PUT', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send(extraParams.parseJSON ? JSON.stringify(data) : data);
};

// DELETE requests
// @url (string) URL to fetch
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.DELETE = function(url, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('DELETE', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send();
};

// backward compatibilty
XHR.prototype.get = XHR.prototype.GET;
XHR.prototype.post = XHR.prototype.POST;
XHR.prototype.put = XHR.prototype.PUT;
XHR.prototype.destroy = XHR.prototype.DELETE;

// Helper functions
// =================

// Removes the cached content of a given URL (this is useful if you are not satisfied with the data returned that time)
XHR.prototype.clear = function(url) {

    if (url) {
        // Hash the URL
        var hashedURL = Titanium.Utils.md5HexDigest(url);
        // Check if the file exists in the manager
        var cache = cacheManager[hashedURL];

        // If the file was found
        if (cache) {
            // Delete references and file
            var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);
            // Delete the record and file
            delete cacheManager[hashedURL];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();
        }
    }

};

// Removes all the expired documents from the manager and the file system
XHR.prototype.clean = function() {

    var nowInMilliseconds = new Date().getTime();
    var expiredDocuments = 0;

    for (var key in cacheManager) {
        var cache = cacheManager[key];

        if (cache.timestamp <= nowInMilliseconds) {
            // Delete references and file
            var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, key);
            // Delete the record and file
            delete cacheManager[key];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();

            // Update the deleted documents count
            expiredDocuments = expiredDocuments + 1;
        }

    }

    // Return the number of files deleted
    return expiredDocuments;
};

// Removes all documents from the manager and the file system
XHR.prototype.purge = function() {

    var purgedDocuments = 0;

    for (var key in cacheManager) {
        var cache = cacheManager[key];
        // Delete references and file
        var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, key);
        // Delete the record and file
        delete cacheManager[key];
        file.deleteFile();

        // Update the cache manager
        updateCacheManager();

        // Update the deleted documents count
        purgedDocuments = purgedDocuments + 1;
    }

    // Return the number of files deleted
    return purgedDocuments;
};

XHR.prototype.setStaticOptions = function(params) {
    var params = addDefaultsToOptions(params);
    Ti.App.Properties.setObject("extraXHRParams", params);
    storedExtraParams = params;

};

// Private Helper Functions
// ========================
function addDefaultsToOptions(providedParams) {
    var extraParams = providedParams || {};
    extraParams.async = (extraParams.hasOwnProperty('async')) ? extraParams.async : true;
    extraParams.ttl = (extraParams.hasOwnProperty('ttl')) ? extraParams.ttl : false;
    extraParams.shouldAuthenticate = extraParams.shouldAuthenticate || false;
    extraParams.contentType = extraParams.contentType || "application/json";
    extraParams.parseJSON = (extraParams.hasOwnProperty('parseJSON')) ? extraParams.parseJSON : false;
    extraParams.returnXML = (extraParams.hasOwnProperty('returnXML')) ? extraParams.returnXML : false;
    extraParams.debug = (extraParams.hasOwnProperty('debug')) ? extraParams.debug : false;
    return extraParams;
}

// Return a standardized response
function handleSuccess(xhr, extraParams) {
    var result = {};
    result.result = "success";
    result.status = xhr.status;

    /**
     * Check if the response is XML, if not try to parse JSON (if that was requested)
     * As a final catch, when that fails too, return the data that was received;
     * xhr.responseXML is null by default unless the response actually is XML
     */
    try {
        if (extraParams.returnXML && xhr.responseXML) {
            result.data = xhr.responseXML;
        } else {
            result.data = extraParams.parseJSON ? JSON.parse(xhr.responseText) : xhr.responseText;
        }
    } catch(e) {
        result.data = xhr.responseData;
    }

    return result;
}

// Return a standardized response
function handleError(xhr, error) {
    var result = {};
    result.result = "error";
    result.status = xhr.status;
    result.error = error.error;
    result.data = xhr.responseData;
    return result;
}

function initXHRRequest(method, url, extraParams) {
    // Create the HTTP connection
    var xhr = Titanium.Network.createHTTPClient({
        enableKeepAlive : false
    });

    // Open the HTTP connection
    xhr.open(method, url, extraParams.async);
    xhr.setRequestHeader('Content-Type', extraParams.contentType);

    if (extraParams.debug) {
        Ti.API.info(method + ': ' + url);
    }

    // If we need to authenticate
    if (extraParams.shouldAuthenticate) {
        if (extraParams.oAuthToken) {
            var authstr = 'Bearer ' + extraParams.oAuthToken;
        } else {
            var authstr = 'Basic ' + Titanium.Utils.base64encode(extraParams.username + ':' + extraParams.password);
        }
        xhr.setRequestHeader('Authorization', authstr);
    }
    return xhr;
}

// Private functions
// =================
function readCache(url) {
    // Hash the URL
    var hashedURL = Titanium.Utils.md5HexDigest(url);

    // Check if the file exists in the manager
    var cache = cacheManager[hashedURL];
    // Default the return value to false
    var result = false;

    //Titanium.API.info("CHECKING CACHE");

    // If the file was found
    if (cache) {
        // Fetch a reference to the cache file
        var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);

        // Check that the TTL is further than the current date
        if (cache.timestamp >= new Date().getTime()) {
            //Titanium.API.info("CACHE FOUND");

            // Return the content of the file
            result = file.read();

        } else {
            //Titanium.API.info("OLD CACHE");

            // Delete the record and file
            delete cacheManager[hashedURL];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();
        }
    } else {
        //Titanium.API.info("CACHE " + hashedURL + " NOT FOUND");
    }

    return result;
};

function updateCacheManager() {
    Titanium.App.Properties.setObject("cachedXHRDocuments", cacheManager);
};

function writeCache(data, url, ttl) {

    //Titanium.API.info("WRITING CACHE");

    // hash the url
    var hashedURL = Titanium.Utils.md5HexDigest(url);

    // Write the file to the disk
    var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);

    // Write the file to the disk
    // TODO: There appears to be a bug in Titanium and makes the method
    // below always return false when dealing with binary files
    file.write(data);

    // Insert the cached object in the cache manager
    cacheManager[hashedURL] = {
        "timestamp" : (new Date().getTime()) + (ttl * 60 * 1000)
    };
    updateCacheManager();

    //Titanium.API.info("WROTE CACHE");
};

// Return everything
module.exports = XHR;
<commit_msg>don't store params cross session, this might cause issues (#24)<commit_after>// Create the cache manager (a shared object)
var cacheManager = Ti.App.Properties.getObject("cachedXHRDocuments", {});
var storedExtraParams = addDefaultsToOptions({});

XHR = function() {};

// Public functions
// ================

// GET
// @url (string) URL to fetch
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.GET = function(url, onSuccess, onError, extraParams) {
    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var cache = readCache(url);

    // If there is nothing cached, send the request
    if (cache === false || !extraParams.ttl) {

        var xhr = initXHRRequest('GET', url, extraParams);

        // When the connection was successful
        xhr.onload = function() {
            var result = handleSuccess(xhr, extraParams);
            onSuccess(result);

            // only cache if there is a ttl
            if (extraParams.ttl) {
                writeCache(result.data, url, extraParams.ttl);
            }
        };

        // When there was an error
        xhr.onerror = function(e) {
            onError(handleError(xhr, e));
        };

        xhr.send();

    } else {

        var result = {};
        result.result = "cache";
        result.status = 304;
        // not modified
        result.data = cache;

        onSuccess(result);
    }
};

// POST requests
// @url (string) URL to fetch
// @data (object)
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.POST = function(url, data, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('POST', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send(extraParams.parseJSON ? JSON.stringify(data) : data);
};

// PUT requests
// @url (string) URL to fetch
// @data (object)
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.PUT = function(url, data, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('PUT', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send(extraParams.parseJSON ? JSON.stringify(data) : data);
};

// DELETE requests
// @url (string) URL to fetch
// @onSuccess (function) success callback
// @onError (function) error callback
// @extraParams (object)
XHR.prototype.DELETE = function(url, onSuccess, onError, extraParams) {

    // Create some default params
    var onSuccess = onSuccess || function() {};
    var onError = onError || function() {};

    if (extraParams) {
        var extraParams = addDefaultsToOptions(extraParams);
    } else {
        var extraParams = storedExtraParams;
    }

    var xhr = initXHRRequest('DELETE', url, extraParams);

    // When the connection was successful
    xhr.onload = function() {
        onSuccess(handleSuccess(xhr, extraParams));
    };

    // When there was an error
    xhr.onerror = function(e) {
        // Check the status of this
        onError(handleError(xhr, e));
    };

    xhr.send();
};

// backward compatibilty
XHR.prototype.get = XHR.prototype.GET;
XHR.prototype.post = XHR.prototype.POST;
XHR.prototype.put = XHR.prototype.PUT;
XHR.prototype.destroy = XHR.prototype.DELETE;

// Helper functions
// =================

// Removes the cached content of a given URL (this is useful if you are not satisfied with the data returned that time)
XHR.prototype.clear = function(url) {

    if (url) {
        // Hash the URL
        var hashedURL = Titanium.Utils.md5HexDigest(url);
        // Check if the file exists in the manager
        var cache = cacheManager[hashedURL];

        // If the file was found
        if (cache) {
            // Delete references and file
            var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);
            // Delete the record and file
            delete cacheManager[hashedURL];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();
        }
    }

};

// Removes all the expired documents from the manager and the file system
XHR.prototype.clean = function() {

    var nowInMilliseconds = new Date().getTime();
    var expiredDocuments = 0;

    for (var key in cacheManager) {
        var cache = cacheManager[key];

        if (cache.timestamp <= nowInMilliseconds) {
            // Delete references and file
            var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, key);
            // Delete the record and file
            delete cacheManager[key];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();

            // Update the deleted documents count
            expiredDocuments = expiredDocuments + 1;
        }

    }

    // Return the number of files deleted
    return expiredDocuments;
};

// Removes all documents from the manager and the file system
XHR.prototype.purge = function() {

    var purgedDocuments = 0;

    for (var key in cacheManager) {
        var cache = cacheManager[key];
        // Delete references and file
        var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, key);
        // Delete the record and file
        delete cacheManager[key];
        file.deleteFile();

        // Update the cache manager
        updateCacheManager();

        // Update the deleted documents count
        purgedDocuments = purgedDocuments + 1;
    }

    // Return the number of files deleted
    return purgedDocuments;
};

XHR.prototype.setStaticOptions = function(params) {
    var params = addDefaultsToOptions(params);
    storedExtraParams = params;

};

// Private Helper Functions
// ========================
function addDefaultsToOptions(providedParams) {
    var extraParams = providedParams || {};
    extraParams.async = (extraParams.hasOwnProperty('async')) ? extraParams.async : true;
    extraParams.ttl = (extraParams.hasOwnProperty('ttl')) ? extraParams.ttl : false;
    extraParams.shouldAuthenticate = extraParams.shouldAuthenticate || false;
    extraParams.contentType = extraParams.contentType || "application/json";
    extraParams.parseJSON = (extraParams.hasOwnProperty('parseJSON')) ? extraParams.parseJSON : false;
    extraParams.returnXML = (extraParams.hasOwnProperty('returnXML')) ? extraParams.returnXML : false;
    extraParams.debug = (extraParams.hasOwnProperty('debug')) ? extraParams.debug : false;
    return extraParams;
}

// Return a standardized response
function handleSuccess(xhr, extraParams) {
    var result = {};
    result.result = "success";
    result.status = xhr.status;

    /**
     * Check if the response is XML, if not try to parse JSON (if that was requested)
     * As a final catch, when that fails too, return the data that was received;
     * xhr.responseXML is null by default unless the response actually is XML
     */
    try {
        if (extraParams.returnXML && xhr.responseXML) {
            result.data = xhr.responseXML;
        } else {
            result.data = extraParams.parseJSON ? JSON.parse(xhr.responseText) : xhr.responseText;
        }
    } catch(e) {
        result.data = xhr.responseData;
    }

    return result;
}

// Return a standardized response
function handleError(xhr, error) {
    var result = {};
    result.result = "error";
    result.status = xhr.status;
    result.error = error.error;
    result.data = xhr.responseData;
    return result;
}

function initXHRRequest(method, url, extraParams) {
    // Create the HTTP connection
    var xhr = Titanium.Network.createHTTPClient({
        enableKeepAlive : false
    });

    // Open the HTTP connection
    xhr.open(method, url, extraParams.async);
    xhr.setRequestHeader('Content-Type', extraParams.contentType);

    if (extraParams.debug) {
        Ti.API.info(method + ': ' + url);
    }

    // If we need to authenticate
    if (extraParams.shouldAuthenticate) {
        if (extraParams.oAuthToken) {
            var authstr = 'Bearer ' + extraParams.oAuthToken;
        } else {
            var authstr = 'Basic ' + Titanium.Utils.base64encode(extraParams.username + ':' + extraParams.password);
        }
        xhr.setRequestHeader('Authorization', authstr);
    }
    return xhr;
}

// Private functions
// =================
function readCache(url) {
    // Hash the URL
    var hashedURL = Titanium.Utils.md5HexDigest(url);

    // Check if the file exists in the manager
    var cache = cacheManager[hashedURL];
    // Default the return value to false
    var result = false;

    //Titanium.API.info("CHECKING CACHE");

    // If the file was found
    if (cache) {
        // Fetch a reference to the cache file
        var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);

        // Check that the TTL is further than the current date
        if (cache.timestamp >= new Date().getTime()) {
            //Titanium.API.info("CACHE FOUND");

            // Return the content of the file
            result = file.read();

        } else {
            //Titanium.API.info("OLD CACHE");

            // Delete the record and file
            delete cacheManager[hashedURL];
            file.deleteFile();

            // Update the cache manager
            updateCacheManager();
        }
    } else {
        //Titanium.API.info("CACHE " + hashedURL + " NOT FOUND");
    }

    return result;
};

function updateCacheManager() {
    Titanium.App.Properties.setObject("cachedXHRDocuments", cacheManager);
};

function writeCache(data, url, ttl) {

    //Titanium.API.info("WRITING CACHE");

    // hash the url
    var hashedURL = Titanium.Utils.md5HexDigest(url);

    // Write the file to the disk
    var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, hashedURL);

    // Write the file to the disk
    // TODO: There appears to be a bug in Titanium and makes the method
    // below always return false when dealing with binary files
    file.write(data);

    // Insert the cached object in the cache manager
    cacheManager[hashedURL] = {
        "timestamp" : (new Date().getTime()) + (ttl * 60 * 1000)
    };
    updateCacheManager();

    //Titanium.API.info("WROTE CACHE");
};

// Return everything
module.exports = XHR;
<|endoftext|>


<commit_before>'use strict';

let XLSX   = require('xlsx');
let a2u    = require('./a2u');
let moment = require('moment');

module.exports = function (file) {
    let workbook = XLSX.readFile(file);
    let sheet    = workbook.Sheets.Sheet1;
    let entries  = [];

    if (sheet == null || sheet['!ref'] == null) return;
    let r            = sheet['!range'];
    let row          = '', rr = '', cols = [];
    let R            = 0, C = 0;
    let firstRawSeen = false;

    for (C = r.s.c; C <= r.e.c; ++C) cols[C] = XLSX.utils.encode_col(C);
    for (R = r.s.r; R <= r.e.r; ++R) {
        row = '';
        rr  = XLSX.utils.encode_row(R);

        if (!sheet[cols[1] + rr]) {
            continue;
        }

        if (!firstRawSeen) {
            firstRawSeen = true;
            continue;
        }

        entries.push({
            firstName: a2u(XLSX.utils.format_cell(sheet[cols[1] + rr])),
            lastName: a2u(XLSX.utils.format_cell(sheet[cols[2] + rr])),
            fatherName: a2u(XLSX.utils.format_cell(sheet[cols[3] + rr])),
            birthDate: moment(XLSX.utils.format_cell(sheet[cols[4] + rr]), 'DD/MM/YYYY').toDate(),
            address: a2u(XLSX.utils.format_cell(sheet[cols[5] + rr])),
            area: a2u(XLSX.utils.format_cell(sheet[cols[6] + rr])),
            sector: a2u(XLSX.utils.format_cell(sheet[cols[7] + rr]))
        });
    }

    return entries;
};<commit_msg>swap first and last names<commit_after>'use strict';

let XLSX   = require('xlsx');
let a2u    = require('./a2u');
let moment = require('moment');

module.exports = function (file) {
    let workbook = XLSX.readFile(file);
    let sheet    = workbook.Sheets.Sheet1;
    let entries  = [];

    if (sheet == null || sheet['!ref'] == null) return;
    let r            = sheet['!range'];
    let row          = '', rr = '', cols = [];
    let R            = 0, C = 0;
    let firstRawSeen = false;

    for (C = r.s.c; C <= r.e.c; ++C) cols[C] = XLSX.utils.encode_col(C);
    for (R = r.s.r; R <= r.e.r; ++R) {
        row = '';
        rr  = XLSX.utils.encode_row(R);

        if (!sheet[cols[1] + rr]) {
            continue;
        }

        if (!firstRawSeen) {
            firstRawSeen = true;
            continue;
        }

        entries.push({
            lastName: a2u(XLSX.utils.format_cell(sheet[cols[1] + rr])),
            firstName: a2u(XLSX.utils.format_cell(sheet[cols[2] + rr])),
            fatherName: a2u(XLSX.utils.format_cell(sheet[cols[3] + rr])),
            birthDate: moment(XLSX.utils.format_cell(sheet[cols[4] + rr]), 'DD/MM/YYYY').toDate(),
            address: a2u(XLSX.utils.format_cell(sheet[cols[5] + rr])),
            area: a2u(XLSX.utils.format_cell(sheet[cols[6] + rr])),
            sector: a2u(XLSX.utils.format_cell(sheet[cols[7] + rr]))
        });
    }

    return entries;
};<|endoftext|>


<commit_before>function xpm( opt ) {

	this.opt = opt || {};

	this.getPromise = function(){
		if ( typeof Promise == 'undefined' ) { var _Promise = require('lib/promise.min.js').Promise; } else { var _P = Promise }
		return _Promise;
	}

	/**
	 * 载入服务文件
	 * @param  {[type]} service_name [description]
	 * @param  {[type]} params       [description]
	 * @return {[type]}              [description]
	 */
	this.require = function ( service_name, params  ) {
		var se = require( 'service'  +  '/' + service_name.toLowerCase() + '.js' );
		params = params || {};
		return new se( this.opt , params);
	}

	/**
	 * 设定配置信息
	 * @param  array option 设置或读取配置信息
	 * @return this / option = null return option
	 */
	this.option = function ( option ) {
		if ( typeof option != 'undefined' ) {
			this.opt = option;
			return this;
		} else {
			return this.opt;
		}
	}

}

module.exports = new xpm()

<commit_msg>Promise 兼容<commit_after>function xpm( opt ) {

	this.opt = opt || {};

	this.getPromise = function(){
		if ( typeof Promise == 'undefined' ) { var _Promise = require('lib/promise.min.js').Promise; } else { var _Promise = Promise }
		return _Promise;
	}

	/**
	 * 载入服务文件
	 * @param  {[type]} service_name [description]
	 * @param  {[type]} params       [description]
	 * @return {[type]}              [description]
	 */
	this.require = function ( service_name, params  ) {
		var se = require( 'service'  +  '/' + service_name.toLowerCase() + '.js' );
		params = params || {};
		return new se( this.opt , params);
	}

	/**
	 * 设定配置信息
	 * @param  array option 设置或读取配置信息
	 * @return this / option = null return option
	 */
	this.option = function ( option ) {
		if ( typeof option != 'undefined' ) {
			this.opt = option;
			return this;
		} else {
			return this.opt;
		}
	}

}

module.exports = new xpm()

<|endoftext|>


<commit_before>var tls = require('tls');
var Q = require('q');
var ca = require('./ca');
var MAX_SERVERS = 360;
var MAX_PORT = 60000;
var curPort = 40000;
var TIMEOUT = 6000;
var DELAY = 100;

function ServerAgent() {
  this._cache = {};
  this._serverCount = 0;
}

var proto = ServerAgent.prototype;

proto.createServer = function createServer(hostname, secureConnectionListener, callback) {
  var self = this;
  var cache = self._cache;

  var promise = cache[hostname];
  var defer;

  if (!promise) {
    defer = Q.defer();
    cache[hostname] = promise = defer.promise;
  }

  promise.done(callback);

  if (!defer) {
    return ;
  }

  self.freeServer();
  getServer(ca.createCertificate(hostname), secureConnectionListener,
function(port, server) {
  var removeServer = function() {
    self.removeServer(hostname);
  };
  server.on('error', removeServer);
  setTimeout(function() {
    promise.server = server;
    var timeout = setTimeout(removeServer, TIMEOUT);
    server.once('secureConnection', function() {
      clearTimeout(timeout);
    });
    defer.resolve(port);
  }, DELAY);
});
  self._serverCount++;

  return self;
};

proto.removeServer = function removeServer(hostname) {
  var self = this;
  var cache = self._cache;
  var promise = cache[hostname];
  if (!promise) {
    return;
  }
  delete cache[hostname];
  --self._serverCount;
  setTimeout(function() {
    try {
      promise.server.close();
    } catch(e) {} //重复关闭会导致异常
  }, TIMEOUT);
};

proto.freeServer = function() {
  var self = this;
  if (self._serverCount < MAX_SERVERS) {
    return;
  }

  var cache = self._cache;
  for (var i in cache) {
    destroy(i);
  }

  function destroy(hostname) {
    var promise = cache[hostname];
    if (promise._pending) {
      return;
    }
    promise._pending = true;
    promise.done(function(port) {
      var server = promise.server;
      server.getConnections(function(err, count) {
        promise._pending = false;
        if (!err && !count && self._serverCount > MAX_SERVERS) {
          delete cache[hostname];
          --self._serverCount;
          setTimeout(function() {
            try {
              server.close();
            } catch(e) {} //重复关闭会导致异常
          }, DELAY);
        }
      });
    });
  }
};

proto.destroy = function destroy() {
  var cache = this._cache;
  this._cache = {};
  this._serverCount = 0;
  for (var i in cache) {
    var promise = cache[i];
    promise.done(function() {
      setTimeout(function() {
        try {
          promise.server.close();
        } catch(e) {} //重复关闭会导致异常
      }, DELAY);
    });
  }
};

function getServer(options, secureConnectionListener, callback) {
  if (curPort > MAX_PORT) {
    curPort = 40000;
  }

  var server = tls.createServer(options, secureConnectionListener);
  var next = function() {
    getServer(options, secureConnectionListener, callback);
  };
  server.on('error', next);

  var port = curPort++;
  server.listen(port, function() {
    server.removeListener('error', next);
    callback(port, server);
  });
}

module.exports = ServerAgent;

<commit_msg>chore: Remove unused code<commit_after>var tls = require('tls');
var Q = require('q');
var ca = require('./ca');
var MAX_SERVERS = 360;
var MAX_PORT = 60000;
var curPort = 40000;
var TIMEOUT = 6000;
var DELAY = 100;

function ServerAgent() {
  this._cache = {};
  this._serverCount = 0;
}

var proto = ServerAgent.prototype;

proto.createServer = function createServer(hostname, secureConnectionListener, callback) {
  var self = this;
  var cache = self._cache;

  var promise = cache[hostname];
  var defer;

  if (!promise) {
    defer = Q.defer();
    cache[hostname] = promise = defer.promise;
  }

  promise.done(callback);

  if (!defer) {
    return ;
  }

  self.freeServer();
  getServer(ca.createCertificate(hostname), secureConnectionListener,
function(port, server) {
  var removeServer = function() {
    self.removeServer(hostname);
  };
  server.on('error', removeServer);
  setTimeout(function() {
    promise.server = server;
    var timeout = setTimeout(removeServer, TIMEOUT);
    server.once('secureConnection', function() {
      clearTimeout(timeout);
    });
    defer.resolve(port);
  }, DELAY);
});
  self._serverCount++;

  return self;
};

proto.removeServer = function removeServer(hostname) {
  var self = this;
  var cache = self._cache;
  var promise = cache[hostname];
  if (!promise) {
    return;
  }
  delete cache[hostname];
  --self._serverCount;
  setTimeout(function() {
    try {
      promise.server.close();
    } catch(e) {} //重复关闭会导致异常
  }, TIMEOUT);
};

proto.freeServer = function() {
  var self = this;
  if (self._serverCount < MAX_SERVERS) {
    return;
  }

  var cache = self._cache;
  for (var i in cache) {
    destroy(i);
  }

  function destroy(hostname) {
    var promise = cache[hostname];
    if (promise._pending) {
      return;
    }
    promise._pending = true;
    promise.done(function(port) {
      var server = promise.server;
      server.getConnections(function(err, count) {
        promise._pending = false;
        if (!err && !count && self._serverCount > MAX_SERVERS) {
          delete cache[hostname];
          --self._serverCount;
          setTimeout(function() {
            try {
              server.close();
            } catch(e) {} //重复关闭会导致异常
          }, DELAY);
        }
      });
    });
  }
};

//proto.destroy = function destroy() {
//  var cache = this._cache;
//  this._cache = {};
//  this._serverCount = 0;
//  for (var i in cache) {
//    var promise = cache[i];
//    promise.done(function() {
//      setTimeout(function() {
//        try {
//          promise.server.close();
//        } catch(e) {} //重复关闭会导致异常
//      }, DELAY);
//    });
//  }
//};

function getServer(options, secureConnectionListener, callback) {
  if (curPort > MAX_PORT) {
    curPort = 40000;
  }

  var server = tls.createServer(options, secureConnectionListener);
  var next = function() {
    getServer(options, secureConnectionListener, callback);
  };
  server.on('error', next);

  var port = curPort++;
  server.listen(port, function() {
    server.removeListener('error', next);
    callback(port, server);
  });
}

module.exports = ServerAgent;

<|endoftext|>


<commit_before>import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
  layout,
  options: null,
  value: null,
  labelTop: null,
  labels: null,
  formatLabel: false
});
<commit_msg>Extend exp radio-group component<commit_after>import Ember from 'ember';
import ExpRadioGroupComponent from 'exp-player/components/radio-group';
import layout from './template';

export default ExpRadioGroupComponent.extend({
  layout,
  labelTop: null,
  labels: null,
  formatLabel: false
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';

const { Component, computed, observer, on, ObjectProxy, RSVP, run } = Ember;
const { debounce } = run;
const { defer } = RSVP;
const { PromiseArray, PromiseObject } = DS;

const objectiveProxy = ObjectProxy.extend({
  sessionObjective: null,
  selected: computed('content', 'sessionObjective.parents.[]', function(){
    return this.get('sessionObjective.parents').includes(this.get('content'));
  }),
});

export default Component.extend({
  classNames: ['objective-manager'],
  sessionObjective: null,
  showObjectiveList: false,
  course: computed('sessionObjective.courses.[]', function(){
    let sessionObjective = this.get('sessionObjective');
    if(!sessionObjective){
      return null;
    }
    let deferred = defer();
    sessionObjective.get('sessions').then(function(sessions){
      let session =  sessions.get('firstObject');
      session.get('course').then(function(course){
        deferred.resolve(course);
      });
    });
    return PromiseObject.create({
      promise:deferred.promise
    });
  }),
  proxiedObjectives: computed('course', 'course.objectives.[]', function(){
    let sessionObjective = this.get('sessionObjective');
    if(!sessionObjective){
      return [];
    }
    let deferred = defer();
    this.get('course').then(function(course){
      if(!course){
        deferred.resolve([]);
      }
      course.get('objectives').then(function(objectives){
        let objectiveProxies = objectives.map(function(objective){
          return objectiveProxy.create({
            content: objective,
            sessionObjective: sessionObjective,
          });
        });
        deferred.resolve(objectiveProxies.sortBy('id'));
      });
    });
    return PromiseArray.create({
      promise: deferred.promise
    });
  }),
  watchProxiedObjectives: on('init', observer('proxiedObjectives.length', function(){
    //debounce setting showObjectiveList to avoid animating changes when
    //a save causes the proxied list to change
    debounce(this, function(){
      if(!this.get('isDestroyed')){
        this.set('showObjectiveList', this.get('proxiedObjectives.length') > 0);
      }
    }, 500);
  })),
  actions: {
    addParent: function(parentProxy){
      let newParent = parentProxy.get('content');
      let sessionObjective = this.get('sessionObjective');
      sessionObjective.get('parents').addObject(newParent);
      newParent.get('children').addObject(sessionObjective);
    },
    removeParent: function(parentProxy){
      let removingParent = parentProxy.get('content');
      let sessionObjective = this.get('sessionObjective');
      sessionObjective.get('parents').removeObject(removingParent);
      removingParent.get('children').removeObject(sessionObjective);
    }
  }
});
<commit_msg>replaced promise implementations.<commit_after>import Ember from 'ember';

const { Component, computed, observer, on, ObjectProxy, RSVP, run } = Ember;
const { debounce } = run;
const { Promise } = RSVP;

const objectiveProxy = ObjectProxy.extend({
  sessionObjective: null,
  selected: computed('content', 'sessionObjective.parents.[]', function(){
    return this.get('sessionObjective.parents').includes(this.get('content'));
  }),
});

export default Component.extend({
  classNames: ['objective-manager'],
  sessionObjective: null,
  showObjectiveList: false,
  course: computed('sessionObjective.courses.[]', function(){
    return new Promise(resolve => {
      let sessionObjective = this.get('sessionObjective');
      if(!sessionObjective){
        resolve(null);
        return;
      }
      sessionObjective.get('sessions').then(function(sessions){
        let session =  sessions.get('firstObject');
        session.get('course').then(function(course){
          resolve(course);
        });
      });
    });
  }),
  proxiedObjectives: computed('course', 'course.objectives.[]', function(){
    return new Promise(resolve => {
      let sessionObjective = this.get('sessionObjective');
      if(!sessionObjective){
        resolve([]);
        return;
      }
      this.get('course').then(function(course){
        if(!course){
          resolve([]);
          return;
        }
        course.get('objectives').then(function(objectives){
          let objectiveProxies = objectives.map(function(objective){
            return objectiveProxy.create({
              content: objective,
              sessionObjective: sessionObjective,
            });
          });
          resolve(objectiveProxies.sortBy('id'));
        });
      });
    });
  }),
  watchProxiedObjectives: on('init', observer('proxiedObjectives.length', function(){
    //debounce setting showObjectiveList to avoid animating changes when
    //a save causes the proxied list to change
    debounce(this, function(){
      if(!this.get('isDestroyed')){
        this.set('showObjectiveList', this.get('proxiedObjectives.length') > 0);
      }
    }, 500);
  })),
  actions: {
    addParent: function(parentProxy){
      let newParent = parentProxy.get('content');
      let sessionObjective = this.get('sessionObjective');
      sessionObjective.get('parents').addObject(newParent);
      newParent.get('children').addObject(sessionObjective);
    },
    removeParent: function(parentProxy){
      let removingParent = parentProxy.get('content');
      let sessionObjective = this.get('sessionObjective');
      sessionObjective.get('parents').removeObject(removingParent);
      removingParent.get('children').removeObject(sessionObjective);
    }
  }
});
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { inject as service } from "@ember/service";

import { task } from 'ember-concurrency';
import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';

export default Component.extend(AlertifyHandler, {

  // No Ember generated container
  tagName: '',

  store: service(),

  showSpinner: null,

  user: null,
  roles: null,

  didInsertElement() {
    this._super(...arguments);
    this.set('roles', []);
    const user = this.get('user');
    if(user) {
      this.setProperties({
        id_change: user.id,
        username_change: user.username,
        roles_change: user.roles
      });
    }
  },

  saveUserChanges: task(function * () {
    const userData = this.getProperties('username_change', 'password_change', 'roles_change');

    const user = this.get('user');

    if(user) {
      // check for valid input
      if(!userData.username_change || userData.username_change.length === 0) {
        this.showAlertifyWarning('Username cannot be empty.');
        return;
      } else if(!userData.roles_change || userData.roles_change.length === 0) {
        this.showAlertifyWarning('User needs at least 1 role.');
        return;
      }

      if(user.get('username') !== userData.username_change)
        user.set('username', userData.username_change);

      if(userData.password_change && userData.password_change !== '')
        user.set('password', userData.password_change);

      user.set('roles', userData.roles_change);

      try {
        yield user.save();
        this.showAlertifySuccess(`User updated.`);
        clearInputFields.bind(this)();
      } catch(reason) {
        this.showAlertifyError(reason);
      }
    } else {
      this.showAlertifyError(`User not found.`);
    }

    function clearInputFields() {
      this.setProperties({
        // id_change: "",
        // username_change: "",
        password_change: "",
        // roles_change: []
      });
    }
  }).drop(),

  showReasonErrorAlert(reason) {
    const {title, detail} = reason.errors[0];
    this.showAlertifyError(`<b>${title}:</b> ${detail}`);
  },

  getRoles: task(function * () {
    yield this.set('roles', this.store.findAll('role'));
  })
});
<commit_msg>Remove commented out code<commit_after>import Component from '@ember/component';
import { inject as service } from "@ember/service";

import { task } from 'ember-concurrency';
import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';

export default Component.extend(AlertifyHandler, {

  // No Ember generated container
  tagName: '',

  store: service(),

  showSpinner: null,

  user: null,
  roles: null,

  didInsertElement() {
    this._super(...arguments);
    this.set('roles', []);
    const user = this.get('user');
    if(user) {
      this.setProperties({
        id_change: user.id,
        username_change: user.username,
        roles_change: user.roles
      });
    }
  },

  saveUserChanges: task(function * () {
    const userData = this.getProperties('username_change', 'password_change', 'roles_change');

    const user = this.get('user');

    if(user) {
      // check for valid input
      if(!userData.username_change || userData.username_change.length === 0) {
        this.showAlertifyWarning('Username cannot be empty.');
        return;
      } else if(!userData.roles_change || userData.roles_change.length === 0) {
        this.showAlertifyWarning('User needs at least 1 role.');
        return;
      }

      if(user.get('username') !== userData.username_change)
        user.set('username', userData.username_change);

      if(userData.password_change && userData.password_change !== '')
        user.set('password', userData.password_change);

      user.set('roles', userData.roles_change);

      try {
        yield user.save();
        this.showAlertifySuccess(`User updated.`);
        clearInputFields.bind(this)();
      } catch(reason) {
        this.showAlertifyError(reason);
      }
    } else {
      this.showAlertifyError(`User not found.`);
    }

    function clearInputFields() {
      this.set('password_change', '');
    }
  }).drop(),

  showReasonErrorAlert(reason) {
    const {title, detail} = reason.errors[0];
    this.showAlertifyError(`<b>${title}:</b> ${detail}`);
  },

  getRoles: task(function * () {
    yield this.set('roles', this.store.findAll('role'));
  })
});
<|endoftext|>


<commit_before>// @flow
import React, { Component, PropTypes } from 'react';
import { observer } from 'mobx-react';
import classnames from 'classnames';
import Dialog from 'react-toolbox/lib/dialog/Dialog';
import Input from 'react-toolbox/lib/input/Input';
import Dropup from '../widgets/forms/Dropup';
import MobxReactForm from 'mobx-react-form';
import { defineMessages, intlShape } from 'react-intl';
import DialogCloseButton from '../widgets/DialogCloseButton';
import styles from './WalletCreateDialog.scss';

const messages = defineMessages({
  walletName: {
    id: 'wallet.create.dialog.name.label',
    defaultMessage: '!!!Wallet Name',
    description: 'Label for the "Wallet Name" text input in the wallet create form.'
  },
  currency: {
    id: 'wallet.create.dialog.currency.label',
    defaultMessage: '!!!Currency',
    description: 'Label for the "Currency" dropdown in the wallet create form.'
  },
  invalidWalletName: {
    id: 'wallet.create.dialog.errors.invalidWalletName',
    defaultMessage: '!!!The wallet name must have at least 3 letters.',
    description: 'Error message shown when invalid wallet name was entered in create wallet dialog.'
  },
  invalidCurrency: {
    id: 'wallet.create.dialog.errors.invalidCurrency',
    defaultMessage: '!!!This currency is not yet supported.',
    description: 'Error message shown when invalid currency was selected in create wallet dialog.'
  },
  createPersonalWallet: {
    id: 'wallet.create.dialog.create.personal.wallet.button.label',
    defaultMessage: '!!!Create personal wallet',
    description: 'Label for the "Create personal wallet" button on create wallet dialog.'
  }
});

const currencies = [
  { value: 'ada', label: 'ADA' },
];

const isValidWalletName = ({ field }) => {
  const isValid = field.value.length >= 3;
  return [isValid, 'invalidWalletName'];
};

const isValidCurrency = ({ field }) => {
  const isValid = field.value === 'ada';
  return [isValid, 'invalidCurrency'];
};

const fields = {
  walletName: {
    value: '',
    validate: [isValidWalletName]
  },
  currency: {
    value: 'ada',
    validate: [isValidCurrency]
  },
};

const options = {
  validateOnChange: false
};

@observer
export default class WalletCreateDialog extends Component {

  static propTypes = {
    onSubmit: PropTypes.func.isRequired,
    onCancel: PropTypes.func.isRequired
  };

  static contextTypes = {
    intl: intlShape.isRequired,
  };

  state = {
    isSubmitting: false
  };

  componentDidMount() {
    this.walletNameInput.getWrappedInstance().focus();
  }

  walletNameInput: Input;
  validator = new MobxReactForm({ options, fields }, {});
  actions = [
    {
      label: this.context.intl.formatMessage(messages.createPersonalWallet),
      onClick: this.submit
    }
  ];

  submit = () => {
    this.validator.submit({
      onSuccess: (form) => {
        this.setState({ isSubmitting: true });
        this.props.onSubmit(form.values());
      },
      onError: () => {
        this.setState({ isSubmitting: false });
      }
    });
  };

  checkForEnterKey(event: KeyboardEvent) {
    if (event.key === 'Enter') {
      this.submit();
    }
  }

  render() {
    const { intl } = this.context;
    const { validator } = this;
    const walletName = validator.$('walletName');
    const currency = validator.$('currency');
    const errors = {
      walletName: walletName.error ? intl.formatMessage(messages[walletName.error]) : null,
      currency: currency.error ? intl.formatMessage(messages[currency.error]) : null,
    };
    const dialogClasses = classnames([
      'WalletCreateDialog',
      this.state.isSubmitting ? styles.isSubmitting : null
    ]);
    return (
      <Dialog
        className={dialogClasses}
        title="Create Wallet"
        actions={this.actions}
        onOverlayClick={this.props.onCancel}
        active
      >

        <Input
          type="text"
          className="walletName"
          label={intl.formatMessage(messages.walletName)}
          hint="e.g: Shopping Wallet"
          value={walletName.value}
          error={errors.walletName}
          onChange={walletName.onChange}
          onFocus={walletName.onFocus}
          onBlur={walletName.onBlur}
          onKeyPress={this.checkForEnterKey.bind(this)}
          ref={(input) => { this.walletNameInput = input; }}
        />

        <Dropup
          className="currency"
          label={intl.formatMessage(messages.currency)}
          value={currency.value}
          onChange={currency.onChange}
          onFocus={currency.onFocus}
          onBlur={currency.onBlur}
          error={errors.currency}
          source={currencies}
        />

        <DialogCloseButton onClose={this.props.onCancel} />

      </Dialog>
    );
  }

}
<commit_msg>Fix submit action on wallet create dialog<commit_after>// @flow
import React, { Component, PropTypes } from 'react';
import { observer } from 'mobx-react';
import classnames from 'classnames';
import Dialog from 'react-toolbox/lib/dialog/Dialog';
import Input from 'react-toolbox/lib/input/Input';
import Dropup from '../widgets/forms/Dropup';
import MobxReactForm from 'mobx-react-form';
import { defineMessages, intlShape } from 'react-intl';
import DialogCloseButton from '../widgets/DialogCloseButton';
import styles from './WalletCreateDialog.scss';

const messages = defineMessages({
  walletName: {
    id: 'wallet.create.dialog.name.label',
    defaultMessage: '!!!Wallet Name',
    description: 'Label for the "Wallet Name" text input in the wallet create form.'
  },
  currency: {
    id: 'wallet.create.dialog.currency.label',
    defaultMessage: '!!!Currency',
    description: 'Label for the "Currency" dropdown in the wallet create form.'
  },
  invalidWalletName: {
    id: 'wallet.create.dialog.errors.invalidWalletName',
    defaultMessage: '!!!The wallet name must have at least 3 letters.',
    description: 'Error message shown when invalid wallet name was entered in create wallet dialog.'
  },
  invalidCurrency: {
    id: 'wallet.create.dialog.errors.invalidCurrency',
    defaultMessage: '!!!This currency is not yet supported.',
    description: 'Error message shown when invalid currency was selected in create wallet dialog.'
  },
  createPersonalWallet: {
    id: 'wallet.create.dialog.create.personal.wallet.button.label',
    defaultMessage: '!!!Create personal wallet',
    description: 'Label for the "Create personal wallet" button on create wallet dialog.'
  }
});

const currencies = [
  { value: 'ada', label: 'ADA' },
];

const isValidWalletName = ({ field }) => {
  const isValid = field.value.length >= 3;
  return [isValid, 'invalidWalletName'];
};

const isValidCurrency = ({ field }) => {
  const isValid = field.value === 'ada';
  return [isValid, 'invalidCurrency'];
};

const fields = {
  walletName: {
    value: '',
    validate: [isValidWalletName]
  },
  currency: {
    value: 'ada',
    validate: [isValidCurrency]
  },
};

const options = {
  validateOnChange: false
};

@observer
export default class WalletCreateDialog extends Component {

  static propTypes = {
    onSubmit: PropTypes.func.isRequired,
    onCancel: PropTypes.func.isRequired
  };

  static contextTypes = {
    intl: intlShape.isRequired,
  };

  state = {
    isSubmitting: false
  };

  componentDidMount() {
    this.walletNameInput.getWrappedInstance().focus();
  }

  walletNameInput: Input;
  validator = new MobxReactForm({ options, fields }, {});
  actions = [
    {
      label: this.context.intl.formatMessage(messages.createPersonalWallet),
      onClick: () => this.submit()
    }
  ];

  submit = () => {
    this.validator.submit({
      onSuccess: (form) => {
        this.setState({ isSubmitting: true });
        this.props.onSubmit(form.values());
      },
      onError: () => {
        this.setState({ isSubmitting: false });
      }
    });
  };

  checkForEnterKey(event: KeyboardEvent) {
    if (event.key === 'Enter') {
      this.submit();
    }
  }

  render() {
    const { intl } = this.context;
    const { validator } = this;
    const walletName = validator.$('walletName');
    const currency = validator.$('currency');
    const errors = {
      walletName: walletName.error ? intl.formatMessage(messages[walletName.error]) : null,
      currency: currency.error ? intl.formatMessage(messages[currency.error]) : null,
    };
    const dialogClasses = classnames([
      'WalletCreateDialog',
      this.state.isSubmitting ? styles.isSubmitting : null
    ]);
    return (
      <Dialog
        className={dialogClasses}
        title="Create Wallet"
        actions={this.actions}
        onOverlayClick={this.props.onCancel}
        active
      >

        <Input
          type="text"
          className="walletName"
          label={intl.formatMessage(messages.walletName)}
          hint="e.g: Shopping Wallet"
          value={walletName.value}
          error={errors.walletName}
          onChange={walletName.onChange}
          onFocus={walletName.onFocus}
          onBlur={walletName.onBlur}
          onKeyPress={this.checkForEnterKey.bind(this)}
          ref={(input) => { this.walletNameInput = input; }}
        />

        <Dropup
          className="currency"
          label={intl.formatMessage(messages.currency)}
          value={currency.value}
          onChange={currency.onChange}
          onFocus={currency.onFocus}
          onBlur={currency.onBlur}
          error={errors.currency}
          source={currencies}
        />

        <DialogCloseButton onClose={this.props.onCancel} />

      </Dialog>
    );
  }

}
<|endoftext|>


<commit_before>var _ = require('lodash');
var path = require("path");
var xmldom = require('xmldom');
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var log = require("../logger");
//var f1 = "./fixtures/ui/me.pou.app-188.xml";
//var f = "/Users/khalid/git/sieveable/test-1.xml";
//var expected = "./fixtures/examples/index/me.pou.app-188.expected.result.txt"

function FileExtractingError(message, fileName) {
    this.message = message;
    this.fileName = fileName;
    this.name = "FileExtractingError";
    //Error.captureStackTrace(this, FileExtractingError);
}
FileExtractingError.prototype = Object.create(Error.prototype);
FileExtractingError.prototype.constructor = FileExtractingError;

module.exports = function (xmlFileNames, targetDir, callback) {
    log.info("Extracting parent-child tags (h1 index data) for %d files to %s",
        xmlFileNames.length, targetDir);
    Promise.map(xmlFileNames, function (xmlFile) {
        var outFile = path.resolve(targetDir, path.basename(xmlFile, '.xml') +
            '-ui-h1.txt');
        var writeStream = fs.createWriteStream(outFile, {encoding: "utf8"});
        return extract(xmlFile, writeStream)
            .then(function (res) {
                log.info(res);
            });

    }, {concurrency: 1}).then(function () {
        callback(null, "Done");
    }).catch(FileExtractingError, function (e) {
        log.error("Failed to extract h1-index data for %s. %s", e.fileName, e.message);
        callback(e);
    });
}

function extract(xmlFile, writeStream) {
    return new Promise(function (resolve, reject) {
        var xmlFileContent = fs.readFileSync(xmlFile, "utf8");
        var doc = new xmldom.DOMParser().parseFromString(xmlFileContent,
            "text/xml");
        var fileElements = doc.getElementsByTagName('File');
        _.forEach(fileElements, function (fileElement) {
            var rootElementList = _.filter(fileElement.childNodes, function (child) {
                return child.nodeType === 1;
            });
            // Each layout file must contain exactly one root element.
            if (rootElementList.length != 1) {
                reject(new Error('File node has more than one child. %s',
                    xmlFile));
            }
            var rootElement = rootElementList[0];
            var children = _.filter(rootElement.childNodes, function (child) {
                return child.nodeType === 1;
            });
            _.forEach(children, function (child) {
                doChildren(child, rootElement, writeStream);
            })
        });
        writeStream.end();
        writeStream.on("finish", function () {
            resolve("H1 tags have been extracted for " + xmlFile);
        })
    });
}

function doChildren(element, parent, writeStream) {
    if (element.hasChildNodes()) {
        emitPairs(parent, element, writeStream);
        var children = _.filter(element.childNodes, function (child) {
            return child.nodeType === 1;
        });
        _.forEach(children, function (child) {
            doChildren(child, element, writeStream)
        })
    }
    else {
        emitPairs(parent, element, writeStream);
    }
}

function emitPairs(parent, child, writeStream) {
    writeStream.write(parent.localName + "-" + child.localName + "\n");
    //var parentAttrs = getAttributes(parent);
    //console.log(parentAttrs.join('-'));
}

function getAttributes(elem) {
    return _.map(elem.attributes, function (attr) {
        var name = attr.nodeName;
        var value = attr.nodeValue;
        return name + "=" + value;
    })
}
<commit_msg>fix asynchronous issue<commit_after>var _ = require('lodash');
var path = require("path");
var xmldom = require('xmldom');
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var log = require("../logger");
//var f1 = "./fixtures/ui/me.pou.app-188.xml";
//var f = "/Users/khalid/git/sieveable/test-1.xml";
//var expected = "./fixtures/examples/index/me.pou.app-188.expected.result.txt"

function FileExtractingError(message, fileName) {
    this.message = message;
    this.fileName = fileName;
    this.name = "FileExtractingError";
    //Error.captureStackTrace(this, FileExtractingError);
}
FileExtractingError.prototype = Object.create(Error.prototype);
FileExtractingError.prototype.constructor = FileExtractingError;

module.exports = function (xmlFileNames, targetDir, callback) {
    log.info("Extracting parent-child tags (h1 index data) for %d files to %s",
        xmlFileNames.length, targetDir);
    Promise.map(xmlFileNames, function (xmlFile) {
        return extract(xmlFile, targetDir)
            .then(function (res) {
                log.info(res);
            });

    }, {concurrency: 1}).then(function () {
        callback(null, "Done");
    }).catch(FileExtractingError, function (e) {
        log.error("Failed to extract h1-index data for %s. %s", e.fileName, e.message);
        callback(e);
    });
}

function extract(xmlFile, targetDir) {
    return new Promise(function (resolve, reject) {
        var outFile = path.resolve(targetDir, path.basename(xmlFile, '.xml') +
            '-ui-h1.txt');
        var writeStream = fs.createWriteStream(outFile, {encoding: "utf8"});
        var xmlFileContent = fs.readFileSync(xmlFile, "utf8");
        var doc = new xmldom.DOMParser().parseFromString(xmlFileContent,
            "text/xml");
        var fileElements = doc.getElementsByTagName('File');
        _.forEach(fileElements, function (fileElement) {
            var rootElementList = _.filter(fileElement.childNodes, function (child) {
                return child.nodeType === 1;
            });
            // Each layout file must contain exactly one root element.
            if (rootElementList.length != 1) {
                reject(new Error('File node has more than one child. %s',
                    xmlFile));
            }
            var rootElement = rootElementList[0];
            var children = _.filter(rootElement.childNodes, function (child) {
                return child.nodeType === 1;
            });
            _.forEach(children, function (child) {
                doChildren(child, rootElement, writeStream);
            })
        });

        writeStream.on("finish", function () {
            resolve("H1 tags have been extracted for " + xmlFile);
        })
        writeStream.end();
    });
}

function doChildren(element, parent, writeStream) {
    if (element.hasChildNodes()) {
        emitPairs(parent, element, writeStream);
        var children = _.filter(element.childNodes, function (child) {
            return child.nodeType === 1;
        });
        _.forEach(children, function (child) {
            doChildren(child, element, writeStream)
        })
    }
    else {
        emitPairs(parent, element, writeStream);
    }
}

function emitPairs(parent, child, writeStream) {
    writeStream.write(parent.localName + "-" + child.localName + "\n");
    //var parentAttrs = getAttributes(parent);
    //console.log(parentAttrs.join('-'));
}

function getAttributes(elem) {
    return _.map(elem.attributes, function (attr) {
        var name = attr.nodeName;
        var value = attr.nodeValue;
        return name + "=" + value;
    })
}
<|endoftext|>


<commit_before>const parse = require('../parse')

module.exports = {turnInfo}

function turnInfo (readline) {
  return parse.entities(readline, 'id', 'type', 'x', 'y', 'vx', 'vy', 'state')
    .map(entity => Object.assign(entity, {
      position: {x: entity.x, y: entity.y},
      velocity: {x: entity.vx, y: entity.vy},
      hasSnaffle: entity.state === 1,
      isWizard: entity.type === 'WIZARD',
      isOpponent: entity.type === 'OPPONENT_WIZARD',
      isSnaffle: entity.type === 'SNAFFLE',
      isBludger: entity.type === 'BLUDGER'
    }))
    .map(entity => Object.assign(entity, {
      isPlayer: entity.isWizard || entity.isOpponent,
      isBall: entity.isSnaffle || entity.isBludger
    }))
    .reduce((entities, entity) => {
      entities.all.push(entity)
      if (entity.isPlayer) entities.players.push(entity)
      if (entity.isWizard) entities.wizards.push(entity)
      if (entity.isOpponent) entities.opponents.push(entity)
      if (entity.isBall) entities.balls.push(entity)
      if (entity.isSnaffle) entities.snaffles.push(entity)
      if (entity.isBludger) entities.bludgers.push(entity)
    }, {
      all: [],
      players: [],
      wizards: [],
      opponents: [],
      balls: [],
      snaffles: [],
      bludgers: []
    })
}
<commit_msg>fix(fantastic-bits): parse.turnInfo crashes<commit_after>const parse = require('../parse')

module.exports = {turnInfo}

function turnInfo (readline) {
  return parse.entities(readline, 'id', 'type', 'x', 'y', 'vx', 'vy', 'state')
    .map(entity => Object.assign(entity, {
      position: {x: entity.x, y: entity.y},
      velocity: {x: entity.vx, y: entity.vy},
      hasSnaffle: entity.state === 1,
      isWizard: entity.type === 'WIZARD',
      isOpponent: entity.type === 'OPPONENT_WIZARD',
      isSnaffle: entity.type === 'SNAFFLE',
      isBludger: entity.type === 'BLUDGER'
    }))
    .map(entity => Object.assign(entity, {
      isPlayer: entity.isWizard || entity.isOpponent,
      isBall: entity.isSnaffle || entity.isBludger
    }))
    .reduce((entities, entity) => {
      entities.all.push(entity)
      if (entity.isPlayer) entities.players.push(entity)
      if (entity.isWizard) entities.wizards.push(entity)
      if (entity.isOpponent) entities.opponents.push(entity)
      if (entity.isBall) entities.balls.push(entity)
      if (entity.isSnaffle) entities.snaffles.push(entity)
      if (entity.isBludger) entities.bludgers.push(entity)
      return entities
    }, {
      all: [],
      players: [],
      wizards: [],
      opponents: [],
      balls: [],
      snaffles: [],
      bludgers: []
    })
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.resource('listItems', { path: '/' });
});

export default Router;
<commit_msg>Switch away from resource to route in ember router<commit_after>import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('listItems', { path: '/' });
});

export default Router;
<|endoftext|>