<commit_before>var fs = require('fs')
var level = require('level')
var encoding = require('dat-encoding')

module.exports = function getDb (dat, cb) {
  if (!dat.db) {
    try {
      fs.accessSync(dat.datPath, fs.F_OK)
    } catch (e) { fs.mkdirSync(dat.datPath) }
  }
  var db = dat.db = dat.db || level(dat.datPath)
  tryResume()

  function tryResume () {
    if (dat.port) db.put('!dat!port', dat.port)
    db.get('!dat!key', function (err, value) {
      if (err && !err.notFound) return cb(err)
      if (!value) return cb(null, db)
      if (dat.key && dat.key.toString('hex') !== value) return cb('Another Dat was already downloaded here.')

      value = encoding.decode(value)
      dat.key = value
      dat.resume = true

      if (dat.port) return cb(null) // Port set in opts
      db.get('!dat!port', function (err, portVal) {
        if (err && !err.notFound) return cb(err)
        if (portVal) dat.port = portVal
        cb(null)
      })
    })
  }
}
<commit_msg>only require level when no db is specified<commit_after>var fs = require('fs')
var encoding = require('dat-encoding')

module.exports = function getDb (dat, cb) {
  if (!dat.db) {
    try {
      fs.accessSync(dat.datPath, fs.F_OK)
    } catch (e) { fs.mkdirSync(dat.datPath) }
    dat.db = require('level')(dat.datPath)
  }
  tryResume()

  function tryResume () {
    var db = dat.db
    if (dat.port) db.put('!dat!port', dat.port)
    db.get('!dat!key', function (err, value) {
      if (err && !err.notFound) return cb(err)
      if (!value) return cb(null, db)
      if (dat.key && dat.key.toString('hex') !== value) return cb('Another Dat was already downloaded here.')

      value = encoding.decode(value)
      dat.key = value
      dat.resume = true

      if (dat.port) return cb(null) // Port set in opts
      db.get('!dat!port', function (err, portVal) {
        if (err && !err.notFound) return cb(err)
        if (portVal) dat.port = portVal
        cb(null)
      })
    })
  }
}
<|endoftext|>


<commit_before><commit_msg>do not make server calls unecessarily<commit_after><|endoftext|>


<commit_before>import React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import PhoneIcon from '@material-ui/icons/PhoneAndroid'
import LaptopIcon from '@material-ui/icons/Laptop'
import FileIcon from '@material-ui/icons/Usb'
import ErrorIcon from '@material-ui/icons/Error'
import Paper from '@material-ui/core/Paper'
import { Typography } from '@material-ui/core'
import SyncButton from './SyncButton'
import DateDistance from '../DateDistance'
import { defineMessages, useIntl } from 'react-intl'

const m = defineMessages({
  // Message shown when there is an error while syncing
  errorMsg: 'Syncronization Error',
  // Shown before last sync time, e.g. 'Last synchronized: 2 hours ago'
  lastSync: 'Last synchronized:',
  // Prompt of how many database objects have synced
  database: 'Database: {sofar} / {total}',
  // Prompt for how many media items have synced
  media: 'Photos: {sofar} / {total}'
})

const SyncTarget = ({
  // Unique identifier for the peer
  id,
  // User friendly peer name
  name = 'Android Phone',
  // See above peerStatus
  status,
  // If connected
  connected,
  // Sync progress object, with props `percent`, `mediaSofar`, `mediaTotal`,
  // `dbSofar`, `dbTotal`
  progress,
  // The time of last completed sync in milliseconds since UNIX Epoch
  lastCompleted,
  errorMsg,
  // "mobile" or "desktop" or "file"
  deviceType,
  onClick
}) => {
  const cx = useStyles()
  const { formatMessage: t, formatNumber } = useIntl()
  // TODO need to render device name in error screen
  return (
    <Paper className={cx.root}>

          {status === 'error' ? (
            <ErrorIcon
              fontSize='inherit'
              className={cx.icon}
              style={{ color: 'red' }}
            />
          ) : deviceType === 'desktop' ? (
            <LaptopIcon fontSize='inherit' className={cx.icon} />
          ) : deviceType === 'file' ? (
            <FileIcon fontSize='inherit' className={cx.icon} />
          ) : (
            <PhoneIcon fontSize='inherit' className={cx.icon} />
          )}
          <Typography variant='h5' component='h2'>
            {status === 'error' ? t(m.errorMsg) : name}
          </Typography>
          {status === 'error' ? (
            <Typography className={cx.errorDetail} align='center'>
              {errorMsg}
            </Typography>
          ) : status === 'progress' && progress ? (
            <Typography className={cx.progress} align='center'>
              {t(m.database, {
                sofar: formatNumber(progress.dbSofar),
                total: formatNumber(progress.dbTotal)
              })}

              {t(m.media, {
                sofar: formatNumber(progress.mediaSofar),
                total: formatNumber(progress.mediaTotal)
              })}
            </Typography>
          ) : (
            lastCompleted && (
              <Typography className={cx.lastSync}>
                {t(m.lastSync)}

                <DateDistance date={lastCompleted} />
              </Typography>
            )
          )}

        <SyncButton
          connected={connected}
          onClick={onClick}
          variant={status}
          progress={progress && progress.percent}
        />

    </Paper>
  )
}

export default SyncTarget

const useStyles = makeStyles(theme => ({
  root: {
    paddingTop: '100%',
    position: 'relative'
  },
  icon: {
    marginBottom: theme.spacing(2),
    fontSize: 48
  },
  lastSync: {
    textAlign: 'center',
    fontStyle: 'italic'
  },
  errorDetail: {
    textAlign: 'center',
    fontStyle: 'italic'
  },
  content: {
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center'
  },
  wrapper: {
    alignItems: 'center',
    justifyContent: 'center',
    position: 'absolute',
    display: 'flex',
    flexDirection: 'column',
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
    padding: '10%'
  },
  progress: {
    fontVariantNumeric: 'tabular-nums'
  }
}))
<commit_msg>fix: After a sync error, keep the device name visible (#369)<commit_after>import React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import PhoneIcon from '@material-ui/icons/PhoneAndroid'
import LaptopIcon from '@material-ui/icons/Laptop'
import FileIcon from '@material-ui/icons/Usb'
import ErrorIcon from '@material-ui/icons/Error'
import Paper from '@material-ui/core/Paper'
import { Typography } from '@material-ui/core'
import SyncButton from './SyncButton'
import DateDistance from '../DateDistance'
import { defineMessages, useIntl } from 'react-intl'

const m = defineMessages({
  // Message shown when there is an error while syncing
  errorMsg: 'Syncronization Error',
  // Shown before last sync time, e.g. 'Last synchronized: 2 hours ago'
  lastSync: 'Last synchronized:',
  // Prompt of how many database objects have synced
  database: 'Database: {sofar} / {total}',
  // Prompt for how many media items have synced
  media: 'Photos: {sofar} / {total}'
})

const SyncTarget = ({
  // Unique identifier for the peer
  id,
  // User friendly peer name
  name = 'Android Phone',
  // See above peerStatus
  status,
  // If connected
  connected,
  // Sync progress object, with props `percent`, `mediaSofar`, `mediaTotal`,
  // `dbSofar`, `dbTotal`
  progress,
  // The time of last completed sync in milliseconds since UNIX Epoch
  lastCompleted,
  errorMsg,
  // "mobile" or "desktop" or "file"
  deviceType,
  onClick
}) => {
  const cx = useStyles()
  const { formatMessage: t, formatNumber } = useIntl()
  // TODO need to render device name in error screen
  return (
    <Paper className={cx.root}>

          {status === 'error' ? (
            <ErrorIcon
              fontSize='inherit'
              className={cx.icon}
              style={{ color: 'red' }}
            />
          ) : deviceType === 'desktop' ? (
            <LaptopIcon fontSize='inherit' className={cx.icon} />
          ) : deviceType === 'file' ? (
            <FileIcon fontSize='inherit' className={cx.icon} />
          ) : (
            <PhoneIcon fontSize='inherit' className={cx.icon} />
          )}
          <Typography variant='h5' component='h2'>
            {name}
          </Typography>
          {status === 'error' ? (
            <Typography className={cx.errorDetail} align='center'>
              {errorMsg}
            </Typography>
          ) : status === 'progress' && progress ? (
            <Typography className={cx.progress} align='center'>
              {t(m.database, {
                sofar: formatNumber(progress.dbSofar),
                total: formatNumber(progress.dbTotal)
              })}

              {t(m.media, {
                sofar: formatNumber(progress.mediaSofar),
                total: formatNumber(progress.mediaTotal)
              })}
            </Typography>
          ) : (
            lastCompleted && (
              <Typography className={cx.lastSync}>
                {t(m.lastSync)}

                <DateDistance date={lastCompleted} />
              </Typography>
            )
          )}

        <SyncButton
          connected={connected}
          onClick={onClick}
          variant={status}
          progress={progress && progress.percent}
        />

    </Paper>
  )
}

export default SyncTarget

const useStyles = makeStyles(theme => ({
  root: {
    paddingTop: '100%',
    position: 'relative'
  },
  icon: {
    marginBottom: theme.spacing(2),
    fontSize: 48
  },
  lastSync: {
    textAlign: 'center',
    fontStyle: 'italic'
  },
  errorDetail: {
    textAlign: 'center',
    fontStyle: 'italic'
  },
  content: {
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center'
  },
  wrapper: {
    alignItems: 'center',
    justifyContent: 'center',
    position: 'absolute',
    display: 'flex',
    flexDirection: 'column',
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
    padding: '10%'
  },
  progress: {
    fontVariantNumeric: 'tabular-nums'
  }
}))
<|endoftext|>


<commit_before>var collections = {
		scores: null,
		log: null
	},
	_exports = {};

_exports.scores = {
	get: function(o, cb) {
		var id = o.id, revision = o.revision || 1;
		collections.scores.findOne({_id: id}, {revisions: {$slice: [revision - 1, 1]}}, function(err, score) {
			if (cb) cb(err, (score || {revisions: [null]}).revisions[0]);
		});
	},
	save: function(score, cb) {
		var id = score.id,
			revision = {code: score.code, version: score.version};

		collections.scores.update({_id: id}, {$push: {revisions: revision}}, {upsert: true}, function(err) {
			if (err) console.log(err);
			if (cb) {
				collections.scores.findOne({_id: id}, function(_err, score) {
					cb(err, score.revisions.length);
				});
			}
		});
	}
};

_exports.log = function(o) {
	o.time = new Date();
	collections.log.insert(o);
};

module.exports = function(db, cb) {
	db.open(function(err, db) {
		for (var c in collections) {
			db.collection(c, function(err, collection) {
				collections[c] = collection;
			});
		}

		if (cb) cb(_exports);
	});
};
<commit_msg>for-in loops considered harmful<commit_after>var collections = {
		scores: null,
		log: null
	},
	_exports = {};

_exports.scores = {
	get: function(o, cb) {
		var id = o.id, revision = o.revision || 1;
		collections.scores.findOne({_id: id}, {revisions: {$slice: [revision - 1, 1]}}, function(err, score) {
			if (cb) cb(err, (score || {revisions: [null]}).revisions[0]);
		});
	},
	save: function(score, cb) {
		var id = score.id,
			revision = {code: score.code, version: score.version};

		collections.scores.update({_id: id}, {$push: {revisions: revision}}, {upsert: true}, function(err) {
			if (err) console.log(err);
			if (cb) {
				collections.scores.findOne({_id: id}, function(_err, score) {
					cb(err, score.revisions.length);
				});
			}
		});
	}
};

_exports.log = function(o) {
	o.time = new Date();
	collections.log.insert(o);
};

module.exports = function(db, cb) {
	db.open(function(err, db) {
		var cols = Object.keys(collections);
		for (var i = 0; i < cols.length; i++) {
			db.collection(cols[i], function(err, collection) {
				collections[cols[i]] = collection;
			});
		}

		if (cb) cb(_exports);
	});
};
<|endoftext|>


<commit_before><commit_msg>tweak transitions<commit_after><|endoftext|>


<commit_before>jQuery(document).ready(function($) {
    var IMAGE_URL = "img/orion-{width}.jpg";

    // set global settings
    // this settings object can also be passed in the element call below
    $.responsive({
        urlSource: function(data) {
            console.log("urlSource", data);
            // for the demo we will use the list of locally stored images
            // this is easier with a webserver that generates images
            var url = IMAGE_URL.replace("{width}", data.width);
            $("#image-input").text(data.width);
            $("#image-source").text(url);
            $("#input-time").text(new Date().toLocaleTimeString("en-US", {hour12: false}));
            // because we are emulating a webserver, we don't change the image source here
            // instead we just return the url
            return url;
        }
    });

    $("img.my-image").responsive();
});
<commit_msg>Remove debug leftover<commit_after>jQuery(document).ready(function($) {
    var IMAGE_URL = "img/orion-{width}.jpg";

    // set global settings
    // this settings object can also be passed in the element call below
    $.responsive({
        urlSource: function(data) {
            // for the demo we will use the list of locally stored images
            // this is easier with a webserver that generates images
            var url = IMAGE_URL.replace("{width}", data.width);
            $("#image-input").text(data.width);
            $("#image-source").text(url);
            $("#input-time").text(new Date().toLocaleTimeString("en-US", {hour12: false}));
            // because we are emulating a webserver, we don't change the image source here
            // instead we just return the url
            return url;
        }
    });

    $("img.my-image").responsive();
});
<|endoftext|>


<commit_before><commit_msg>Add cache method<commit_after><|endoftext|>


<commit_before>import React from 'react'

import { requestAndResponse, removeNull } from '../../../utils/query'

const studentHeader = [
  {
    title: 'Edit',
    prop: 'edit',
    isEdit: true,
    onEdit: (resolve, reject, data) => {
      requestAndResponse(
        '../api/student/update',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            student_id: data.student_id,
            data: removeNull(data)
          })
        },
        resolve,
        reject
      )
    }
  },
  {
    title: 'Delete',
    prop: 'delete',
    isDelete: true,
    formatter: () =>
Delete
,
    onDelete: (resolve, reject, data) => {
      requestAndResponse(
        '../api/student/delete',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            where: {
              student_id: data.student_id
            }
          })
        },
        resolve,
        reject
      )
    }
  },
  {
    title: 'รหัสนิสิต',
    prop: 'student_id',
    isEditable: false,
    isNullable: false
  },
  {
    title: 'CurID',
    prop: 'curid',
    isNullable: false
  },
  {
    title: 'MemID',
    prop: 'member_id',
    validate: (resolve, reject, data) => {
      setTimeout(() => resolve('eiei'), 500)
    }
  },
  {
    title: 'คำนำหน้าชื่อ',
    prop: 'title',
    isNullable: false
  },
  {
    title: 'ชื่อ',
    prop: 'firstname',
    isNullable: false
  },
  {
    title: 'นามสกุล',
    prop: 'lastname',
    isNullable: false
  },
  {
    title: 'อีเมล์',
    prop: 'email'
  },
  {
    title: 'สัญชาติ',
    prop: 'nationality'
  },
  {
    title: 'วันเกิด',
    prop: 'birthdate',
    formatter: (date) => {
      if (date) return date.slice(0, 10)
      return null
    }
  },
  {
    title: 'เพศ',
    prop: 'gender',
    isNullable: false
    // TODO: option F M
  },
  {
    title: 'รหัสประชาชน',
    prop: 'citizen_id',
    isNullable: false
  },
  {
    title: 'ศาสนา',
    prop: 'religion'
  },
  {
    title: 'มือถือ',
    prop: 'mobile'
  },
  {
    title: 'Img',
    prop: 'img'
  },
  {
    title: 'ที่อยู่',
    prop: 'addr'
  },
  {
    title: 'รหัสไปรษณีย์',
    prop: 'zipcode'
  },
  {
    title: 'ประเทศ',
    prop: 'country'
  },
  {
    title: 'เบอร์โทรฉุกเฉิน',
    prop: 'emer_name'
  },
  {
    title: 'เบอร์โทรศัพท์ฉุกเฉิน',
    prop: 'emer_mobile'
  },
  {
    title: 'ที่อยู่ฉุกเฉิน',
    prop: 'emer_addr'
  },
  {
    title: 'รหัสไปรษณีย์ฉุกเฉิน',
    prop: 'emer_zipcode'
  },
  {
    title: 'ประเทศฉุกเฉิน',
    prop: 'emer_country'
  },
  {
    title: 'โรงเรียนมัธยม',
    prop: 'highschool_name'
  },
  {
    title: 'เกรดมัธยม',
    prop: 'highschool_grade'
  },
  {
    title: 'GPAX',
    prop: 'gpax'
  },
  {
    title: 'จำนวนเทอม',
    prop: 'semester_count',
    isNullable: false
  },
  {
    title: 'SummerCount',
    prop: 'summer_count',
    isNullable: false
  },
  {
    title: 'สถานะ',
    prop: 'status',
    isNullable: false
  },
  {
    title: 'คะแนนความประพฤติ',
    prop: 'behavioral_score',
    isNullable: false
  }
]

export default {
  table: {
    add: (resolve, reject, newData) => {
      requestAndResponse(
        '../api/student/insert',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            data: removeNull(newData)
          })
        },
        resolve,
        reject
      )
    }
  },
  header: studentHeader,
  pagination: {
    pageSize: 25,
    paginationBarSize: 10
  },
  src: {
    url: '../api/student/all',
    parser: (raw) => raw.data
  }
}

<commit_msg>Change pagination size<commit_after>import React from 'react'

import { requestAndResponse, removeNull } from '../../../utils/query'

const studentHeader = [
  {
    title: 'Edit',
    prop: 'edit',
    isEdit: true,
    onEdit: (resolve, reject, data) => {
      requestAndResponse(
        '../api/student/update',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            student_id: data.student_id,
            data: removeNull(data)
          })
        },
        resolve,
        reject
      )
    }
  },
  {
    title: 'Delete',
    prop: 'delete',
    isDelete: true,
    formatter: () =>
Delete
,
    onDelete: (resolve, reject, data) => {
      requestAndResponse(
        '../api/student/delete',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            where: {
              student_id: data.student_id
            }
          })
        },
        resolve,
        reject
      )
    }
  },
  {
    title: 'รหัสนิสิต',
    prop: 'student_id',
    isEditable: false,
    isNullable: false
  },
  {
    title: 'CurID',
    prop: 'curid',
    isNullable: false
  },
  {
    title: 'MemID',
    prop: 'member_id',
    validate: (resolve, reject, data) => {
      setTimeout(() => resolve('eiei'), 500)
    }
  },
  {
    title: 'คำนำหน้าชื่อ',
    prop: 'title',
    isNullable: false
  },
  {
    title: 'ชื่อ',
    prop: 'firstname',
    isNullable: false
  },
  {
    title: 'นามสกุล',
    prop: 'lastname',
    isNullable: false
  },
  {
    title: 'อีเมล์',
    prop: 'email'
  },
  {
    title: 'สัญชาติ',
    prop: 'nationality'
  },
  {
    title: 'วันเกิด',
    prop: 'birthdate',
    formatter: (date) => {
      if (date) return date.slice(0, 10)
      return null
    }
  },
  {
    title: 'เพศ',
    prop: 'gender',
    isNullable: false
    // TODO: option F M
  },
  {
    title: 'รหัสประชาชน',
    prop: 'citizen_id',
    isNullable: false
  },
  {
    title: 'ศาสนา',
    prop: 'religion'
  },
  {
    title: 'มือถือ',
    prop: 'mobile'
  },
  {
    title: 'Img',
    prop: 'img'
  },
  {
    title: 'ที่อยู่',
    prop: 'addr'
  },
  {
    title: 'รหัสไปรษณีย์',
    prop: 'zipcode'
  },
  {
    title: 'ประเทศ',
    prop: 'country'
  },
  {
    title: 'เบอร์โทรฉุกเฉิน',
    prop: 'emer_name'
  },
  {
    title: 'เบอร์โทรศัพท์ฉุกเฉิน',
    prop: 'emer_mobile'
  },
  {
    title: 'ที่อยู่ฉุกเฉิน',
    prop: 'emer_addr'
  },
  {
    title: 'รหัสไปรษณีย์ฉุกเฉิน',
    prop: 'emer_zipcode'
  },
  {
    title: 'ประเทศฉุกเฉิน',
    prop: 'emer_country'
  },
  {
    title: 'โรงเรียนมัธยม',
    prop: 'highschool_name'
  },
  {
    title: 'เกรดมัธยม',
    prop: 'highschool_grade'
  },
  {
    title: 'GPAX',
    prop: 'gpax'
  },
  {
    title: 'จำนวนเทอม',
    prop: 'semester_count',
    isNullable: false
  },
  {
    title: 'SummerCount',
    prop: 'summer_count',
    isNullable: false
  },
  {
    title: 'สถานะ',
    prop: 'status',
    isNullable: false
  },
  {
    title: 'คะแนนความประพฤติ',
    prop: 'behavioral_score',
    isNullable: false
  }
]

export default {
  table: {
    add: (resolve, reject, newData) => {
      requestAndResponse(
        '../api/student/insert',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            data: removeNull(newData)
          })
        },
        resolve,
        reject
      )
    }
  },
  header: studentHeader,
  pagination: {
    pageSize: 25,
    paginationBarSize: 20
  },
  src: {
    url: '../api/student/all',
    parser: (raw) => raw.data
  }
}

<|endoftext|>


<commit_before>var VIDEO_PATH = 'https://x20web.corp.google.com/~kgr/power/videos/DemoDen/';

MODEL({
  name: 'Demo',
  properties: [
    'name', 'path', 'keywords', 'image', 'video', 'description',
    {
      name: 'src',
      defaultValueFn: function() {
        var i = window.location.href.indexOf('DemoCat.html');
        var path = window.location.href.substring(0, i);
        return 'view-source: ' + path + this.path;
      }
    }
  ]
});

var demos = JSONUtil.arrayToObjArray(X, [
  {
    name: 'Solar System',
    path: 'SolarSystem.html',
    description: 'An animation which demonstrates reactive-programming.  Use the Time-Wheel to spin-time.',
    keywords: ['animation', 'reactive'],
    src: 'SolarSystem.js',
    image: 'SolarSystem.png',
  },
  {
    name: 'Canvas Scrolling',
    path: 'canvasscrolling.html',
    description: 'A demonstration of high-performance canvas (DOM-less) scrolling..',
    keywords: ['canvas'],
    src: 'canvasscrolling.js',
    image: 'canvasscrolling.png',
  },
  {
    name: 'Reactive Clocks',
    path: 'ReactiveClocks.html',
    description: 'A simple demo of reactive programming.  The first clocks reacts to the position of the mouse while the second clock reacts to the position of the first clock and to time.  Reacting to time essentially gives you an animation system for free.',
    keywords: ['animation', 'reactive'],
    image: 'ReactiveClocks.png',
    video: 'part11.ogv'
  },
  {
    name: 'Unix Simulator',
    path: 'UnixSimulator.html',
    description: "A simulator which demonstrates the advantage of UNIX's architecture over previous operating-sytems.",
    keywords: ['simulation', 'animation', 'architecture'],
    image: 'UnixSimulator.png',
    video: 'part1.ogv'
  },
  {
    name: 'Google Simulator',
    path: 'GoogleSimulator.html',
    description: 'A simulation of the growth of Google.',
    keywords: ['simulation', 'animation', 'architecture'],
    image: 'GoogleSimulator.png',
    video: 'part15.ogv'
  },
  {
    name: 'Fading Circles',
    path: 'FadingCircles.html',
    description: 'An reactive-programming animation which demonstrates the use of Events.dynamic() and Movement.animate().',
    keywords: ['animation'],
    image: 'FadingCircles.png'
  },
  {
    name: 'Follow The Leader',
    path: 'FollowTheLeader.html',
    description: 'An animation which uses Movement.moveTowards() to create a chain of circles which follow the mouse.',
    keywords: ['animation'],
    image: 'FollowTheLeader.png'
  },
  {
    name: 'InterpolatedClocks',
    path: 'InterpolatedClocks.html',
    description: 'A demonstration of animation interpolators.  Click to animate the clocks.  Notice how the different clocks use different acceleration curves to reach their targets.',
    keywords: ['animation'],
    image: 'InterpolatedClocks.png'
  },
  {
    name: 'FOAM Architecture Diagram',
    path: 'demoBlockDiagram.html',
    description: 'An animated diagram of FOAM\'s architecture.  Notice the reflections.',
    keywords: ['architecture', 'animation'],
    image: 'DemoBlockDiagram.png',
    video: 'part6.ogv'
  },
  {
    name: 'Dragon Live-Coding',
    path: 'DragonLiveCoding.html',
    description: 'A version of the dragon animation that you can live-code.  Use the Model editor to update methods while the animation is running.',
    keywords: ['animation', 'live-coding'],
    src: 'DragonLiveCoding.js',
    image: 'LiveDragon.png',
    video: 'part12.ogv'
  },
  {
    name: 'Pong',
    path: 'Pong.html',
    description: 'A simple pong game which demonstrates the both the use of graphical traits (motion blur and shadow) and of the physics engine.',
    keywords: ['animation', 'game', 'physics', 'traits', '14'],
    src: 'Pong.js',
    image: 'Pong.png'
  },
  {
    name: 'DAO Samples',
    path: 'dao.html',
    description: 'An extensive set of DAO (Data-Access-Object) samples.  A must read for learning FOAM.',
    keywords: ['DAO', 'database', '14'],
    image: 'DAO.png'
  },
  {
    name: 'Collision',
    path: 'Collision.html',
    description: 'Demonstration of the physics engine and collision-detection.',
    keywords: ['physics', '14'],
    src: 'Collision.js',
    image: 'Collision.png'
  },
  {
    name: 'Collision With Spring',
    path: 'CollisionWithSpring.html',
    description: 'A simple physics simulation which shows the use of springs and collision detection.',
    keywords: ['physics', '14'],
    src: 'CollisionWithSpring.js',
    image: 'CollisionWithSpring.png'
  },
  {
    name: 'Spring',
    path: 'Spring.html',
    description: 'Addictive spring physics simulation.',
    keywords: ['physics', '14'],
    src: 'Spring.js',
    image: 'Spring.png'
  },
  {
    name: 'Trait Graphics',
    path: 'TraitGraphics.html',
    description: 'Demonstrates the use of graphical Traits.  The circles on the left have shadows and those on the right have motion-blur.  Traits are not limited to graphics and are a generalized method for safely providing multiple inheritance.',
    keywords: ['traits','graphics', '14'],
    src: 'TraitGraphics.js',
    image: 'TraitGraphics.png'
  },
  {
    name: 'Internationalization',
    path: 'I18N.html',
    description: 'Simple I18N Example.',
    keywords: ['i18n'],
    src: 'I18N.js',
    image: 'I18N.png'
  },
  {
    name: 'Crop Circles',
    path: 'CropCircle.html',
    description: 'Crop Circle inspired fractals graphics. Can take 10-20 seconds to load on slow machines. Each fractal is implemented in only one line of code.  Just started: needs animation and a graphical live-coding system.',
    keywords: ['graphics', '14'],
    src: 'CropCircle.js',
    image: 'CropCircle.png'
  },
  {
    name: 'Complements',
    path: 'Complements.html',
    description: 'An animated colour wheel.  Ported from the Elm demo.  Shows use of Events.dynamic().',
    keywords: ['animation', '14'],
    image: 'Complements.png'
  },
  {
    name: 'Dragon',
    path: 'Tags.html',
    description: 'Demonstrates use of the FOAM tag to instantiate three views: an animated dragon, a time-wheel, and a DetailView of time.  Use the time-wheel to control the animation.',
    keywords: ['animation', '14'],
    image: 'Dragon.png'
  },
  {
    name: 'Two-Way Data-Binding',
    path: 'TwoWayDataBinding.html',
    description: 'Demonstrates how to do two way data-binding in FOAM. See the same demo implemented with other JS libraries.',
    keywords: ['tutorial', '14'],
    image: 'TwoWayDataBinding.png'
  },
  {
    name: 'Calculator',
    path: '../apps/calc/Calc.html',
    description: 'A simple calculator application.  Demonstrates the use of templates to completely change the appearance of a DetailView.',
    keywords: ['app', '14'],
    src: '../apps/calc/',
    image: 'Calc.png'
  },
  {
    name: 'Calculator (Material-Design)',
    path: '../apps/acalc/Calc.html',
    description: 'A calculator application with an animated Material-Design interface.',
    keywords: ['app', 'material-design', '14'],
    src: '../apps/acalc/',
    image: 'ACalc.png'
  },
  {
    name: 'GMail (Material-Design)',
    path: '../apps/gmail/main.html',
    description: 'A simple mobile GMail client with a Material-Design interface, in less than 1k lines of code.',
    keywords: ['app', 'material-design', 'gmail', 'mobile', '14'],
    src: '../apps/gmail/',
    image: 'GMail.png'
  },
  {
    name: 'QuickBug',
    path: 'https://chrome.google.com/webstore/detail/quickbug/hmdcjljmcglpjnmmbjhpialomleabcmg',
    description: 'A Chrome packaged-app clone of the crbug.com issue tracker.  Provides many extra features and improved performance.  Be sure to try out grid-view\'s drag-and-drop tiles and PIE charts with warped scrolling features. See: http://quickbug.foamdev.com',
    keywords: ['app', '14'],
    src: '../apps/quickbug/',
    image: 'QuickBug.png'
  },
  {
    name: 'Issue Tracker (Material-Design)',
    path: '../apps/mbug/main.html',
    description: 'A simple mobile code.google.com issue-tracker client with a Material-Design interface.  Triage your Crbugs on the go.  See: http://mbug.foamdev.com',
    keywords: ['app', 'material-design', 'mobile', '14', 'android'],
    src: '../apps/mbug/',
    image: 'MBug.png'
  },
  {
    name: 'Phone Catalog',
    path: '../apps/phonecat/Cat.html',
    description: 'A port of an Angular application for browsing a Cellphone catalog.  Create this app yourself by following the tutorial.',
    keywords: ['tutorial', '14'],
    src: '../apps/phonecat/',
    image: 'PhoneCat.png'
  },
  {
    name: 'Quick-Compose',
    path: 'https://chrome.google.com/webstore/detail/quickcompose/elckoikggmpkacmbmpbgdepginigahja',
    description: 'A Chrome App for composing (and sending) quick GMails.  Compose emails while offline and have them delivered when you eventually get a network connection.',
    keywords: ['app', '14'],
    src: '../apps/quickcompose/',
    image: 'QuickCompose.png'
  },
  {
    name: 'Todo',
    path: '../apps/todo/Todo.html',
    description: 'A FOAM implementation of the http://todomvc.com comparison application.  Notice that the FOAM implementation is by far the shortest listed on the TodoMVC site.',
    keywords: ['tutorial', '14'],
    src: '../apps/todo/',
    image: 'Todo.png'
  },
  {
    name: 'FOAM Code Browser',
    path: '../core/fobrowser.html',
    description: 'A FOAM Model browser.',
    keywords: ['tool', 'dev'],
    src: '../core/fobrowser.js',
    image: 'FOBrowser.png'
  },
  {
    name: 'FOAM Documentation Browser',
    path: '../apps/docs/docbrowser.html',
    description: 'A FOAM Document browser.',
    keywords: ['tool', 'dev', 'docs'],
    src: '../apps/docs/',
    image: '../../apps/docs/images/Model_runtime2.png'
  },
], Demo).dao;

MODEL({
  name: 'Controller',
  properties: [
    { name: 'search', view: { model_: 'TextFieldView', onKeyMode: true } },
    { name: 'dao', defaultValue: demos },
    {
      name: 'filteredDAO',
      model_: 'DAOProperty',
      view: { model_: 'DAOListView', rowView: 'DemoView', mode: 'read-only' },
      dynamicValue: function() {
        return this.dao.where(CONTAINS_IC(SEQ(Demo.NAME, Demo.DESCRIPTION, Demo.KEYWORDS), this.search));
      }
    }
  ],
  methods: {
    init: function(SUPER) {
      SUPER();
      var i = window.location.href.indexOf('?q=');
      if ( i != -1 ) this.search = window.location.href.substring(i+3);
    }
  },
  templates: [
    function CSS() {/* .thumbnail { margin-bottom: 40px; } */},
    function toDetailHTML() {/*
           Search: $$search

        <foam f="filteredDAO" className="demos" tagName="ul">

            $$name{mode: 'read-only'}

            <% if ( this.data.image ) { %>
 <% } %>

$$description{mode: 'read-only', escapeHTML: false}

            Keywords: <%= this.data.keywords.join(', ') %>

            Source: here

            <% if ( VIDEO_PATH && this.data.video ) { %>
            Video: <a href="<%= VIDEO_PATH + this.data.video%>">
            <% } %>

        </foam>
    */}
  ]
});
<commit_msg>Removed stale code from DemoCat.<commit_after>var VIDEO_PATH = 'https://x20web.corp.google.com/~kgr/power/videos/DemoDen/';

MODEL({
  name: 'Demo',
  properties: [
    'name', 'path', 'keywords', 'image', 'video', 'description',
    {
      name: 'src',
      defaultValueFn: function() {
        var i = window.location.href.indexOf('DemoCat.html');
        var path = window.location.href.substring(0, i);
        return 'view-source: ' + path + this.path;
      }
    }
  ]
});

var demos = JSONUtil.arrayToObjArray(X, [
  {
    name: 'Solar System',
    path: 'SolarSystem.html',
    description: 'An animation which demonstrates reactive-programming.  Use the Time-Wheel to spin-time.',
    keywords: ['animation', 'reactive'],
    src: 'SolarSystem.js',
    image: 'SolarSystem.png',
  },
  {
    name: 'Canvas Scrolling',
    path: 'canvasscrolling.html',
    description: 'A demonstration of high-performance canvas (DOM-less) scrolling..',
    keywords: ['canvas'],
    src: 'canvasscrolling.js',
    image: 'canvasscrolling.png',
  },
  {
    name: 'Reactive Clocks',
    path: 'ReactiveClocks.html',
    description: 'A simple demo of reactive programming.  The first clocks reacts to the position of the mouse while the second clock reacts to the position of the first clock and to time.  Reacting to time essentially gives you an animation system for free.',
    keywords: ['animation', 'reactive'],
    image: 'ReactiveClocks.png',
    video: 'part11.ogv'
  },
  {
    name: 'Unix Simulator',
    path: 'UnixSimulator.html',
    description: "A simulator which demonstrates the advantage of UNIX's architecture over previous operating-sytems.",
    keywords: ['simulation', 'animation', 'architecture'],
    image: 'UnixSimulator.png',
    video: 'part1.ogv'
  },
  {
    name: 'Google Simulator',
    path: 'GoogleSimulator.html',
    description: 'A simulation of the growth of Google.',
    keywords: ['simulation', 'animation', 'architecture'],
    image: 'GoogleSimulator.png',
    video: 'part15.ogv'
  },
  {
    name: 'Fading Circles',
    path: 'FadingCircles.html',
    description: 'An reactive-programming animation which demonstrates the use of Events.dynamic() and Movement.animate().',
    keywords: ['animation'],
    image: 'FadingCircles.png'
  },
  {
    name: 'Follow The Leader',
    path: 'FollowTheLeader.html',
    description: 'An animation which uses Movement.moveTowards() to create a chain of circles which follow the mouse.',
    keywords: ['animation'],
    image: 'FollowTheLeader.png'
  },
  {
    name: 'InterpolatedClocks',
    path: 'InterpolatedClocks.html',
    description: 'A demonstration of animation interpolators.  Click to animate the clocks.  Notice how the different clocks use different acceleration curves to reach their targets.',
    keywords: ['animation'],
    image: 'InterpolatedClocks.png'
  },
  {
    name: 'FOAM Architecture Diagram',
    path: 'demoBlockDiagram.html',
    description: 'An animated diagram of FOAM\'s architecture.  Notice the reflections.',
    keywords: ['architecture', 'animation'],
    image: 'DemoBlockDiagram.png',
    video: 'part6.ogv'
  },
  {
    name: 'Dragon Live-Coding',
    path: 'DragonLiveCoding.html',
    description: 'A version of the dragon animation that you can live-code.  Use the Model editor to update methods while the animation is running.',
    keywords: ['animation', 'live-coding'],
    src: 'DragonLiveCoding.js',
    image: 'LiveDragon.png',
    video: 'part12.ogv'
  },
  {
    name: 'Pong',
    path: 'Pong.html',
    description: 'A simple pong game which demonstrates the both the use of graphical traits (motion blur and shadow) and of the physics engine.',
    keywords: ['animation', 'game', 'physics', 'traits', '14'],
    src: 'Pong.js',
    image: 'Pong.png'
  },
  {
    name: 'DAO Samples',
    path: 'dao.html',
    description: 'An extensive set of DAO (Data-Access-Object) samples.  A must read for learning FOAM.',
    keywords: ['DAO', 'database', '14'],
    image: 'DAO.png'
  },
  {
    name: 'Collision',
    path: 'Collision.html',
    description: 'Demonstration of the physics engine and collision-detection.',
    keywords: ['physics', '14'],
    src: 'Collision.js',
    image: 'Collision.png'
  },
  {
    name: 'Collision With Spring',
    path: 'CollisionWithSpring.html',
    description: 'A simple physics simulation which shows the use of springs and collision detection.',
    keywords: ['physics', '14'],
    src: 'CollisionWithSpring.js',
    image: 'CollisionWithSpring.png'
  },
  {
    name: 'Spring',
    path: 'Spring.html',
    description: 'Addictive spring physics simulation.',
    keywords: ['physics', '14'],
    src: 'Spring.js',
    image: 'Spring.png'
  },
  {
    name: 'Trait Graphics',
    path: 'TraitGraphics.html',
    description: 'Demonstrates the use of graphical Traits.  The circles on the left have shadows and those on the right have motion-blur.  Traits are not limited to graphics and are a generalized method for safely providing multiple inheritance.',
    keywords: ['traits','graphics', '14'],
    src: 'TraitGraphics.js',
    image: 'TraitGraphics.png'
  },
  {
    name: 'Internationalization',
    path: 'I18N.html',
    description: 'Simple I18N Example.',
    keywords: ['i18n'],
    src: 'I18N.js',
    image: 'I18N.png'
  },
  {
    name: 'Crop Circles',
    path: 'CropCircle.html',
    description: 'Crop Circle inspired fractals graphics. Can take 10-20 seconds to load on slow machines. Each fractal is implemented in only one line of code.  Just started: needs animation and a graphical live-coding system.',
    keywords: ['graphics', '14'],
    src: 'CropCircle.js',
    image: 'CropCircle.png'
  },
  {
    name: 'Complements',
    path: 'Complements.html',
    description: 'An animated colour wheel.  Ported from the Elm demo.  Shows use of Events.dynamic().',
    keywords: ['animation', '14'],
    image: 'Complements.png'
  },
  {
    name: 'Dragon',
    path: 'Tags.html',
    description: 'Demonstrates use of the FOAM tag to instantiate three views: an animated dragon, a time-wheel, and a DetailView of time.  Use the time-wheel to control the animation.',
    keywords: ['animation', '14'],
    image: 'Dragon.png'
  },
  {
    name: 'Two-Way Data-Binding',
    path: 'TwoWayDataBinding.html',
    description: 'Demonstrates how to do two way data-binding in FOAM. See the same demo implemented with other JS libraries.',
    keywords: ['tutorial', '14'],
    image: 'TwoWayDataBinding.png'
  },
  {
    name: 'Calculator',
    path: '../apps/calc/Calc.html',
    description: 'A simple calculator application.  Demonstrates the use of templates to completely change the appearance of a DetailView.',
    keywords: ['app', '14'],
    src: '../apps/calc/',
    image: 'Calc.png'
  },
  {
    name: 'Calculator (Material-Design)',
    path: '../apps/acalc/Calc.html',
    description: 'A calculator application with an animated Material-Design interface.',
    keywords: ['app', 'material-design', '14'],
    src: '../apps/acalc/',
    image: 'ACalc.png'
  },
  {
    name: 'GMail (Material-Design)',
    path: '../apps/gmail/main.html',
    description: 'A simple mobile GMail client with a Material-Design interface, in less than 1k lines of code.',
    keywords: ['app', 'material-design', 'gmail', 'mobile', '14'],
    src: '../apps/gmail/',
    image: 'GMail.png'
  },
  {
    name: 'QuickBug',
    path: 'https://chrome.google.com/webstore/detail/quickbug/hmdcjljmcglpjnmmbjhpialomleabcmg',
    description: 'A Chrome packaged-app clone of the crbug.com issue tracker.  Provides many extra features and improved performance.  Be sure to try out grid-view\'s drag-and-drop tiles and PIE charts with warped scrolling features. See: http://quickbug.foamdev.com',
    keywords: ['app', '14'],
    src: '../apps/quickbug/',
    image: 'QuickBug.png'
  },
  {
    name: 'Issue Tracker (Material-Design)',
    path: '../apps/mbug/main.html',
    description: 'A simple mobile code.google.com issue-tracker client with a Material-Design interface.  Triage your Crbugs on the go.  See: http://mbug.foamdev.com',
    keywords: ['app', 'material-design', 'mobile', '14', 'android'],
    src: '../apps/mbug/',
    image: 'MBug.png'
  },
  {
    name: 'Phone Catalog',
    path: '../apps/phonecat/Cat.html',
    description: 'A port of an Angular application for browsing a Cellphone catalog.  Create this app yourself by following the tutorial.',
    keywords: ['tutorial', '14'],
    src: '../apps/phonecat/',
    image: 'PhoneCat.png'
  },
  {
    name: 'Quick-Compose',
    path: 'https://chrome.google.com/webstore/detail/quickcompose/elckoikggmpkacmbmpbgdepginigahja',
    description: 'A Chrome App for composing (and sending) quick GMails.  Compose emails while offline and have them delivered when you eventually get a network connection.',
    keywords: ['app', '14'],
    src: '../apps/quickcompose/',
    image: 'QuickCompose.png'
  },
  {
    name: 'Todo',
    path: '../apps/todo/Todo.html',
    description: 'A FOAM implementation of the http://todomvc.com comparison application.  Notice that the FOAM implementation is by far the shortest listed on the TodoMVC site.',
    keywords: ['tutorial', '14'],
    src: '../apps/todo/',
    image: 'Todo.png'
  },
  {
    name: 'FOAM Code Browser',
    path: '../core/fobrowser.html',
    description: 'A FOAM Model browser.',
    keywords: ['tool', 'dev'],
    src: '../core/fobrowser.js',
    image: 'FOBrowser.png'
  },
  {
    name: 'FOAM Documentation Browser',
    path: '../apps/docs/docbrowser.html',
    description: 'A FOAM Document browser.',
    keywords: ['tool', 'dev', 'docs'],
    src: '../apps/docs/',
    image: '../../apps/docs/images/Model_runtime2.png'
  },
], Demo).dao;

MODEL({
  name: 'Controller',
  properties: [
    { name: 'search', view: { model_: 'TextFieldView', onKeyMode: true } },
    { name: 'dao', defaultValue: demos },
    {
      name: 'filteredDAO',
      model_: 'DAOProperty',
      view: { model_: 'DAOListView', mode: 'read-only' },
      dynamicValue: function() {
        return this.dao.where(CONTAINS_IC(SEQ(Demo.NAME, Demo.DESCRIPTION, Demo.KEYWORDS), this.search));
      }
    }
  ],
  methods: {
    init: function(SUPER) {
      SUPER();
      var i = window.location.href.indexOf('?q=');
      if ( i != -1 ) this.search = window.location.href.substring(i+3);
    }
  },
  templates: [
    function CSS() {/* .thumbnail { margin-bottom: 40px; } */},
    function toDetailHTML() {/*
           Search: $$search

        <foam f="filteredDAO" className="demos" tagName="ul">

            $$name{mode: 'read-only'}

            <% if ( this.data.image ) { %>
 <% } %>

$$description{mode: 'read-only', escapeHTML: false}

            Keywords: <%= this.data.keywords.join(', ') %>

            Source: here

            <% if ( VIDEO_PATH && this.data.video ) { %>
            Video: <a href="<%= VIDEO_PATH + this.data.video%>">
            <% } %>

        </foam>
    */}
  ]
});
<|endoftext|>


<commit_before><commit_msg>Add droppable option<commit_after><|endoftext|>


<commit_before><commit_msg>handler returns null if no handled errors<commit_after><|endoftext|>


<commit_before>module.exports = df;
df.pingVersion = pingVersion;
df.apps = apps;
df.logs = logs;

df.usage = "\nfhc df ping"
  + "\nfhc df version"
  + "\nfhc df apps"
  + "\nfhc df logs <app id>"
  + "\nfhc df start <app id>"
  + "\nfhc df stop <app id>"
  + "\nfhc df delete <app id>"
  + "\nfhc df act <app id> <server function> <params>"
  + "\nfhc df url <app id> (returns the full DynoFarm url given an appId)";

var log = require("./utils/log");
var hash = require("./utils/hash");
var fhc = require("./fhc");
var util = require('util');
var output = require("./utils/output");
var request = require('request');
var common = require('./common.js');
var Table = require('cli-table');
var ini = require('./utils/ini');

// main DynoFarm entry point
function df (args, cb) {
  var action = args.shift();
  switch (action) {
    case "ping": return pingVersion("ping", cb);
    case "version": return pingVersion("version", cb);
    case "apps": case "ls": return apps(cb);
    case "logs":  {
      if (args.length != 1) return unknown("logs", cb);
      else return logs(args[0], cb);
    };
    case "stop":  {
      if (args.length != 1) return unknown("stop", cb);
      else return stop(args[0], cb);
    };
    case "start":  {
      if (args.length != 1) return unknown("start", cb);
      else return start(args[0], cb);
    };
    case "url":  {
      if (args.length != 1) return unknown("url", cb);
      else return url(args[0], cb);
    };
    case "act": {
      if (args.length < 2) return unknown("act", cb);
      return act(args[0], args[1], args[2], cb);
    };
    case "delete":  {
      if (args.length != 1) return unknown("delete", cb);
      else return deleteApp(args[0], cb);
    };
    default: return unknown(action, cb);
  }
};

// gets the app endpoint from the dftarget
function getAppUrl(appId){
  var appName = common.getAppName(appId);
  var df = fhc.config.get("dynofarm");
  var uri = require('url').parse(df);

  // replace 'api' with the modified appId to get our enpoint
  var port = uri.port ? ":" +  uri.port : "";
  var url = uri.protocol + "//" + appName + "." + uri.hostname + port;
  url = url.replace(/\.api\./g, '.');

  return url;
}

// our 'act' function
function act(appId, funct, params, cb) {
  var data = {};
  if (params) data = JSON.parse(params);
  log.silly(data, "df act params");

  // firgure out our app endpoint
  var appUrl = getAppUrl(appId);
  log.verbose('' + appUrl, "App endpoint");
  log.verbose('' + funct, "Calling DF function");

  // post to /cloud
  request({uri: appUrl + "/cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
    log.silly(response);
    return cb(nullToUndefined(err), body);
  });
};

// ping
function pingVersion (pingVersion, cb) {
  request(getDynoFarmUrl() + "sys/info/" + pingVersion, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// put our apps into table format..
function createTableForApps(apps) {
  // calculate widths
  var maxApp=4, maxDynoMan=8, maxPort=5, maxState=5;

  for (var a in apps) {
    if (common.strlen(a) > maxApp) maxApp = common.strlen(a);
    var app = apps[a];
    if(common.strlen(app.host) > maxDynoMan) maxDynoMan = common.strlen(app.host);
    if(common.strlen(app.port) > maxPort) maxPort = common.strlen(app.port);
    if(common.strlen(app.state) > maxState) maxState = common.strlen(app.state);
  }

  // create our table
  df.table = new Table({
    head: ['App', 'DynoMan', 'Port', 'State'],
    colWidths: [maxApp +2 , maxDynoMan + 2, maxPort + 2, maxState + 2],
    style: common.style()
  });

  // populate our table
  for (var a in apps) {
    var app = apps[a];
    df.table.push([a, app.host, app.port, app.state]);
  }
}

// DynoFarm apps
function apps (cb) {
  request(getDynoFarmUrl() + "apps", function (err, response, body) {
    if (err) return cb(nullToUndefined(err));
    var apps;
    try{
      apps = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing apps: " + util.inspect(x));
    }

    if(ini.get('table') === true) {
      createTableForApps(apps);
    }

    return cb(undefined, apps);
  });
};

// DynoFarm logs
function logs(appId, cb) {
  request(getDynoFarmUrl() + "logs/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Stop app
function stop(appId, cb) {
  request(getDynoFarmUrl() + "stop/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Start app
function start(appId, cb) {
  request(getDynoFarmUrl() + "start/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Given an app id, returns its DynoFarm endpoint
function url(appId, cb) {
  var appName = common.getAppName(appId);
  var url = getAppUrl(appId);
  return cb(undefined, {name: appName, url:url});
};

function unknown (action, cb) {
  var msg = action ? "Wrong arguments for or unknown action: " + action + "\n" : "";
  msg += "Usage:\n" + df.usage;
  cb(msg);
};

// get our DF endpoint
function getDynoFarmUrl () {
  var r = fhc.config.get("dynofarm");
  if (!r) {
    return new Error("Must define DynoFarm URLs before accessing FeedHenry DynoFarm Server.")
  }
  if (r.substr(-1) !== "/") r += "/";
  fhc.config.set("dynofarm", r);
  return r;
};

// Annoyingly, 'request' returns nulls, the rest of FHC uses undefined, so return undefined to keep
// things consistent.
function nullToUndefined(err) {
  return err == null? undefined: err;
}

// delete an app
function deleteApp(appId, cb) {
  request({url: getDynoFarmUrl() + "delete/" + appId, method: 'POST'}, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// bash completion
df.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "df") argv.unshift("df");
  if (argv.length === 2) {
    var cmds = ["apps", "logs", "start", "stop", "delete", "act", "url", "version"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    // todo: complete with valid values, if possible.
    case "apps":
    case "logs":
    case "start":
    case "delete":
    case "act":
    case "url":
    case "version":
      return cb(null, Object.keys(types));
    default: return cb(null, []);
  }
};
<commit_msg>Table formats in df.js<commit_after>module.exports = df;
df.pingVersion = pingVersion;
df.apps = apps;
df.logs = logs;

df.usage = "\nfhc df ping"
  + "\nfhc df version"
  + "\nfhc df apps"
  + "\nfhc df logs <app id>"
  + "\nfhc df start <app id>"
  + "\nfhc df stop <app id>"
  + "\nfhc df delete <app id>"
  + "\nfhc df act <app id> <server function> <params>"
  + "\nfhc df url <app id> (returns the full DynoFarm url given an appId)";

var log = require("./utils/log");
var hash = require("./utils/hash");
var fhc = require("./fhc");
var util = require('util');
var output = require("./utils/output");
var request = require('request');
var common = require('./common.js');
var Table = require('cli-table');
var ini = require('./utils/ini');

// main DynoFarm entry point
function df (args, cb) {
  var action = args.shift();
  switch (action) {
    case "ping": return pingVersion("ping", cb);
    case "version": return pingVersion("version", cb);
    case "apps": case "ls": return apps(cb);
    case "logs":  {
      if (args.length != 1) return unknown("logs", cb);
      else return logs(args[0], cb);
    };
    case "stop":  {
      if (args.length != 1) return unknown("stop", cb);
      else return stop(args[0], cb);
    };
    case "start":  {
      if (args.length != 1) return unknown("start", cb);
      else return start(args[0], cb);
    };
    case "url":  {
      if (args.length != 1) return unknown("url", cb);
      else return url(args[0], cb);
    };
    case "act": {
      if (args.length < 2) return unknown("act", cb);
      return act(args[0], args[1], args[2], cb);
    };
    case "delete":  {
      if (args.length != 1) return unknown("delete", cb);
      else return deleteApp(args[0], cb);
    };
    default: return unknown(action, cb);
  }
};

// gets the app endpoint from the dftarget
function getAppUrl(appId){
  var appName = common.getAppName(appId);
  var df = fhc.config.get("dynofarm");
  var uri = require('url').parse(df);

  // replace 'api' with the modified appId to get our enpoint
  var port = uri.port ? ":" +  uri.port : "";
  var url = uri.protocol + "//" + appName + "." + uri.hostname + port;
  url = url.replace(/\.api\./g, '.');

  return url;
}

// our 'act' function
function act(appId, funct, params, cb) {
  var data = {};
  if (params) data = JSON.parse(params);
  log.silly(data, "df act params");

  // firgure out our app endpoint
  var appUrl = getAppUrl(appId);
  log.verbose('' + appUrl, "App endpoint");
  log.verbose('' + funct, "Calling DF function");

  // post to /cloud
  request({uri: appUrl + "/cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
    log.silly(response);
    return cb(nullToUndefined(err), body);
  });
};

// ping
function pingVersion (pingVersion, cb) {
  request(getDynoFarmUrl() + "sys/info/" + pingVersion, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// put our apps into table format..
function createTableForApps(apps) {
  // calculate widths
  var maxApp=4, maxDynoMan=8, maxPort=5, maxState=5, maxUrl = 3;

  for (var a in apps) {
    if(common.strlen(a) > maxApp) maxApp = common.strlen(a);
    var url = getAppUrl(a);
    if(common.strlen(url) > maxUrl) maxUrl = common.strlen(url);

    var app = apps[a];
    if(common.strlen(app.dynoman) > maxDynoMan) maxDynoMan = common.strlen(app.dynoman);
    if(common.strlen(app.port) > maxPort) maxPort = common.strlen(app.port);
    if(common.strlen(app.state) > maxState) maxState = common.strlen(app.state);
  }

  // create our table
  df.table = new Table({
    head: ['App', 'Url', 'DynoMan', 'Port', 'State'],
    colWidths: [maxApp+2 , maxUrl+2, maxDynoMan+2, maxPort+2, maxState+2],
    style: common.style()
  });

  // populate our table
  for (var a in apps) {
    var url = getAppUrl(a);
    var app = apps[a];
    df.table.push([a, url, app.dynoman, app.port, app.state]);
  }
}

// DynoFarm apps
function apps (cb) {
  request(getDynoFarmUrl() + "apps", function (err, response, body) {
    if (err) return cb(nullToUndefined(err));
    var apps;
    try{
      apps = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing apps: " + util.inspect(x));
    }

    if(ini.get('table') === true) {
      createTableForApps(apps);
    }

    return cb(undefined, apps);
  });
};

// DynoFarm logs
function logs(appId, cb) {
  request(getDynoFarmUrl() + "logs/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Stop app
function stop(appId, cb) {
  request(getDynoFarmUrl() + "stop/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Start app
function start(appId, cb) {
  request(getDynoFarmUrl() + "start/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Given an app id, returns its DynoFarm endpoint
function url(appId, cb) {
  var appName = common.getAppName(appId);
  var url = getAppUrl(appId);
  return cb(undefined, {name: appName, url:url});
};

function unknown (action, cb) {
  var msg = action ? "Wrong arguments for or unknown action: " + action + "\n" : "";
  msg += "Usage:\n" + df.usage;
  cb(msg);
};

// get our DF endpoint
function getDynoFarmUrl () {
  var r = fhc.config.get("dynofarm");
  if (!r) {
    return new Error("Must define DynoFarm URLs before accessing FeedHenry DynoFarm Server.")
  }
  if (r.substr(-1) !== "/") r += "/";
  fhc.config.set("dynofarm", r);
  return r;
};

// Annoyingly, 'request' returns nulls, the rest of FHC uses undefined, so return undefined to keep
// things consistent.
function nullToUndefined(err) {
  return err == null? undefined: err;
}

// delete an app
function deleteApp(appId, cb) {
  request({url: getDynoFarmUrl() + "delete/" + appId, method: 'POST'}, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// bash completion
df.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "df") argv.unshift("df");
  if (argv.length === 2) {
    var cmds = ["apps", "logs", "start", "stop", "delete", "act", "url", "version"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    // todo: complete with valid values, if possible.
    case "apps":
    case "logs":
    case "start":
    case "delete":
    case "act":
    case "url":
    case "version":
      return cb(null, Object.keys(types));
    default: return cb(null, []);
  }
};
<|endoftext|>


<commit_before><commit_msg>Use ES6 strings for #32<commit_after><|endoftext|>


<commit_before>//Import dependencies
var fs = require('fs');
var crypto = require('crypto');
var path = require('path');

//Generate the checksum of a file
module.exports.checksum = function(file, opt, cb)
{
  //Check the options
  if(typeof opt === 'function')
  {
    //Save the new callback method
    cb = opt;

    //Initialize the options object
    opt = {};
  }

  //Check for string algorithm
  if(typeof opt === 'string'){ opt = { algorithm: opt }; }

  //Check for no object
  if(typeof opt !== 'object'){ opt = {}; }

  //Check the algorithm option
  if(typeof opt.algorithm !== 'string'){ opt.algorithm = 'md5'; }

  //Check the encoding option
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'hex'; }

  //Check if the file exists
  return fs.stat(file, function(error, stat)
  {
    //Check the error
    if(error){ return cb(error, null); }

    //Check for not a file
    if(stat.isFile() ===false){ return cb(new Error('Provided path is not a file'), null); }

    //Create the new hash
    var hash = crypto.createHash(opt.algorithm);

    //Initialize the read stream
    var reader = fs.createReadStream(file);

    //Read data from file
    reader.on('data', function(data)
    {
      //Update the hash with the new chunk of data
      hash.update(data);
    });

    //Data read end
    reader.on('end', function()
    {
      //Return the checksum fo the file
      return cb(null, hash.digest(opt.encoding));
    });

    //Error event handler
    reader.on('error', function(error)
    {
      //Do the callback with the error
      return cb(error, null);
    });
  });
};

//Copy a file
module.exports.copy = function(input, output, cb)
{
  //Check the callback method
  if(typeof cb !== 'function'){ throw new Error('No callback method provided'); }

  //Check the input file
  if(typeof input !== 'string'){ return cb(new Error('Input path must be a string')); }

  //Check the output file
  if(typeof output !== 'string'){ return cb(new Error('Output path must be a string')); }

  //Parse the input file
  input = path.resolve(process.cwd(), input);

  //Parse the output file
  output = path.resolve(process.cwd(), output);

  //Check the paths
  if(input === output){ return cb(new Error('Input and Output must not be the same.')); }

  //Create the readable stream
  var reader = fs.createReadStream(input);

  //Create the writable stream
  var writer = fs.createWriteStream(output);

  //Process is completed
  var completed = false;

  //Done method
  var done = function(error)
  {
    //Check the error
    if(typeof error === 'undefined'){ error = null; }

    //Check if process is completed
    if(completed === false)
    {
      //Destroy the streams
      writer.destroy();
      reader.destroy();

      //Set as completed
      completed = true;

      //Do the callback
      return cb(error);
    }
  };

  //Reader error
  reader.on('error', done);

  //Writer error
  writer.on('error', done);

  //Writer finish method
  writer.on('finish', done);

  //Pipe
  reader.pipe(writer);
};

//Check if a file or a directory exists
module.exports.exists = function(file, cb)
{
  //Get the status of the file
  return fs.stat(file, function(error, stats)
  {
    //Check the error
    if(error)
    {
      //Check the error code
      if(error.code !== 'ENOENT')
      {
        //Do the callback with the error
        return cb(error, false);
      }
      else
      {
        //Do the callback without error
        return cb(null, false);
      }
    }

    //Do the callback with the boolean if file exists
    return cb(null, stats.isFile() || stats.isDirectory());
  });
};

//Create a directory
module.exports.mkdir = function(folder, cb)
{
  //Check the folder
  if(typeof folder !== 'string'){ return cb(new Error('Invalid folder path')); }

  //Create the folder recursive
  var create_folder = function(dir, callback)
  {
    //Check if the folder exists
    return fs.stat(dir, function(error, stat)
    {
      //Check for no error
      if(!error)
      {
        //Check if folder exists
        if(stat.isDirectory() === true)
        {
          //Continue with the next chunk on the list
          return callback(null);
        }
        else
        {
          //Display the path exists and is a directory
          return callback(new Error('Path ' + dir + ' exists and is not a directory'));
        }
      }
      else
      {
        //Check the error code
        if(error.code === 'ENOENT')
        {
          //Check if the parent directory exists
          return create_folder(path.dirname(dir), function(err)
          {
            //Check the error
            if(err){ return callback(err); }

            //Create the directory
            return fs.mkdir(dir, callback);
          });
        }
        else
        {
          //Do the callback with the error
          return callback(error);
        }
      }
    });
  };

  //Create the folder
  return create_folder(path.resolve(folder), cb);
};

//Get the size of a file
module.exports.size = function(file, cb)
{
  //Get the status of the file
  return fs.stat(file, function(error, stats)
  {
    //Check the error
    if(error){ return cb(error, 0); }

    //Do the callback with the size of the file
    return cb(null, stats.size);
  });
};

//Remove a list of files
module.exports.unlink = function(files, cb)
{
  //Check the list of files
  if(typeof files === 'string'){ files = [ files ]; }

  //Remove file method
  var remove_file = function(index)
  {
    //Check the index
    if(index >= files.length)
    {
      //Do the callback
      return cb(null);
    }

    //Get the file to remove
    var file = files[index];

    //Remove the file
    fs.unlink(file, function(error)
    {
      //Check the error
      if(error)
      {
        //Check the error code
        if(error.code !== 'ENOENT')
        {
          //Do the callback with the error
          return cb(error);
        }
      }

      //Continue with the next file
      return remove_file(index + 1);
    });
  };

  //Remove the first file of the list
  return remove_file(0);
};
<commit_msg>lib/fs.js: added isDir and isFile methods<commit_after>//Import dependencies
var fs = require('fs');
var crypto = require('crypto');
var path = require('path');

//Generate the checksum of a file
module.exports.checksum = function(file, opt, cb)
{
  //Check the options
  if(typeof opt === 'function')
  {
    //Save the new callback method
    cb = opt;

    //Initialize the options object
    opt = {};
  }

  //Check for string algorithm
  if(typeof opt === 'string'){ opt = { algorithm: opt }; }

  //Check for no object
  if(typeof opt !== 'object'){ opt = {}; }

  //Check the algorithm option
  if(typeof opt.algorithm !== 'string'){ opt.algorithm = 'md5'; }

  //Check the encoding option
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'hex'; }

  //Check if the file exists
  return fs.stat(file, function(error, stat)
  {
    //Check the error
    if(error){ return cb(error, null); }

    //Check for not a file
    if(stat.isFile() ===false){ return cb(new Error('Provided path is not a file'), null); }

    //Create the new hash
    var hash = crypto.createHash(opt.algorithm);

    //Initialize the read stream
    var reader = fs.createReadStream(file);

    //Read data from file
    reader.on('data', function(data)
    {
      //Update the hash with the new chunk of data
      hash.update(data);
    });

    //Data read end
    reader.on('end', function()
    {
      //Return the checksum fo the file
      return cb(null, hash.digest(opt.encoding));
    });

    //Error event handler
    reader.on('error', function(error)
    {
      //Do the callback with the error
      return cb(error, null);
    });
  });
};

//Copy a file
module.exports.copy = function(input, output, cb)
{
  //Check the callback method
  if(typeof cb !== 'function'){ throw new Error('No callback method provided'); }

  //Check the input file
  if(typeof input !== 'string'){ return cb(new Error('Input path must be a string')); }

  //Check the output file
  if(typeof output !== 'string'){ return cb(new Error('Output path must be a string')); }

  //Parse the input file
  input = path.resolve(process.cwd(), input);

  //Parse the output file
  output = path.resolve(process.cwd(), output);

  //Check the paths
  if(input === output){ return cb(new Error('Input and Output must not be the same.')); }

  //Create the readable stream
  var reader = fs.createReadStream(input);

  //Create the writable stream
  var writer = fs.createWriteStream(output);

  //Process is completed
  var completed = false;

  //Done method
  var done = function(error)
  {
    //Check the error
    if(typeof error === 'undefined'){ error = null; }

    //Check if process is completed
    if(completed === false)
    {
      //Destroy the streams
      writer.destroy();
      reader.destroy();

      //Set as completed
      completed = true;

      //Do the callback
      return cb(error);
    }
  };

  //Reader error
  reader.on('error', done);

  //Writer error
  writer.on('error', done);

  //Writer finish method
  writer.on('finish', done);

  //Pipe
  reader.pipe(writer);
};

//Check if a path exists
var fs_exists = function(p, cb)
{
  //Get the status of the path
  return fs.stat(p, function(error, stat)
  {
    //Check the error
    if(error)
    {
      //Check the error code
      if(error.code !== 'ENOENT')
      {
        //Do the callback with the error
        return cb(error, false, stat);
      }
      else
      {
        //Do the callback without error
        return cb(null, false, stat);
      }
    }

    //Do the callback with the stat
    return cb(null, true, stat);
  });
};

//Exports the exists method
module.exports.exists = fs_exists;

//Check if a path is a directory
module.exports.isDir = function(p, cb)
{
  //Check the callback method
  if(typeof cb !== 'function'){ throw new Error('No callback function provided'); }

  //Check if exists
  return fs_exists(p, function(error, exists, stat)
  {
    //Check the error
    if(error || exists === false){ return cb(error, exists); }

    //Check if path is a directory
    return cb(null, stat.isDirectory());
  });
};

//Check if a path is a file
module.exports.isFile = function(p, cb)
{
  //Check the callback method
  if(typeof cb !== 'function'){ throw new Error('No callback function provided'); }

  //Check if exists
  return fs_exists(p, function(error, exists, stat)
  {
    //Check the error
    if(error || exists === false){ return cb(error, exists); }

    //Check if path is a file
    return cb(null, stat.isFile());
  });
};

//Create a directory
module.exports.mkdir = function(folder, cb)
{
  //Check the folder
  if(typeof folder !== 'string'){ return cb(new Error('Invalid folder path')); }

  //Create the folder recursive
  var create_folder = function(dir, callback)
  {
    //Check if the folder exists
    return fs.stat(dir, function(error, stat)
    {
      //Check for no error
      if(!error)
      {
        //Check if folder exists
        if(stat.isDirectory() === true)
        {
          //Continue with the next chunk on the list
          return callback(null);
        }
        else
        {
          //Display the path exists and is a directory
          return callback(new Error('Path ' + dir + ' exists and is not a directory'));
        }
      }
      else
      {
        //Check the error code
        if(error.code === 'ENOENT')
        {
          //Check if the parent directory exists
          return create_folder(path.dirname(dir), function(err)
          {
            //Check the error
            if(err){ return callback(err); }

            //Create the directory
            return fs.mkdir(dir, callback);
          });
        }
        else
        {
          //Do the callback with the error
          return callback(error);
        }
      }
    });
  };

  //Create the folder
  return create_folder(path.resolve(folder), cb);
};

//Get the size of a file
module.exports.size = function(file, cb)
{
  //Get the status of the file
  return fs.stat(file, function(error, stats)
  {
    //Check the error
    if(error){ return cb(error, 0); }

    //Do the callback with the size of the file
    return cb(null, stats.size);
  });
};

//Remove a list of files
module.exports.unlink = function(files, cb)
{
  //Check the list of files
  if(typeof files === 'string'){ files = [ files ]; }

  //Remove file method
  var remove_file = function(index)
  {
    //Check the index
    if(index >= files.length)
    {
      //Do the callback
      return cb(null);
    }

    //Get the file to remove
    var file = files[index];

    //Remove the file
    fs.unlink(file, function(error)
    {
      //Check the error
      if(error)
      {
        //Check the error code
        if(error.code !== 'ENOENT')
        {
          //Do the callback with the error
          return cb(error);
        }
      }

      //Continue with the next file
      return remove_file(index + 1);
    });
  };

  //Remove the first file of the list
  return remove_file(0);
};
<|endoftext|>


<commit_before><commit_msg>56025 - fix for crossdomain logo image<commit_after><|endoftext|>


<commit_before>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

/**
 * @fileOverview Module containing file I/O helpers.
 */

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");

let {TimeLine} = require("timeline");

let IO = exports.IO =
{
  /**
   * Retrieves the platform-dependent line break string.
   */
  get lineBreak()
  {
    let lineBreak = (Services.appinfo.OS == "WINNT" ? "\r\n" : "\n");
    delete IO.lineBreak;
    IO.__defineGetter__("lineBreak", function() lineBreak);
    return IO.lineBreak;
  },

  /**
   * Tries to interpret a file path as an absolute path or a path relative to
   * user's profile. Returns a file or null on failure.
   */
  resolveFilePath: function(/**String*/ path) /**nsIFile*/
  {
    if (!path)
      return null;

    try {
      // Assume an absolute path first
      return new FileUtils.File(path);
    } catch (e) {}

    try {
      // Try relative path now
      return FileUtils.getFile("ProfD", path.split("/"));
    } catch (e) {}

    return null;
  },

  /**
   * Reads strings from a file asynchronously, calls listener.process() with
   * each line read and with a null parameter once the read operation is done.
   * The callback will be called when the operation is done.
   */
  readFromFile: function(/**nsIFile|nsIURI*/ file, /**Boolean*/ decode, /**Object*/ listener, /**Function*/ callback, /**String*/ timeLineID)
  {
    try
    {
      let processing = false;
      let buffer = "";
      let loadEvent = null;
      let errorEvent = null;
      let uri = file instanceof Ci.nsIFile ? Services.io.newFileURI(file) : file;
      let request = new XMLHttpRequest();
      request.mozBackgroundRequest = true;
      request.open("GET", uri.spec);
      request.responseType = "moz-chunked-text";
      request.overrideMimeType("text/plain" + (decode ? "? charset=utf-8" : ""));

      let onProgress = function(event)
      {
        if (timeLineID)
        {
          TimeLine.asyncStart(timeLineID);
        }

        let data = event.target.response;
        let index = (processing ? -1 : Math.max(data.lastIndexOf("\n"), data.lastIndexOf("\r")));
        if (index >= 0)
        {
          // Protect against reentrance in case the listener processes events.
          processing = true;
          try
          {
            let oldBuffer = buffer;
            buffer = data.substr(index + 1);
            data = data.substr(0, index + 1);
            let lines = data.split(/[\r\n]+/);
            lines.pop();
            lines[0] = oldBuffer + lines[0];
            for (let i = 0; i < lines.length; i++)
              listener.process(lines[i]);
          }
          finally
          {
            processing = false;
            let e = {
              target: {response: buffer}
            };
            buffer = "";
            onProgress(e);

            if (loadEvent)
            {
              let event = loadEvent;
              loadEvent = null;
              onLoad(event);
            }

            if (errorEvent)
            {
              let event = errorEvent;
              errorEvent = null;
              onError(event);
            }
          }
        }
        else
          buffer += data;

        if (timeLineID)
        {
          TimeLine.asyncEnd(timeLineID);
        }
      };

      let onLoad = function(event)
      {
        if (processing)
        {
          // Still processing data, delay processing this event.
          loadEvent = event;
          return;
        }

        if (timeLineID)
        {
          TimeLine.asyncStart(timeLineID);
        }

        if (buffer !== "")
        listener.process(buffer);
        listener.process(null);

          if (timeLineID)
        {
          TimeLine.asyncEnd(timeLineID);
          TimeLine.asyncDone(timeLineID);
        }

        callback(null);
      };

      let onError = function(event)
      {
        if (processing)
        {
          // Still processing data, delay processing this event.
          errorEvent = event;
          return;
        }

        let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
        e.initialize("File read operation failed", result, null, Components.stack, file, null);
        callback(e);

        if (timeLineID)
        {
          TimeLine.asyncDone(timeLineID);
        }
      };

      request.addEventListener("progress", onProgress, false);
      request.addEventListener("load", onLoad, false);
      request.addEventListener("error", onError, false);
      request.send(null);
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Writes string data to a file asynchronously, optionally encodes it into
   * UTF-8 first. The callback will be called when the write operation is done.
   */
  writeToFile: function(/**nsIFile*/ file, /**Boolean*/ encode, /**Iterator*/ data, /**Function*/ callback, /**String*/ timeLineID)
  {
    try
    {
      let fileStream = FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);

      let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
      pipe.init(true, true, 0, 0x8000, null);

      let outStream = pipe.outputStream;
      if (encode)
      {
        outStream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
        outStream.init(pipe.outputStream, "UTF-8", 0, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
      }

      let copier = Cc["@mozilla.org/network/async-stream-copier;1"].createInstance(Ci.nsIAsyncStreamCopier);
      copier.init(pipe.inputStream, fileStream, null, true, false, 0x8000, true, true);
      copier.asyncCopy({
        onStartRequest: function(request, context) {},
        onStopRequest: function(request, context, result)
        {
          if (timeLineID)
          {
            TimeLine.asyncDone(timeLineID);
          }

          if (!Components.isSuccessCode(result))
          {
            let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
            e.initialize("File write operation failed", result, null, Components.stack, file, null);
            callback(e);
          }
          else
            callback(null);
        }
      }, null);

      let lineBreak = this.lineBreak;
      let writeNextChunk = function()
      {
        let buf = [];
        let bufLen = 0;
        while (bufLen < 0x4000)
        {
          try
          {
            let str = data.next();
            buf.push(str);
            bufLen += str.length;
          }
          catch (e)
          {
            if (e instanceof StopIteration)
              break;
            else if (typeof e == "number")
              pipe.outputStream.closeWithStatus(e);
            else if (e instanceof Ci.nsIException)
              pipe.outputStream.closeWithStatus(e.result);
            else
            {
              Cu.reportError(e);
              pipe.outputStream.closeWithStatus(Cr.NS_ERROR_FAILURE);
            }
            return;
          }
        }

        pipe.outputStream.asyncWait({
          onOutputStreamReady: function()
          {
            if (timeLineID)
            {
              TimeLine.asyncStart(timeLineID);
            }

            if (buf.length)
            {
              let str = buf.join(lineBreak) + lineBreak;
              if (encode)
                outStream.writeString(str);
              else
                outStream.write(str, str.length);
              writeNextChunk();
            }
            else
              outStream.close();

            if (timeLineID)
            {
              TimeLine.asyncEnd(timeLineID);
            }
          }
        }, 0, 0, Services.tm.currentThread);
      };
      writeNextChunk();
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Copies a file asynchronously. The callback will be called when the copy
   * operation is done.
   */
  copyFile: function(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback)
  {
    try
    {
      let inStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
      inStream.init(fromFile, FileUtils.MODE_RDONLY, 0, Ci.nsIFileInputStream.DEFER_OPEN);

      let outStream = FileUtils.openFileOutputStream(toFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);

      NetUtil.asyncCopy(inStream, outStream, function(result)
      {
        if (!Components.isSuccessCode(result))
        {
          let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
          e.initialize("File write operation failed", result, null, Components.stack, file, null);
          callback(e);
        }
        else
          callback(null);
      });
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Renames a file within the same directory, will call callback when done.
   */
  renameFile: function(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback)
  {
    try
    {
      fromFile.moveTo(null, newName);
      callback(null);
    }
    catch(e)
    {
      callback(e);
    }
  },

  /**
   * Removes a file, will call callback when done.
   */
  removeFile: function(/**nsIFile*/ file, /**Function*/ callback)
  {
    try
    {
      file.remove(false);
      callback(null);
    }
    catch(e)
    {
      callback(e);
    }
      },

  /**
   * Gets file information such as whether the file exists.
   */
  statFile: function(/**nsIFile*/ file, /**Function*/ callback)
  {
    try
    {
      let exists = file.exists();
      callback(null, {
        exists: exists,
        isDirectory: exists && file.isDirectory(),
        isFile: exists && file.isFile(),
        lastModified: exists ? file.lastModifiedTime : 0
      });
    }
    catch(e)
    {
      callback(e);
    }
  }
}
<commit_msg>Fixed: patterns.ini contents are being processed multiple timesIssue: https://issues.adblockplus.org/ticket/152 https://hg.adblockplus.org/adblockplus/rev/a6027547d626 Author:wladimir Palant<commit_after>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

/**
 * @fileOverview Module containing file I/O helpers.
 */

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");

let {TimeLine} = require("timeline");
let {Utils} = require("utils");

let IO = exports.IO =
{
  /**
   * Retrieves the platform-dependent line break string.
   */
  get lineBreak()
  {
    let lineBreak = (Services.appinfo.OS == "WINNT" ? "\r\n" : "\n");
    delete IO.lineBreak;
    IO.__defineGetter__("lineBreak", function() lineBreak);
    return IO.lineBreak;
  },

  /**
   * Tries to interpret a file path as an absolute path or a path relative to
   * user's profile. Returns a file or null on failure.
   */
  resolveFilePath: function(/**String*/ path) /**nsIFile*/
  {
    if (!path)
      return null;

    try {
      // Assume an absolute path first
      return new FileUtils.File(path);
    } catch (e) {}

    try {
      // Try relative path now
      return FileUtils.getFile("ProfD", path.split("/"));
    } catch (e) {}

    return null;
  },

  /**
   * Reads strings from a file asynchronously, calls listener.process() with
   * each line read and with a null parameter once the read operation is done.
   * The callback will be called when the operation is done.
   */
  readFromFile: function(/**nsIFile|nsIURI*/ file, /**Boolean*/ decode, /**Object*/ listener, /**Function*/ callback, /**String*/ timeLineID)
  {
    try
    {
      let processing = false;
      let buffer = "";
      let loaded = false;
      let error = Cr.NS_OK;
      let uri = file instanceof Ci.nsIFile ? Services.io.newFileURI(file) : file;
      let request = new XMLHttpRequest();
      request.mozBackgroundRequest = true;
      request.open("GET", uri.spec);
      request.responseType = "moz-chunked-text";
      request.overrideMimeType("text/plain" + (decode ? "? charset=utf-8" : ""));

      let onProgress = function(data)
      {
        if (timeLineID)
        {
          TimeLine.asyncStart(timeLineID);
        }

        let index = (processing ? -1 : Math.max(data.lastIndexOf("\n"), data.lastIndexOf("\r")));
        if (index >= 0)
        {
          // Protect against reentrance in case the listener processes events.
          processing = true;
          try
          {
            let oldBuffer = buffer;
            buffer = data.substr(index + 1);
            data = data.substr(0, index + 1);
            let lines = data.split(/[\r\n]+/);
            lines.pop();
            lines[0] = oldBuffer + lines[0];
            for (let i = 0; i < lines.length; i++)
              listener.process(lines[i]);
          }
          finally
          {
            processing = false;
            data = buffer;
            buffer = "";
            onProgress(data);

            if (loaded)
            {
              loaded = false;
              onLoad();
            }

            if (error != Cr.NS_OK)
            {
              let param = error;
              error = Cr.NS_OK;
              onError(param);
            }
          }
        }
        else
          buffer += data;

        if (timeLineID)
        {
          TimeLine.asyncEnd(timeLineID);
        }
      };

      let onLoad = function()
      {
        if (processing)
        {
          // Still processing data, delay processing this event.
          loaded = true;
          return;
        }

        if (timeLineID)
        {
          TimeLine.asyncStart(timeLineID);
        }

        if (buffer !== "")
        listener.process(buffer);
        listener.process(null);

          if (timeLineID)
        {
          TimeLine.asyncEnd(timeLineID);
          TimeLine.asyncDone(timeLineID);
        }

        callback(null);
      };

      let onError = function(status)
      {
        if (processing)
        {
          // Still processing data, delay processing this event.
          error = status;
          return;
        }

        let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
        e.initialize("File read operation failed", status, null, Components.stack, file, null);
        callback(e);

        if (timeLineID)
        {
          TimeLine.asyncDone(timeLineID);
        }
      };

      request.addEventListener("progress", function(event)
      {
        Utils.runAsync(onProgress.bind(this, event.target.response));
      }, false);
      request.addEventListener("load", function(event)
      {
        Utils.runAsync(onLoad.bind(this));
      }, false);
      request.addEventListener("error", function(event)
      {
        Utils.runAsync(onError.bind(this, event.target.channel.status));
      }, false);

      request.send(null);
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Writes string data to a file asynchronously, optionally encodes it into
   * UTF-8 first. The callback will be called when the write operation is done.
   */
  writeToFile: function(/**nsIFile*/ file, /**Boolean*/ encode, /**Iterator*/ data, /**Function*/ callback, /**String*/ timeLineID)
  {
    try
    {
      let fileStream = FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);

      let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
      pipe.init(true, true, 0, 0x8000, null);

      let outStream = pipe.outputStream;
      if (encode)
      {
        outStream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
        outStream.init(pipe.outputStream, "UTF-8", 0, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
      }

      let copier = Cc["@mozilla.org/network/async-stream-copier;1"].createInstance(Ci.nsIAsyncStreamCopier);
      copier.init(pipe.inputStream, fileStream, null, true, false, 0x8000, true, true);
      copier.asyncCopy({
        onStartRequest: function(request, context) {},
        onStopRequest: function(request, context, result)
        {
          if (timeLineID)
          {
            TimeLine.asyncDone(timeLineID);
          }

          if (!Components.isSuccessCode(result))
          {
            let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
            e.initialize("File write operation failed", result, null, Components.stack, file, null);
            callback(e);
          }
          else
            callback(null);
        }
      }, null);

      let lineBreak = this.lineBreak;
      let writeNextChunk = function()
      {
        let buf = [];
        let bufLen = 0;
        while (bufLen < 0x4000)
        {
          try
          {
            let str = data.next();
            buf.push(str);
            bufLen += str.length;
          }
          catch (e)
          {
            if (e instanceof StopIteration)
              break;
            else if (typeof e == "number")
              pipe.outputStream.closeWithStatus(e);
            else if (e instanceof Ci.nsIException)
              pipe.outputStream.closeWithStatus(e.result);
            else
            {
              Cu.reportError(e);
              pipe.outputStream.closeWithStatus(Cr.NS_ERROR_FAILURE);
            }
            return;
          }
        }

        pipe.outputStream.asyncWait({
          onOutputStreamReady: function()
          {
            if (timeLineID)
            {
              TimeLine.asyncStart(timeLineID);
            }

            if (buf.length)
            {
              let str = buf.join(lineBreak) + lineBreak;
              if (encode)
                outStream.writeString(str);
              else
                outStream.write(str, str.length);
              writeNextChunk();
            }
            else
              outStream.close();

            if (timeLineID)
            {
              TimeLine.asyncEnd(timeLineID);
            }
          }
        }, 0, 0, Services.tm.currentThread);
      };
      writeNextChunk();
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Copies a file asynchronously. The callback will be called when the copy
   * operation is done.
   */
  copyFile: function(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback)
  {
    try
    {
      let inStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
      inStream.init(fromFile, FileUtils.MODE_RDONLY, 0, Ci.nsIFileInputStream.DEFER_OPEN);

      let outStream = FileUtils.openFileOutputStream(toFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);

      NetUtil.asyncCopy(inStream, outStream, function(result)
      {
        if (!Components.isSuccessCode(result))
        {
          let e = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(Ci.nsIXPCException);
          e.initialize("File write operation failed", result, null, Components.stack, file, null);
          callback(e);
        }
        else
          callback(null);
      });
    }
    catch (e)
    {
      callback(e);
    }
  },

  /**
   * Renames a file within the same directory, will call callback when done.
   */
  renameFile: function(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback)
  {
    try
    {
      fromFile.moveTo(null, newName);
      callback(null);
    }
    catch(e)
    {
      callback(e);
    }
  },

  /**
   * Removes a file, will call callback when done.
   */
  removeFile: function(/**nsIFile*/ file, /**Function*/ callback)
  {
    try
    {
      file.remove(false);
      callback(null);
    }
    catch(e)
    {
      callback(e);
    }
      },

  /**
   * Gets file information such as whether the file exists.
   */
  statFile: function(/**nsIFile*/ file, /**Function*/ callback)
  {
    try
    {
      let exists = file.exists();
      callback(null, {
        exists: exists,
        isDirectory: exists && file.isDirectory(),
        isFile: exists && file.isFile(),
        lastModified: exists ? file.lastModifiedTime : 0
      });
    }
    catch(e)
    {
      callback(e);
    }
  }
}
<|endoftext|>


<commit_before>const daggy = require('daggy')
const Task = require('data.task')
const $ = require('./types')

const _IO = daggy.tagged('interpret')

const IO = $.def(
  'IO',
  {},
  [$.Function, $.$IO($.a)],
  function (interpret) {
    const _interpret = $.def(
      'interpret',
      {},
      [$.Function, $.$Task($.a)],
      interpret
    )
    return new _IO(_interpret)
  }
)

IO.of = function of (x) {
  return new _IO(
    (interpreter) => Task.of(x)
  )
}

IO.error = function error (x) {
  return new _IO(
    (interpreter) => Task.rejected(x)
  )
}

_IO.prototype['@@type'] = 'future-io/IO'

_IO.prototype.chain = method($.def(
  'IO#chain',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function chain (io, g) {
    const _g = $.def(
      'f in IO#chain(f)',
      {},
      [$.a, $.$IO($.b)],
      g
    )
    return new _IO(
      (interpreter) => io.interpret(interpreter).chain(
        (x) => _g(x).interpret(interpreter)
      )
    )
  }
))

_IO.prototype.ap = method($.def(
  'IO#ap',
  {},
  [$.$IO($.Function), $.$IO($.a), $.$IO($.b)],
  function ap (io, m) {
    return io.chain((f) => m.map(f))
  }
))

_IO.prototype.map = method($.def(
  'IO#map',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function map (io, f) {
    return io.chain((x) => IO.of(f(x)))
  }
))

_IO.prototype.catch = method($.def(
  'IO#catch',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function _catch (io, g) {
    const _g = $.def(
      'f in IO#catch(f)',
      {},
      [$.a, $.$IO($.b)],
      g
    )
    return new _IO(
      (interpreter) => io.interpret(interpreter).orElse(
        (x) => _g(x).interpret(interpreter)
      )
    )
  }
))

_IO.prototype.run = method($.def(
  'IO#run',
  {},
  [$.$IO($.a), $.Function, $.Undefined],
  function run (io, interpreter) {
    const _interpreter = $.def(
      'interpreter',
      {},
      [$.String, $.Function, $.Array($.Any), $.$Task($.a)],
      interpreter
    )
    const noop = () => {}
    // When encountering an error, throw it outside of all contexts.
    const onIoError = (err) => setImmediate(() => { throw err })
    io.interpret(_interpreter).fork(onIoError, noop)
  }
))

// Create a `method` by taking an ordinary function and pre-applying `this` as its first agument.
function method (f) {
  return function () {
    const args = [this].concat(Array.prototype.slice.call(arguments))
    return f.apply(null, args)
  }
}

module.exports = IO
<commit_msg>Add `toString` and `inspect` methods.<commit_after>const daggy = require('daggy')
const Task = require('data.task')
const $ = require('./types')

const _IO = daggy.tagged('interpret')

const IO = $.def(
  'IO',
  {},
  [$.Function, $.$IO($.a)],
  function (interpret) {
    const _interpret = $.def(
      'interpret',
      {},
      [$.Function, $.$Task($.a)],
      interpret
    )
    return new _IO(_interpret)
  }
)

IO.of = function of (x) {
  return new _IO(
    (interpreter) => Task.of(x)
  )
}

IO.error = function error (x) {
  return new _IO(
    (interpreter) => Task.rejected(x)
  )
}

_IO.prototype['@@type'] = 'future-io/IO'

_IO.prototype.toString = () => 'IO'
_IO.prototype.inspect = () => 'IO'

_IO.prototype.chain = method($.def(
  'IO#chain',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function chain (io, g) {
    const _g = $.def(
      'f in IO#chain(f)',
      {},
      [$.a, $.$IO($.b)],
      g
    )
    return new _IO(
      (interpreter) => io.interpret(interpreter).chain(
        (x) => _g(x).interpret(interpreter)
      )
    )
  }
))

_IO.prototype.ap = method($.def(
  'IO#ap',
  {},
  [$.$IO($.Function), $.$IO($.a), $.$IO($.b)],
  function ap (io, m) {
    return io.chain((f) => m.map(f))
  }
))

_IO.prototype.map = method($.def(
  'IO#map',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function map (io, f) {
    return io.chain((x) => IO.of(f(x)))
  }
))

_IO.prototype.catch = method($.def(
  'IO#catch',
  {},
  [$.$IO($.a), $.Function, $.$IO($.b)],
  function _catch (io, g) {
    const _g = $.def(
      'f in IO#catch(f)',
      {},
      [$.a, $.$IO($.b)],
      g
    )
    return new _IO(
      (interpreter) => io.interpret(interpreter).orElse(
        (x) => _g(x).interpret(interpreter)
      )
    )
  }
))

_IO.prototype.run = method($.def(
  'IO#run',
  {},
  [$.$IO($.a), $.Function, $.Undefined],
  function run (io, interpreter) {
    const _interpreter = $.def(
      'interpreter',
      {},
      [$.String, $.Function, $.Array($.Any), $.$Task($.a)],
      interpreter
    )
    const noop = () => {}
    // When encountering an error, throw it outside of all contexts.
    const onIoError = (err) => setImmediate(() => { throw err })
    io.interpret(_interpreter).fork(onIoError, noop)
  }
))

// Create a `method` by taking an ordinary function and pre-applying `this` as its first agument.
function method (f) {
  return function () {
    const args = [this].concat(Array.prototype.slice.call(arguments))
    return f.apply(null, args)
  }
}

module.exports = IO
<|endoftext|>