<commit_before>
const ActorClass = {};
const RG = require('./rg');
RG.Component = require('./component');
RG.Spell = require('./spell');

class ActorClassBase {

    constructor(actor, name) {
        this._actor = actor;
        actor.setActorClass(this);
        this._className = name;
    }

    getClassName() {
        return this._className;
    }

    /* Called when a level is advanced by the actor. Checks for messages, and if
     * the next ability is triggered. */
    advanceLevel() {
        const newLevel = this._actor.get('Experience').getExpLevel();
        if (this._messages.hasOwnProperty(newLevel)) {
            const cell = this._actor.getCell();
            RG.gameMsg({cell, msg: this._messages[newLevel]});
        }
        if (this._advances.hasOwnProperty(newLevel)) {
            this._advances[newLevel]();
        }
    }
}

//-------------------------------------------------------------------------
/* Adventurer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Adventurer extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Adventurer');
    }

    /* Called when a level is advanced by the actor. Checks for messages, and if
     * the next ability is triggered. */
    advanceLevel() {
        const newLevel = this._actor.get('Experience').getExpLevel();
        if (newLevel % 4 === 0) {
            // Get other random actor class
            // Use it to add new abilities to the actor
        }
    }

    /* Called at the creation of the actor. Gives certain set of starting items.
     */
    addStartingItems() {

    }

    setStartingStats() {

    }
}

ActorClass.Adventurer = Adventurer;

//-------------------------------------------------------------------------
/* Blademaster actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Blademaster extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Blademaster');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} knows now how to defend more skillfully`,
            8: `${_name} knows now how to hit enemies more accurately`,
            12: `${_name} knows now how to handle equipment better`,
            16: `${_name} can now strike in two directions`,
            20: `${_name} can now keep the weapons sharp`,
            24: `${_name} can now wield two blades at once`,
            28: `${_name} can now strike back immediately when attacked`,
            32: `${_name} has become a True Blademaster`
        };

        this._advances = {
            1: () => {

            },
            4: () => {
                this._actor.add(new RG.Component.Defender());
            },
            8: () => {
                this._actor.add(new RG.Component.Attacker());
            },
            12: () => {
                this._actor.add(new RG.Component.MasterEquipper());
            },
            16: () => {
                this._actor.add(new RG.Component.BiDirStrike());
            },
            20: () => {
                this._actor.add(new RG.Component.Sharpener());
            },
            24: () => {
                this._actor.add(new RG.Component.Ambidexterity());
            },
            28: () => {
                this._actor.add(new RG.Component.CounterAttack());
            },
            32: () => {
                actor.get('Combat').setRange(2);
                this._actor.add(new RG.Component.LongReach());
            }
        };
    }

    /* Called at the creation of the actor. Gives certain set of starting items.
     */
    addStartingItems() {
        // Start with longsword and some armour
    }

    setStartingStats() {
        // Add some strength + agi
    }

}

ActorClass.Blademaster = Blademaster;

//-------------------------------------------------------------------------
/* Cryomancer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Cryomancer extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Cryomancer');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} learns a protection spell`,
            8: `${_name} learns to attack enemies from distance`,
            12: `${_name} can freeze enemies on their tracks`,
            16: `${_name} can summon an ice companion now`,
            20: `${_name} can drain power from other spellcasters`,
            24: `${_name} can fire ice arrows towards enemies`,
            28: `${_name} can control their enemies now`,
            32: `${_name} has become a True Cryomancer, Bringer of Blizzard`
        };

        this._advances = {
            1: () => {
                // Create the spellbook
                const book = new RG.Spell.SpellBook(this._actor);
                const grasp = new RG.Spell.GraspOfWinter();
                book.addSpell(grasp);
                this._actor.setBook(book);
            },
            4: () => {
                this._actor.getBook().addSpell(new RG.Spell.IceShield());
            },
            8: () => {
                this._actor.getBook().addSpell(new RG.Spell.FrostBolt());
            },
            12: () => {
                this._actor.getBook().addSpell(new RG.Spell.IcyPrison());
            },
            16: () => {
                this._actor.getBook().addSpell(new RG.Spell.SummonIceMinion());
            },
            20: () => {
                this._actor.getBook().addSpell(new RG.Spell.PowerDrain());
            },
            24: () => {
                this._actor.getBook().addSpell(new RG.Spell.IceArrow());
            },
            28: () => {
                this._actor.getBook().addSpell(new RG.Spell.MindControl());
            },
            32: () => {
                this._actor.getBook().addSpell(new RG.Spell.Blizzard());
            }
        };
    }

    getStartingItems() {
        return {
            inventory: [],
            equipment: []
        };
    }

    setStartingStats() {
        // Add magic
    }

}

ActorClass.Cryomancer = Cryomancer;

//-------------------------------------------------------------------------
/* Cryomancer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Marksman extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Marksman');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} can now see and shoot further`,
            8: `${_name} deals now more damage with shots`,
            12: `${_name} can bypass enemies with ranged attacks`,
            16: `${_name} can use arrows/bolts interchangeably`,
            20: `${_name} can shoot even further`,
            24: `${_name} can evade ranged attacks`,
            28: `${_name} can shoot enemies critically`,
            32: `${_name} has become a True Marksman`
        };

        this._advances = {
            1: () => {

            },
            4: () => {
                this._actor.add(new RG.Component.EagleEye());
            },
            8: () => {
                this._actor.add(new RG.Component.StrongShot());
            },
            12: () => {
                this._actor.add(new RG.Component.ThroughShot());
            },
            16: () => {
                this._actor.add(new RG.Component.MixedShot());
            },
            20: () => {
                this._actor.add(new RG.Component.LongRangeShot());
            },
            24: () => {
                this._actor.add(new RG.Component.RangedEvasion());
            },
            28: () => {
                this._actor.add(new RG.Component.CriticalShot());
            },
            32: () => {
                this._actor.add(new RG.Component.DoubleShot());
            }
        };
    }

    addStartingItems() {

    }

    setStartingStats() {

    }

}
ActorClass.Marksman = Marksman;

//-------------------------------------------------------------------------
/* Spellsinger actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Spellsinger extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Spellsinger');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} gains new skill`,
            8: `${_name} gains new skill`,
            12: `${_name} gains new skill`,
            16: `${_name} gains new skill`,
            20: `${_name} gains new skill`,
            24: `${_name} gains new skill`,
            28: `${_name} gains new skill`,
            32: `${_name} has become a Mighty Spellsinger`
        };

        this._advances = {
            1: () => {

            },
            4: () => {

            },
            8: () => {

            },
            12: () => {

            },
            16: () => {

            },
            20: () => {

            },
            24: () => {

            },
            28: () => {

            },
            32: () => {

            }
        };
    }

    addStartingItems() {
        // Starting instrument

    }

    setStartingStats() {

    }

}
ActorClass.Spellsinger = Spellsinger;

RG.ACTOR_CLASSES = Object.keys(ActorClass);

module.exports = ActorClass;
<commit_msg>Added getStartingEquipment functions.<commit_after>
const ActorClass = {};
const RG = require('./rg');
RG.Component = require('./component');
RG.Spell = require('./spell');

class ActorClassBase {

    constructor(actor, name) {
        this._actor = actor;
        actor.setActorClass(this);
        this._className = name;
    }

    getClassName() {
        return this._className;
    }

    /* Called when a level is advanced by the actor. Checks for messages, and if
     * the next ability is triggered. */
    advanceLevel() {
        const newLevel = this._actor.get('Experience').getExpLevel();
        if (this._messages.hasOwnProperty(newLevel)) {
            const cell = this._actor.getCell();
            RG.gameMsg({cell, msg: this._messages[newLevel]});
        }
        if (this._advances.hasOwnProperty(newLevel)) {
            this._advances[newLevel]();
        }
    }
}

//-------------------------------------------------------------------------
/* Adventurer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Adventurer extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Adventurer');
    }

    /* Called when a level is advanced by the actor. Checks for messages, and if
     * the next ability is triggered. */
    advanceLevel() {
        const newLevel = this._actor.get('Experience').getExpLevel();
        if (newLevel % 4 === 0) {
            // Get other random actor class
            // Use it to add new abilities to the actor
        }
    }

    /* Called at the creation of the actor. Gives certain set of starting items.
     */
    getStartingItems() {
        return [
            {name: 'Ration', count: 2}
        ];
    }

    getStartingEquipment() {
        return [
            {name: 'Short sword', count: 1},
            {name: 'Leather armour', count: 1}
        ];
    }

    setStartingStats() {
        // const stats = this._actor.get('Stats');
    }
}

ActorClass.Adventurer = Adventurer;

//-------------------------------------------------------------------------
/* Blademaster actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Blademaster extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Blademaster');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} knows now how to defend more skillfully`,
            8: `${_name} knows now how to hit enemies more accurately`,
            12: `${_name} knows now how to handle equipment better`,
            16: `${_name} can now strike in two directions`,
            20: `${_name} can now keep the weapons sharp`,
            24: `${_name} can now wield two blades at once`,
            28: `${_name} can now strike back immediately when attacked`,
            32: `${_name} has become a True Blademaster`
        };

        this._advances = {
            1: () => {

            },
            4: () => {
                this._actor.add(new RG.Component.Defender());
            },
            8: () => {
                this._actor.add(new RG.Component.Attacker());
            },
            12: () => {
                this._actor.add(new RG.Component.MasterEquipper());
            },
            16: () => {
                this._actor.add(new RG.Component.BiDirStrike());
            },
            20: () => {
                this._actor.add(new RG.Component.Sharpener());
            },
            24: () => {
                this._actor.add(new RG.Component.Ambidexterity());
            },
            28: () => {
                this._actor.add(new RG.Component.CounterAttack());
            },
            32: () => {
                actor.get('Combat').setRange(2);
                this._actor.add(new RG.Component.LongReach());
            }
        };
    }

    /* Called at the creation of the actor. Gives certain set of starting items.
     */
    getStartingItems() {
        return [
            {name: 'Ration', count: 1}
        ];
    }

    getStartingEquipment() {
        return [
            {name: 'Longsword', count: 1},
            {name: 'Chain armour', count: 1}
        ];
    }

    setStartingStats() {
        const stats = this._actor.get('Stats');
        stats.incrStat('strength', 3);
        stats.incrStat('magic', -3);
    }

}

ActorClass.Blademaster = Blademaster;

//-------------------------------------------------------------------------
/* Cryomancer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Cryomancer extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Cryomancer');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} learns a protection spell`,
            8: `${_name} learns to attack enemies from distance`,
            12: `${_name} can freeze enemies on their tracks`,
            16: `${_name} can summon an ice companion now`,
            20: `${_name} can drain power from other spellcasters`,
            24: `${_name} can fire ice arrows towards enemies`,
            28: `${_name} can control their enemies now`,
            32: `${_name} has become a True Cryomancer, Bringer of Blizzard`
        };

        this._advances = {
            1: () => {
                // Create the spellbook
                const book = new RG.Spell.SpellBook(this._actor);
                const grasp = new RG.Spell.GraspOfWinter();
                book.addSpell(grasp);
                this._actor.setBook(book);
            },
            4: () => {
                this._actor.getBook().addSpell(new RG.Spell.IceShield());
            },
            8: () => {
                this._actor.getBook().addSpell(new RG.Spell.FrostBolt());
            },
            12: () => {
                this._actor.getBook().addSpell(new RG.Spell.IcyPrison());
            },
            16: () => {
                this._actor.getBook().addSpell(new RG.Spell.SummonIceMinion());
            },
            20: () => {
                this._actor.getBook().addSpell(new RG.Spell.PowerDrain());
            },
            24: () => {
                this._actor.getBook().addSpell(new RG.Spell.IceArrow());
            },
            28: () => {
                this._actor.getBook().addSpell(new RG.Spell.MindControl());
            },
            32: () => {
                this._actor.getBook().addSpell(new RG.Spell.Blizzard());
            }
        };
    }

    getStartingItems() {
        return [
            {name: 'Ration', count: 1},
            {name: 'Potion of power', count: 1}
        ];
    }

    getStartingEquipment() {
        return [
            {name: 'Robe', count: 1},
            {name: 'Wooden staff', count: 1}
        ];

    }

    setStartingStats() {
        const stats = this._actor.get('Stats');
        stats.incrStat('strength', -2);
        stats.incrStat('magic', 3);
    }

}

ActorClass.Cryomancer = Cryomancer;

//-------------------------------------------------------------------------
/* Cryomancer actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Marksman extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Marksman');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} can now see and shoot further`,
            8: `${_name} deals now more damage with shots`,
            12: `${_name} can bypass enemies with ranged attacks`,
            16: `${_name} can use arrows/bolts interchangeably`,
            20: `${_name} can shoot even further`,
            24: `${_name} can evade ranged attacks`,
            28: `${_name} can shoot enemies critically`,
            32: `${_name} has become a True Marksman`
        };

        this._advances = {
            1: () => {

            },
            4: () => {
                this._actor.add(new RG.Component.EagleEye());
            },
            8: () => {
                this._actor.add(new RG.Component.StrongShot());
            },
            12: () => {
                this._actor.add(new RG.Component.ThroughShot());
            },
            16: () => {
                this._actor.add(new RG.Component.MixedShot());
            },
            20: () => {
                this._actor.add(new RG.Component.LongRangeShot());
            },
            24: () => {
                this._actor.add(new RG.Component.RangedEvasion());
            },
            28: () => {
                this._actor.add(new RG.Component.CriticalShot());
            },
            32: () => {
                this._actor.add(new RG.Component.DoubleShot());
            }
        };
    }

    getStartingItems() {
        return [
            {name: 'Ration', count: 1}
        ];
    }

    getStartingEquipment() {
        return [
            {name: 'Leather armour', count: 1},
            {name: 'Wooden bow', count: 1},
            {name: 'Wooden arrow', count: 15}
        ];

    }

    setStartingStats() {
        const stats = this._actor.get('Stats');
        stats.incrStat('accuracy', 3);
        stats.incrStat('perception', 2);
        stats.incrStat('magic', -3);
    }

}
ActorClass.Marksman = Marksman;

//-------------------------------------------------------------------------
/* Spellsinger actor class and its experience level-specific features. */
//-------------------------------------------------------------------------
class Spellsinger extends ActorClassBase {

    constructor(actor) {
        super(actor, 'Spellsinger');
        const _name = actor.getName();

        this._messages = {
            4: `${_name} gains new skill`,
            8: `${_name} gains new skill`,
            12: `${_name} gains new skill`,
            16: `${_name} gains new skill`,
            20: `${_name} gains new skill`,
            24: `${_name} gains new skill`,
            28: `${_name} gains new skill`,
            32: `${_name} has become a Mighty Spellsinger`
        };

        this._advances = {
            1: () => {

            },
            4: () => {

            },
            8: () => {

            },
            12: () => {

            },
            16: () => {

            },
            20: () => {

            },
            24: () => {

            },
            28: () => {

            },
            32: () => {

            }
        };
    }

    getStartingItems() {
        // Starting instrument

    }

    getStartingEquipment() {

    }

    setStartingStats() {

    }

}
ActorClass.Spellsinger = Spellsinger;

RG.ACTOR_CLASSES = Object.keys(ActorClass);

module.exports = ActorClass;
<|endoftext|>


<commit_before>/*
 * grunt-ng-template
 * https://github.com/duckbox/grunt-ng-template.git
 *
 * Copyright (c) 2013 Chris Grant (@duckbox)
 * Licensed under the MIT license.
 */
'use strict';

module.exports = function (grunt) {

    grunt.registerMultiTask('ng_template', 'Make external angular templates inline', function () {

        var configs = {
            TEMPLATE: '',
            partials: [],
            comment_line: '' + grunt.util.linefeed + '<% content %>' + grunt.util.linefeed + '',
            PATH: require('path'),
            appDir_path: require('path').resolve(this.options().appDir)
        },
            BASE_FILE = this.options().appDir + '/' + this.options().indexFile,
            ABS_PATH = process.cwd();

        function stripTemplates() {

            var base_file = grunt.file.read(BASE_FILE),

                stripped_html = base_file.replace(/',
            partials: [],
            comment_line: '' + grunt.util.linefeed + '<% content %>' + grunt.util.linefeed + '',
            PATH: require('path'),
            appDir_path: require('path').resolve(this.options().appDir)
        },
            BASE_FILE = this.options().appDir + '/' + this.options().indexFile,
            ABS_PATH = process.cwd();

        function stripTemplates() {

            var base_file = grunt.file.read(BASE_FILE),

                stripped_html = base_file.replace(/


<commit_before>let azure = require('azure-storage');

// The AzDriver utilized the azure nodejs sdk to write files to azure blob storage
class AzDriver {

  constructor (config) {
    this.blobService = azure.createBlobService(config.azCredentials.accountName,config.azCredentials.accountKey)
    this.bucket = config.bucket
    this.logger = config.logger
    this.accountName = config.azCredentials.accountName
    this.readURL = config.readURL
    this.cacheControl = config.cacheControl

    this.backupProfiles = true

    // Check for container(bucket), create it if does not exist
    // Set permissions to 'blob' to allow public reads
    this.blobService.createContainerIfNotExists(config.bucket, { publicAccessLevel: 'blob' }, (error, result, response) => {
      if (error) {
        config.logger.error(`failed to initialize azure container: ${error}`)
        process.exit()
      }
      config.logger.info(`container initialized: ${result}`)
    });
  }

  static isPathValid (path) {
    // for now, only disallow double dots.
    return (path.indexOf("..") === -1)
  }

  getReadURLPrefix () {
    if (this.readURL) {
      return `https://${this.readURL}/${this.bucket}/`
    }
    return `https://${this.accountName}.blob.core.windows.net/${this.bucket}/`
  }

  performWrite (args) {
    // cancel write and return 402 if path is invalid
    if (! AzDriver.isPathValid(args.path)){
      args.sr.callback({"message": "Invalid path"}, null, 402)
      return
    }

    // Prepend ${address}/ to filename
    let azBlob = `${args.storageToplevel}/${args.path}`
    let azOpts = {}
    if (this.cacheControl) {
      azOpts.contentSettings = { 'cacheControl' : this.cacheControl }
    }
    this.blobService.createBlockBlobFromStream(this.bucket, azBlob, (args.stream), args.contentLength, azOpts, (error, result, response) => {

      // return error to user, and log on error
      if (error) {
        this.logger.error(`failed to store ${azBlob} in container ${this.bucket}: ${error}`)
        args.sr.callback(error, response, 500)
        return
      }

      if (this.backupProfiles && azBlob.endsWith('profile.json')) {
        // make a backup!
        this.logger.info('trying to back up profile.json')
        const timestamp = Math.floor(Date.now() / 1000)
        const backupBucket = 'hubbackup'
        this.blobService.createBlockBlobFromStream(
          backupBucket, `${azBlob}.{timestamp}`, (args.stream), args.contentLength, azOpts,
          (errorBackup, resultBackup, responseBackup) => {
            if (errorBackup){
              this.logger.error(`failed to backup ${azBlob}.${timestamp} in container ${backupBucket}: ${error}`)
              return
            }
            this.logger.info(`backed up ${azBlob}.${timestamp} in container ${backupBucket}`)
            // Return success and url to user
            let readURL = this.getReadURLPrefix()
            let publicURL = `${readURL}${azBlob}`
            this.logger.info(`storing ${azBlob} in container ${this.bucket}, URL: ${publicURL}`)
            args.sr.callback(error, { publicURL }, 202)
          }
        )
      }else{
        // Return success and url to user
        let readURL = this.getReadURLPrefix()
        let publicURL = `${readURL}${azBlob}`
        this.logger.info(`storing ${azBlob} in container ${this.bucket}, URL: ${publicURL}`)
        args.sr.callback(error, { publicURL }, 202)
      }
    });
  }

}

module.exports = AzDriver
<commit_msg>revert those backup changes<commit_after>let azure = require('azure-storage');

// The AzDriver utilized the azure nodejs sdk to write files to azure blob storage
class AzDriver {

  constructor (config) {
    this.blobService = azure.createBlobService(config.azCredentials.accountName,config.azCredentials.accountKey)
    this.bucket = config.bucket
    this.logger = config.logger
    this.accountName = config.azCredentials.accountName
    this.readURL = config.readURL
    this.cacheControl = config.cacheControl

    // Check for container(bucket), create it if does not exist
    // Set permissions to 'blob' to allow public reads
    this.blobService.createContainerIfNotExists(config.bucket, { publicAccessLevel: 'blob' }, (error, result, response) => {
      if (error) {
        config.logger.error(`failed to initialize azure container: ${error}`)
        process.exit()
      }
      config.logger.info(`container initialized: ${result}`)
    });
  }

  static isPathValid (path) {
    // for now, only disallow double dots.
    return (path.indexOf("..") === -1)
  }

  getReadURLPrefix () {
    if (this.readURL) {
      return `https://${this.readURL}/${this.bucket}/`
    }
    return `https://${this.accountName}.blob.core.windows.net/${this.bucket}/`
  }

  performWrite (args) {
    // cancel write and return 402 if path is invalid
    if (! AzDriver.isPathValid(args.path)){
      args.sr.callback({"message": "Invalid path"}, null, 402)
      return
    }

    // Prepend ${address}/ to filename
    let azBlob = `${args.storageToplevel}/${args.path}`
    let azOpts = {}
    if (this.cacheControl) {
      azOpts.contentSettings = { 'cacheControl' : this.cacheControl }
    }
    this.blobService.createBlockBlobFromStream(this.bucket, azBlob, (args.stream), args.contentLength, azOpts, (error, result, response) => {

      // return error to user, and log on error
      if (error) {
        this.logger.error(`failed to store ${azBlob} in container ${this.bucket}: ${error}`)
        args.sr.callback(error, response, 500)
        return
      }

      // Return success and url to user
      let readURL = this.getReadURLPrefix()
      let publicURL = `${readURL}${azBlob}`
      this.logger.info(`storing ${azBlob} in container ${this.bucket}, URL: ${publicURL}`)
      args.sr.callback(error, { publicURL }, 202)
    });
  }

}

module.exports = AzDriver
<|endoftext|>


<commit_before>const express = require('express');
const shortid = require('shortid');
const aws = require('aws-sdk');
const { ungzip } = require('pako');
const { gzipSync } = require('zlib');
const pretty = require('prettysize');
const metrics = require('../lib/metrics');
const serializer = require('../lib/iterators/serializer');
const { transform, symbolicate } = require('../lib/iterators/transform');

const s3Defaults = { Bucket: process.env.S3_BUCKET };
const cacheExpire = 600;
const queueMax = 2;

const waitFor = (test, proceed) => {
  return new Promise(resolve => {
    const next = () => {
      const result = test();
      if (result) {
        proceed(result);
        return resolve(result);
      }
      setTimeout(next, 500);
    };
    process.nextTick(next);
  });
};

const mapProfilePending = new Set();
const mapProfileActive = new Set();

const mapProfile = async (redis, key) => {
  console.time(`${key} queued`);
  mapProfilePending.add(key);
  await waitFor(
    () => {
      return mapProfileActive.size < queueMax;
    },
    () => {
      mapProfileActive.add(key);
    }
  );
  console.timeEnd(`${key} queued`);
  console.time(`${key} processing`);
  const profile = await fetchTransformedProfile(redis, key);
  if (profile) {
    const mapped = metrics.mapAll(profile);
    await redis.hset('mapped', key, serializer.stringify(mapped));
  }
  mapProfilePending.delete(key);
  mapProfileActive.delete(key);
  console.timeEnd(`${key} processing`);
};

const validateProfile = profile => {
  for (const [key, meta] of metrics.meta) {
    if (!profile.has(key) && !meta.extra) {
      return false;
    }
  }
  return true;
};

const mapProfiles = async (redis, prefix = null) => {
  const list = await listProfiles(prefix);
  const cached = (await redis.hgetall('mapped')) || {};
  const profiles = new Map(
    Object.entries(cached)
      .filter(entry => !prefix || entry[0].startsWith(prefix))
      .map(entry => {
        entry[1] = serializer.parse(entry[1]);
        return entry;
      })
      .filter(entry => validateProfile(entry[1]))
  );
  let pending = 0;
  for (const { key } of list) {
    if (profiles.has(key)) {
      profiles.get(key).set('exists', true);
    } else {
      pending += 1;
      if (!mapProfilePending.has(key)) {
        mapProfile(redis, key);
      }
    }
  }
  return { profiles, pending };
};

const listProfiles = async (prefix = null) => {
  const s3 = new aws.S3();
  const params = Object.assign({}, s3Defaults);
  if (prefix) {
    params.Prefix = prefix;
  }
  const contents = [];
  do {
    const response = await s3.listObjectsV2(params).promise();
    response.Contents.forEach(file => {
      if (!file.Key.includes('.')) {
        contents.push({
          key: file.Key,
          size: file.Size,
        });
      }
    });
    params.ContinuationToken = response.NextContinuationToken;
  } while (params.ContinuationToken);
  return contents;
};

const symbolicateAndStoreProfile = async (key, profile, object) => {
  const s3 = new aws.S3();
  await symbolicate(profile);
  try {
    const copyKey = key + '.symbolicated';
    const metadata = {
      ContentType: 'application/json',
      ContentEncoding: 'gzip',
      ACL: 'authenticated-read',
      Expires: object.Expires,
      Metadata: {
        symbolicated: profile.meta.symbolicated,
        uploaded: object.Metadata.uploaded || object.LastModified.toJSON(),
      },
    };
    await s3
      .putObject(
        Object.assign(
          {
            Key: copyKey,
            Body: gzipSync(JSON.stringify(profile)),
          },
          metadata,
          s3Defaults
        )
      )
      .promise();
    await s3
      .copyObject(
        Object.assign(
          {
            Key: key,
            CopySource: `/${s3Defaults.Bucket}/${copyKey}`,
          },
          metadata,
          s3Defaults
        )
      )
      .promise();
    await s3
      .deleteObject(
        Object.assign(
          {
            Key: copyKey,
          },
          s3Defaults
        )
      )
      .promise();
  } catch (err) {
    console.error('[report]', 'Could not store symbolicated profile', err);
  }
};

const fetchTransformedProfile = async (redis, key) => {
  const s3 = new aws.S3();
  const params = Object.assign(
    {
      Key: key,
    },
    s3Defaults
  );
  const object = await s3
    .getObject(params)
    .promise()
    .catch(err => console.error('[report]', err));
  if (!object) {
    return null;
  }
  const binary = object.Body.toString('binary');
  let profile = null;
  try {
    profile = JSON.parse(ungzip(binary, { to: 'string' }));
  } catch (err) {
    console.error(
      '[report]',
      key,
      'Corrupt profile, marked for deletion.',
      err.message || err
    );
    const deletion = await s3
      .deleteObject(params)
      .promise()
      .catch(err => console.error('[report]', err));
    return null;
  }
  if (!profile.meta.symbolicated) {
    await symbolicateAndStoreProfile(key, profile, object);
  }
  const transformed = transform(profile);
  return transformed;
};

const router = express.Router();
module.exports = router;

// router.use((req, res, next) => {
//   if (process.env.NODE_ENV === 'production') {
//     return res.sendStatus(405);
//   }
//   next();
// });

router
  .get('/', async (req, res) => {
    const { prefix } = req.query || {};
    if (prefix && !prefix.split('/').every(shortid.isValid)) {
      return res.sendStatus(500);
    }
    let profiles = null;
    try {
      profiles = await mapProfiles(req.app.get('redis'), prefix);
    } catch (err) {
      console.error(err);
      return res.sendStatus(500);
    }
    res.json(profiles);
  })
  .get('/stats', async (req, res) => {
    let files = [];
    try {
      files = await listProfiles();
    } catch (err) {
      console.error(err);
      return res.sendStatus(500);
    }
    const users = files.reduce((unique, entry) => {
      return unique.add(entry.key.split('/')[0]);
    }, new Set());
    res.json({
      profiles: files.length,
      users: users.size,
      size: pretty(
        files.reduce((sum, entry) => {
          return sum + entry.size;
        }, 0)
      ),
    });
  })
  .get('/metrics', (req, res) => {
    res.json(metrics.meta);
  })
  // .get('/transformed/:user/:file', async (req, res) => {
  //   const { user, file } = req.params;
  //   if (!shortid.isValid(user) || !shortid.isValid(file)) {
  //     return res.sendStatus(500);
  //   }
  //   try {
  //     const json = await fetchTransformedProfile(req.app.get('redis'), `${user}/${file}`);
  //     return res.json(json);
  //   } catch (err) {
  //     console.error(err);
  //   }
  //   res.sendStatus(500);
  // })
  .get('/view/:user/:file', async (req, res) => {
    const { user, file } = req.params;
    if (!shortid.isValid(user) || !shortid.isValid(file)) {
      return res.sendStatus(500);
    }
    const s3 = new aws.S3();
    const key = `${user}/${file}`;
    const params = Object.assign(
      {
        Key: key,
      },
      s3Defaults
    );
    const response = await s3.headObject(params).promise();
    if (response && !response.Metadata.symbolicated) {
      // TODO: Generic loader, duplicates code from transform
      const object = await s3.getObject(params).promise();
      const profile = JSON.parse(
        ungzip(object.Body.toString('binary'), { to: 'string' })
      );
      await symbolicateAndStoreProfile(key, profile, object);
    }
    const url = s3.getSignedUrl(
      'getObject',
      Object.assign(
        {
          Key: key,
          Expires: 60,
        },
        s3Defaults
      )
    );
    res.redirect(
      302,
      `https://perf-html.io/from-url/${encodeURIComponent(url)}`
    );
  });
<commit_msg>Don't delete, something is wrong<commit_after>const express = require('express');
const shortid = require('shortid');
const aws = require('aws-sdk');
const { ungzip } = require('pako');
const { gzipSync } = require('zlib');
const pretty = require('prettysize');
const metrics = require('../lib/metrics');
const serializer = require('../lib/iterators/serializer');
const { transform, symbolicate } = require('../lib/iterators/transform');

const s3Defaults = { Bucket: process.env.S3_BUCKET };
const cacheExpire = 600;
const queueMax = 2;

const waitFor = (test, proceed) => {
  return new Promise(resolve => {
    const next = () => {
      const result = test();
      if (result) {
        proceed(result);
        return resolve(result);
      }
      setTimeout(next, 500);
    };
    process.nextTick(next);
  });
};

const mapProfilePending = new Set();
const mapProfileActive = new Set();

const mapProfile = async (redis, key) => {
  console.time(`${key} queued`);
  mapProfilePending.add(key);
  await waitFor(
    () => {
      return mapProfileActive.size < queueMax;
    },
    () => {
      mapProfileActive.add(key);
    }
  );
  console.timeEnd(`${key} queued`);
  console.time(`${key} processing`);
  const profile = await fetchTransformedProfile(redis, key);
  if (profile) {
    const mapped = metrics.mapAll(profile);
    await redis.hset('mapped', key, serializer.stringify(mapped));
  }
  mapProfilePending.delete(key);
  mapProfileActive.delete(key);
  console.timeEnd(`${key} processing`);
};

const validateProfile = profile => {
  for (const [key, meta] of metrics.meta) {
    if (!profile.has(key) && !meta.extra) {
      return false;
    }
  }
  return true;
};

const mapProfiles = async (redis, prefix = null) => {
  const list = await listProfiles(prefix);
  const cached = (await redis.hgetall('mapped')) || {};
  const profiles = new Map(
    Object.entries(cached)
      .filter(entry => !prefix || entry[0].startsWith(prefix))
      .map(entry => {
        entry[1] = serializer.parse(entry[1]);
        return entry;
      })
      .filter(entry => validateProfile(entry[1]))
  );
  let pending = 0;
  for (const { key } of list) {
    if (profiles.has(key)) {
      profiles.get(key).set('exists', true);
    } else {
      pending += 1;
      if (!mapProfilePending.has(key)) {
        mapProfile(redis, key);
      }
    }
  }
  return { profiles, pending };
};

const listProfiles = async (prefix = null) => {
  const s3 = new aws.S3();
  const params = Object.assign({}, s3Defaults);
  if (prefix) {
    params.Prefix = prefix;
  }
  const contents = [];
  do {
    const response = await s3.listObjectsV2(params).promise();
    response.Contents.forEach(file => {
      if (!file.Key.includes('.')) {
        contents.push({
          key: file.Key,
          size: file.Size,
        });
      }
    });
    params.ContinuationToken = response.NextContinuationToken;
  } while (params.ContinuationToken);
  return contents;
};

const symbolicateAndStoreProfile = async (key, profile, object) => {
  const s3 = new aws.S3();
  await symbolicate(profile);
  try {
    const copyKey = key + '.symbolicated';
    const metadata = {
      ContentType: 'application/json',
      ContentEncoding: 'gzip',
      ACL: 'authenticated-read',
      Expires: object.Expires,
      Metadata: {
        symbolicated: profile.meta.symbolicated,
        uploaded: object.Metadata.uploaded || object.LastModified.toJSON(),
      },
    };
    await s3
      .putObject(
        Object.assign(
          {
            Key: copyKey,
            Body: gzipSync(JSON.stringify(profile)),
          },
          metadata,
          s3Defaults
        )
      )
      .promise();
    await s3
      .copyObject(
        Object.assign(
          {
            Key: key,
            CopySource: `/${s3Defaults.Bucket}/${copyKey}`,
          },
          metadata,
          s3Defaults
        )
      )
      .promise();
    await s3
      .deleteObject(
        Object.assign(
          {
            Key: copyKey,
          },
          s3Defaults
        )
      )
      .promise();
  } catch (err) {
    console.error('[report]', 'Could not store symbolicated profile', err);
  }
};

const fetchTransformedProfile = async (redis, key) => {
  const s3 = new aws.S3();
  const params = Object.assign(
    {
      Key: key,
    },
    s3Defaults
  );
  const object = await s3
    .getObject(params)
    .promise()
    .catch(err => console.error('[report]', err));
  if (!object) {
    return null;
  }
  const binary = object.Body.toString('binary');
  let profile = null;
  try {
    profile = JSON.parse(ungzip(binary, { to: 'string' }));
  } catch (err) {
    console.error(
      '[report]',
      key,
      'Corrupt profile, not marked for deletion.',
      err.message || err
    );
    // await s3
    //   .deleteObject(params)
    //   .promise()
    //   .catch(err => console.error('[report]', err));
    return null;
  }
  if (!profile.meta.symbolicated) {
    await symbolicateAndStoreProfile(key, profile, object);
  }
  const transformed = transform(profile);
  return transformed;
};

const router = express.Router();
module.exports = router;

// router.use((req, res, next) => {
//   if (process.env.NODE_ENV === 'production') {
//     return res.sendStatus(405);
//   }
//   next();
// });

router
  .get('/', async (req, res) => {
    const { prefix } = req.query || {};
    if (prefix && !prefix.split('/').every(shortid.isValid)) {
      return res.sendStatus(500);
    }
    let profiles = null;
    try {
      profiles = await mapProfiles(req.app.get('redis'), prefix);
    } catch (err) {
      console.error(err);
      return res.sendStatus(500);
    }
    res.json(profiles);
  })
  .get('/stats', async (req, res) => {
    let files = [];
    try {
      files = await listProfiles();
    } catch (err) {
      console.error(err);
      return res.sendStatus(500);
    }
    const users = files.reduce((unique, entry) => {
      return unique.add(entry.key.split('/')[0]);
    }, new Set());
    res.json({
      profiles: files.length,
      users: users.size,
      size: pretty(
        files.reduce((sum, entry) => {
          return sum + entry.size;
        }, 0)
      ),
    });
  })
  .get('/metrics', (req, res) => {
    res.json(metrics.meta);
  })
  // .get('/transformed/:user/:file', async (req, res) => {
  //   const { user, file } = req.params;
  //   if (!shortid.isValid(user) || !shortid.isValid(file)) {
  //     return res.sendStatus(500);
  //   }
  //   try {
  //     const json = await fetchTransformedProfile(req.app.get('redis'), `${user}/${file}`);
  //     return res.json(json);
  //   } catch (err) {
  //     console.error(err);
  //   }
  //   res.sendStatus(500);
  // })
  .get('/view/:user/:file', async (req, res) => {
    const { user, file } = req.params;
    if (!shortid.isValid(user) || !shortid.isValid(file)) {
      return res.sendStatus(500);
    }
    const s3 = new aws.S3();
    const key = `${user}/${file}`;
    const params = Object.assign(
      {
        Key: key,
      },
      s3Defaults
    );
    const response = await s3.headObject(params).promise();
    if (response && !response.Metadata.symbolicated) {
      // TODO: Generic loader, duplicates code from transform
      const object = await s3.getObject(params).promise();
      const profile = JSON.parse(
        ungzip(object.Body.toString('binary'), { to: 'string' })
      );
      await symbolicateAndStoreProfile(key, profile, object);
    }
    const url = s3.getSignedUrl(
      'getObject',
      Object.assign(
        {
          Key: key,
          Expires: 60,
        },
        s3Defaults
      )
    );
    res.redirect(
      302,
      `https://perf-html.io/from-url/${encodeURIComponent(url)}`
    );
  });
<|endoftext|>


<commit_before>(new function() {

	var element;

	$.fn.imageWall = function(options) {

		element = $(this);

		element.find('img').unbind('load');
		element.find('img').bind('load', function() {
			update(1000);
		});

		update();
		$(window).resize(function() {
			update(200);
		});

	};

	var grid = {
		width: null,
		height: null,
		row: []
	};

	var updateDelay;
	var update = function(delay) {
		if(!delay) return _update();
		if(updateDelay) clearTimeout(updateDelay);
		updateDelay = setTimeout(_update, delay);
	};

	var _update = function() {

		var currentScrollTop = $(window).scrollTop();

		// first setup
		// get image-wall's container width & height

		element.append('
')

		grid = {
			width: $('.image-wall .row').outerWidth(),
			height: $('.image-wall .row').outerHeight(),
			row: [],
		};

		element.find('.row.dummy-row').remove();

		// first alignment grid

		alignmentGrid();

		// fix if last row not full

		if(grid.row.length > 0) {
			while(grid.row[grid.row.length - 1].width < grid.width * 0.8) {
				var r = grid.row.length - 1;

				if(grid.row[r] ? grid.row[r].photos.length > 0 : false) {

					var i = gridRowIndex_MinWidth();
					grid.row[i].maxWidth = Math.max(grid.row[i].width, grid.row[i].maxWidth) + grid.row[i + 1].photos[0].width;

					for(var _i=i + 1; _i<grid.row.length; _i++) {
						grid.row[_i] = {};
					}

					alignmentGrid();

				}

			}
		}

		// render to page

		element.html('');
		for(var r=0; r<grid.row.length; r++) {

			var row = $('

').appendTo(element);
			for(var c=0; c<grid.row[r].photos.length; c++) {
				row.append('\

\
						\
							' + grid.row[r].photos[c].element[0].outerHTML + '\
						\

\
				');
			}

		}

		element.find('img').unbind('load');
		element.find('img').each(function() {
			if(this.complete) return;
			$(this).bind('load', function() {
				update(1000);
			});
		});

		$(window).scrollTop(currentScrollTop);

	};

	var alignmentGrid = function() {

		if(grid.row.length > 0) {
			for(var r=0; r<grid.row.length; r++) {
				grid.row[r].width = 0;
				grid.row[r].photos = [];
			}
		}

		var r = 0;
		element.find('img').each(function(index) {

			if(!grid.row[r]) {
				grid.row[r] = {};
			}

			if(!grid.row[r].width) {
				grid.row[r].width = 0;
			}

			if(!grid.row[r].photos) {
				grid.row[r].photos = [];
			}

			if(!grid.row[r].maxWidth) {
				grid.row[r].maxWidth = grid.width;
			}

			var targetWidth = $(this)[0].naturalWidth ? ($(this)[0].naturalWidth / $(this)[0].naturalHeight * grid.height) : grid.height;

			grid.row[r].width += targetWidth;
			grid.row[r].photos.push({
				index: index,
				width: targetWidth,
				element: $(this)
			});

			if(grid.row[r].width > grid.row[r].maxWidth) {
				r++;
			}

		});

		while(true) {
			if(grid.row.length == 0) break;
			if(grid.row[grid.row.length - 1]) {
				if(!grid.row[grid.row.length - 1] || !grid.row[grid.row.length - 1].photos || grid.row[grid.row.length - 1].photos.length == 0) {
					grid.row.pop();
				} else {
					break;
				}
			} else {
				break;
			}
		}

	};

	var gridRowIndex_MinWidth = function() {

		var i = 0;
		for(var r=0; r<grid.row.length - 1; r++) {
			if(grid.row[r].width < grid.row[i].width) {
				i = r;
			}
		}

		return i;

	};
});<commit_msg>update license / add comments<commit_after>/**
 * image-wall
 * https://github.com/vedsmith92/image-wall
 *
 * Copyright 2016, Ved Smithiprechawongse
 * Licensed under the MIT license.
 * Version: 1.0.1
 */

$(function() {

	var element;

	$.fn.imageWall = function(options) {

		element = $(this);

		element.find('img').unbind('load');
		element.find('img').bind('load', function() {
			update(1000);
		});

		update();
		$(window).resize(function() {
			update(200);
		});

	};

	var grid = {
		width: null,
		height: null,
		row: []
	};

	var updateDelay;
	var update = function(delay) {
		if(!delay) return _update();
		if(updateDelay) clearTimeout(updateDelay);
		updateDelay = setTimeout(_update, delay);
	};

	var _update = function() {

		var currentScrollTop = $(window).scrollTop();

		// first setup
		// get image-wall's container width & height

		element.append('
')

		grid = {
			width: $('.image-wall .row').outerWidth(),
			height: $('.image-wall .row').outerHeight(),
			row: [],
		};

		element.find('.row.dummy-row').remove();

		// first alignment grid

		alignmentGrid();

		// fix if last row not fill fully

		if(grid.row.length > 0) {
			while(grid.row[grid.row.length - 1].width < grid.width * 0.8) {
				var r = grid.row.length - 1;

				if(grid.row[r] ? grid.row[r].photos.length > 0 : false) {

					var i = gridRowIndex_MinWidth();
					grid.row[i].maxWidth = Math.max(grid.row[i].width, grid.row[i].maxWidth) + grid.row[i + 1].photos[0].width;

					for(var _i=i + 1; _i<grid.row.length; _i++) {
						grid.row[_i] = {};
					}

					alignmentGrid();

				}

			}
		}

		// render to page

		element.html('');
		for(var r=0; r<grid.row.length; r++) {

			var row = $('

').appendTo(element);
			for(var c=0; c<grid.row[r].photos.length; c++) {
				row.append('\

\
						\
							' + grid.row[r].photos[c].element[0].outerHTML + '\
						\

\
				');
			}

		}

		// bind image load

		element.find('img').unbind('load');
		element.find('img').each(function() {
			if(this.complete) return;
			$(this).bind('load', function() {
				update(1000);
			});
		});

		$(window).scrollTop(currentScrollTop);

	};

	var alignmentGrid = function() {

		if(grid.row.length > 0) {
			for(var r=0; r<grid.row.length; r++) {
				grid.row[r].width = 0;
				grid.row[r].photos = [];
			}
		}

		var r = 0;
		element.find('img').each(function(index) {

			if(!grid.row[r]) {
				grid.row[r] = {};
			}

			if(!grid.row[r].width) {
				grid.row[r].width = 0;
			}

			if(!grid.row[r].photos) {
				grid.row[r].photos = [];
			}

			if(!grid.row[r].maxWidth) {
				grid.row[r].maxWidth = grid.width;
			}

			var targetWidth = $(this)[0].naturalWidth ? ($(this)[0].naturalWidth / $(this)[0].naturalHeight * grid.height) : grid.height;

			grid.row[r].width += targetWidth;
			grid.row[r].photos.push({
				index: index,
				width: targetWidth,
				element: $(this)
			});

			if(grid.row[r].width > grid.row[r].maxWidth) {
				r++;
			}

		});

		while(true) {
			if(grid.row.length == 0) break;
			if(grid.row[grid.row.length - 1]) {
				if(!grid.row[grid.row.length - 1] || !grid.row[grid.row.length - 1].photos || grid.row[grid.row.length - 1].photos.length == 0) {
					grid.row.pop();
				} else {
					break;
				}
			} else {
				break;
			}
		}

	};

	var gridRowIndex_MinWidth = function() {

		var i = 0;
		for(var r=0; r<grid.row.length - 1; r++) {
			if(grid.row[r].width < grid.row[i].width) {
				i = r;
			}
		}

		return i;

	};

});<|endoftext|>


<commit_before>/* Copyright (c) 2012-2015 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
/* global define, nativeIO, isWin */

define(function(require, exports, module) {
  "use strict";

  console.log("Loading Lite chrome.api.js..");

  // chrome.browserAction.setBadgeBackgroundColor({ color: '#00ff00' });
  // chrome.browserAction.setBadgeText({text: '9999'});

  // changing the name of the app
  $("#logo").text("TagSpaces Lite");

  var TSCORE = require("tscore");
  var TSPOSTIO = require("tspostioapi");
  require("libs/filesaver.js/FileSaver");

  var dataBegin = "<script>addRow(";
  var dataEnd = ");</script>";
  var dataFile = '",0,"';
  var dataDir = '",1,"';

  function getURLParameter(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split("=");
      if (pair[0] == variable) {
        return pair[1];
      }
    }
    return (false);
  }

  function checkAccessFileURLAllowed() {
    chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
      if (!isAllowedAccess) {
        TSCORE.showAlertDialog($.i18n.t("ns.dialogs:accessFileURLNotAllowedAlert"));
      }
    });
  };

  function handleStartParameters() {
    var openFile = getURLParameter("openFile");
    if (openFile !== undefined && (openFile.length > 0)) { //  && openFile.indexOf("file://") === 0
      console.log("Opening file in browser: " + openFile);
      openFile = openFile.split("file://")[1];
      //var dirPath = TSCORE.TagUtils.extractContainingDirectoryPath(filePath);
      //TSCORE.IO.listDirectory(dirPath);
      TSCORE.FileOpener.openFileOnStartup(openFile);
    }
  };

  function focusWindow() {
    // Places the TagSpaces window on top of the windows
    window.focus();
  };

  function saveSettings(content) {
    /*chrome.storage.sync.set({'tagSpacesSettings': content}, function() {
        // Notify that we saved.
        message('Settings saved');
    });*/
  };

  function checkNewVersion() {
    console.log("Checking for new version...");
    var cVer = TSCORE.Config.DefaultSettings.appVersion + "." + TSCORE.Config.DefaultSettings.appBuild;
    $.ajax({
        url: 'http://tagspaces.org/releases/version.json?cVer=' + cVer,
        type: 'GET'
      })
      .done(function(data) {
        TSPOSTIO.checkNewVersion(data);
      })
      .fail(function(data) {
        console.log("AJAX failed " + data);
      });
  };

  function createDirectoryIndex(dirPath) {
    TSCORE.showWaitingDialog($.i18n.t("ns.common:waitDialogDiectoryIndexing"));

    var directoryIndex = [];
    TSCORE.Utils.walkDirectory(dirPath, {recursive: true}, function(fileEntry) {
      directoryIndex.push(fileEntry);
    }).then(
      function(entries) {
        TSPOSTIO.createDirectoryIndex(directoryIndex);
      },
      function(err) {
        console.warn("Error creating index: " + err);
      }
    ).catch(function() {
      TSCORE.hideWaitingDialog();
    });
  };

  function createDirectoryTree(dirPath) {
    TSCORE.showLoadingAnimation();
    console.log("Creating directory not supported: " + dirPath);
    //var directoyTree = generateDirectoryTree(dirPath);
    //console.log(JSON.stringify(directoyTree));
    //TSPOSTIO.createDirectoryTree(directoyTree);
  };

  function listDirectoryPromise(dirPath) {
    console.log("Listing directory: " + dirPath);
    return new Promise(function(resolve, reject) {
      var anotatedDirList = [];
      $.ajax({
          url: "file://" + dirPath,
          type: 'GET'
        })
        .done(function(data) {
          //console.log("Dir List "+data);
          var folders = data.substring(data.indexOf(dataBegin) + dataBegin.length, data.lastIndexOf(dataEnd));
          folders = folders.split(dataBegin).join("");
          folders = folders.split(dataEnd);

          var name,
            path,
            isFile,
            fileSize,
            lastDateModified,
            fileProp;

          anotatedDirList = [];
          // sciping the first entry pointing to the parent directory
          for (var i = 1; i < folders.length; i++) {
            console.log("Dir " + folders[i]);
            name = folders[i].substring(2, folders[i].indexOf('","'));
            path = dirPath + TSCORE.dirSeparator + name;
            isFile = (folders[i].indexOf(dataFile) > 1);
            fileSize = 0;
            lastDateModified = 0;
            if (isFile) {
              fileProp = folders[i].substring(folders[i].indexOf(dataFile) + dataFile.length + 1, folders[i].length - 1);
              fileProp = fileProp.split('","');
              fileSize = fileProp[0];
              lastDateModified = fileProp[1];
            }
            anotatedDirList.push({
              "name": name,
              "isFile": isFile,
              "size": fileSize,
              "lmdt": lastDateModified,
              "path": path
            });
          }
          resolve(anotatedDirList);
        }).fail(function(error) {
          console.warn("Error listing files" + JSON.stringify(error));
          reject(error);
        });
    });
  }

  function listDirectory(dirPath, resultCallback) {
    TSCORE.showLoadingAnimation();
    listDirectoryPromise(dirPath).then(function(anotatedDirList) {
        if (resultCallback) {
          resultCallback(anotatedDirList);
        } else {
          TSPOSTIO.listDirectory(anotatedDirList);
        }
      }, function(error) {
        if (resultCallback) {
          resultCallback();
        } else {
          TSPOSTIO.errorOpeningPath(dirPath);
        }
        TSCORE.hideLoadingAnimation();
        console.error("Error listDirectory " + dirPath + " error: " + error);
      }
    );
  };

  function getDirectoryMetaInformation(dirPath, readyCallback) {
    listDirectory(dirPath, function(anotatedDirList) {
      TSCORE.metaFileList = anotatedDirList;
      readyCallback(anotatedDirList);
    });
  };

  function listSubDirectories(dirPath) {
    console.log("Listing sub directories: " + dirPath);
    TSCORE.showLoadingAnimation();
    listDirectoryPromise(dirPath).then(function(entries) {
      var anotatedDirList = [];
      // skiping the first entry pointing to the parent directory
      for (var i = 1; i < entries.length; i++) {
        if (!entries[i].isFile) {
          anotatedDirList.push({
            "name": entries[i].name,
            "path": entries[i].path
          });
        }
      }
      TSPOSTIO.listSubDirectories(anotatedDirList, dirPath);
    }, function(error) {
      TSPOSTIO.errorOpeningPath(dirPath);
      TSCORE.hideLoadingAnimation();
      console.error("Error listDirectory " + dirPath + " error: " + error);
    });
  };

  function getPropertiesPromise(filePath) {
    return new Promise(function(resolve, reject) {
      // TODO use listDirectory to get size and lmdt
      var fileProperties = {};
      fileProperties.path = filePath;
      fileProperties.size = 0;
      fileProperties.lmdt = 0;
      resolve(fileProperties);
    });
  };

  function getFileProperties(filePath) {
    getPropertiesPromise().then(function(fileProperties) {
      TSPOSTIO.getFileProperties(fileProperties);
    }, function(err) {
      TSCORE.showAlertDialog("Could not get properties for: " + filePath);
    })
  };

  function loadTextFile(filePath) {
    console.log("Loading file: " + filePath);
    getFileContentPromise(filePath, "text").then(function(data) {
        TSPOSTIO.loadTextFile(data);
      }, function(error) {
        TSCORE.hideLoadingAnimation();
        console.error("loading text file failed " + data);
      }
    );
  };

  function getFileContent(fullPath, result, error) {
    // TODO 4remove
    getFileContentPromise(fullPath).then(result, error);
  }

  function getFileContentPromise(fullPath, type) {
    console.log("getFileContentPromise: " + fullPath);
    return new Promise(function(resolve, reject) {
      var fileURL = fullPath;
      if (fileURL.indexOf("file://") === -1) {
        fileURL = "file://" + fileURL;
      }
      var xhr = new XMLHttpRequest();
      xhr.open("GET", fileURL, true);
      xhr.responseType = type || "arraybuffer";
      xhr.onerror = reject;

      xhr.onload = function() {
        var response = xhr.response || xhr.responseText;
        if (response) {
          resolve(response);
        } else {
          reject("getFileContentPromise error");
        }
      };
      xhr.send();
    });
  }

  function saveFilePromise(filePath, content, mode) {
    console.log("Saving binary file: " + filePath);
    return new Promise(function(resolve, reject){
      var blob = new Blob([content], {
        type: "text/plain;charset=utf-8"
      });
      saveAs(blob, TSCORE.TagUtils.extractFileName(filePath));
      resolve();
    });
  }

  function saveTextFile(filePath, content) {
    TSCORE.showLoadingAnimation();
    console.log("Saving file: " + filePath);
    saveFilePromise(filePath).then(function() {
        // TODO close file after save
        //TSPOSTIO.saveTextFile(filePath);
      }, function(error) {
        TSCORE.showAlertDialog("Save text file " + filePath + "filed");
        console.error(error);
      }
    );
  };

  function saveBinaryFile(filePath, content) {
    TSCORE.showLoadingAnimation();
    console.log("Saving binary file: " + filePath);
    saveFilePromise(filePath).then(function() {
        // TODO close file after save
        //TSPOSTIO.saveTextFile(filePath);
      }, function(error) {
        TSCORE.showAlertDialog("Save binary file " + filePath + "filed");
        console.error(error);
      }
    );
  };

  function createDirectoryPromise(dirPath) {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Creating directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function createDirectory(dirPath) {
    // TODO 4 remove
    createDirectoryPromise();
  };

  function renameDirectoryPromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Renaming directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function renameDirectory() {
    // TODO 4remove
    renameDirectoryPromise();
  };

  function renameFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Renaming file is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function renameFile() {
    // TODO 4remove
    renameFilePromise();
  };

  function copyFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Copy file is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function copyFile() {
    // TODO 4remove
    copyFilePromise();
  };

  function deleteFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Creating directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function deleteElement() {
    // TODO 4remove
    deleteDirectoryPromise();
  };

  function deleteDirectoryPromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Deleting directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function deleteDirectory() {
    // TODO 4remove
    deleteDirectoryPromise();
  };

  function selectDirectory() {
    console.log("Select directory!");
    var rootPath = "/";
    if (isWin) {
      rootPath = "C:";
    }
    TSCORE.showDirectoryBrowserDialog(rootPath);
  };

  function selectFile() {
    // TODO
    TSCORE.showAlertDialog("Select file not implemented!");
  };

  function openDirectory(dirPath) {
    // TODO
    TSCORE.showAlertDialog($.i18n.t("ns.dialogs:openContainingDirectoryAlert"));
  };

  function openFile(filePath) {
    // TODO
    TSCORE.showAlertDialog($.i18n.t("ns.dialogs:openFileNativelyAlert"));
  };

  exports.handleStartParameters = handleStartParameters;
  exports.checkAccessFileURLAllowed = checkAccessFileURLAllowed;
  exports.focusWindow = focusWindow;
  exports.saveSettings = saveSettings;
  exports.checkNewVersion = checkNewVersion;

  exports.createDirectoryIndex = createDirectoryIndex;
  exports.createDirectoryTree = createDirectoryTree;

  exports.listDirectoryPromise = listDirectoryPromise;
  exports.listDirectory = listDirectory; /** @deprecated */
  exports.listSubDirectories = listSubDirectories; /** TODO move in ioutils */
  exports.getDirectoryMetaInformation = getDirectoryMetaInformation; /** @deprecated */

  exports.getPropertiesPromise = getPropertiesPromise;
  exports.getFileProperties = getFileProperties; /** @deprecated */

  exports.createDirectoryPromise = createDirectoryPromise;
  exports.createDirectory = createDirectory; /** @deprecated */

  exports.getFileContentPromise = getFileContentPromise;
  exports.loadTextFile = loadTextFile; /** @deprecated */
  exports.getFileContent = getFileContent; /** @deprecated */

  exports.saveFilePromise = saveFilePromise;
  exports.saveTextFile = saveTextFile; /** @deprecated */
  exports.saveBinaryFile = saveBinaryFile; /** @deprecated */

  exports.copyFilePromise = copyFilePromise;
  exports.copyFile = copyFile; /** @deprecated */

  exports.renameFilePromise = renameFilePromise;
  exports.renameFile = renameFile; /** @deprecated */

  exports.renameDirectoryPromise = renameDirectoryPromise;
  exports.renameDirectory = renameDirectory; /** @deprecated */

  exports.deleteFilePromise = deleteFilePromise;
  exports.deleteElement = deleteElement; /** @deprecated */

  exports.deleteDirectoryPromise = deleteDirectoryPromise;
  exports.deleteDirectory = deleteDirectory; /** @deprecated */

  exports.selectFile = selectFile;
  exports.selectDirectory = selectDirectory;

  exports.openDirectory = openDirectory;
  exports.openFile = openFile;

});
<commit_msg>fixing save file issue<commit_after>/* Copyright (c) 2012-2015 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
/* global define, nativeIO, isWin */

define(function(require, exports, module) {
  "use strict";

  console.log("Loading Lite chrome.api.js..");

  // chrome.browserAction.setBadgeBackgroundColor({ color: '#00ff00' });
  // chrome.browserAction.setBadgeText({text: '9999'});

  // changing the name of the app
  $("#logo").text("TagSpaces Lite");

  var TSCORE = require("tscore");
  var TSPOSTIO = require("tspostioapi");
  require("libs/filesaver.js/FileSaver");

  var dataBegin = "<script>addRow(";
  var dataEnd = ");</script>";
  var dataFile = '",0,"';
  var dataDir = '",1,"';

  function getURLParameter(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split("=");
      if (pair[0] == variable) {
        return pair[1];
      }
    }
    return (false);
  }

  function checkAccessFileURLAllowed() {
    chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
      if (!isAllowedAccess) {
        TSCORE.showAlertDialog($.i18n.t("ns.dialogs:accessFileURLNotAllowedAlert"));
      }
    });
  };

  function handleStartParameters() {
    var openFile = getURLParameter("openFile");
    if (openFile !== undefined && (openFile.length > 0)) { //  && openFile.indexOf("file://") === 0
      console.log("Opening file in browser: " + openFile);
      openFile = openFile.split("file://")[1];
      //var dirPath = TSCORE.TagUtils.extractContainingDirectoryPath(filePath);
      //TSCORE.IO.listDirectory(dirPath);
      TSCORE.FileOpener.openFileOnStartup(openFile);
    }
  };

  function focusWindow() {
    // Places the TagSpaces window on top of the windows
    window.focus();
  };

  function saveSettings(content) {
    /*chrome.storage.sync.set({'tagSpacesSettings': content}, function() {
        // Notify that we saved.
        message('Settings saved');
    });*/
  };

  function checkNewVersion() {
    console.log("Checking for new version...");
    var cVer = TSCORE.Config.DefaultSettings.appVersion + "." + TSCORE.Config.DefaultSettings.appBuild;
    $.ajax({
        url: 'http://tagspaces.org/releases/version.json?cVer=' + cVer,
        type: 'GET'
      })
      .done(function(data) {
        TSPOSTIO.checkNewVersion(data);
      })
      .fail(function(data) {
        console.log("AJAX failed " + data);
      });
  };

  function createDirectoryIndex(dirPath) {
    TSCORE.showWaitingDialog($.i18n.t("ns.common:waitDialogDiectoryIndexing"));

    var directoryIndex = [];
    TSCORE.Utils.walkDirectory(dirPath, {recursive: true}, function(fileEntry) {
      directoryIndex.push(fileEntry);
    }).then(
      function(entries) {
        TSPOSTIO.createDirectoryIndex(directoryIndex);
      },
      function(err) {
        console.warn("Error creating index: " + err);
      }
    ).catch(function() {
      TSCORE.hideWaitingDialog();
    });
  };

  function createDirectoryTree(dirPath) {
    TSCORE.showLoadingAnimation();
    console.log("Creating directory not supported: " + dirPath);
    //var directoyTree = generateDirectoryTree(dirPath);
    //console.log(JSON.stringify(directoyTree));
    //TSPOSTIO.createDirectoryTree(directoyTree);
  };

  function listDirectoryPromise(dirPath) {
    console.log("Listing directory: " + dirPath);
    return new Promise(function(resolve, reject) {
      var anotatedDirList = [];
      $.ajax({
          url: "file://" + dirPath,
          type: 'GET'
        })
        .done(function(data) {
          //console.log("Dir List "+data);
          var folders = data.substring(data.indexOf(dataBegin) + dataBegin.length, data.lastIndexOf(dataEnd));
          folders = folders.split(dataBegin).join("");
          folders = folders.split(dataEnd);

          var name,
            path,
            isFile,
            fileSize,
            lastDateModified,
            fileProp;

          anotatedDirList = [];
          // sciping the first entry pointing to the parent directory
          for (var i = 1; i < folders.length; i++) {
            console.log("Dir " + folders[i]);
            name = folders[i].substring(2, folders[i].indexOf('","'));
            path = dirPath + TSCORE.dirSeparator + name;
            isFile = (folders[i].indexOf(dataFile) > 1);
            fileSize = 0;
            lastDateModified = 0;
            if (isFile) {
              fileProp = folders[i].substring(folders[i].indexOf(dataFile) + dataFile.length + 1, folders[i].length - 1);
              fileProp = fileProp.split('","');
              fileSize = fileProp[0];
              lastDateModified = fileProp[1];
            }
            anotatedDirList.push({
              "name": name,
              "isFile": isFile,
              "size": fileSize,
              "lmdt": lastDateModified,
              "path": path
            });
          }
          resolve(anotatedDirList);
        }).fail(function(error) {
          console.warn("Error listing files" + JSON.stringify(error));
          reject(error);
        });
    });
  }

  function listDirectory(dirPath, resultCallback) {
    TSCORE.showLoadingAnimation();
    listDirectoryPromise(dirPath).then(function(anotatedDirList) {
        if (resultCallback) {
          resultCallback(anotatedDirList);
        } else {
          TSPOSTIO.listDirectory(anotatedDirList);
        }
      }, function(error) {
        if (resultCallback) {
          resultCallback();
        } else {
          TSPOSTIO.errorOpeningPath(dirPath);
        }
        TSCORE.hideLoadingAnimation();
        console.error("Error listDirectory " + dirPath + " error: " + error);
      }
    );
  };

  function getDirectoryMetaInformation(dirPath, readyCallback) {
    listDirectory(dirPath, function(anotatedDirList) {
      TSCORE.metaFileList = anotatedDirList;
      readyCallback(anotatedDirList);
    });
  };

  function listSubDirectories(dirPath) {
    console.log("Listing sub directories: " + dirPath);
    TSCORE.showLoadingAnimation();
    listDirectoryPromise(dirPath).then(function(entries) {
      var anotatedDirList = [];
      // skiping the first entry pointing to the parent directory
      for (var i = 1; i < entries.length; i++) {
        if (!entries[i].isFile) {
          anotatedDirList.push({
            "name": entries[i].name,
            "path": entries[i].path
          });
        }
      }
      TSPOSTIO.listSubDirectories(anotatedDirList, dirPath);
    }, function(error) {
      TSPOSTIO.errorOpeningPath(dirPath);
      TSCORE.hideLoadingAnimation();
      console.error("Error listDirectory " + dirPath + " error: " + error);
    });
  };

  function getPropertiesPromise(filePath) {
    return new Promise(function(resolve, reject) {
      // TODO use listDirectory to get size and lmdt
      var fileProperties = {};
      fileProperties.path = filePath;
      fileProperties.size = 0;
      fileProperties.lmdt = 0;
      resolve(fileProperties);
    });
  };

  function getFileProperties(filePath) {
    getPropertiesPromise().then(function(fileProperties) {
      TSPOSTIO.getFileProperties(fileProperties);
    }, function(err) {
      TSCORE.showAlertDialog("Could not get properties for: " + filePath);
    })
  };

  function loadTextFile(filePath) {
    console.log("Loading file: " + filePath);
    getFileContentPromise(filePath, "text").then(function(data) {
        TSPOSTIO.loadTextFile(data);
      }, function(error) {
        TSCORE.hideLoadingAnimation();
        console.error("loading text file failed " + data);
      }
    );
  };

  function getFileContent(fullPath, result, error) {
    // TODO 4remove
    getFileContentPromise(fullPath).then(result, error);
  }

  function getFileContentPromise(fullPath, type) {
    console.log("getFileContentPromise: " + fullPath);
    return new Promise(function(resolve, reject) {
      var fileURL = fullPath;
      if (fileURL.indexOf("file://") === -1) {
        fileURL = "file://" + fileURL;
      }
      var xhr = new XMLHttpRequest();
      xhr.open("GET", fileURL, true);
      xhr.responseType = type || "arraybuffer";
      xhr.onerror = reject;

      xhr.onload = function() {
        var response = xhr.response || xhr.responseText;
        if (response) {
          resolve(response);
        } else {
          reject("getFileContentPromise error");
        }
      };
      xhr.send();
    });
  }

  function saveFilePromise(filePath, content, mode) {
    console.log("Saving binary file: " + filePath);
    return new Promise(function(resolve, reject){
      var blob = new Blob([content], {
        type: "text/plain;charset=utf-8"
      });
      saveAs(blob, TSCORE.TagUtils.extractFileName(filePath));
      resolve();
    });
  }

  function saveTextFile(filePath, content) {
    TSCORE.showLoadingAnimation();
    console.log("Saving file: " + filePath);
    saveFilePromise(filePath, content).then(function() {
        // TODO close file after save
        TSPOSTIO.saveTextFile(filePath);
      }, function(error) {
        TSCORE.showAlertDialog("Save text file " + filePath + "filed");
        console.error(error);
      }
    );
  };

  function saveBinaryFile(filePath, content) {
    TSCORE.showLoadingAnimation();
    console.log("Saving binary file: " + filePath);
    saveFilePromise(filePath, content).then(function() {
        // TODO close file after save
        TSPOSTIO.saveTextFile(filePath);
      }, function(error) {
        TSCORE.showAlertDialog("Save binary file " + filePath + "filed");
        console.error(error);
      }
    );
  };

  function createDirectoryPromise(dirPath) {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Creating directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function createDirectory(dirPath) {
    // TODO 4 remove
    createDirectoryPromise();
  };

  function renameDirectoryPromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Renaming directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function renameDirectory() {
    // TODO 4remove
    renameDirectoryPromise();
  };

  function renameFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Renaming file is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function renameFile() {
    // TODO 4remove
    renameFilePromise();
  };

  function copyFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Copy file is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function copyFile() {
    // TODO 4remove
    copyFilePromise();
  };

  function deleteFilePromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Creating directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function deleteElement() {
    // TODO 4remove
    deleteDirectoryPromise();
  };

  function deleteDirectoryPromise() {
    return new Promise(function(res, rej) {
      TSCORE.showAlertDialog("Deleting directory is not supported in Chrome, please use the desktop version.");
      res(true);
    });
  };

  function deleteDirectory() {
    // TODO 4remove
    deleteDirectoryPromise();
  };

  function selectDirectory() {
    console.log("Select directory!");
    var rootPath = "/";
    if (isWin) {
      rootPath = "C:";
    }
    TSCORE.showDirectoryBrowserDialog(rootPath);
  };

  function selectFile() {
    // TODO
    TSCORE.showAlertDialog("Select file not implemented!");
  };

  function openDirectory(dirPath) {
    // TODO
    TSCORE.showAlertDialog($.i18n.t("ns.dialogs:openContainingDirectoryAlert"));
  };

  function openFile(filePath) {
    // TODO
    TSCORE.showAlertDialog($.i18n.t("ns.dialogs:openFileNativelyAlert"));
  };

  exports.handleStartParameters = handleStartParameters;
  exports.checkAccessFileURLAllowed = checkAccessFileURLAllowed;
  exports.focusWindow = focusWindow;
  exports.saveSettings = saveSettings;
  exports.checkNewVersion = checkNewVersion;

  exports.createDirectoryIndex = createDirectoryIndex;
  exports.createDirectoryTree = createDirectoryTree;

  exports.listDirectoryPromise = listDirectoryPromise;
  exports.listDirectory = listDirectory; /** @deprecated */
  exports.listSubDirectories = listSubDirectories; /** TODO move in ioutils */
  exports.getDirectoryMetaInformation = getDirectoryMetaInformation; /** @deprecated */

  exports.getPropertiesPromise = getPropertiesPromise;
  exports.getFileProperties = getFileProperties; /** @deprecated */

  exports.createDirectoryPromise = createDirectoryPromise;
  exports.createDirectory = createDirectory; /** @deprecated */

  exports.getFileContentPromise = getFileContentPromise;
  exports.loadTextFile = loadTextFile; /** @deprecated */
  exports.getFileContent = getFileContent; /** @deprecated */

  exports.saveFilePromise = saveFilePromise;
  exports.saveTextFile = saveTextFile; /** @deprecated */
  exports.saveBinaryFile = saveBinaryFile; /** @deprecated */

  exports.copyFilePromise = copyFilePromise;
  exports.copyFile = copyFile; /** @deprecated */

  exports.renameFilePromise = renameFilePromise;
  exports.renameFile = renameFile; /** @deprecated */

  exports.renameDirectoryPromise = renameDirectoryPromise;
  exports.renameDirectory = renameDirectory; /** @deprecated */

  exports.deleteFilePromise = deleteFilePromise;
  exports.deleteElement = deleteElement; /** @deprecated */

  exports.deleteDirectoryPromise = deleteDirectoryPromise;
  exports.deleteDirectory = deleteDirectory; /** @deprecated */

  exports.selectFile = selectFile;
  exports.selectDirectory = selectDirectory;

  exports.openDirectory = openDirectory;
  exports.openFile = openFile;

});
<|endoftext|>


<commit_before>'use strict';

var Pili = require('../index.js');

// ======================== Configurations =========================
// Replace with your keys here
var ACCESS_KEY  = 'QiniuAccessKey';
var SECRET_KEY  = 'QiniuSecretKey';
var credentials = new Pili.Credentials(ACCESS_KEY, SECRET_KEY);

// Replace with your hub name
var HUB = 'PiliHubName'; // The Hub must be exists before use

// Change API host as necessary
//
// pili.qiniuapi.com as default
// pili-lte.qiniuapi.com is the latest RC version
//
Pili.config.API_HOST = 'pili.qiniuapi.com'; // default

// ========================== Hub ============================

var streamKey = 'streamkey';

/**
 * URLs
 */

var pu = Pili.publishURL(credentials,'publish-rtmp.test.com', 'PiliSDKTest', 'streamkey', 60);
var rtmpURL = Pili.rtmpPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var hdlURL = Pili.hdlPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var hlsURL = Pili.hlsPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var snapURL = Pili.snapshotPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
console.log(pu, rtmpURL, hdlURL, hlsURL, snapURL);

/**
 * Instantiate a Pili hub object
 */

var hub = new Pili.Hub(credentials, HUB);

/**
 * Create a new Stream
 */

hub.createStream(streamKey, function(err, stream) {

  if (!err) {
      console.log(stream);
  } else {
    // Log error
    console.log(err, err.errorCode, err.httpCode);
  }
});

/**
 * List Streams
 */

var listOptions = {
	'liveonly': false,
	'prefix': 'lin',
	'limit': 2,
};

var listCallBack = function(err, marker, streams) {
	if (!err) {
		streams.forEach(function(stream) {
			console.log(stream);
		});
		if (marker) {
			listOptions.marker = marker;
			hub.listStreams(listOptions, listCallBack);
		}
	} else {
    console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
}

hub.listStreams(listOptions, listCallBack);

/**
 * Get Stream Info
 */
var stream = hub.newStream(streamKey);

stream.loadInfo(function(err) {
	if (!err) {
		console.log(stream);
	} else {
    console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
})

// * Disable a Stream
// */
stream.disable(-1, function(err) {
    console.log(stream.disabledTill);
});

/**
 * Enable a Stream
 */
stream.enable(function(err) {
    console.log(stream.disabledTill);
});

/**
 * Get Stream Live Info
 */
stream.liveInfo(function(err, status) {
    if (!err) {
			console.log(status);
		} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
		}
});

/**
 * Get Stream segments
 */
var savePlaybackOptions = {
   start : null,    // optional, in second, unix timestamp
   end   : null,    // optional, in second, unix timestamp
};

stream.savePlayback(savePlaybackOptions, function(err, m3u8Name) {

    if (!err) {
			console.log(m3u8Name);
		} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
		}
});

/**
 *  Get Stream history activity
 */

var publishHistoryOptions = {
   start : null,    // optional, in second, unix timestamp
   end   : null,    // optional, in second, unix timestamp
};
stream.publishHistory(publishHistoryOptions, function(err, history) {
	if (!err) {
		console.log(history);
	} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
})
<commit_msg>update example<commit_after>'use strict';

var Pili = require('../index.js');

// ======================== Configurations =========================
// Replace with your keys here
var ACCESS_KEY  = 'QiniuAccessKey';
var SECRET_KEY  = 'QiniuSecretKey';
var credentials = new Pili.Credentials(ACCESS_KEY, SECRET_KEY);

// Replace with your hub name
var HUB = 'PiliHubName'; // The Hub must be exists before use

// Change API host as necessary
//
// pili.qiniuapi.com as default
// pili-lte.qiniuapi.com is the latest RC version
//
Pili.config.API_HOST = 'pili.qiniuapi.com'; // default

// ========================== Hub ============================

var streamKey = 'streamkey';

/**
 * URLs
 */

var pu = Pili.publishURL(credentials,'publish-rtmp.test.com', 'PiliSDKTest', 'streamkey', 60);
var rtmpURL = Pili.rtmpPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var hdlURL = Pili.hdlPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var hlsURL = Pili.hlsPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
var snapURL = Pili.snapshotPlayURL('live-rtmp.test.com', 'PiliSDKTest', 'streamkey');
console.log(pu, rtmpURL, hdlURL, hlsURL, snapURL);

/**
 * Instantiate a Pili hub object
 */

var hub = new Pili.Hub(credentials, HUB);

/**
 * Create a new Stream
 */

hub.createStream(streamKey, function(err, stream) {

  if (!err) {
      console.log(stream);
  } else {
    // Log error
    console.log(err, err.errorCode, err.httpCode);
  }
});

/**
 * List Streams
 */

var listOptions = {
	'liveonly': false,
	'prefix': 'lin',
	'limit': 2,
};

var listCallBack = function(err, marker, streams) {
	if (!err) {
		streams.forEach(function(stream) {
			console.log(stream);
		});
		if (marker) {
			listOptions.marker = marker;
			hub.listStreams(listOptions, listCallBack);
		}
	} else {
    console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
}

hub.listStreams(listOptions, listCallBack);

/**
 * Get Streams Live Info
 */
hub.listLiveStreams([streamKey], function (err, items) {
    if (!err) {
        console.log('live streams: ');
        items.forEach(function(item) {
            console.log(item);
        });
    }
    else {
        console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
    }
});

/**
 * Get Stream Info
 */
var stream = hub.newStream(streamKey);

stream.loadInfo(function(err) {
	if (!err) {
		console.log(stream);
	} else {
    console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
})

// * Disable a Stream
// */
stream.disable(-1, function(err) {
    console.log(stream.disabledTill);
});

/**
 * Enable a Stream
 */
stream.enable(function(err) {
    console.log(stream.disabledTill);
});

/**
 * Get Stream Live Info
 */
stream.liveInfo(function(err, status) {
    if (!err) {
			console.log(status);
		} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
		}
});

/**
 * Get Stream segments
 */
var savePlaybackOptions = {
    fname: streamKey,
    start : null,    // optional, in second, unix timestamp
    end   : null    // optional, in second, unix timestamp
};

stream.savePlayback(savePlaybackOptions, function(err, m3u8Name) {

    if (!err) {
			console.log(m3u8Name);
		} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
		}
});

/**
 * Get Stream snapshot
 */
var saveSnapshotOptions = {
    fname: streamKey
};

stream.saveSnapshot(saveSnapshotOptions, function(err, snapshotName) {
    if (!err) {
        console.log(snapshotName);
    } else {
        console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
    }
});

/**
 *  Get Stream history activity
 */

var publishHistoryOptions = {
   start : null,    // optional, in second, unix timestamp
   end   : null,    // optional, in second, unix timestamp
};
stream.publishHistory(publishHistoryOptions, function(err, history) {
	if (!err) {
		console.log(history);
	} else {
			console.log(err + 'error code: ' + err.errorCode + 'http code: ' + err.httpCode);
	}
})
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var assert = require('assert');
var request = require('request');
var logger = require('@google/cloud-diagnostics-common').logger;
var config = require('../../config.js');
var Debuglet = require('../../lib/debuglet.js');

var nock = require('nock');
nock.disableNetConnect();

describe(__filename, function(){
  it('should not start unless we know the project num', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    delete process.env.GCLOUD_PROJECT_NUM;
    var scope = nock('http://metadata.google.internal')
      .get('/computeMetadata/v1/project/numeric-project-id')
      .reply(404);

    debuglet.on('error', function(err) {
      assert(err);
      scope.done();
      done();
    });
    debuglet.on('started', function() {
      assert.fail();
    });
    debuglet.start();
  });

  it('should complain if GCLOUD_PROJECT_NUM is not numeric', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM='11020304f2934';

    debuglet.on('error', function(err) {
      assert(err);
      assert(err.message.indexOf('should be numeric') !== -1);
      done();
    });
    debuglet.on('started', function() {
      assert.fail();
    });
    debuglet.start();
  });

  it('should error if a package.json doesn\'t exist');

  it('should register successfully otherwise', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM=0;

    var API = 'https://clouddebugger.googleapis.com';
    var PATH = '/v2/controller/debuggees/register';
    var scope = nock(API)
      .post(PATH)
      .reply(200, {
        debuggee: {
          id: 'foo'
        }
      });

    debuglet.on('started', function() {
      debuglet.debugletApi_.request_ = request; // Avoid authing.
    });
    debuglet.on('registered', function(id) {
      assert(id === 'foo');
      scope.done();
      done();
    });

    debuglet.start();
  });

  it('should de-activate when the server responds with isDisabled');

  it('should re-register when registration expires');

  it('should fetch breakpoints');

  it('should re-fetch breakpoints');

  it('should add a breakpoint');

  it('should expire stale breakpoints');
});

<commit_msg>Improve debug test coverage<commit_after>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var assert = require('assert');
var request = require('request');
var logger = require('@google/cloud-diagnostics-common').logger;
var config = require('../../config.js');
var Debuglet = require('../../lib/debuglet.js');

var nock = require('nock');
nock.disableNetConnect();

describe(__filename, function(){
  it('should not start unless we know the project num', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    delete process.env.GCLOUD_PROJECT_NUM;
    var scope = nock('http://metadata.google.internal')
      .get('/computeMetadata/v1/project/numeric-project-id')
      .reply(404);

    debuglet.once('error', function(err) {
      assert(err);
      debuglet.stop();
      scope.done();
      done();
    });
    debuglet.once('started', function() {
      assert.fail();
    });
    debuglet.start();
  });

  it('should complain if GCLOUD_PROJECT_NUM is not numeric', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM='11020304f2934';

    debuglet.once('error', function(err) {
      assert(err);
      assert(err.message.indexOf('should be numeric') !== -1);
      debuglet.stop();
      done();
    });
    debuglet.once('started', function() {
      assert.fail();
    });
    debuglet.start();
  });

  it('should error if a package.json doesn\'t exist');

  it('should register successfully otherwise', function(done) {
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM=0;

    var API = 'https://clouddebugger.googleapis.com';
    var PATH = '/v2/controller/debuggees/register';
    var scope = nock(API)
      .post(PATH)
      .reply(200, {
        debuggee: {
          id: 'foo'
        }
      });

    debuglet.once('started', function() {
      debuglet.debugletApi_.request_ = request; // Avoid authing.
    });
    debuglet.once('registered', function(id) {
      assert(id === 'foo');
      debuglet.stop();
      scope.done();
      done();
    });

    debuglet.start();
  });

  it('should de-activate when the server responds with isDisabled');

  it('should re-register when registration expires');

  it('should fetch breakpoints');

  it('should re-fetch breakpoints on error', function(done) {
    this.timeout(6000);
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM=0;

    var API = 'https://clouddebugger.googleapis.com';

    var scope = nock(API)
      .post('/v2/controller/debuggees/register')
      .reply(200, {
        debuggee: {
          id: 'bar'
        }
      })
      .post('/v2/controller/debuggees/register')
      .reply(200, {
        debuggee: {
          id: 'bar'
        }
      })
      .get('/v2/controller/debuggees/bar/breakpoints')
      .reply(404)
      .get('/v2/controller/debuggees/bar/breakpoints')
      .reply(409)
      .get('/v2/controller/debuggees/bar/breakpoints')
      .reply(200, {
        breakpoints: [{
          id: 'test',
          location: { path: 'fixtures/foo.js', line: 2 }
        }]
      });

    debuglet.once('started', function() {
      debuglet.debugletApi_.request_ = request; // Avoid authing.
    });
    debuglet.once('registered', function reg(id) {
      assert(id === 'bar');
      setTimeout(function() {
        assert.deepEqual(debuglet.activeBreakpointMap_.test, {
          id: 'test',
          location: { path: 'fixtures/foo.js', line: 2 }
        });
        debuglet.stop();
        scope.done();
        done();
      }, 1000);
    });

    debuglet.start();
  });

  it('should add a breakpoint');

  it('should expire stale breakpoints', function(done) {
    var oldTimeout = config.breakpointExpirationSec;
    config.breakpointExpirationSec = 1;
    this.timeout(6000);
    var debuglet = new Debuglet(
      config, logger.create(config.logLevel, '@google/cloud-debug'));

    process.env.GCLOUD_PROJECT_NUM=0;

    var bp = {
      id: 'test',
      location: { path: 'fixtures/foo.js', line: 2 }
    };

    var API = 'https://clouddebugger.googleapis.com';

    var scope = nock(API)
      .post('/v2/controller/debuggees/register')
      .reply(200, {
        debuggee: {
          id: 'bar'
        }
      })
      .get('/v2/controller/debuggees/bar/breakpoints')
      .reply(200, {
        breakpoints: [bp]
      })
      .put('/v2/controller/debuggees/bar/breakpoints/test', function(body) {
        return body.breakpoint.status.description.format === 'The snapshot has expired';
      })
      .reply(200);

    debuglet.once('started', function() {
      debuglet.debugletApi_.request_ = request; // Avoid authing.
    });
    debuglet.once('registered', function(id) {
      assert(id === 'bar');
      setTimeout(function() {
        assert.deepEqual(debuglet.activeBreakpointMap_.test, bp);
        setTimeout(function() {
          assert(!debuglet.activeBreakpointMap_.test);
          debuglet.stop();
          scope.done();
          config.breakpointExpirationSec = oldTimeout;
          done();
        }, 1100);
      }, 500);
    });

    debuglet.start();
  });
});

<|endoftext|>


<commit_before>;(function() {
"use strict";
var _paq = _paq || [];
// tracker methods like "setCustomDimension" should be called before "trackPageView"
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
  var u="//stats.wjt.me.uk/";
  _paq.push(['setTrackerUrl', u+'piwik.php']);
  _paq.push(['setSiteId', '98']);
  var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
  g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
var urls = ["millerdl_bday.jpg", "foghorn-dlm.png", "beard-hair-redistribution.png", "millerdl_viking.jpg", "millerdl_birb_beard.jpg", "millerdl.png", "millerdl_kwoo.png", "millerdl_trotsky.png", "millerdl_suit.png", "millerdl_birb.png", "president-millerdl.png", "millerdl_chewbacca.png", "millerdl_birb_beard_grin.jpg", "millerdl_question.png", "santa.png"];
var link = document.querySelector('.somewhat-unfortunate');
link.addEventListener('click', function(event) {
    event.preventDefault();
    update();
});
update();

function update() {
    var n = urls.length;
    var i = Math.floor(Math.random() * n);
    var url = 'img/' + urls[i];

    var img = document.createElement('img');
    img.classList.add('really-awful');
    img.onload = function() {
        // Match the top-left pixel's background colour
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        var data = ctx.getImageData(0, 0, 1, 1);
        var r = data.data[0];
        var g = data.data[1];
        var b = data.data[2];
        var a = data.data[3];  // though alpha is really over-egging the pudding
        var rgba = 'rgba(' + [r, g, b, (a / 255).toFixed(3)].join(',') + ')';
        document.body.style.backgroundColor = rgba;

        link.replaceChild(img, link.firstElementChild);
    };
    img.onerror = function(e) {
        console.error("extremely unfortunate", i, url, e);
    };
    img.src = url;
}
}());
<commit_msg>Or maybe just not ignore it?<commit_after><|endoftext|>