text:
var hash = require('./lib/hash')
var messages = require('./lib/messages')
var ReadStream = require('./lib/read-stream')
var WriteStream = require('./lib/write-stream')
var AppendStream = require('./lib/append-stream')
var DiffStream = require('./lib/diff-stream')
var MatchStream = require('./lib/match-stream')
var lexint = require('lexicographic-integer')
var thunky = require('thunky')
var varint = require('varint')
var ids = require('numeric-id-map')
var debug = require('debug')('hypergraph')

module.exports = DAG

function DAG (db) {
  if (!(this instanceof DAG)) return new DAG(db)

  this.db = db
  this.paths = []
  this.flushedPaths = []
  this.headPaths = []
  this.inserting = ids()

  this.ready = thunky(init.bind(null, this))
}

DAG.prototype.count = function (opts, cb) {
  if (typeof opts === 'function') return this.count(null, opts)
  if (!opts) opts = {}

  this._range(opts, function (err, since, until) {
    if (err) return cb(err)
    var sum = 0
    for (var i = 0; i < until.length; i++) {
      if (i >= since.length) sum += until[i]
      else if (until[i] > since[i]) sum += until[i] - since[i]
    }
    process.nextTick(function () {
      cb(null, sum)
    })
  })
}

DAG.prototype.close = function (cb) {
  this.db.close(cb)
}

DAG.prototype.createDiffStream = function (opts) {
  return new DiffStream(this, opts)
}

DAG.prototype.createMatchStream = function (opts) {
  return new MatchStream(this, opts)
}

DAG.prototype.match = function (hashes, cb) {
  var matches = []
  var missing = hashes.length
  var error = null

  for (var i = 0; i < hashes.length; i++) this.get(hashes[i], check(i))

  function check (i) {
    return function (err, node) {
      if (err && !err.notFound) error = err
      if (node) matches.push(i)
      if (--missing) return
      if (error) cb(error)
      else cb(null, matches)
    }
  }
}

DAG.prototype.heads = function (cb) {
  var self = this
  this.ready(function (err) {
    if (err) return cb(err)

    // if there are no heads
    if (!self.headPaths.length) return cb(null, [])

    var error = null
    var missing = 0
    var nodes = []

    for (var i = 0; i < self.headPaths.length; i++) {
      if (!self.headPaths[i]) continue
      push(i, self.headPaths[i])
    }

    function push (path, seq) {
      missing++
      getPathNode(self, path, seq, function (err, node) {
        if (err) error = err
        else nodes.push(node)
        if (--missing) return
        if (error) return cb(error)
        var heads = nodes.sort(compareNodes)
        debug('heads', heads)
        cb(null, heads)
      })
    }
  })
}

DAG.prototype.createReadStream = function (opts) {
  return new ReadStream(this, opts)
}

DAG.prototype.createWriteStream = function (opts) {
  return new WriteStream(this, opts)
}

DAG.prototype.createAppendStream = function (opts) {
  return new AppendStream(this, opts)
}

DAG.prototype.get = function (key, cb) {
  debug('get', key)
  this.db.get('!nodes!' + key.toString('hex'), {valueEncoding: messages.Node}, cb)
}

// TODO we should check that value is a valid value and throw
DAG.prototype.append = function (value, cb) {
  var self = this
  this.heads(function (err, links) {
    if (err) return cb(err)
    self.add(links, value, cb)
  })
}

DAG.prototype.add = function (links, value, cb) {
  if (!links) links = []
  if (!cb) cb = noop

  var self = this
  var node = {
    key: null,
    links: links.map(toKey),
    value: value,
    sort: 0,
    path: 0,
    seq: 0
  }

  node.key = hash(node)

  var key = node.key.toString('hex')
  var id = 0

  this.ready(function ready (err) {
    if (err) return cb(err)
    getNodes(self, node.links, function (err, links) {
      if (err) return cb(err)

      // fast track - if a link was a head we know this is a new node
      if (containsHead(self, links)) insertNode(null, null)
      else self.get(node.key, insertNode)

      function insertNode (_, prev) {
        if (prev) return cb(null, prev)

        // the following if detects if we insert the EXCACT same node twice before flushing
        // and retries in 100ms if that happens (probably not very likely).
        // a simple hash map seemed to consume a lot of cpu hence the array based solution
        if (self.inserting.list.indexOf(key) > -1) return setTimeout(ready, 100)
        id = self.inserting.add(key)

        updateNode(self, node, links, function (err, cache) {
          if (err) return done(err)
          self.db.batch(createBatch(key, node, cache), done)
        })
      }

      function done (err) {
        if (err) { // on batch error reset our path
          if (node.seq) self.paths[node.path]--
          self.inserting.remove(id)
          return cb(err)
        }

        // update flushed caches
        for (var i = 0; i < links.length; i++) {
          var link = links[i]
          if (self.headPaths[link.path] === link.seq) self.headPaths[link.path] = 0
        }
        insert(self.headPaths, node.path, node.seq)
        insert(self.flushedPaths, node.path, node.seq)

        self.inserting.remove(id)
        cb(null, node)
      }
    })
  })
}

DAG.prototype._range = function (opts, cb) {
  if (typeof opts === 'function') return this._range(null, opts)
  if (!opts) opts = {}

  var self = this
  var since = opts.since || []
  var until = opts.until || []

  this.ready(function (err) {
    if (err) return cb(err)
    if (!since.length && !until.length) return cb(null, [], self.flushedPaths)

    var error = null
    var missing = since.length + until.length
    var untilPaths = []
    var sincePaths = []

    for (var i = 0; i < since.length; i++) self.get(toKey(since[i]), addSince)
    for (var j = 0; j < until.length; j++) self.get(toKey(until[j]), addUntil)

    function addSince (err, node) {
      if (err) return cb(err)
      addPaths(self, node, sincePaths, check)
    }

    function addUntil (err, node) {
      if (err) return cb(err)
      addPaths(self, node, untilPaths, check)
    }

    function check (err) {
      if (err) error = err
      if (--missing) return
      if (error) cb(error)
      else cb(null, sincePaths, untilPaths.length ? untilPaths : self.flushedPaths)
    }
  })
}

DAG.prototype._heads = function (key, cb) {
  var self = this
  var links = []

  this.get(key, function (err, node) {
    if (err) return cb(err)
    addPaths(self, node, links, function (err) {
      if (err) return cb(err)
      cb(null, links)
    })
  })
}

function compareNodes (a, b) {
  var len = Math.min(a.key.length, b.key.length) // future proofing
  for (var i = 0; i < len; i++) {
    if (a.key[i] === b.key[i]) continue
    return a.key[i] - b.key[i]
  }
  return a.key.length - b.key.length
}

function updateNode (dag, node, links, cb) {
  for (var j = 0; j < links.length; j++) {
    // its very unlikely that this if will fire but it's here to prevent the head cache being messed up
    if (dag.flushedPaths[node.path] < node.seq) return cb(new Error('Linked node is not flushed'))
    node.sort = Math.max(node.sort, links[j].sort + 1)
  }

  if (links.length === 1 && dag.paths[links[0].path] === links[0].seq) {
    // fast track - the single previous linked path was a head
    node.path = links[0].path
    node.seq = ++dag.paths[node.path]
    return cb(null, null)
  }
  if (!links.length) {
    // no links - create a new path
    node.path = dag.paths.length
    node.seq = 1
    dag.paths[node.path] = node.seq
    return cb(null, null)
  }

  // slow(ish) track - do a path cache lookup
  updateNodeFromCache(dag, node, links, cb)
}

function updateNodeFromCache (dag, node, links, cb) {
  getPaths(dag, links, function (err, paths) {
    if (err) return cb(err)

    for (var i = 0; i < paths.length; i++) {
      if (dag.paths[i] === paths[i]) {
        // linked path is a head - use that one
        node.path = i
        node.seq = dag.paths[i] = paths[i] + 1
        return cb(null, paths)
      }
    }

    // no linked path is a head - create a new path
    node.path = dag.paths.length
    node.seq = 1
    dag.paths[node.path] = node.seq

    cb(null, paths)
  })
}

function createBatch (key, node, cache) {
  var batch = new Array(cache ? 3 : 2)
  var offset = 0

  if (cache) {
    batch[offset++] = {
      type: 'put',
      key: '!heads!' + node.path + '!' + pack(node.seq),
      value: packArray(cache)
    }
  }

  batch[offset++] = {
    type: 'put',
    key: '!nodes!' + key,
    value: messages.Node.encode(node)
  }

  batch[offset++] = {
    type: 'put',
    key: '!paths!' + node.path + '!' + pack(node.seq),
    value: node.key
  }

  return batch
}

function init (dag, cb) {
  if (dag.db.isOpen()) run()
  else dag.db.on('open', run)

  function run (prev) {
    if (!prev) prev = '~'

    var opts = {
      gt: '!paths!',
      lt: '!paths!' + prev + '!',
      valueAsBuffer: true,
      limit: 1,
      reverse: true
    }

    var ite = dag.db.db.iterator(opts)
    ite.next(function (err, key, val) {
      ite.end(noop)
      if (err) return cb(err)
      if (!key) return addHeads(dag, dag.headPaths, done)
      dag.get(val, function (err, node) {
        if (err) return cb(err)
        addPaths(dag, node, dag.paths, function (err) {
          if (err) return cb(err)
          run(node.path.toString())
        })
      })
    })
  }

  function done (err) {
    if (err) return cb(err)
    dag.flushedPaths = dag.paths.slice(0) // copy
    cb()
  }
}

function noop () {}

function containsHead (dag, nodes) {
  for (var i = 0; i < nodes.length; i++) {
    var n = nodes[i]
    if (dag.headPaths[n.path] === n.seq) return true
  }
  return false
}

function toKey (key) {
  if (Buffer.isBuffer(key)) return key
  if (typeof key === 'string') return new Buffer(key, 'hex')
  return key.key
}

function getNodes (dag, links, cb) {
  if (!links.length) return cb(null, [])

  var nodes = new Array(links.length)
  var error = null
  var missing = nodes.length

  for (var i = 0; i < links.length; i++) dag.get(links[i], add)

  function add (err, node) {
    if (err) error = err
    nodes[--missing] = node
    if (missing) return
    if (error) cb(error)
    else cb(null, nodes)
  }
}

function addHeads (dag, heads, cb) {
  if (!dag.paths.length) return cb()

  var error = null
  var missing = dag.paths.length

  for (var i = 0; i < dag.paths.length; i++) heads[i] = 1
  for (var j = 0; j < dag.paths.length; j++) checkNode(j, dag.paths[j], next)

  function next (err) {
    if (err) error = err
    if (--missing) return
    for (var i = 0; i < heads.length; i++) {
      if (heads[i]) heads[i] = dag.paths[i]
    }
    cb(error)
  }

  function checkNode (path, seq, cb) {
    var paths = []
    getPathNode(dag, path, seq, function (err, node) {
      if (err) return cb(err)
      addPaths(dag, node, paths, function (err) {
        if (err) return cb(err)
        for (var i = 0; i < paths.length; i++) {
          if (paths[i] === dag.paths[i] && path !== i) heads[i] = 0
        }
        cb()
      })
    })
  }
}

function getPathNode (dag, path, seq, cb) {
  dag.db.get('!paths!' + path + '!' + pack(seq), {valueEncoding: 'binary'}, function (err, key) {
    if (err) return cb(err)
    dag.get(key, cb)
  })
}

function getPaths (dag, nodes, cb) {
  if (!nodes.length) return cb(null, [])

  var paths = []
  var missing = nodes.length
  var error = null

  for (var i = 0; i < nodes.length; i++) addPaths(dag, nodes[i], paths, next)

  function next (err) {
    if (err) error = err
    if (--missing) return
    if (error) cb(error)
    else cb(null, paths)
  }
}

function addPaths (dag, node, paths, cb) {
  var prefix = '!heads!' + node.path + '!'
  var opts = {
    gt: prefix,
    lte: prefix + pack(node.seq),
    valueAsBuffer: true,
    limit: 1,
    reverse: true
  }

  insert(paths, node.path, node.seq)

  var ite = dag.db.db.iterator(opts)
  ite.next(function (err, key, val) {
    ite.end(noop)

    if (err) return cb(err)
    if (!val) return cb(null)

    var prev = unpackArray(val)
    for (var i = 0; i < prev.length; i++) insert(paths, i, prev[i])

    cb(null)
  })
}

function insert (paths, id, seq) {
  for (var i = paths.length; i <= id; i++) paths[i] = 0 // TODO needs comment
  paths[id] = Math.max(seq, paths[id])
}

function unpackArray (buf) {
  var offset = 0
  var arr = []
  while (offset < buf.length) {
    arr.push(varint.decode(buf, offset))
    offset += varint.decode.bytes
  }
  return arr
}

function packArray (arr) {
  var size = 0
  var offset = 0
  for (var i = 0; i < arr.length; i++) {
    size += varint.encodingLength(arr[i])
  }
  var buf = new Buffer(size)
  for (var j = 0; j < arr.length; j++) {
    varint.encode(arr[j], buf, offset)
    offset += varint.encode.bytes
  }
  return buf
}

function pack (i) {
  return lexint.pack(i, 'hex')
}


text:
(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as anonymous module.
    define('formcache', ['jquery'], factory);
  } else {
    // Browser globals.
    factory(jQuery);
  }
})(function ($) {

  'use strict';

  var $window = $(window),
      sessionStorage = window.sessionStorage,
      localStorage = window.localStorage,

      // Constants
      STRING_UNDEFINED = 'undefined',
      FORMCACHE_NAMESPACE = '.formcache',

      // Patterns
      REGEXP_CHARACTERS = /[\.\*\+\^\$\:\!\[\]#>~]+/g,

      // Events
      EVENT_CHANGE = 'change' + FORMCACHE_NAMESPACE,
      EVENT_BEFOREUNLOAD = 'beforeunload' + FORMCACHE_NAMESPACE,

      isCheckboxOrRadio = function (input) {
        return input.type === 'checkbox' || input.type === 'radio';
      },

      toNumber = function (n) {
        return parseInt(n, 10);
      },

      // Constructor
      FormCache = function (form, options) {
        this.form = form;
        this.$form = $(form);
        this.defaults = $.extend({}, FormCache.DEFAULTS, $.isPlainObject(options) ? options : {});
        this.init();
      };

  FormCache.prototype = {
    constructor: FormCache,

    init: function () {
      var defaults = this.defaults;

      defaults.maxAge = Math.abs(defaults.maxAge || defaults.maxage);
      defaults.autoStore = Boolean(defaults.autoStore || defaults.autostore);
      this.initKey();
      this.initStorage();
      this.caches = this.storage.caches;
      this.index = 0;
      this.activeIndex = 0;
      this.storing = null;

      if (!$.isArray(defaults.controls)) {
        defaults.controls = [];
      }

      this.$controls = this.$form.find(defaults.controls.join()).not(':file'); // Ignores file inputs

      this.addListeners();
      this.outputCache();
    },

    initKey: function () {
      var $this = this.$form,
          key = this.defaults.key || $this.data('key');

      if (!key) {
        $('form').each(function (i) {
          $(this).data('key', i);
        });

        key = $this.data('key');
      }

      this.key = (location.pathname + '#formcache-' + key);
    },

    initStorage: function () {
      var defaults = this.defaults,
          key = this.key,
          now = new Date(),
          original = {
            date: now,
            maxAge: defaults.maxAge,
            caches: []
          },
          storage;

      if (sessionStorage) {
        storage = sessionStorage.getItem(key);
      }

      if (!storage && localStorage) {
        storage = localStorage.getItem(key);
      }

      storage = typeof storage === 'string' ? JSON.parse(storage) : null;

      if ($.isPlainObject(storage)) {
        if (typeof storage.maxAge === 'number' && ((now - new Date(storage.date)) / 1000) > storage.maxAge) {
          storage = original;
          // this.clear(); // Clears expired storage
        }
      } else {
        storage = original;
      }

      this.storage = storage;
    },

    addListeners: function () {
      if (this.defaults.autoStore) {
        this.$controls.on(EVENT_CHANGE, $.proxy(this.change, this));
        $window.on(EVENT_BEFOREUNLOAD, $.proxy(this.beforeunload, this));
      }
    },

    removeListeners: function () {
      if (this.defaults.autoStore) {
        this.$controls.off(EVENT_CHANGE, this.change);
        $window.off(EVENT_BEFOREUNLOAD, this.beforeunload);
      }
    },

    change: function (e) {
      var input = e.target,
          $this = $(input),
          name = $this.attr('name'),
          value = [],
          tmpName,
          val;

      if (!name) {
        return;
      }

      tmpName = name.replace(REGEXP_CHARACTERS, ''); // Replaces unintended characters

      this.$controls.filter('[name*="' + tmpName + '"]').each(function () {
        if (isCheckboxOrRadio(input)) {
          value.push(this.checked);
        } else {
          val = $(this).val();

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

      if (value.length) {
        this.update(name, value);

        clearTimeout(this.storing);
        this.storing = setTimeout($.proxy(this.store, this), 1000);
      }
    },

    beforeunload: function () {
      this.update();
      this.store();
    },

    update: function (name, value) {
      var activeIndex = this.activeIndex || this.index,
          cache = this.getCache(activeIndex);

      if (typeof name === 'string') {
        cache[name] = value;
      } else {
        cache = this.serialize();
      }

      this.setCache(activeIndex, cache);
    },

    serialize: function () {
      var cache = {};

      this.$controls.each(function () {
        var $this = $(this),
            name = $this.attr('name'),
            value,
            val;

        if (!name) {
          return;
        }

        value = cache[name];
        value = $.isArray(value) ? value : [];

        if (isCheckboxOrRadio(this)) {
          value.push(this.checked);
        } else {
          val = $this.val();

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

        if (value.length) {
          cache[name] = value;
        }
      });

      return cache;
    },

    getCache: function (index) {
      return this.caches[(toNumber(index) || this.index)] || {};
    },

    getCaches: function () {
      return this.caches;
    },

    setCache: function (index, data) {
      if (typeof data === STRING_UNDEFINED) {
        data = index;
        index = NaN;
      }

      if ($.isPlainObject(data)) {
        index = toNumber(index) || this.index;
        this.caches[index] = data;
        this.store();
      }
    },

    setCaches: function (data) {
      if ($.isArray(data)) {
        this.caches = data;
        this.store();
      }
    },

    removeCache: function (index) {
      this.caches.splice((toNumber(index) || this.index), 1);
      this.store();
    },

    removeCaches: function () {
      this.caches = [];
      this.store();
    },

    outputCache: function (index) {
      var cache = this.getCache(index);

      if ($.isPlainObject(cache)) {

        this.activeIndex = toNumber(index) || this.index;

        // Clone a new one deeply, avoid to change the original data
        cache = $.extend(true, {}, cache);

        this.$controls.each(function () {
          var $this = $(this),
              name = $this.attr('name'),
              value,
              val;

          if (!name) {
            return;
          }

          value = cache[name];

          if ($.isArray(value) && value.length) {
            val = value.shift();

            if (isCheckboxOrRadio(this)) {
              this.checked = val;
            } else {
              $this.val(val);
            }
          }
        });
      }
    },

    store: function () {
      var storage = this.storage,
          key = this.key,
          defaults = this.defaults;

      storage.date = new Date();
      storage.maxAge = defaults.maxAge;
      storage = JSON.stringify(storage);

      if (defaults.session && sessionStorage) {
        sessionStorage.setItem(key, storage);
      }

      if (defaults.local && localStorage) {
        localStorage.setItem(key, storage);
      }
    },

    clear: function () {
      var key = this.key,
          defaults = this.defaults;

      if (defaults.session && sessionStorage) {
        sessionStorage.removeItem(key);
      }

      if (defaults.local && localStorage) {
        localStorage.removeItem(key);
      }
    },

    destroy: function () {
      this.removeListeners();
      this.$form.removeData('formcache');
    }
  };

  FormCache.DEFAULTS = {
    key: '',
    local: true,
    session: true,
    autoStore: true,
    maxAge: undefined,
    controls: [
      'select',
      'textarea',
      'input'
      // 'input[type="text"]',
      // 'input[type="password"]',
      // 'input[type="datetime"]',
      // 'input[type="checkbox"]',
      // 'input[type="radio"]',
      // 'input[type="datetime-local"]',
      // 'input[type="date"]',
      // 'input[type="month"]',
      // 'input[type="time"]',
      // 'input[type="week"]',
      // 'input[type="number"]',
      // 'input[type="email"]',
      // 'input[type="url"]',
      // 'input[type="search"]',
      // 'input[type="tel"]',
      // 'input[type="color"]'
    ]
  };

  FormCache.setDefaults = function (options) {
    $.extend(FormCache.DEFAULTS, options);
  };

  // Save the other formcache
  FormCache.other = $.fn.formcache;

  // Register as jQuery plugin
  $.fn.formcache = function (options) {
    var args = [].slice.call(arguments, 1),
        result;

    this.each(function () {
      var $this = $(this),
          data = $this.data('formcache'),
          fn;

      if (!data) {
        $this.data('formcache', (data = new FormCache(this, options)));
      }

      if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
        result = fn.apply(data, args);
      }
    });

    return typeof result !== STRING_UNDEFINED ? result : this;
  };

  $.fn.formcache.Constructor = FormCache;
  $.fn.formcache.setDefaults = FormCache.setDefaults;

  // No conflict
  $.fn.formcache.noConflict = function () {
    $.fn.formcache = FormCache.other;
    return this;
  };

  $(function () {
    $('form[data-toggle="formcache"]').formcache();
  });
});

redpajama_set_name: RedPajamaGithub


text:
using System;

namespace Orleans
{
    namespace Concurrency
    {
        /// <summary>
        /// The ReadOnly attribute is used to mark methods that do not modify the state of a grain.
        /// <para>
        /// Marking methods as ReadOnly allows the run-time system to perform a number of optimizations
        /// that may significantly improve the performance of your application.
        /// </para>
        /// </summary>
        [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
        internal sealed class ReadOnlyAttribute : Attribute
        {
        }

        /// <summary>
        /// The Reentrant attribute is used to mark grain implementation classes that allow request interleaving within a task.
        /// <para>
        /// This is an advanced feature and should not be used unless the implications are fully understood.
        /// That said, allowing request interleaving allows the run-time system to perform a number of optimizations
        /// that may significantly improve the performance of your application.
        /// </para>
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public sealed class ReentrantAttribute : Attribute
        {
        }

        /// <summary>
        /// The Unordered attribute is used to mark grain interface in which the delivery order of
        /// messages is not significant.
        /// </summary>
        [AttributeUsage(AttributeTargets.Interface)]
        public sealed class UnorderedAttribute : Attribute
        {
        }

        /// <summary>
        /// The StatelessWorker attribute is used to mark grain class in which there is no expectation
        /// of preservation of grain state between requests and where multiple activations of the same grain are allowed to be created by the runtime.
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public sealed class StatelessWorkerAttribute : Attribute
        {
        }

        /// <summary>
        /// The AlwaysInterleaveAttribute attribute is used to mark methods that can interleave with any other method type, including write (non ReadOnly) requests.
        /// </summary>
        [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
        public sealed class AlwaysInterleaveAttribute : Attribute
        {
        }

        /// <summary>
        /// The Immutable attribute indicates that instances of the marked class or struct are never modified
        /// after they are created.
        /// </summary>
        /// <remarks>
        /// Note that this implies that sub-objects are also not modified after the instance is created.
        /// </remarks>
        [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
        public sealed class ImmutableAttribute : Attribute
        {
        }
    }

    namespace Placement
    {
        using Orleans.Runtime;

        /// <summary>
        /// Base for all placement policy marker attributes.
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
        public abstract class PlacementAttribute : Attribute
        {
            internal PlacementStrategy PlacementStrategy { get; private set; }

            internal PlacementAttribute(PlacementStrategy placement)
            {
                PlacementStrategy = placement ?? PlacementStrategy.GetDefault();
            }
        }

        /// <summary>
        /// Marks a grain class as using the <c>RandomPlacement</c> policy.
        /// </summary>
        /// <remarks>
        /// This is the default placement policy, so this attribute does not need to be used for normal grains.
        /// </remarks>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
        public sealed class RandomPlacementAttribute : PlacementAttribute
        {
            public RandomPlacementAttribute() :
                base(RandomPlacement.Singleton)
            { }
        }

        /// <summary>
        /// Marks a grain class as using the <c>PreferLocalPlacement</c> policy.
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false) ]
        public sealed class PreferLocalPlacementAttribute : PlacementAttribute
        {
            public PreferLocalPlacementAttribute() :
                base(PreferLocalPlacement.Singleton)
            { }
        }

        /// <summary>
        /// Marks a grain class as using the <c>ActivationCountBasedPlacement</c> policy.
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
        public sealed class ActivationCountBasedPlacementAttribute : PlacementAttribute
        {
            public ActivationCountBasedPlacementAttribute() :
                base(ActivationCountBasedPlacement.Singleton)
            { }
        }
    }

    namespace CodeGeneration
    {
        /// <summary>
        /// The TypeCodeOverrideAttribute attribute allows to specify the grain interface ID or the grain class type code
        /// to override the default ones to avoid hash collisions
        /// </summary>
        [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)]
        public sealed class TypeCodeOverrideAttribute : Attribute
        {
            /// <summary>
            /// Use a specific grain interface ID or grain class type code (e.g. to avoid hash collisions)
            /// </summary>
            public int TypeCode { get; private set; }

            public TypeCodeOverrideAttribute(int typeCode)
            {
                TypeCode = typeCode;
            }
    }

    /// <summary>
    /// Used to mark a method as providing a copier function for that type.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class CopierMethodAttribute : Attribute
    {
    }

    /// <summary>
    /// Used to mark a method as providinga serializer function for that type.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class SerializerMethodAttribute : Attribute
    {
    }

    /// <summary>
    /// Used to mark a method as providing a deserializer function for that type.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class DeserializerMethodAttribute : Attribute
    {
    }

    /// <summary>
    /// Used to make a class for auto-registration as a serialization helper.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class RegisterSerializerAttribute : Attribute
    {
    }
    }

    namespace Providers
    {
        /// <summary>
        /// The [Orleans.Providers.StorageProvider] attribute is used to define which storage provider to use for persistence of grain state.
        /// <para>
        /// Specifying [Orleans.Providers.StorageProvider] property is recommended for all grains which extend Grain<T>.
        /// If no [Orleans.Providers.StorageProvider] attribute is  specified, then a "Default" strorage provider will be used.
        /// If a suitable storage provider cannot be located for this grain, then the grain will fail to load into the Silo.
        /// </para>
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public sealed class StorageProviderAttribute : Attribute
        {
            public StorageProviderAttribute()
            {
                    ProviderName = Runtime.Constants.DEFAULT_STORAGE_PROVIDER_NAME;
            }
            /// <summary>
            /// The name of the storage provider to ne used for persisting state for this grain.
            /// </summary>
            public string ProviderName { get; set; }
        }
    }

    [AttributeUsage(AttributeTargets.Interface)]
    internal sealed class FactoryAttribute : Attribute
    {
        public enum FactoryTypes
        {
            Grain,
            ClientObject,
            Both
        };

        private readonly FactoryTypes factoryType = FactoryTypes.Grain;

        public FactoryAttribute(FactoryTypes factoryType)
        {
            this.factoryType = factoryType;
        }

        internal static FactoryTypes CollectFactoryTypesSpecified(Type type)
        {
            var attribs = type.GetCustomAttributes(typeof(FactoryAttribute), inherit: true);

            // if no attributes are specified, we default to FactoryTypes.Grain.
            if (0 == attribs.Length)
                return FactoryTypes.Grain;

            // otherwise, we'll consider all of them and aggregate the specifications
            // like flags.
            FactoryTypes? result = null;
            foreach (var i in attribs)
            {
                var a = (FactoryAttribute)i;
                if (result.HasValue)
                {
                    if (a.factoryType == FactoryTypes.Both)
                        result = a.factoryType;
                    else if (a.factoryType != result.Value)
                        result = FactoryTypes.Both;
                }
                else
                    result = a.factoryType;
            }

            if (result.Value == FactoryTypes.Both)
            {
                throw
                    new NotSupportedException(
                        "Orleans doesn't currently support generating both a grain and a client object factory but we really want to!");
            }

            return result.Value;
        }

        public static FactoryTypes CollectFactoryTypesSpecified<T>()
        {
            return CollectFactoryTypesSpecified(typeof(T));
        }
    }

    [AttributeUsage(AttributeTargets.Class)]
    public sealed class ImplicitStreamSubscriptionAttribute : Attribute
    {
        internal string Namespace { get; private set; }

        // We have not yet come to an agreement whether the provider should be specified as well.
        public ImplicitStreamSubscriptionAttribute(string streamNamespace)
        {
            Namespace = streamNamespace;
        }
    }
}


text:
<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>面包屑</title>


text:
dojo.provide("dojoui.widget.DropDownButtonLink");
dojo.require("dijit.form.DropDownButton");
dojo.require("dojoui.widget.DropDownButton");

/**
 * As a Link
 */
dojo.declare("dojoui.widget.DropDownButtonLink",dojoui.widget.DropDownButton,{
  templateString: dojo.cache("dojoui", "widget/templates/DropDownButtonLink.html")
});


text:
extern crate glium;

use glium::Surface;

mod support;

#[test]
fn get_opengl_version() {
    let display = support::build_display();
    let version = display.get_opengl_version();
    display.assert_no_error(None);

    assert!(version.1 >= 1);
}

#[test]
fn clear_color() {
    let display = support::build_display();

    let texture = support::build_renderable_texture(&display);
    texture.as_surface().clear_color(1.0, 0.0, 0.0, 1.0);

    let data: Vec<Vec<(u8, u8, u8, u8)>> = texture.read();

    for row in data.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 0, 0, 255));
        }
    }

    display.assert_no_error(None);
}

#[test]
fn clear_color_rect() {
    let display = support::build_display();

    let texture = support::build_renderable_texture(&display);
    texture.as_surface().clear_color(1.0, 0.0, 0.0, 1.0);

    let rect = glium::Rect { left: 512, bottom: 0, width: 512, height: 1024 };
    texture.as_surface().clear(Some(&rect), Some((0.0, 1.0, 0.0, 1.0)), false, None, None);

    let data: Vec<Vec<(u8, u8, u8, u8)>> = texture.read();

    for row in data.iter() {
        for (col, pixel) in row.iter().enumerate() {
            if col >= 512 {
                assert_eq!(pixel, &(0, 255, 0, 255));
            } else {
                assert_eq!(pixel, &(255, 0, 0, 255));
            }
        }
    }

    display.assert_no_error(None);
}

#[test]
fn release_shader_compiler() {
    let display = support::build_display();
    display.release_shader_compiler();
    display.assert_no_error(None);
}

#[test]
fn timestamp_query() {
    let display = support::build_display();

    let query1 = glium::debug::TimestampQuery::new(&display);
    let query1 = query1.map(|q| q.get());

    let query2 = glium::debug::TimestampQuery::new(&display);
    let query2 = query2.map(|q| q.get());

    match (query1, query2) {
        (Some(q1), Some(q2)) => assert!(q2 >= q1 && q1 != 0),
        _ => ()
    };

    display.assert_no_error(None);
}

#[test]
fn sync() {
    let display = support::build_display();

    let fence = glium::SyncFence::new(&display);
    if let Ok(fence) = fence {
        fence.wait();
    }

    display.assert_no_error(None);
}

#[test]
fn multiple_displays() {
    let display1 = support::build_display();
    let display2 = support::build_display();

    let (vb1, ib1, program1) = support::build_fullscreen_red_pipeline(&display1);
    let (vb2, ib2, program2) = support::build_fullscreen_red_pipeline(&display2);

    let texture1 = support::build_renderable_texture(&display1);
    let texture2 = support::build_renderable_texture(&display2);

    texture1.as_surface().clear_color(0.0, 0.0, 0.0, 0.0);
    texture2.as_surface().clear_color(0.0, 0.0, 0.0, 0.0);

    texture1.as_surface().draw(&vb1, &ib1, &program1, &glium::uniforms::EmptyUniforms,
                               &Default::default()).unwrap();

    texture2.as_surface().draw(&vb2, &ib2, &program2, &glium::uniforms::EmptyUniforms,
                               &Default::default()).unwrap();
    texture2.as_surface().clear_color(0.0, 1.0, 0.0, 0.0);

    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = texture1.read();
    for row in read_back.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 0, 0, 255));
        }
    }

    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = texture2.read();
    for row in read_back.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(0, 255, 0, 0));
        }
    }

    display1.assert_no_error(None);
    display2.assert_no_error(None);
}

#[test]
fn debug_string() {
    // tests that `insert_debug_marker` doesn't trigger an OpenGL error
    let display = support::build_display();
    display.insert_debug_marker("Hello world").ok();
    display.assert_no_error(None);
}

#[test]
fn is_context_lost() {
    // tests that `is_context_lost` doesn't trigger an OpenGL error
    let display = support::build_display();
    display.is_context_lost();
    display.assert_no_error(None);
}


text:
require 'spec_helper'

describe Stratify::Garmin::Activity do
  describe "#permalink" do
    it "returns the URL for this activity on Garmin Connect" do
      activity = Stratify::Garmin::Activity.new(:guid => 12345678)
      activity.permalink.should == "http://connect.garmin.com/activity/12345678"
    end
  end
end


text:
#include <iostream>
#include <iomanip>
#include <fstream>

#include "log/log.hpp"
#include "win32/registry.hpp"
#include "win32/environment.hpp"
#include "util/singleton.hpp"

using namespace Log;

class NullBuffer : public std::streambuf
{
public:
  int overflow(int c) { return c; }
};

std::wstring Logger::getPathFromRegistry()
{
  return Windows::Registry::Key(L"Software\\xfspp",HKEY_LOCAL_MACHINE).value(L"logFileName",L"xfspp_mgr.log");
}

std::ostream &Logger::getFileStreamInstance()
{
  static std::ofstream f(convertTo(getPathFromRegistry()),std::ios::out);

  return f;
}

std::ostream &Logger::getNullStreamInstance()
{
  static NullBuffer nullBuffer;
  static std::ostream nullStream(&nullBuffer);

  return nullStream;
}

bool Logger::isLogEnabled()
{
  CREATE_INSTANCE(Windows::Environment::Manager);
  return INSTANCE(Windows::Environment::Manager).get(L"XFSPP_NO_LOG") != L"1";
}

std::ostream &Logger::streamInstance()
{
  static bool canLog = isLogEnabled();

  return (canLog)? getFileStreamInstance() : getNullStreamInstance();
}

Logger::Logger()
{

}

Logger::~Logger()
{
  SYSTEMTIME st;
  GetLocalTime(&st);

  streamInstance() <<
    st.wYear << "-" <<
    std::setw(2) << std::setfill('0') << st.wMonth << "-" <<
    std::setw(2) << std::setfill('0') << st.wDay << "-" <<
    "T" <<
    std::setw(2) << std::setfill('0') << st.wHour << ":" <<
    std::setw(2) << std::setfill('0') << st.wMinute << ":" <<
    std::setw(2) << std::setfill('0') << st.wSecond << "." <<
    st.wMilliseconds << "\t" <<
    std::setw(6) << std::setfill('0') << GetCurrentProcessId() << "\t" <<
    std::setw(6) << std::setfill('0') << GetCurrentThreadId() << "\t" <<
    str() << std::endl;
}

Method::Method(const std::string &fName, const std::string &params) :
  _tick(GetTickCount()),
  _fName(fName),
  _params(params)
{
  Logger() << "ENTER\t" << _fName << "\t" << _params;
}

Method::~Method()
{
  Logger() << "EXIT\t" << _fName << "\t" << _params << "\telapsed = " << (GetTickCount() - _tick);
}


text:
#import "MWLibraryMenuController.h"

#import <AppKit/NSMenu.h>
#import <AppKit/NSImage.h>
#import "MWMudLibrary.h"
#import "MWLibraryItem.h"

@implementation MWLibraryMenuController

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self name:MWLibraryDidChangeNotification object:theLibrary];
  [theMenu autorelease]; theMenu = nil;
  [theLibrary autorelease]; theLibrary = nil;
  [super dealloc];
}

- (void)update {
  if (!theMenu)
    return;

  while ([theMenu numberOfItems])
    [theMenu removeItemAtIndex:0];

  int i, n = [theLibrary libItemNumberOfChildren];
  for (i = 0; i < n; i++) {
    id <MWLibraryItem> const libItem = [theLibrary libItemChildAtIndex:i];
    NSMenuItem *const menuItem = [[[NSMenuItem alloc] init] autorelease];

    if ([(id)[libItem objectForKey:@"name"] length])
      [menuItem setTitle:(id)[libItem objectForKey:@"name"]];
    else
      [menuItem setTitle:[[libItem objectForKey:@"location"] description]];
    {
      NSImage *const img = [[[libItem libItemImage] copy] autorelease];
      [img setScalesWhenResized:YES];
      [img setSize:NSMakeSize(16, 16)];
      [menuItem setImage:img];
    }
    [menuItem setTarget:libItem];
    [menuItem setAction:@selector(performOpenAction:)];

    [theMenu addItem:menuItem];
  }
}

- (void)libraryDidChange:(NSNotification *)notif {
  [self update];
}

- (NSMenu *)menu {
  return theMenu;
}

- (void)setMenu:(NSMenu *)newVal {
  [theMenu autorelease];
  theMenu = [newVal retain];
}

- (void)setLibrary:(MWMudLibrary *)newVal {
  [[NSNotificationCenter defaultCenter] removeObserver:self name:MWLibraryDidChangeNotification object:theLibrary];
  [theLibrary autorelease];
  theLibrary = [newVal retain];
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(libraryDidChange:) name:MWLibraryDidChangeNotification object:theLibrary];
  [self update];
}

@end


text:
define("dojox/mobile/DatePicker",["dojo/_base/lang","./_PickerChooser!DatePicker"],function(a,b){return a.setObject("dojox.mobile.DatePicker",b)});
//# sourceMappingURL=DatePicker.js.map


text:
package utils.Responses

import models.{Contact, User}
import play.api.libs.json._

/**
 * Created by carlos on 16/10/15.
 */
case class AvailabilityResponse(result: String, availability: Option[User])

object AvailabilityResponse {
  implicit val responseFormat = Json.format[AvailabilityResponse]
}

case class ErrorResult(status: Int, message: String)
object ErrorResult{
  implicit val format: Format[ErrorResult] = Json.format[ErrorResult]
}

case class EndpointResponse(result: String,
                            response: JsValue,
                            error: Option[ErrorResult]) {
}

object EndpointResponse {
  implicit val format: Format[EndpointResponse] = Json.format[EndpointResponse]
}

object ErrorResponse {

  def apply(status: Int, message: String) = {
    EndpointResponse("NOK", JsNull, Option(ErrorResult(status, message)))
  }
}

object SuccessResponse {
  def apply[A](successResponse: A)(implicit w: Writes[A]) = {
    EndpointResponse("OK", Json.toJson(successResponse), None)
  }
}

case class ContactUnavailable(cont: Contact) extends Throwable


text:
    Actor Identifiers

                {% if not actor_identifiers  %}

                {% else %}

                {% endif %}
                    Type
                    Identifier
                    Confidence
                    Analyst
                    Date

            {% for identifier in actor_identifiers %}
                {% include "actor_identifiers_row_widget.html" %}
            {% endfor %}


text:
<?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data>

        <record id="view_account_position_form" model="ir.ui.view">
            <field name="name">account.fiscal.position.form</field>
            <field name="model">account.fiscal.position</field>
            <field name="arch" type="xml">
                <form string="Fiscal Position" version="7.0">
                    <group col="4">
                        <field name="name"/>
                        <field name="active"/>
                        <field name="company_id" widget="selection" groups="base.group_multi_company"/>
                    </group>
                    <separator string="Taxes Mapping"/>
                    <field name="tax_ids" widget="one2many_list">
                        <tree string="Tax Mapping" editable="bottom">
                            <field name="tax_src_id" domain="[('parent_id','=',False)]"/>
                            <field name="tax_dest_id" domain="[('parent_id','=',False)]"/>
                        </tree>
                        <form string="Tax Mapping">
                            <field name="tax_src_id" domain="[('parent_id','=',False)]"/>
                            <field name="tax_dest_id" domain="[('parent_id','=',False)]"/>
                        </form>
                    </field>
                    <separator string="Accounts Mapping"/>
                    <field name="account_ids" widget="one2many_list">
                        <tree string="Account Mapping" editable="bottom">
                            <field name="account_src_id"/>
                            <field name="account_dest_id"/>
                        </tree>
                        <form string="Account Mapping">
                            <field name="account_src_id"/>
                            <field name="account_dest_id"/>
                        </form>
                    </field>
                    <separator string="Notes"/>
                    <field name="note"/>
                </form>
            </field>
        </record>
        <record id="view_account_position_tree" model="ir.ui.view">
            <field name="name">account.fiscal.position.tree</field>
            <field name="model">account.fiscal.position</field>
            <field name="arch" type="xml">
                <tree string="Fiscal Position">
                    <field name="name"/>
                    <field name="company_id" groups="base.group_multi_company" widget="selection"/>
                </tree>
            </field>
        </record>

        <record id="action_account_fiscal_position_form" model="ir.actions.act_window">
            <field name="name">Fiscal Positions</field>
            <field name="res_model">account.fiscal.position</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
        </record>

        <menuitem
            action="action_account_fiscal_position_form"
            id="menu_action_account_fiscal_position_form"
            parent="next_id_27" sequence="20"/>

        <record id="view_partner_property_form" model="ir.ui.view">
            <field name="name">res.partner.property.form.inherit</field>
            <field name="model">res.partner</field>
            <field name="priority">2</field>
            <field name="inherit_id" ref="base.view_partner_form"/>
            <field name="arch" type="xml">
                <page string="History" position="before" version="7.0">
                <page string="Accounting" col="4" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}">
                    <group>
                        <group>
                            <field name="property_account_position" widget="selection"/>
                        </group>
                        <group>
                            <field name="last_reconciliation_date"/>
                        </group>
                        <group>
                            <field name="property_account_receivable" groups="account.group_account_invoice" />
                            <field name="property_payment_term" widget="selection"/>
                            <field name="credit"/>
                            <field name="credit_limit"/>
                        </group>
                        <group>
                            <field name="property_account_payable" groups="account.group_account_invoice"/>
                            <field name="property_supplier_payment_term" widget="selection"/>
                            <field name="debit"/>
                        </group>
                    </group>
                    <field name="bank_ids" context="{'default_partner_id': active_id, 'form_view_ref': 'base.view_partner_bank_form'}">
                        <tree string="Bank Details">
                            <field name="state" invisible="1"/>
                            <field name="sequence" invisible="1"/>
                            <field name="acc_number"/>
                            <field name="bank_name"/>
                            <field name="owner_name"/>
                        </tree>
                    </field>
                </page>
                <page string="Accounting" name="accounting_disabled" attrs="{'invisible': ['|',('is_company','=',True),('parent_id','=',False)]}">

Accounting-related settings are managed on <button name="open_commercial_entity" type="object" string="the parent company" class="oe_link"/>

                </page>
                </page>
            </field>
        </record>

        <act_window
            id="action_analytic_open"
            name="Contracts/Analytic Accounts"
            res_model="account.analytic.account"
            context="{'search_default_partner_id':[active_id], 'default_partner_id': active_id}"
            src_model="res.partner"
            view_type="form"
            view_mode="tree,form"/>

    </data>
</openerp>


text:
/**
 * @ngdoc service
 * @name $ionicGesture
 * @module ionic
 * @description An angular service exposing ionic
 * {@link ionic.utility:ionic.EventController}'s gestures.
 */
IonicModule
.factory('$ionicGesture', [function() {
  return {
    /**
     * @ngdoc method
     * @name $ionicGesture#on
     * @description Add an event listener for a gesture on an element. See {@link ionic.utility:ionic.EventController#onGesture}.
     * @param {string} eventType The gesture event to listen for.
     * @param {function(e)} callback The function to call when the gesture
     * happens.
     * @param {element} $element The angular element to listen for the event on.
     * @returns {ionic.Gesture} The gesture object (use this to remove the gesture later on).
     */
    on: function(eventType, cb, $element, options) {
      return window.ionic.onGesture(eventType, cb, $element[0], options);
    },
    /**
     * @ngdoc method
     * @name $ionicGesture#off
     * @description Remove an event listener for a gesture on an element. See {@link ionic.utility:ionic.EventController#offGesture}.
     * @param {ionic.Gesture} gesture The gesture that should be removed.
     * @param {string} eventType The gesture event to remove the listener for.
     * @param {function(e)} callback The listener to remove.
     */
    off: function(gesture, eventType, cb) {
      return window.ionic.offGesture(gesture, eventType, cb);
    }
  };
}]);


text:
/*
 * Do not modify this file. This file is generated from the ds-2015-04-16.normal.json service model.
 */
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;
using System.IO;

using Amazon.Runtime;
using Amazon.Runtime.Internal;

namespace Amazon.DirectoryService.Model
{
    ///
    /// Container for the parameters to the CreateAlias operation.
    /// Creates an alias for a directory and assigns the alias to the directory. The alias
    /// is used to construct the access URL for the directory, such as http://<alias>.awsapps.com.
    ///
    ///  <important>
    /// <para>
    /// After an alias has been created, it cannot be deleted or reused, so this operation
    /// should only be used when absolutely necessary.
    /// </para>
    ///  </important>
    ///
    public partial class CreateAliasRequest : AmazonDirectoryServiceRequest
    {
        private string _alias;
        private string _directoryId;

        ///
        /// Gets and sets the property Alias.
        /// <para>
        /// The requested alias.
        /// </para>
        ///
        /// <para>
        /// The alias must be unique amongst all aliases in AWS. This operation will throw an
        /// EntityAlreadyExistsException if this alias already exists.
        /// </para>
        ///
        public string Alias
        {
            get { return this._alias; }
            set { this._alias = value; }
        }

        // Check to see if Alias property is set
        internal bool IsSetAlias()
        {
            return this._alias != null;
        }

        ///
        /// Gets and sets the property DirectoryId.
        /// <para>
        /// The identifier of the directory to create the alias for.
        /// </para>
        ///
        public string DirectoryId
        {
            get { return this._directoryId; }
            set { this._directoryId = value; }
        }

        // Check to see if DirectoryId property is set
        internal bool IsSetDirectoryId()
        {
            return this._directoryId != null;
        }

    }
}


text:
package org.jboss.qa.arquillian.container.configuration;

import org.jboss.arquillian.container.spi.ConfigurationException;
import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration;

/**
 * Configuration for S-RAMP Container.
 *
 * @author sbunciak
 * @since 1.0.0
 */
public class SrampConfiguration implements ContainerConfiguration {

	public SrampConfiguration() {
		srampHost = "localhost";
		srampPort = 8080;
		srampUsername = "admin";
		srampPassword = "overlord";
	}

	private String srampUsername;
	private String srampPassword;
	private String srampHost;
	private int srampPort;

	public String getSrampServerURL() {
		return "http://" + getSrampHost() + ":" + getSrampPort()
				+ "/s-ramp-server";
	}

	public String getSrampUsername() {
		return srampUsername;
	}

	public void setSrampPassword(String password) {
		this.srampPassword = password;
	}

	public String getSrampPassword() {
		return srampPassword;
	}

	public void setSrampUsername(String username) {
		this.srampUsername = username;
	}

	public String getSrampHost() {
		return srampHost;
	}

	public void setSrampHost(String srampHost) {
		this.srampHost = srampHost;
	}

	public int getSrampPort() {
		return srampPort;
	}

	public void setSrampPort(int srampPort) {
		this.srampPort = srampPort;
	}

	public void validate() throws ConfigurationException {
		if (srampHost.isEmpty() || srampPassword.isEmpty()
				|| srampUsername.isEmpty() || srampPort <= 0) {
			throw new ConfigurationException("Empty configuration field found!");
		}
	}

	@Override
	public String toString() {
		return "srampUsername=[" + srampUsername + "], srampServerUrl=[" + getSrampServerURL() + "]";
	}
}


text:
<?xml version="1.0" encoding="utf-8"?>
<GameData>
  <LocalizedText>
    <!-- GERMAN -->

    <!-- Builder Lens -->
    <Replace Tag="LOC_HUD_BUILDER_LENS" Language="de_DE">
      <Text>Handwerker</Text>
    </Replace>
    <Replace Tag="LOC_HUD_BUILDER_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt besondere Felder auf der Karte an, wo gebaut werden kann.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BUILDER_LENS_IMP" Language="de_DE">
      <Text>Res. Geplündert Einzigartig</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BUILDER_LENS_HILL" Language="de_DE">
      <Text>Hügel</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BUILDER_LENS_FEATURE" Language="de_DE">
      <Text>Entfernbares Feature</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BUILDER_LENS_GENERIC" Language="de_DE">
      <Text>Normales Feld</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BUILDER_LENS_NOTHING" Language="de_DE">
      <Text>Nichts zu tun</Text>
    </Replace>

    <!-- Archaeologist Lens -->
    <Replace Tag="LOC_HUD_ARCHAEOLOGIST_LENS" Language="de_DE">
      <Text>Archäologe</Text>
    </Replace>
    <Replace Tag="LOC_HUD_ARCHAEOLOGIST_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Ausgrabungsstätten auf der Karte.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_ARCHAEOLOGIST_LENS_ARTIFACT" Language="de_DE">
      <Text>Artefakt</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_ARCHAEOLOGIST_LENS_SHIPWRECK" Language="de_DE">
      <Text>Schiffswrack</Text>
    </Replace>

    <!-- City Overlap Lens -->
    <Replace Tag="LOC_HUD_CITYOVERLAP6_LENS" Language="de_DE">
      <Text>Neue Stadt 6Feld</Text>
    </Replace>
    <Replace Tag="LOC_HUD_CITYOVERLAP6_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Felder für Städtegründungen mit einem 6 Hexfelder Abstand.</Text>
    </Replace>

    <!-- City Overlap Lens -->
    <Replace Tag="LOC_HUD_CITYOVERLAP9_LENS" Language="de_DE">
      <Text>Neue Stadt 9Feld</Text>
    </Replace>
    <Replace Tag="LOC_HUD_CITYOVERLAP9_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Felder für Städtegründungen mit einem 9 Hexfelder Abstand.</Text>
    </Replace>

    <!-- Barbarian Lens -->
    <Replace Tag="LOC_HUD_BARBARIAN_LENS" Language="de_DE">
      <Text>Barbaren</Text>
    </Replace>
    <Replace Tag="LOC_HUD_BARBARIAN_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Barbaren-Außenposten auf der Karte.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_BARBARIAN_LENS_ENCAPMENT" Language="de_DE">
      <Text>Barbaren- Außenposten</Text>
    </Replace>

    <!-- Resources Lens -->
    <Replace Tag="LOC_HUD_RESOURCE_LENS" Language="de_DE">
      <Text>Ressourcen</Text>
    </Replace>
    <Replace Tag="LOC_HUD_RESOURCE_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Ressourcenfelder.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_LUXURY" Language="de_DE">
      <Text>Luxusressource</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_NLUXURY" Language="de_DE">
      <Text>Unerschlossene Luxusressource</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_STRATEGIC" Language="de_DE">
      <Text>Strategische Ressource</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_NSTRATEGIC" Language="de_DE">
      <Text>Unerschlossene strateg. Ressource</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_BONUS" Language="de_DE">
      <Text>Bonusressource</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_NBONUS" Language="de_DE">
      <Text>Unerschlossene Bonusressource</Text>
    </Replace>

    <!-- Wonder Lens -->
    <Replace Tag="LOC_HUD_WONDER_LENS" Language="de_DE">
      <Text>Wunder</Text>
    </Replace>
    <Replace Tag="LOC_HUD_WONDER_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Naturwunder und gebaute Wunder auf der Karte.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_WONDER_LENS_NWONDER" Language="de_DE">
      <Text>Naturwunder</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_RESOURCE_LENS_PWONDER" Language="de_DE">
      <Text>Gebaute Wunder</Text>
    </Replace>

    <!-- Adjacency Yield Lens -->
    <Replace Tag="LOC_HUD_ADJYIELD_LENS" Language="de_DE">
      <Text>Nachbarerträge</Text>
    </Replace>
    <Replace Tag="LOC_HUD_ADJYIELD_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt die Nachbarschaftserträge der Bezirke.</Text>
    </Replace>

    <!-- Scout Lens -->
    <Replace Tag="LOC_HUD_SCOUT_LENS" Language="de_DE">
      <Text>Späher</Text>
    </Replace>
    <Replace Tag="LOC_HUD_SCOUT_LENS_TOOLTIP" Language="de_DE">
      <Text>Zeigt Stammesdörfer auf der Karte.</Text>
    </Replace>
    <Replace Tag="LOC_TOOLTIP_SCOUT_LENS_GHUT" Language="de_DE">
      <Text>Stammesdorf</Text>
    </Replace>

  </LocalizedText>
</GameData>


text:
template <class TM>
TM occaAtomicAdd(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr += update;

  return old;
}

template <class TM>
TM occaAtomicSub(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr -= update;

  return old;
}

template <class TM>
TM occaAtomicSwap(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr = update;

  return old;
}

template <class TM>
TM occaAtomicInc(TM *ptr){
  const TM old = *ptr;

  ++(*ptr);

  return old;
}

template <class TM>
TM occaAtomicDec(TM *ptr, const TM &update){
  const TM old = *ptr;

  --(*ptr);

  return old;
}

template <class TM>
TM occaAtomicMin(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr = ((old < update) ? old : update);

  return old;
}

template <class TM>
TM occaAtomicAnd(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr &= update;

  return old;
}

template <class TM>
TM occaAtomicOr(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr |= update;

  return old;
}

template <class TM>
TM occaAtomicXor(TM *ptr, const TM &update){
  const TM old = *ptr;

  *ptr ^= update;

  return old;
}

template <class TM>
TM occaAtomicCAS(TM *ptr, const int comp, const TM &update){
  TM old;

#pragma omp critical
  {
    old = *ptr;
    if(comp)
      *ptr = update;
  }

  return old;
}

#define occaAtomicAdd64  occaAtomicAdd
#define occaAtomicSub64  occaAtomicSub
#define occaAtomicSwap64 occaAtomicSwap
#define occaAtomicInc64  occaAtomicInc
#define occaAtomicDec64  occaAtomicDec
//================================================

//---[ Math ]-------------------------------------
#define occaFabs       fabs
#define occaFastFabs   fabs
#define occaNativeFabs fabs

#define occaSqrt       sqrt
#define occaFastSqrt   sqrt
#define occaNativeSqrt sqrt

#define occaCbrt       cbrt
#define occaFastCbrt   cbrt
#define occaNativeCbrt cbrt

#define occaSin       sin
#define occaFastSin   sin
#define occaNativeSin sin

#define occaAsin       asin
#define occaFastAsin   asin
#define occaNativeAsin asin

#define occaSinh       sinh
#define occaFastSinh   sinh
#define occaNativeSinh sinh

#define occaAsinh       asinh
#define occaFastAsinh   asinh
#define occaNativeAsinh asinh

#define occaCos       cos
#define occaFastCos   cos
#define occaNativeCos cos

#define occaAcos       acos
#define occaFastAcos   acos
#define occaNativeAcos acos

#define occaCosh       cosh
#define occaFastCosh   cosh
#define occaNativeCosh cosh

#define occaAcosh       acosh
#define occaFastAcosh   acosh
#define occaNativeAcosh acosh

#define occaTan       tan
#define occaFastTan   tan
#define occaNativeTan tan

#define occaAtan       atan
#define occaFastAtan   atan
#define occaNativeAtan atan

#define occaAtan2       atan2
#define occaFastAtan2   atan2
#define occaNativeAtan2 atan2

#define occaTanh       tanh
#define occaFastTanh   tanh
#define occaNativeTanh tanh

#define occaAtanh       atanh
#define occaFastAtanh   atanh
#define occaNativeAtanh atanh

#define occaExp       exp
#define occaFastExp   exp
#define occaNativeExp exp

#define occaExpm1       expm1
#define occaFastExpm1   expm1
#define occaNativeExpm1 expm1

#define occaPow       pow
#define occaFastPow   pow
#define occaNativePow pow

#define occaLog2       log2
#define occaFastLog2   log2
#define occaNativeLog2 log2

#define occaLog10       log10
#define occaFastLog10   log10
#define occaNativeLog10 log10
//================================================

//---[ Misc ]-------------------------------------
#define occaParallelFor2
#define occaParallelFor1
#define occaParallelFor0
#define occaParallelFor
// - - - - - - - - - - - - - - - - - - - - - - - -
#define occaUnroll3(N) _Pragma(#N)
#define occaUnroll2(N) occaUnroll3(N)
#define occaUnroll(N)  occaUnroll2(unroll N)
//================================================

//---[ Private ]---------------------------------
template <class TM, const int SIZE>
class occaPrivate_t {
public:
  const int dim0, dim1, dim2;
  const int &id0, &id1, &id2;

  TM data[OCCA_MAX_THREADS][SIZE] occaAligned;

  occaPrivate_t(int dim0_, int dim1_, int dim2_,
                int &id0_, int &id1_, int &id2_) :
    dim0(dim0_),
    dim1(dim1_),
    dim2(dim2_),
    id0(id0_),
    id1(id1_),
    id2(id2_) {}

  ~occaPrivate_t(){}

  inline int index() const {
    return ((id2*dim1 + id1)*dim0 + id0);
  }

  inline TM& operator [] (const int n){
    return data[index()][n];
  }

  inline TM operator [] (const int n) const {
    return data[index()][n];
  }

  inline operator TM(){
    return data[index()][0];
  }

  inline operator TM*(){
    return data[index()];
  }

  inline TM& operator = (const TM &t){
    data[index()][0] = t;
    return data[index()][0];
  }

  inline TM& operator += (const TM &t){
    data[index()][0] += t;
    return data[index()][0];
  }

  inline TM& operator -= (const TM &t){
    data[index()][0] -= t;
    return data[index()][0];
  }

  inline TM& operator /= (const TM &t){
    data[index()][0] /= t;
    return data[index()][0];
  }

  inline TM& operator *= (const TM &t){
    data[index()][0] *= t;
    return data[index()][0];
  }

  friend inline TM operator + (const TM &a, const occaPrivate_t &b){
    return (a + b.data[b.index()][0]);
  }

  friend inline TM operator + (const occaPrivate_t &a, const TM &b){
    return (a.data[a.index()][0] + b);
  }

  friend inline TM operator - (const TM &a, const occaPrivate_t &b){
    return (a - b.data[b.index()][0]);
  }

  friend inline TM operator - (const occaPrivate_t &a, const TM &b){
    return (a.data[a.index()][0] - b);
  }

  friend inline TM operator * (const TM &a, const occaPrivate_t &b){
    return (a * b.data[b.index()][0]);
  }

  friend inline TM operator * (const occaPrivate_t &a, const TM &b){
    return (a.data[a.index()][0] * b);
  }

  friend inline TM operator / (const TM &a, const occaPrivate_t &b){
    return (a / b.data[b.index()][0]);
  }

  friend inline TM operator / (const occaPrivate_t &a, const TM &b){
    return (a.data[a.index()][0] / b);
  }

  inline TM& operator ++ (){
    return (++data[index()][0]);
  }

  inline TM& operator ++ (int){
    return (data[index()][0]++);
  }

  inline TM& operator -- (){
    return (--data[index()][0]);
  }

  inline TM& operator -- (int){
    return (data[index()][0]--);
  }
};

#define occaPrivateArray( TYPE , NAME , SIZE )                          \
  occaPrivate_t<TYPE,SIZE> NAME(occaInnerDim0, occaInnerDim1, occaInnerDim2, \
                                occaInnerId0, occaInnerId1, occaInnerId2);

#define occaPrivate( TYPE , NAME )                                      \
  occaPrivate_t<TYPE,1> NAME(occaInnerDim0, occaInnerDim1, occaInnerDim2, \
                             occaInnerId0, occaInnerId1, occaInnerId2);
//================================================

//---[ Texture ]----------------------------------
struct occaTexture {
  void *data;
  int dim;

  uintptr_t w, h, d;
};

#define occaReadOnly  const
#define occaWriteOnly

#define occaTexture1D(TEX) occaTexture &TEX
#define occaTexture2D(TEX) occaTexture &TEX

#define occaTexGet1D(TEX, TYPE, VALUE, X)    VALUE = ((TYPE*) TEX.data)[X]
#define occaTexGet2D(TEX, TYPE, VALUE, X, Y) VALUE = ((TYPE*) TEX.data)[(Y * TEX.w) + X]

#define occaTexSet1D(TEX, TYPE, VALUE, X)    ((TYPE*) TEX.data)[X]               = VALUE
#define occaTexSet2D(TEX, TYPE, VALUE, X, Y) ((TYPE*) TEX.data)[(Y * TEX.w) + X] = VALUE
//================================================

#endif


text:
[![Go Report Card](https://goreportcard.com/badge/github.com/leonlaser/pi-asciicam)](https://goreportcard.com/report/github.com/leonlaser/pi-asciicam)

# Raspberry Pi ASCII-Cam

![pi-asciicam demo GIF](demo.gif)

The __pi-ascii-cam__ project allows you to create an ASCII live camera stream from a Raspberry Pi with an attached Raspberry Pi Camera or any MJPEG stream.
It is utilizing `raspivid` to convert its MJPEG stream into an ASCII character representation and transport them over a websocket.

The servers are written in golang, the client is simply HTML/CSS/JavaScript.

## Binaries

You can find binaries for Linux and MacOS in `bin/`.

On plattforms other than the Raspberry Pi, `asciicam-server` will only be able to do a conversion from MJPEG to ASCII from an external network source. See [Receive an external MJPEG stream](#receive-an-external-mjpeg-stream) on how to do that.

I did not test all binaries. Just `linux-arm` and `macos-amd64`.

## Start the ASCII stream server

    ./asciicam-server

You are now able to connect to a websocket on port 8000 on all network interfaces. There is already an example HTML/JavaScript client you can host: `asciicam-server/example_client.html`. Use a webserver of your choice on the same machine. The client will connect automatically to the websocket.

Show all possible options and defaults:

    ./asciicam-server --help

## Serve clients from other machines

`asciicam-server` can server multiple clients, but a single Raspberry Pi could be quickly overwhelmed. Also you may not want to serve your stream directly from your office or home server.

The `asciicam-imux` is a very simple inverse multiplexer, which connects to your `asciicam-server`, splits the websocket stream for multiple clients and serves them.

To start a single server on an external machine just run:

    ./asciicam-imux -s 10.0.0.10:8000 -p 88888

__-s__ ip and port where `asciicam-server` is running

__-p__ the port you want your clients to connect to

### asciicam-imux docker image

You can use the existing Dockerfile to build your own image or use the ones already available on hub.docker.com.

* [leonlaser/pi-asciicam-imux](https://hub.docker.com/r/leonlaser/pi-asciicam-imux/)
* [leonlaser/pi-asciicam-imux-arm](https://hub.docker.com/r/leonlaser/pi-asciicam-imux-arm/) for usage on a Raspberry Pi

Run the docker image

    docker run -p 9000:9000 -e PORT=9000 -e SOURCE=10.0.0.10:8000 leonlaser/pi-asciicam-imux

## Receive an external MJPEG stream

The `asciicam-server` calls `raspvid` directly and uses its MJPEG stream on stdout to generate the ASCII frames.

A Raspberry Pi Zero is quickly overwhelmed when converting 10 frames per second or more and serving a websocket connection.

To remove the load of converting frames, you can use your Raspberry Pi to only start `raspivid` itself and stream the MJPEG over the network with netcat:

    raspivid -o - -w 320 -h 200 -n -t 0 -cd MJPEG -fps 25 | nc -lkv4 5001

In my expierence netcat somehow gives up at some point. A better alternative for me was to use `ncat`, which belongs to `nmap` and will be installed with it:

    raspivid -o - -w 320 -h 200 -n -t 0 -cd MJPEG -fps 25 | ncat -k -l 5001

Now use `asciicam-server` to connect and open a new websocket:

    ./asciicam-server -net 10.0.0.1:5001

Now your Raspberry Pi only sends a video stream and another machine running `asciicam-server` can convert your video and serve the websocket connections.

Based on your needs, your clients can directly connect to your `asciicam-server` or you can use `asciicam-imux` to scale:

-> Raspberry Pi running `raspivid` streams to -> a Machine running `asciicam-server` serving a websocket, which gets distributes by -> n-Machines running `asciicam-imux` in a docker swarm or using a loadbalancer for your clients to connect to.

## Using an USB webcam

Because `asciicam-server` is able to retrieve any MPJEG stream, you can use any source and convert it to an ASCII video. Here is an example on using `avconv` to access you local video device and start an MJPEG stream:

    avconv -f video4linux2 -s 320x200 -i /dev/video0 -r 15 -f mjpeg tcp://0.0.0.0:5001?listen

Now use `asciicam-server` with the `-net` parameter to connect.

# Client

Without a client nobody can see your live stream. You can use two different files. As mentioned earlier, there is a really simple client to show you what is going on: `asciicam-server/example_client.html`.

`webclient/webclient.html` is a bit more advanced, allowing you to connect to any websocket stream by entering an address. It is using requestAnimationFrame() and shows the frames per second, received through the websocket connection. It is very helpfull for debugging your setup.

# Build

This section is mostly for myself. But if you want to built your own setup for streaming your video feed, want to modify the sources and deploy them on different machines, help yourself:

## Compile go sources

See makefile.

## Build docker images

See makefile.

# But why?

I was looking for project to learn more about golang, Docker, Docker Swarm and Raspberry Pi.

# Thanks

A thank you goes to [idevelop](https://github.com/idevelop) for his awesome [ascii-camera](https://github.com/idevelop/ascii-camera). My image to character conversion is simply a port of his [ascii.js](https://github.com/idevelop/ascii-camera/blob/master/script/ascii.js), which features some links to every step of his image pre-processing before converting it to actual characters.


text:
using System;
using System.Collections.Generic;
using System.IO;
using Lucene.Net.Analysis;

namespace TextMatch
{
    /// <summary>
    /// A tokenizer that breaks sentences using a list of separator chars
    /// </summary>
    class CustomTokenizer : CharTokenizer
    {
        public const string DEFAULT_SEPARATOR_CHARS = @",:;.()?!@#%^&*|/\+÷°±{}[]<>-`~'""$£€¢¥©®™•§†‡–—¶";
        readonly HashSet<char> _separatorCharsLookup;

        /// <summary>
        /// Initializes a new instance of the <see cref="CustomTokenizer"/> class.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="separatorChars">The separator chars.</param>
        public CustomTokenizer(TextReader reader, string separatorChars) : base(reader)
        {
            _separatorCharsLookup = new HashSet<char>(separatorChars);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CustomTokenizer"/> class.
        /// </summary>
        /// <param name="reader">The reader.</param>
        public CustomTokenizer(TextReader reader) : this(reader, DEFAULT_SEPARATOR_CHARS)
        {
        }

        /// <summary>
        /// Determines whether the specified character is a token character.
        /// </summary>
        /// <param name="c">The character.</param>
        /// <returns></returns>
        protected override bool IsTokenChar(char c)
        {
            return !Char.IsWhiteSpace(c) && !_separatorCharsLookup.Contains(c);
        }
    }
}


text:
import io
import os
import re

from django.conf import settings
from django.utils.http import urlencode

from kolibri.core.content.errors import InvalidStorageFilenameError
from kolibri.core.utils.urls import join_url
from kolibri.utils import conf
from kolibri.utils.server import get_zip_port

# valid storage filenames consist of 32-char hex plus a file extension
VALID_STORAGE_FILENAME = re.compile(r"[0-9a-f]{32}(-data)?\.[0-9a-z]+")

def _maybe_makedirs(path):
    if not os.path.isdir(path):
        try:
            os.makedirs(path)
        # When importing from USB etc, it does not need to create
        # directories under external drives that are not writable.
        except OSError:
            pass

def get_attribute(obj, key):
    """
    Get an attribute from an object, regardless of whether it is a dict or an object
    """
    if not isinstance(obj, dict):
        return getattr(obj, key)
    return obj[key]

def get_content_file_name(obj):
    return "{checksum}.{extension}".format(
        checksum=get_attribute(obj, "id"), extension=get_attribute(obj, "extension")
    )

def get_local_content_storage_file_url(obj):
    """
    Return a url for the client side to retrieve the content file.
    The same url will also be exposed by the file serializer.
    """
    if get_attribute(obj, "available"):
        filename = get_content_file_name(obj)
        return "/{}{}/{}/{}".format(
            get_content_storage_url(
                conf.OPTIONS["Deployment"]["URL_PATH_PREFIX"]
            ).lstrip("/"),
            filename[0],
            filename[1],
            filename,
        )
    return None

# DISK PATHS

def get_content_dir_path(datafolder=None, contentfolder=None):
    if contentfolder:
        return contentfolder
    if datafolder:
        return os.path.join(datafolder, "content")
    return conf.OPTIONS["Paths"]["CONTENT_DIR"]

def get_content_fallback_paths():
    paths = []
    fallback_dirs = conf.OPTIONS["Paths"]["CONTENT_FALLBACK_DIRS"]
    for path in fallback_dirs:
        path = path.strip()
        if not path:
            continue
        paths.append(path)
    return paths

def get_all_content_dir_paths():
    return [get_content_dir_path()] + get_content_fallback_paths()

def existing_file_path_in_content_fallback_dirs(subpath):
    # see whether the file exists in any of our content fallback directories
    for prefix in get_content_fallback_paths():
        path = os.path.join(prefix, subpath)
        if os.path.exists(path):
            return path
    # if not, return None
    return None

def get_content_database_dir_path(datafolder=None, contentfolder=None):
    """
    Returns the path to the content sqlite databases
    ($HOME/.kolibri/content/databases on POSIX systems, by default)
    """
    path = os.path.join(
        get_content_dir_path(datafolder=datafolder, contentfolder=contentfolder),
        "databases",
    )
    _maybe_makedirs(path)
    return path

def get_content_database_file_path(channel_id, datafolder=None, contentfolder=None):
    """
    Given a channel_id, returns the path to the sqlite3 file
    ($HOME/.kolibri/content/databases/<channel_id>.sqlite3 on POSIX systems, by default)
    """
    suffix = "{}.sqlite3".format(channel_id)
    primary_path = os.path.join(
        get_content_database_dir_path(
            datafolder=datafolder, contentfolder=contentfolder
        ),
        suffix,
    )
    # if the primary path already exists, or the datafolder/contentfolder is overridden, use the primary path
    if (
        os.path.exists(primary_path)
        or datafolder is not None
        or contentfolder is not None
    ):
        return primary_path
    backup_path = existing_file_path_in_content_fallback_dirs(
        os.path.join("databases", suffix)
    )
    # return backup path if one exists; otherwise, return primary path (even though it doesn't exist yet)
    return backup_path or primary_path

def get_upgrade_content_database_file_path(
    channel_id, datafolder=None, contentfolder=None
):
    return os.path.join(
        get_content_database_dir_path(
            datafolder=datafolder, contentfolder=contentfolder
        ),
        "{}-upgrade.sqlite3".format(channel_id),
    )

def get_annotated_content_database_file_path(
    channel_id, datafolder=None, contentfolder=None
):
    return os.path.join(
        get_content_database_dir_path(
            datafolder=datafolder, contentfolder=contentfolder
        ),
        "{}-annotated.sqlite3".format(channel_id),
    )

def get_content_storage_dir_path(datafolder=None, contentfolder=None):
    path = os.path.join(
        get_content_dir_path(datafolder=datafolder, contentfolder=contentfolder),
        "storage",
    )
    _maybe_makedirs(path)
    return path

def get_content_storage_file_path(filename, datafolder=None, contentfolder=None):
    if not VALID_STORAGE_FILENAME.match(filename):
        raise InvalidStorageFilenameError(
            "'{}' is not a valid content storage filename".format(filename)
        )
    suffix = os.path.join(filename[0], filename[1], filename)
    primary_path = os.path.join(
        get_content_storage_dir_path(
            datafolder=datafolder, contentfolder=contentfolder
        ),
        suffix,
    )
    # if the primary path already exists, or the datapath is overridden, use the primary path
    if (
        os.path.exists(primary_path)
        or datafolder is not None
        or contentfolder is not None
    ):
        return primary_path
    backup_path = existing_file_path_in_content_fallback_dirs(
        os.path.join("storage", suffix)
    )
    # return backup path if one exists; otherwise, return the primary path (even though it doesn't exist yet)
    return backup_path or primary_path

def using_remote_storage():
    return conf.OPTIONS["Deployment"]["REMOTE_CONTENT"]

# URL PATHS

def get_content_url(baseurl=None):
    return get_content_server_url("content/", baseurl=baseurl)

def get_content_database_url(baseurl=None):
    return join_url(get_content_url(baseurl), "databases/")

def get_content_database_file_url(channel_id, baseurl=None):
    return join_url(get_content_database_url(baseurl), "{}.sqlite3".format(channel_id))

def get_content_storage_url(baseurl=None):
    return join_url(get_content_url(baseurl), "storage/")

def get_content_storage_remote_url(filename, baseurl=None):
    return "{}{}/{}/{}".format(
        get_content_storage_url(baseurl), filename[0], filename[1], filename
    )

def get_content_server_url(path, baseurl=None):
    if not baseurl:
        baseurl = conf.OPTIONS["Urls"]["CENTRAL_CONTENT_BASE_URL"]
    return join_url(baseurl, path)

def get_info_url(baseurl=None):
    return get_content_server_url("api/public/info", baseurl=baseurl)

def get_channel_lookup_url(
    version="1", identifier=None, baseurl=None, keyword=None, language=None
):
    content_server_path = "api/public/v{}/channels".format(version)
    if identifier:
        content_server_path += "/lookup/{}".format(identifier)
    content_server_path += "?"
    query_params = {}
    if keyword:
        query_params["keyword"] = keyword
    if language:
        query_params["language"] = language
    content_server_path += urlencode(query_params)

    return get_content_server_url(content_server_path, baseurl=baseurl)

def get_file_checksums_url(channel_id, baseurl, version="1"):
    # This endpoint does not exist on Studio, so a baseurl is required.
    return get_content_server_url(
        "api/public/v{version}/file_checksums/{channel_id}".format(
            version=version, channel_id=channel_id
        ),
        baseurl=baseurl,
    )

HASHI = "hashi/"

ZIPCONTENT = "zipcontent/"

def get_zip_content_config():
    zip_content_origin = conf.OPTIONS["Deployment"]["ZIP_CONTENT_ORIGIN"]
    if not zip_content_origin:
        zip_content_port = str(
            get_zip_port() or conf.OPTIONS["Deployment"]["ZIP_CONTENT_PORT"]
        )
    elif type(zip_content_origin) is int:
        zip_content_port = str(zip_content_origin)
        zip_content_origin = ""
    else:
        zip_content_port = ""
    return zip_content_origin, zip_content_port

def zip_content_path_prefix():
    path_prefix = conf.OPTIONS["Deployment"]["ZIP_CONTENT_URL_PATH_PREFIX"]

    if path_prefix != "/":
        path_prefix = "/" + path_prefix
    return path_prefix

def get_zip_content_base_path():
    return "{}{}".format(get_content_url(zip_content_path_prefix()), ZIPCONTENT)

HASHI_FILENAME = None

def get_hashi_html_filename():
    global HASHI_FILENAME
    if HASHI_FILENAME is None or getattr(settings, "DEVELOPER_MODE", None):
        with io.open(
            os.path.abspath(
                os.path.join(os.path.dirname(__file__), "../build/hashi_filename")
            ),
            mode="r",
            encoding="utf-8",
        ) as f:
            HASHI_FILENAME = f.read().strip()
    return HASHI_FILENAME

def zip_content_static_root():
    return join_url(get_content_url(zip_content_path_prefix()), "static/")

def get_hashi_path():
    return "{}{}{}".format(zip_content_static_root(), HASHI, get_hashi_html_filename())