<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',
    padding: t.spacing(1),
  },
  input: {
    fontSize: 14,
    height: 20,
    lineHeight: 20,
    padding: 0,
  },
  clear: {
    left: 'calc(100% - 4px)',
    position: 'absolute',
  },
  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 }) {
  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],
  )

  return (

      <M.InputBase
        {...filtering.input}
        onKeyDown={handleKeyDown}
        placeholder="Filter current directory by substring"
        classes={{ input: classes.input }}
        inputComponent={WrappedAutosizeInput}
        inputRef={inputRef}
        startAdornment={<M.Icon className={classes.searchIcon}>search</M.Icon>}
        endAdornment={
          !!filtering.input.value && (
            <M.IconButton
              className={classes.clear}
              size="small"
              onClick={() => filtering.set('')}
            >
              <M.Icon fontSize="small">clear</M.Icon>
            </M.IconButton>
          )
        }
      />

        {!!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 filtering = useDebouncedInput('', 200)
  const filtered = React.useMemo(
    () =>
      filtering.value
        ? items.filter(
            R.pipe(
              ListingItem.case({
                Dir: R.prop('name'),
                File: R.prop('name'),
              }),
              (name) => name.toLowerCase().includes(filtering.value.toLowerCase()),
            ),
          )
        : items,
    [filtering.value, items],
  )

  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, { 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}
              unfiltered={items}
              filtering={filtering}
              truncated={truncated}
            />

            {!filtered.length && (

                No entries matching "{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>Listing: support regex filtering, adjust UI (#1585)<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(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>
  )
}
<|endoftext|>


<commit_before>
var headingTags = ["H1", "H2", "H3", "H4", "H5", "H6"];
var paragraphTags = ["P", "BLOCKQUOTE", "PRE"];

function parseDocument() {
  var tags = headingTags.concat(paragraphTags);

  //clear markers
  $(".read-aloud").removeClass("read-aloud");

  //find text blocks with at least 1 paragraphs
  var textBlocks = $("p").not("blockquote > p").parent().get();
  $.uniqueSort(textBlocks);

  //visible only
  textBlocks = $(textBlocks).filter(":visible").filter(notOutOfView).get();

  if (textBlocks.length) {
    //remove any block less than 1/7 the length of the longest block
    var lengths = textBlocks.map(function(block) {
      return $(block).children(paragraphTags.join(", ")).text().length;
    });
    var longest = Math.max.apply(null, lengths);
    textBlocks = textBlocks.filter(function(block, index) {
      return lengths[index] > longest/7;
    });

    //mark the elements to be read
    textBlocks.forEach(function(block) {
      $(findHeadingsFor(block)).addClass("read-aloud");
      $(block).children(tags.join(", ")).addClass("read-aloud");
    });
  }
  else {
    //if no text blocks found, read all headings
    $(tags.join(", ")).filter(":visible").addClass("read-aloud");
  }

  //extract texts
  var texts = $(".read-aloud").get().map(getText).filter(isNotEmpty).map(removeLinks).map(addMissingPunctuation);
  return texts;
}

(function() {
  var selectedText = window.getSelection().toString();
  var texts = selectedText ? [selectedText] : parseDocument();
  console.log(texts.join("\n\n"));

  //return
  return {
    domain: location.hostname,
    title: document.title,
    texts: texts,
    lang: document.documentElement.lang || $("meta[http-equiv=content-language]").attr("content")
  };
})();

function notOutOfView() {
  return $(this).offset().left >= 0;
}

function getText(elem) {
  $(elem).find(":hidden").remove();
  return $(elem).text().trim();
}

function isNotEmpty(text) {
  return text;
}

function removeLinks(text) {
  return text.replace(/https?:\/\/\S+/g, "this link.");
}

function addMissingPunctuation(text) {
  return text.split(/ *\n */).map(function(line) {
    if (/[^,;:.!?]$/.test(line)) line += ".";
    return line;
  })
  .join("\n");
}

function findHeadingsFor(block) {
  var result = [];
  var firstInnerElem = $(block).children(headingTags.concat(paragraphTags).join(", ")).get(0);
  var currentLevel = getHeadingLevel(firstInnerElem);
  var node = previousNode(firstInnerElem, true);
  while (node && !$(node).hasClass("read-aloud")) {
    if (node.nodeType == 1) {
      var level = getHeadingLevel(node);
      if (level < currentLevel) {
        result.push(node);
        currentLevel = level;
      }
    }
    node = previousNode(node);
  }
  return result.reverse();
}

function getHeadingLevel(elem) {
  var index = elem ? headingTags.indexOf(elem.tagName) : -1;
  return index == -1 ? 100 : index + 1;
}

function previousNode(node, skipChildren) {
  if (node == document.body) return null;
  if (node.nodeType == 1 && !skipChildren && node.lastChild) return node.lastChild;
  if (node.previousSibling) return node.previousSibling;
  return previousNode(node.parentNode, true);
}
<commit_msg>xml:lang<commit_after>
var headingTags = ["H1", "H2", "H3", "H4", "H5", "H6"];
var paragraphTags = ["P", "BLOCKQUOTE", "PRE"];

function parseDocument() {
  var tags = headingTags.concat(paragraphTags);

  //clear markers
  $(".read-aloud").removeClass("read-aloud");

  //find text blocks with at least 1 paragraphs
  var textBlocks = $("p").not("blockquote > p").parent().get();
  $.uniqueSort(textBlocks);

  //visible only
  textBlocks = $(textBlocks).filter(":visible").filter(notOutOfView).get();

  if (textBlocks.length) {
    //remove any block less than 1/7 the length of the longest block
    var lengths = textBlocks.map(function(block) {
      return $(block).children(paragraphTags.join(", ")).text().length;
    });
    var longest = Math.max.apply(null, lengths);
    textBlocks = textBlocks.filter(function(block, index) {
      return lengths[index] > longest/7;
    });

    //mark the elements to be read
    textBlocks.forEach(function(block) {
      $(findHeadingsFor(block)).addClass("read-aloud");
      $(block).children(tags.join(", ")).addClass("read-aloud");
    });
  }
  else {
    //if no text blocks found, read all headings
    $(tags.join(", ")).filter(":visible").addClass("read-aloud");
  }

  //extract texts
  var texts = $(".read-aloud").get().map(getText).filter(isNotEmpty).map(removeLinks).map(addMissingPunctuation);
  return texts;
}

(function() {
  var selectedText = window.getSelection().toString();
  var texts = selectedText ? [selectedText] : parseDocument();
  console.log(texts.join("\n\n"));

  //return
  return {
    domain: location.hostname,
    title: document.title,
    texts: texts,
    lang: document.documentElement.lang || $("html").attr("xml:lang") || $("meta[http-equiv=content-language]").attr("content")
  };
})();

function notOutOfView() {
  return $(this).offset().left >= 0;
}

function getText(elem) {
  $(elem).find(":hidden").remove();
  return $(elem).text().trim();
}

function isNotEmpty(text) {
  return text;
}

function removeLinks(text) {
  return text.replace(/https?:\/\/\S+/g, "this link.");
}

function addMissingPunctuation(text) {
  return text.split(/ *\n */).map(function(line) {
    if (/[^,;:.!?]$/.test(line)) line += ".";
    return line;
  })
  .join("\n");
}

function findHeadingsFor(block) {
  var result = [];
  var firstInnerElem = $(block).children(headingTags.concat(paragraphTags).join(", ")).get(0);
  var currentLevel = getHeadingLevel(firstInnerElem);
  var node = previousNode(firstInnerElem, true);
  while (node && !$(node).hasClass("read-aloud")) {
    if (node.nodeType == 1) {
      var level = getHeadingLevel(node);
      if (level < currentLevel) {
        result.push(node);
        currentLevel = level;
      }
    }
    node = previousNode(node);
  }
  return result.reverse();
}

function getHeadingLevel(elem) {
  var index = elem ? headingTags.indexOf(elem.tagName) : -1;
  return index == -1 ? 100 : index + 1;
}

function previousNode(node, skipChildren) {
  if (node == document.body) return null;
  if (node.nodeType == 1 && !skipChildren && node.lastChild) return node.lastChild;
  if (node.previousSibling) return node.previousSibling;
  return previousNode(node.parentNode, true);
}
<|endoftext|>


<commit_before>function sampleDetailsRql(rql, r) {
    return rql.merge(function(sample) {
        return {
            versions: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                .filter({direction: 'out'})
                .eqJoin('process_id', r.table('processes')).zip()
                .coerceTo('array'),
            files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                .coerceTo('array'),
            properties: r.table('propertyset2property')
                .getAll(sample('property_set_id'), {index: 'property_set_id'})
                .eqJoin('property_id', r.table('properties')).zip()
                .orderBy('name')
                .merge(function(property) {
                    return {
                        best_measure: r.table('best_measure_history')
                            .getAll(property('best_measure_id'))
                            .eqJoin('measurement_id', r.table('measurements'))
                            .zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
        }
    });
}

function fileDetailsRql(rql, r) {
    return rql.merge(file => {
        return {
            samples: r.table('sample2datafile').getAll(file('id'), {index: 'datafile_id'})
                .eqJoin('sample_id', r.table('samples')).zip().pluck('id', 'name')
                .coerceTo('array'),
            processes: r.table('process2file').getAll(file('id'), {index: 'datafile_id'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array')
        };
    });
}

function datasetDetailsRql(rql, r) {
    return rql.merge(ds => {
        return {
            processes: processDetailsRql(r.table('dataset2process').getAll(ds('id'), {index: 'dataset_id'})
                .eqJoin('process_id', r.table('processes')).zip(), r).coerceTo('array'),
            comments: r.table('comments').getAll(ds('id'),{index: 'item_id'}).coerceTo('array')
        };
    });
}

function processDetailsSimpleRql(rql, r) {
    return rql.merge(function(process) {
        return {
            setup: r.table('process2setup').getAll(process('id'), {index: 'process_id'})
                .eqJoin('setup_id', r.table('setups')).zip()
                .merge(function(setup) {
                    return {
                        properties: r.table('setupproperties')
                            .getAll(setup('setup_id'), {index: 'setup_id'})
                            .coerceTo('array')
                    }
                }).coerceTo('array'),
            input_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'in'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function(sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function(property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array')
                    }
                })
                .coerceTo('array'),
            output_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'out'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function(sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function(property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array')
                    }
                })
                .coerceTo('array'),
            files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .eqJoin('datafile_id', r.table('datafiles')).zip().coerceTo('array'),
        }
    });
}

function processDetailsRql(rql, r) {
    return rql.merge(function(process) {
        return {
            setup: r.table('process2setup').getAll(process('id'), {index: 'process_id'})
                .eqJoin('setup_id', r.table('setups')).zip()
                .merge(function(setup) {
                    return {
                        properties: r.table('setupproperties')
                            .getAll(setup('setup_id'), {index: 'setup_id'})
                            .coerceTo('array')
                    }
                }).coerceTo('array'),

            input_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'in'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function(sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function(property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array'),
                        files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                            .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                            .coerceTo('array')
                        // processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                        //     .pluck('process_id', 'sample_id').distinct()
                        //     .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            output_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'out'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function(sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function(property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array'),
                        files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                            .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                            .coerceTo('array')
                        // processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                        //     .pluck('process_id', 'sample_id').distinct()
                        //     .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            measurements: r.table('process2measurement').getAll(process('id'), {index: 'process_id'})
                .eqJoin('measurement_id', r.table('measurements')).zip()
                .merge(p2m => {
                    return {
                        is_best_measure: r.db('materialscommons').table('best_measure_history')
                            .getAll(p2m('measurement_id'), {index: 'measurement_id'}).count()
                    }
                })
                .coerceTo('array'),
            files_count: r.table('process2file').getAll(process('id'), {index: 'process_id'}).count(),
            files: [],
            filesLoaded: false,
            // files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
            //     .eqJoin('datafile_id', r.table('datafiles')).zip()
            //     .merge(f => {
            //         return {
            //             samples: r.table('sample2datafile').getAll(f('id'), {index: 'datafile_id'})
            //                 .eqJoin('sample_id', r.table('samples')).zip()
            //                 .distinct().coerceTo('array')
            //         };
            //     })
            //     .coerceTo('array'),
            input_files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .filter({direction: 'in'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array'),
            output_files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .filter({direction: 'out'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array')
        }
    });
}

module.exports = {
    sampleDetailsRql,
    fileDetailsRql,
    datasetDetailsRql,
    processDetailsSimpleRql,
    processDetailsRql
};
<commit_msg>Add path for files<commit_after>function sampleDetailsRql (rql, r) {
    return rql.merge(function (sample) {
        return {
            versions: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                .filter({direction: 'out'})
                .eqJoin('process_id', r.table('processes')).zip()
                .coerceTo('array'),
            files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                .coerceTo('array'),
            properties: r.table('propertyset2property')
                .getAll(sample('property_set_id'), {index: 'property_set_id'})
                .eqJoin('property_id', r.table('properties')).zip()
                .orderBy('name')
                .merge(function (property) {
                    return {
                        best_measure: r.table('best_measure_history')
                            .getAll(property('best_measure_id'))
                            .eqJoin('measurement_id', r.table('measurements'))
                            .zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
        }
    })
}

function fileDetailsRql (rql, r) {
    return rql.merge(file => {
        return {
            samples: r.table('sample2datafile').getAll(file('id'), {index: 'datafile_id'})
                .eqJoin('sample_id', r.table('samples')).zip().pluck('id', 'name')
                .coerceTo('array'),
            processes: r.table('process2file').getAll(file('id'), {index: 'datafile_id'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array')
        }
    })
}

function datasetDetailsRql (rql, r) {
    return rql.merge(ds => {
        return {
            samples: r.table('dataset2sample').getAll(ds('id'), {index: 'dataset_id'})
                .eqJoin('sample_id', r.table('samples')).zip().coerceTo('array'),
            processes: processDetailsRql(r.table('dataset2process').getAll(ds('id'), {index: 'dataset_id'})
                .eqJoin('process_id', r.table('processes')).zip(), r).coerceTo('array'),
            comments: r.table('comments').getAll(ds('id'), {index: 'item_id'}).coerceTo('array'),
            files: r.table('dataset2datafile').getAll(ds('id'), {index: 'dataset_id'})
                .eqJoin('datafile_id', r.table('datafiles')).zip()
                .merge(df => {
                    return {
                        path: r.table('datadir2datafile').getAll(df('datafile_id'), {index: 'datafile_id'})
                            .eqJoin('datadir_id', r.table('datadirs')).zip().pluck('name').nth(0).getField('name')
                    }
                }).coerceTo('array'),
        }
    });
}

function processDetailsSimpleRql (rql, r) {
    return rql.merge(function (process) {
        return {
            setup: r.table('process2setup').getAll(process('id'), {index: 'process_id'})
                .eqJoin('setup_id', r.table('setups')).zip()
                .merge(function (setup) {
                    return {
                        properties: r.table('setupproperties')
                            .getAll(setup('setup_id'), {index: 'setup_id'})
                            .coerceTo('array')
                    }
                }).coerceTo('array'),
            input_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'in'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function (sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function (property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array')
                    }
                })
                .coerceTo('array'),
            output_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'out'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function (sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function (property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array')
                    }
                })
                .coerceTo('array'),
            files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .eqJoin('datafile_id', r.table('datafiles')).zip().coerceTo('array'),
        }
    })
}

function processDetailsRql (rql, r) {
    return rql.merge(function (process) {
        return {
            setup: r.table('process2setup').getAll(process('id'), {index: 'process_id'})
                .eqJoin('setup_id', r.table('setups')).zip()
                .merge(function (setup) {
                    return {
                        properties: r.table('setupproperties')
                            .getAll(setup('setup_id'), {index: 'setup_id'})
                            .coerceTo('array')
                    }
                }).coerceTo('array'),

            input_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'in'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function (sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function (property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array'),
                        files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                            .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                            .coerceTo('array')
                        // processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                        //     .pluck('process_id', 'sample_id').distinct()
                        //     .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            output_samples: r.table('process2sample').getAll(process('id'), {index: 'process_id'})
                .filter({'direction': 'out'})
                .eqJoin('sample_id', r.table('samples')).zip()
                .merge(function (sample) {
                    return {
                        properties: r.table('propertyset2property')
                            .getAll(sample('property_set_id'), {index: 'property_set_id'})
                            .eqJoin('property_id', r.table('properties')).zip()
                            .orderBy('name')
                            .merge(function (property) {
                                return {
                                    best_measure: r.table('best_measure_history')
                                        .getAll(property('best_measure_id'))
                                        .eqJoin('measurement_id', r.table('measurements'))
                                        .zip().coerceTo('array')
                                }
                            }).coerceTo('array'),
                        files: r.table('sample2datafile').getAll(sample('id'), {index: 'sample_id'})
                            .eqJoin('datafile_id', r.table('datafiles')).zip().pluck('id', 'name')
                            .coerceTo('array')
                        // processes: r.table('process2sample').getAll(sample('id'), {index: 'sample_id'})
                        //     .pluck('process_id', 'sample_id').distinct()
                        //     .eqJoin('process_id', r.table('processes')).zip().coerceTo('array')
                    }
                }).coerceTo('array'),
            measurements: r.table('process2measurement').getAll(process('id'), {index: 'process_id'})
                .eqJoin('measurement_id', r.table('measurements')).zip()
                .merge(p2m => {
                    return {
                        is_best_measure: r.db('materialscommons').table('best_measure_history')
                            .getAll(p2m('measurement_id'), {index: 'measurement_id'}).count()
                    }
                })
                .coerceTo('array'),
            files_count: r.table('process2file').getAll(process('id'), {index: 'process_id'}).count(),
            files: [],
            filesLoaded: false,
            // files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
            //     .eqJoin('datafile_id', r.table('datafiles')).zip()
            //     .merge(f => {
            //         return {
            //             samples: r.table('sample2datafile').getAll(f('id'), {index: 'datafile_id'})
            //                 .eqJoin('sample_id', r.table('samples')).zip()
            //                 .distinct().coerceTo('array')
            //         };
            //     })
            //     .coerceTo('array'),
            input_files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .filter({direction: 'in'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array'),
            output_files: r.table('process2file').getAll(process('id'), {index: 'process_id'})
                .filter({direction: 'out'})
                .eqJoin('datafile_id', r.table('datafiles'))
                .zip().coerceTo('array')
        }
    })
}

module.exports = {
    sampleDetailsRql,
    fileDetailsRql,
    datasetDetailsRql,
    processDetailsSimpleRql,
    processDetailsRql
}
<|endoftext|>


<commit_before><commit_msg>fix(PopupEntry): bind attrs<commit_after><|endoftext|>


<commit_before>var app = app || {};

(function ($) {
  'use strict';

  app.AppView = Backbone.View.extend({
    el: 'body',

    initialize: function () {
      this.$title = this.$('#title');
      this.$hotkeyImgAutoOpen = this.$('#img_auto_open_op');
      this.$hotkeyLiveStream = this.$('#live_stream_op');
      this.$hotkeyFocus = this.$('#focus_hotkey');
      this.$hotkeyRefresh = this.$('#refresh_hotkey');
      this.$tagSelector = this.$('#select-tag');
      this.$info = this.$('#info');
      this.originTitle = this.$title.text();

      // load initial state from localStorage
      window.localStorage['auto_image_open'] = (window.localStorage['auto_image_open'] == '1' ? '0' : '1');
      this.toggleImgAutoOpen(null, true);
      window.localStorage['live_stream'] = (window.localStorage['live_stream'] == '1' ? '0' : '1');
      this.toggleLiveStream(null, true);

      this.listenTo(app.firewoods, 'activeTag', this.setTagSelector);
      this.listenTo(app.channel, 'ajaxError', this.disableApp);

      this.$info.html(this.$info.html().autoLink({ target: "_blank", rel: "nofollow" }));

      $(document).keycut();
    },

    events: {
      'click #img_auto_open_op': 'toggleImgAutoOpen',
      'click #live_stream_op': 'toggleLiveStream',
      'click #focus_hotkey': 'focusToInput',
      'click #refresh_hotkey': 'refreshTL',
      'keypress #select-tag': 'selectNewTag',
      'click #info': 'removeInfo'
    },

    toggleImgAutoOpen: function (e, silent) {
      if ( e ) {
        e.preventDefault();
      }

      var $iao = this.$hotkeyImgAutoOpen;
      var newState = (window.localStorage['auto_image_open'] == '1' ? '0' : '1');
      window.localStorage['auto_image_open'] = newState;
      var msg;

      $iao.toggleClass('true');
      if (newState == '1') {
        $iao.html($iao.html() + '');
        msg = '이미지 자동 열기가 활성화되었습니다.';
        app.firewoods.trigger('timeline:unFoldAll');
      } else {
        $iao.find('.glyphicon-ok').remove();
        msg = '이미지 자동 열기가 비활성화되었습니다.';
        app.firewoods.trigger('timeline:foldAll');
      }

      if ( !silent ) {
        this.notifyWithWindow(msg, 'alert-info');
      }

      return this;
    },

    toggleLiveStream: function(e, silent) {
      if ( e ) {
        e.preventDefault();
      }

      var $ls = this.$hotkeyLiveStream;
      var newState = (window.localStorage['live_stream'] == '1' ? '0' : '1');
      window.localStorage['live_stream'] = newState;
      var msg;

      $ls.toggleClass('true');
      if (newState == '1') {
        $ls.html($ls.html() + '');
        msg = 'Live Stream이 활성화되었습니다.';
        app.channel.toggleLiveStream(true);
      } else {
        $ls.find('.glyphicon-ok').remove();
        msg = 'Live Stream이 비활성화되었습니다.';
        app.channel.toggleLiveStream(false);
      }

      if ( !silent ) {
        this.notifyWithWindow(msg, 'alert-info');
      }

      return this;
    },

    refreshTL: function (e) {
      e.preventDefault();
      app.channel.load();

      return this;
    },

    focusToInput: function (e) {
      e.preventDefault();

      $('html, body').animate({scrollTop: 0}, 600);
      $('#contents').focus();

      return this;
    },

    notifyWithWindow: function (msg, option) {
      var $alert = $('

');
      var $timeline = $('#timeline');
      var left = $timeline.offset().left + $timeline.width()/2;

      $alert
        .appendTo('body')
        .html(msg)
        .addClass(option)
        .css({left: left, top: 80})
        .clearQueue()
        .stop()
        .fadeIn(600)
        .delay(1000)
        .fadeOut(1000);

      return this;
    },

    selectNewTag: function (e) {
      if ( e.which === ENTER_KEY ) {
        e.preventDefault();
        var newTag = this.$tagSelector.val();

        if ( newTag[0] != "#" && newTag.length > 1) {
          alert("태그는 #으로 시작해야합니다.");
        } else {
          app.firewoods.highlightTag(newTag);
        }
      }
    },

    setTagSelector: function (tag) {
      this.$tagSelector.val(tag);
    },

    removeInfo: function (e) {
      var $self = this.$info;
      $self.slideUp( function () {
        $self.remove();
      });
    },

    disableApp: function () {
      var $panel = $(".panel-info");
      $panel.removeClass("panel-info")
            .addClass("panel-danger");
      $("#info, #div-form").css("background-color","#f2dede");
      $('#new_firewood').find("fieldset").attr("disabled","a");
      $('#timeline_stack')
        .css("background-color","#f5c5c5")
        .html("서버와의 접속이 끊어졌습니다. 새로고침 해주세요.")
        .slideDown();
      this.$title.html("새로고침 해주세요.");
    }
  });
})(jQuery);<commit_msg>when user focut using hotkey, caret go to Last of input field<commit_after>var app = app || {};

(function ($) {
  'use strict';

  app.AppView = Backbone.View.extend({
    el: 'body',

    initialize: function () {
      this.$title = this.$('#title');
      this.$hotkeyImgAutoOpen = this.$('#img_auto_open_op');
      this.$hotkeyLiveStream = this.$('#live_stream_op');
      this.$hotkeyFocus = this.$('#focus_hotkey');
      this.$hotkeyRefresh = this.$('#refresh_hotkey');
      this.$tagSelector = this.$('#select-tag');
      this.$info = this.$('#info');
      this.originTitle = this.$title.text();

      // load initial state from localStorage
      window.localStorage['auto_image_open'] = (window.localStorage['auto_image_open'] == '1' ? '0' : '1');
      this.toggleImgAutoOpen(null, true);
      window.localStorage['live_stream'] = (window.localStorage['live_stream'] == '1' ? '0' : '1');
      this.toggleLiveStream(null, true);

      this.listenTo(app.firewoods, 'activeTag', this.setTagSelector);
      this.listenTo(app.channel, 'ajaxError', this.disableApp);

      this.$info.html(this.$info.html().autoLink({ target: "_blank", rel: "nofollow" }));

      $(document).keycut();
    },

    events: {
      'click #img_auto_open_op': 'toggleImgAutoOpen',
      'click #live_stream_op': 'toggleLiveStream',
      'click #focus_hotkey': 'focusToInput',
      'click #refresh_hotkey': 'refreshTL',
      'keypress #select-tag': 'selectNewTag',
      'click #info': 'removeInfo'
    },

    toggleImgAutoOpen: function (e, silent) {
      if ( e ) {
        e.preventDefault();
      }

      var $iao = this.$hotkeyImgAutoOpen;
      var newState = (window.localStorage['auto_image_open'] == '1' ? '0' : '1');
      window.localStorage['auto_image_open'] = newState;
      var msg;

      $iao.toggleClass('true');
      if (newState == '1') {
        $iao.html($iao.html() + '');
        msg = '이미지 자동 열기가 활성화되었습니다.';
        app.firewoods.trigger('timeline:unFoldAll');
      } else {
        $iao.find('.glyphicon-ok').remove();
        msg = '이미지 자동 열기가 비활성화되었습니다.';
        app.firewoods.trigger('timeline:foldAll');
      }

      if ( !silent ) {
        this.notifyWithWindow(msg, 'alert-info');
      }

      return this;
    },

    toggleLiveStream: function(e, silent) {
      if ( e ) {
        e.preventDefault();
      }

      var $ls = this.$hotkeyLiveStream;
      var newState = (window.localStorage['live_stream'] == '1' ? '0' : '1');
      window.localStorage['live_stream'] = newState;
      var msg;

      $ls.toggleClass('true');
      if (newState == '1') {
        $ls.html($ls.html() + '');
        msg = 'Live Stream이 활성화되었습니다.';
        app.channel.toggleLiveStream(true);
      } else {
        $ls.find('.glyphicon-ok').remove();
        msg = 'Live Stream이 비활성화되었습니다.';
        app.channel.toggleLiveStream(false);
      }

      if ( !silent ) {
        this.notifyWithWindow(msg, 'alert-info');
      }

      return this;
    },

    refreshTL: function (e) {
      e.preventDefault();
      app.channel.load();

      return this;
    },

    focusToInput: function (e) {
      e.preventDefault();

      $('html, body').animate({scrollTop: 0}, 600);
      app.util.placeCaretAtEnd('contents');

      return this;
    },

    notifyWithWindow: function (msg, option) {
      var $alert = $('

');
      var $timeline = $('#timeline');
      var left = $timeline.offset().left + $timeline.width()/2;

      $alert
        .appendTo('body')
        .html(msg)
        .addClass(option)
        .css({left: left, top: 80})
        .clearQueue()
        .stop()
        .fadeIn(600)
        .delay(1000)
        .fadeOut(1000);

      return this;
    },

    selectNewTag: function (e) {
      if ( e.which === ENTER_KEY ) {
        e.preventDefault();
        var newTag = this.$tagSelector.val();

        if ( newTag[0] != "#" && newTag.length > 1) {
          alert("태그는 #으로 시작해야합니다.");
        } else {
          app.firewoods.highlightTag(newTag);
        }
      }
    },

    setTagSelector: function (tag) {
      this.$tagSelector.val(tag);
    },

    removeInfo: function (e) {
      var $self = this.$info;
      $self.slideUp( function () {
        $self.remove();
      });
    },

    disableApp: function () {
      var $panel = $(".panel-info");
      $panel.removeClass("panel-info")
            .addClass("panel-danger");
      $("#info, #div-form").css("background-color","#f2dede");
      $('#new_firewood').find("fieldset").attr("disabled","a");
      $('#timeline_stack')
        .css("background-color","#f5c5c5")
        .html("서버와의 접속이 끊어졌습니다. 새로고침 해주세요.")
        .slideDown();
      this.$title.html("새로고침 해주세요.");
    }
  });
})(jQuery);<|endoftext|>


<commit_before>import h from 'react-hyperscript'

import { Collapsible } from 'reusableComponents/collapsible'
import {
  BackEnd,
  Code,
  FrontEnd,
  Movie,
  Music,
  Pencil,
  People,
  SupaHappy,
  ThumbUp,
  TV
} from 'svg'
import { link } from 'utils//misc'
import { settings } from 'settings'

const { greyDarken } = settings

const li = text => h('li', {}, text)

export const clFrontEnd = h(
  Collapsible,
  {
    titleIcon: FrontEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Front-end',
    popOut: true
  },
  [
    h('ul', [
      li('HTML5 / CSS3'),
      li('Jade (I mean Pug 🐶...)'),
      li('SCSS / Less / Stylus'),
      li('PostCSS')
    ]),
    h('p', [
      'To organize my stylesheets, I try to follow the ',
      link(
        'https://sass-guidelin.es/#architecture',
        'Sass guidelines',
        'u-linkSweep.u-highlight'
      ),
      ' folder architecture and the ',
      link(
        'https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md',
        'SUIT CSS ',
        'u-linkSweep.u-highlight'
      ),
      'naming conventions.'
    ]),
    h('p', [
      'On the JS side, I follow the ',
      link(
        'https://standardjs.com/',
        'Standard JS ',
        'u-linkSweep.u-highlight'
      ),
      'rules.'
    ]),
    h(
      Collapsible,
      {
        titleIcon: Code,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'JS'
      },
      h('ul', [
        li('TypeScript'),
        li('ES6 & beyond'),
        li('Flux-like architectures')
      ])
    ),
    h(
      Collapsible,
      {
        titleIcon: Pencil,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Design'
      },
      h('ul', [li('Figma'), li('Sketch')])
    )
  ]
)

export const clBackEnd = h(
  Collapsible,
  {
    titleIcon: BackEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Back-end',
    popOut: true
  },
  [h('ul', [li('Node.js / Express'), li('MongoDB')])]
)

export const clTools = h(
  Collapsible,
  {
    titleIcon: ThumbUp,
    iconColor: greyDarken,
    titleIconSize: 30,
    title: 'Tools I like',
    popOut: true
  },
  [
    h('ul', [
      li('iTerm2'),
      li('npm / yarn'),
      li('Webpack'),
      li('CSS Modules'),
      li('Linters'),
      li('Homebrew 🍺'),
      li(`Git (GitKraken doesn't hurt ;)`)
    ]),
    h('p', [
      'And if you must know, I work on a ',
      h('span.u-highlight', 'MacBook Pro '),
      'using ',
      h('span.u-highlight', 'Visual Studio Code '),
      'as my code editor.'
    ])
  ]
)

export const clMusic = h(
  Collapsible,
  {
    titleIcon: Music,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Music',
    popOut: true
  },
  [
    h(
      'p',
      `Music is so many things, it can soothe you, move you, make you move, annoy you or even make you fall asleep, it's just fundamental :)`
    ),
    h(Collapsible, { iconColor: greyDarken, title: 'Rap' }, [
      h('p', 'Of course this is not an exhaustive list :'),
      h('ul', [
        li('Kendrick Lamar'),
        li(`ScHoolboy Q`),
        li('Evidence'),
        li('Young Thug'),
        li('Drake'),
        li(`ASAP Mob (not all of 'em...)`),
        li(
          `Outkast, Cam'ron, The Notorious B.I.G, The Wu-Tang Clan...(don't forget what time it is ;)`
        )
      ])
    ]),
    h(Collapsible, { iconColor: greyDarken, title: 'B-Side' }, [
      h(
        'p',
        'All right, now get ready for the dummy mix, no rules, just me, my taste and no filter :'
      ),
      h('ul', [
        li('Jhené Aiko'),
        li('Yuna'),
        li('Frank Ocean'),
        li('SZA'),
        li(
          `Blink-182 (didn't even listen to them as a teen, but man they're good)`
        ),
        li('A-Trak'),
        li('...')
      ])
    ])
  ]
)

export const clTVMovies = h(
  Collapsible,
  {
    titleIcon: TV,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Netflix & ...',
    popOut: true
  },
  [
    h('p', 'Another non exhaustive list :'),
    h('ul', [
      li('Stranger Things'),
      li('Black Mirror'),
      li('Daredevil'),
      li('Atlanta'),
      li('Dark'),
      li('GoT'),
      li('Narcos'),
      li('...')
    ]),
    h(
      Collapsible,
      {
        titleIcon: Movie,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Movies'
      },
      [
        h(
          'p',
          `Maybe not my favorites of all time, but the ones that pop into my head as I'm writing this.`
        ),
        h('ul', [
          li('The Nice Guys'),
          li('End of watch'),
          li('Drive'),
          li('Logan'),
          li(`Kingsman`),
          li('22 Jump Street'),
          li('...')
        ])
      ]
    )
  ]
)

export const clPeople = h(
  Collapsible,
  {
    titleIcon: People,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Following',
    popOut: true
  },
  [
    h('p', 'Some devs I follow, look up to, and/or simply like :'),
    h('ul', [
      h('li', [
        link(
          'https://twitter.com/mpjme',
          'Mattias Petter Johansson',
          'u-linkSweep'
        )
      ]),
      h('li', [
        link('https://twitter.com/mariusschulz', 'Marius Schulz', 'u-linkSweep')
      ]),
      h('li', [
        link('https://twitter.com/sachagreif', 'Sacha Greif', 'u-linkSweep')
      ]),
      h('li', [link('https://twitter.com/una', 'Una Kravets', 'u-linkSweep')]),
      h('li', [
        link('https://twitter.com/philwalton', 'Philip Walton', 'u-linkSweep')
      ]),
      h('li', [
        link('https://twitter.com/pawelgrzybek', 'Pawel Grzybek', 'u-linkSweep')
      ])
    ])
  ]
)

export const clMisc = h(
  Collapsible,
  {
    titleIcon: SupaHappy,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Misc',
    popOut: true
  },
  [
    h('p', [
      'And of course, I like to have my ',
      h('span.u-highlight', '5 vegetables '),
      'a day (I mean, it feels good when I do...which is like once a month).'
    ]),
    h('p', [
      'And last but not least, I like people (well,',
      h('span.u-highlight', ` some of 'em, `),
      `sometimes..., my heart's not that big 😛), I mean music, tv series, your opinion about what's happening on the other side of the world and stuff is great...`
    ]),
    h(
      'p',
      `But what's greater is when you get to share (and disagree with) all that with someone else, otherwise, what's the point, right?`
    )
  ]
)
<commit_msg>chore: update content<commit_after>import h from 'react-hyperscript'

import { Collapsible } from 'reusableComponents/collapsible'
import {
  BackEnd,
  Code,
  FrontEnd,
  Movie,
  Music,
  Pencil,
  People,
  SupaHappy,
  ThumbUp,
  TV
} from 'svg'
import { link } from 'utils//misc'
import { settings } from 'settings'

const { greyDarken } = settings

const li = text => h('li', {}, text)

export const clFrontEnd = h(
  Collapsible,
  {
    titleIcon: FrontEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Front-end',
    popOut: true
  },
  [
    h('ul', [
      li('HTML5 / CSS3'),
      li('Jade (I mean Pug 🐶...)'),
      li('SCSS / Less / Stylus'),
      li('PostCSS')
    ]),
    h('p', [
      'To organize my stylesheets, I try to follow the ',
      link(
        'https://sass-guidelin.es/#architecture',
        'Sass guidelines',
        'u-linkSweep.u-highlight'
      ),
      ' folder architecture and the ',
      link(
        'https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md',
        'SUIT CSS ',
        'u-linkSweep.u-highlight'
      ),
      'naming conventions.'
    ]),
    h('p', [
      'On the JS side, I follow the ',
      link(
        'https://standardjs.com/',
        'Standard JS ',
        'u-linkSweep.u-highlight'
      ),
      'rules.'
    ]),
    h(
      Collapsible,
      {
        titleIcon: Code,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'JS'
      },
      h('ul', [
        li('TypeScript'),
        li('ES6 & beyond'),
        li('Flux-like architectures')
      ])
    ),
    h(
      Collapsible,
      {
        titleIcon: Pencil,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Design'
      },
      h('ul', [li('Figma'), li('Sketch')])
    )
  ]
)

export const clBackEnd = h(
  Collapsible,
  {
    titleIcon: BackEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Back-end',
    popOut: true
  },
  [h('ul', [li('Node.js / Express'), li('MongoDB')])]
)

export const clTools = h(
  Collapsible,
  {
    titleIcon: ThumbUp,
    iconColor: greyDarken,
    titleIconSize: 30,
    title: 'Tools I like',
    popOut: true
  },
  [
    h('ul', [
      li('iTerm2'),
      li('yarn'),
      li('Webpack'),
      li('CSS Modules'),
      li('Prettier'),
      li('Homebrew 🍺'),
      li(`Git (GitKraken doesn't hurt ;)`)
    ]),
    h('p', [
      'And if you must know, I work on a ',
      h('span.u-highlight', 'MacBook Pro '),
      'using ',
      h('span.u-highlight', 'Visual Studio Code '),
      'as my code editor.'
    ])
  ]
)

export const clMusic = h(
  Collapsible,
  {
    titleIcon: Music,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Music',
    popOut: true
  },
  [
    h(
      'p',
      `Music is so many things, it can soothe you, move you, make you move, annoy you or even make you fall asleep, it's just fundamental :)`
    ),
    h(Collapsible, { iconColor: greyDarken, title: 'Rap' }, [
      h('p', 'Of course this is not an exhaustive list :'),
      h('ul', [
        li('Kendrick Lamar'),
        li(`ScHoolboy Q`),
        li('Evidence'),
        li('Young Thug'),
        li('Drake'),
        li(`ASAP Mob (not all of 'em...)`),
        li(
          `Outkast, Cam'ron, The Notorious B.I.G, The Wu-Tang Clan...(don't forget what time it is ;)`
        )
      ])
    ]),
    h(Collapsible, { iconColor: greyDarken, title: 'B-Side' }, [
      h(
        'p',
        'All right, now get ready for the dummy mix, no rules, just me, my taste and no filter :'
      ),
      h('ul', [
        li('Jhené Aiko'),
        li('Yuna'),
        li('Frank Ocean'),
        li('SZA'),
        li(
          `Blink-182 (didn't even listen to them as a teen, but man they're good)`
        ),
        li('A-Trak'),
        li('...')
      ])
    ])
  ]
)

export const clTVMovies = h(
  Collapsible,
  {
    titleIcon: TV,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Netflix & ...',
    popOut: true
  },
  [
    h('p', 'Another non exhaustive list :'),
    h('ul', [
      li('Stranger Things'),
      li('Black Mirror'),
      li('Daredevil'),
      li('Atlanta'),
      li('Dark'),
      li('GoT'),
      li('Narcos'),
      li('...')
    ]),
    h(
      Collapsible,
      {
        titleIcon: Movie,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Movies'
      },
      [
        h(
          'p',
          `Maybe not my favorites of all time, but the ones that pop into my head as I'm writing this.`
        ),
        h('ul', [
          li('The Nice Guys'),
          li('End of watch'),
          li('Drive'),
          li('Logan'),
          li(`Kingsman`),
          li('22 Jump Street'),
          li('...')
        ])
      ]
    )
  ]
)

export const clPeople = h(
  Collapsible,
  {
    titleIcon: People,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Following',
    popOut: true
  },
  [
    h('p', 'Some devs I follow, look up to, and/or simply like :'),
    h('ul', [
      h('li', [
        link(
          'https://twitter.com/mpjme',
          'Mattias Petter Johansson',
          'u-linkSweep'
        )
      ]),
      h('li', [
        link('https://twitter.com/mariusschulz', 'Marius Schulz', 'u-linkSweep')
      ]),
      h('li', [
        link('https://twitter.com/sachagreif', 'Sacha Greif', 'u-linkSweep')
      ]),
      h('li', [link('https://twitter.com/una', 'Una Kravets', 'u-linkSweep')]),
      h('li', [
        link('https://twitter.com/philwalton', 'Philip Walton', 'u-linkSweep')
      ]),
      h('li', [
        link('https://twitter.com/pawelgrzybek', 'Pawel Grzybek', 'u-linkSweep')
      ])
    ])
  ]
)

export const clMisc = h(
  Collapsible,
  {
    titleIcon: SupaHappy,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Misc',
    popOut: true
  },
  [
    h('p', [
      'And of course, I like to have my ',
      h('span.u-highlight', '5 vegetables '),
      'a day (I mean, it feels good when I do...which is like once a month).'
    ]),
    h('p', [
      'And last but not least, I like people (well,',
      h('span.u-highlight', ` some of 'em, `),
      `sometimes..., my heart's not that big 😛), I mean music, tv series, your opinion about what's happening on the other side of the world and stuff is great...`
    ]),
    h(
      'p',
      `But what's greater is when you get to share (and disagree with) all that with someone else, otherwise, what's the point, right?`
    )
  ]
)
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Putlocker Navigation Buttons
// @name:zh-CN   Putlocker电视剧上/下集按钮
// @namespace    http://rotar.tk/
// @version      0.1.3
// @description  Add navigation buttons (previous,next) under putlocker tvshow videos.
// @description:zh-CN  在Putlocker电视剧播放页面添加上/下集按钮。
// @author       Rotar
// @match        http://putlocker.is/watch*
// @grant        none
// @downloadURL  https://github.com/kaneorotar/putlocker-userscript/raw/master/putlocker-navi.user.js
// ==/UserScript==

(function() {
	'use strict';
	var curl = window.location.href;
	var vals = /watch-([a-z0-9\-]*)-tvshow(-season-([0-9]{1,2})-episode-([0-9]{1,2}))?-online/.exec(curl);
	var se = 0, ep = 0;
	var iurl = curl.replace(/-season-([0-9]{1,2})-episode-([0-9]{1,2})/,"");
	var retries = 3;

	var list = {
		seasons: [],
		season: function(){
			return this.seasons.length-1;
		},
		episode: function(season){
			return this.seasons[season];
		},
		next: function(season,episode){
			if((episode+1)>this.episode(season)){
				if((season+1)>this.season()){
					return null;
				}else{
					return [season+1,1];
				}
			}else{
				return [season,episode+1];
			}
		},
		previous: function(season,episode){
			if((episode-1)<1){
				if((season-1)<1){
					return null;
				}else{
					return [season-1,this.episode(season-1)];
				}
			}else{
				return [season,episode-1];
			}
		}
	};

	if(typeof(vals[2])!="undefined"){//on an episode page
		se = parseInt(vals[3]);
		ep = parseInt(vals[4]);

		var contentbox = document.getElementsByClassName("content-box")[0];
		var msgdiv = document.getElementsByClassName("message")[0];

		var navi = document.createElement("div");
		navi.id = "navi_box";
		navi.style.height = "40px";
		navi.style.position = "relative";
		navi.style.textAlign = "center";
		navi.style.fontFamily = "Arial";
		navi.style.fontSize = "22px";
		navi.style.marginTop = "-5px";
		navi.style.display = "None";

		var prev = document.createElement("a");
		prev.id = "prev_btn";
		prev.style.position = "absolute";
		prev.style.left = "5px";
		prev.style.padding = "5px";
		prev.style.color = "#EEEEEE";
		prev.innerHTML = "PREVIOUS";
		prev.className = "movgr";
		prev.style.display = "None";
		navi.appendChild(prev);

		var next = document.createElement("a");
		next.id = "next_btn";
		next.style.position = "absolute";
		next.style.right = "5px";
		next.style.padding = "5px";
		next.style.color = "#EEEEEE";
		next.innerHTML = "NEXT";
		next.className = "movgr";
		next.style.display = "None";
		navi.appendChild(next);

		contentbox.insertBefore(navi,msgdiv);
		getIndex(iurl);
	}

	function validate(elem){
		var result;
		if(elem.innerHTML.toLowerCase().substr(0,4)=="prev"){
			result = list.previous(se,ep);
		}else{
			result = list.next(se,ep);
		}
		if(result){
			var nurl = window.location.href.replace("-season-"+se+"-episode-"+ep,"-season-"+result[0]+"-episode-"+result[1]);
			elem.href = nurl;
			if(result[0]<se){
				elem.innerHTML = "PREVIOUS SEASON";
			}else if(result[0]>se){
				elem.innerHTML = "NEXT SEASON";
			}
			elem.style.display = "block";
			navi.style.display = "block";
		}
	}

	function getIndex(lurl){
		var responseb;
		var xhr = new XMLHttpRequest();
		xhr.onloadend = function() {
			if (xhr.status == 200 || xhr.status == 304) {
				responseb = xhr.responseText;
				var dp = new DOMParser();
				var rdom = dp.parseFromString(responseb,'text/html');
				console.log("Index Successfully Fetched");

				var icontentbox = rdom.getElementsByClassName("content-box")[0];
				var tbs = icontentbox.getElementsByTagName("table");
				for(var i=0; i<(tbs.length-5); i++){//put number of episodes for each season into list.seasons
					list.seasons[i+1]=tbs[2+i].childNodes[0].childNodes.length;
				}
				validate(prev);
				validate(next);
			}else{
				console.log("[Request Error] Index fetching failed.");
				retries--;
				if(retries>=0){
					console.log("[Request Error] Retrying in 3 seconds");
					setTimeOut(function(){
						console.log("Fetching Index...");
						getIndex(lurl);
					},3000);
				}
			}
		};

		xhr.open('GET', lurl, true);
		xhr.send(null);
	}
})();<commit_msg>Updated putlocker URL<commit_after>// ==UserScript==
// @name         Putlocker Navigation Buttons
// @name:zh-CN   Putlocker电视剧上/下集按钮
// @namespace    http://rotar.tk/
// @version      0.1.4
// @description  Add navigation buttons (previous,next) under putlocker tvshow videos.
// @description:zh-CN  在Putlocker电视剧播放页面添加上/下集按钮。
// @author       Rotar
// @match        http://putlockers.ch/watch*
// @grant        none
// @downloadURL  https://github.com/kaneorotar/putlocker-userscript/raw/master/putlocker-navi.user.js
// ==/UserScript==

(function() {
	'use strict';
	var curl = window.location.href;
	var vals = /watch-([a-z0-9\-]*)-tvshow(-season-([0-9]{1,2})-episode-([0-9]{1,2}))?-online/.exec(curl);
	var se = 0, ep = 0;
	var iurl = curl.replace(/-season-([0-9]{1,2})-episode-([0-9]{1,2})/,"");
	var retries = 3;

	var list = {
		seasons: [],
		season: function(){
			return this.seasons.length-1;
		},
		episode: function(season){
			return this.seasons[season];
		},
		next: function(season,episode){
			if((episode+1)>this.episode(season)){
				if((season+1)>this.season()){
					return null;
				}else{
					return [season+1,1];
				}
			}else{
				return [season,episode+1];
			}
		},
		previous: function(season,episode){
			if((episode-1)<1){
				if((season-1)<1){
					return null;
				}else{
					return [season-1,this.episode(season-1)];
				}
			}else{
				return [season,episode-1];
			}
		}
	};

	if(typeof(vals[2])!="undefined"){//on an episode page
		se = parseInt(vals[3]);
		ep = parseInt(vals[4]);

		var contentbox = document.getElementsByClassName("content-box")[0];
		var msgdiv = document.getElementsByClassName("message")[0];

		var navi = document.createElement("div");
		navi.id = "navi_box";
		navi.style.height = "40px";
		navi.style.position = "relative";
		navi.style.textAlign = "center";
		navi.style.fontFamily = "Arial";
		navi.style.fontSize = "22px";
		navi.style.marginTop = "-5px";
		navi.style.display = "None";

		var prev = document.createElement("a");
		prev.id = "prev_btn";
		prev.style.position = "absolute";
		prev.style.left = "5px";
		prev.style.padding = "5px";
		prev.style.color = "#EEEEEE";
		prev.innerHTML = "PREVIOUS";
		prev.className = "movgr";
		prev.style.display = "None";
		navi.appendChild(prev);

		var next = document.createElement("a");
		next.id = "next_btn";
		next.style.position = "absolute";
		next.style.right = "5px";
		next.style.padding = "5px";
		next.style.color = "#EEEEEE";
		next.innerHTML = "NEXT";
		next.className = "movgr";
		next.style.display = "None";
		navi.appendChild(next);

		contentbox.insertBefore(navi,msgdiv);
		getIndex(iurl);
	}

	function validate(elem){
		var result;
		if(elem.innerHTML.toLowerCase().substr(0,4)=="prev"){
			result = list.previous(se,ep);
		}else{
			result = list.next(se,ep);
		}
		if(result){
			var nurl = window.location.href.replace("-season-"+se+"-episode-"+ep,"-season-"+result[0]+"-episode-"+result[1]);
			elem.href = nurl;
			if(result[0]<se){
				elem.innerHTML = "PREVIOUS SEASON";
			}else if(result[0]>se){
				elem.innerHTML = "NEXT SEASON";
			}
			elem.style.display = "block";
			navi.style.display = "block";
		}
	}

	function getIndex(lurl){
		var responseb;
		var xhr = new XMLHttpRequest();
		xhr.onloadend = function() {
			if (xhr.status == 200 || xhr.status == 304) {
				responseb = xhr.responseText;
				var dp = new DOMParser();
				var rdom = dp.parseFromString(responseb,'text/html');
				console.log("Index Successfully Fetched");

				var icontentbox = rdom.getElementsByClassName("content-box")[0];
				var tbs = icontentbox.getElementsByTagName("table");
				for(var i=0; i<(tbs.length-5); i++){//put number of episodes for each season into list.seasons
					list.seasons[i+1]=tbs[2+i].childNodes[0].childNodes.length;
				}
				validate(prev);
				validate(next);
			}else{
				console.log("[Request Error] Index fetching failed.");
				retries--;
				if(retries>=0){
					console.log("[Request Error] Retrying in 3 seconds");
					setTimeOut(function(){
						console.log("Fetching Index...");
						getIndex(lurl);
					},3000);
				}
			}
		};

		xhr.open('GET', lurl, true);
		xhr.send(null);
	}
})();<|endoftext|>


<commit_before>var suffix="+";
$('.counter').each(function() {
  var $this = $(this),
      countTo = $this.attr('data-count');

  $({ countNum: $this.text()}).animate({
    countNum: countTo
  },

  {

    duration: 8000,
    easing:'linear',
    step: function() {
      $this.text(Math.floor(this.countNum + suffix ));
    },
    complete: function() {
      $this.text(this.countNum + suffix );
      //alert('finished');
    }

  });

});
<commit_msg>Update counter.js<commit_after>var suffix="+";
     var prefix="%";
    $('.counter').each(function() {
    var $this = $(this),
    countTo = $this.attr('data-count');
    $({ countNum: $this.text()}).animate({
    countNum: countTo
    },
    {
    duration: 5000,
    easing:'linear',
    step: function() {
    $this.text(suffix+Math.floor(this.countNum)+ prefix);
    },
    complete: function() {
    $this.text(suffix+this.countNum + suffix );
    }
    });
    });
<|endoftext|>