<commit_before>import { List } from 'immutable';
import { enforestExpr, Enforester } from "./enforester";
import TermExpander from "./term-expander.js";
import BindingMap from "./binding-map.js";
import Env from "./env";
import Reader from "./shift-reader";
import * as _ from "ramda";
import Term, {
  isEOF, isBindingIdentifier, isBindingPropertyProperty, isBindingPropertyIdentifier, isObjectBinding, isArrayBinding, isFunctionDeclaration, isFunctionExpression,
  isFunctionTerm, isFunctionWithName, isSyntaxDeclaration, isSyntaxrecDeclaration, isVariableDeclaration,
  isVariableDeclarationStatement, isImport, isExport, isPragma, isExportSyntax
} from "./terms";
import { Maybe } from 'ramda-fantasy';
import { gensym } from './symbol';
import { VarBindingTransform, CompiletimeTransform } from './transforms';
import { expect, assert } from "./errors";
import { evalCompiletimeValue } from './load-syntax';
import { Scope, freshScope } from "./scope";
import Syntax, { ALL_PHASES } from './syntax';
import ASTDispatcher from './ast-dispatcher';

const Just = Maybe.Just;
const Nothing = Maybe.Nothing;

const registerSyntax = (stx, context) => {
  let newBinding = gensym(stx.val());
  context.env.set(newBinding.toString(), new VarBindingTransform(stx));
  context.bindings.add(stx, {
    binding: newBinding,
    phase: context.phase,
    // skip dup because js allows variable redeclarations
    // (technically only for `var` but we can let later stages of the pipeline
    // handle incorrect redeclarations of `const` and `let`)
    skipDup: true
  });
};

function bindImports(impTerm, exModule, context) {
  let names = [];
  let phase = impTerm.forSyntax ? context.phase + 1 : context.phase;
  impTerm.namedImports.forEach(specifier => {
    let name = specifier.binding.name;
    let exportName = findNameInExports(name, exModule.exportEntries);
    if (exportName != null) {
      let newBinding = gensym(name.val());
      context.store.set(newBinding.toString(), new VarBindingTransform(name));
      context.bindings.addForward(name, exportName, newBinding, phase);
      names.push(name);
    }
  });
  return List(names);
}

let registerBindings = _.cond([
  [isBindingIdentifier, ({name}, context) => {
    registerSyntax(name, context);
  }],
  [isBindingPropertyIdentifier, ({binding}, context) => {
    registerBindings(binding, context);
  }],
  [isBindingPropertyProperty, ({binding}, context) => {
    registerBindings(binding, context);
  }],
  [isArrayBinding, ({elements, restElement}, context) => {
    if (restElement != null) {
      registerBindings(restElement, context);
    }
    elements.forEach(el => {
      if (el != null) {
        registerBindings(el, context);
      }
    });
  }],
  [isObjectBinding, ({properties}, context) => {
    // properties.forEach(prop => registerBindings(prop, context));
  }],
  [_.T, binding => assert(false, "not implemented yet for: " + binding.type)]
]);

let removeScope = _.cond([
  [isBindingIdentifier, ({name}, scope, phase) => new Term('BindingIdentifier', {
    name: name.removeScope(scope, phase)
  })],
  [isArrayBinding, ({elements, restElement}, scope, phase) => {
    return new Term('ArrayBinding', {
      elements: elements.map(el => el == null ? null : removeScope(el, scope, phase)),
      restElement: restElement == null ? null : removeScope(restElement, scope, phase)
    });
  }],
  [isBindingPropertyIdentifier, ({binding, init}, scope, phase) => new Term('BindingPropertyIdentifier', {
    binding: removeScope(binding, scope, phase),
    init
  })],
  [isBindingPropertyProperty, ({binding, name}, scope, phase) => new Term('BindingPropertyProperty', {
    binding: removeScope(binding, scope, phase), name
  })],
  [isObjectBinding, ({properties}, scope, phase) => new Term('ObjectBinding', {
    properties: properties.map(prop => removeScope(prop, scope, phase))
  })],
  [_.T, binding => assert(false, "not implemented yet for: " + binding.type)]
]);

function findNameInExports(name, exp) {
  let foundNames = exp.reduce((acc, e) => {
    if (e.declaration) {
      return acc.concat(e.declaration.declarators.reduce((acc, decl) => {
        if (decl.binding.name.val() === name.val()) {
          return acc.concat(decl.binding.name);
        }
        return acc;
      }, List()));
    }
    return acc;
  }, List());
  assert(foundNames.size <= 1, 'expecting no more than 1 matching name in exports');
  return foundNames.get(0);
}

function removeNames(impTerm, names) {
  let namedImports = impTerm.namedImports.filter(specifier => !names.contains(specifier.binding.name));
  return impTerm.extend({ namedImports });
}

function bindAllSyntaxExports(exModule, toSynth, context) {
  let phase = context.phase;
  exModule.exportEntries.forEach(ex => {
    if (isExportSyntax(ex)) {
      ex.declaration.declarators.forEach(decl => {
        let name = decl.binding.name;
        let newBinding = gensym(name.val());
        let storeName = exModule.moduleSpecifier + ":" + name.val() + ":" + phase;
        let synthStx = Syntax.fromIdentifier(name.val(), toSynth);
        let storeStx = Syntax.fromIdentifier(storeName, toSynth);
        context.bindings.addForward(synthStx, storeStx, newBinding, phase);
      });
    }
  });
}

export default class TokenExpander extends ASTDispatcher {
  constructor(context) {
    super(false);
    this.context = context;
  }

  expand(stxl) {
    let result = [];
    if (stxl.size === 0) {
      return List(result);
    }
    let prev = List();
    let enf = new Enforester(stxl, prev, this.context);

    while(!enf.done) {
      let term = enf.enforest();
      result.push(this.dispatch(term));
    }

    return List(result);
  }

  bindFunctionDeclaration(decl) {
    let name = removeScope(decl.name, this.context.useScope, this.context.phase);
    registerBindings(name, this.context);
    return decl.extend({ name });
  }

  bindVariableDeclaration (declaration) {
    let declarators = declaration.declarators.map(decl => {
      let newDecl = decl.extend({
        // first, remove the use scope from each binding
        binding: removeScope(decl.binding, this.context.useScope, this.context.phase)
      });
      // mutate the binding map
      // TODO: make this functional
      registerBindings(newDecl.binding, this.context);
      return newDecl;
    });
    return declaration.extend({ declarators });
  }

  expandVariableDeclarationStatement(term) {
    term = term.extend({
      declaration: this.bindVariableDeclaration(term.declaration)
    });

    // syntax id^{a, b} = <init>^{a, b}
    // ->
    // syntaxrec id^{a,b,c} = function() { return <<id^{a}>> }
    // syntaxrec id^{a,b} = <init>^{a,b,c}
    if (isSyntaxDeclaration(term.declaration)) {
      let scope = freshScope('nonrec');
      term.declaration.declarators.forEach(decl => {
        let name = decl.binding.name;
        let nameAdded = name.addScope(scope, this.context.bindings, ALL_PHASES);
        let nameRemoved = name.removeScope(this.context.currentScope[this.context.currentScope.length - 1], this.context.phase);
        let newBinding = gensym(name.val());
        this.context.bindings.addForward(nameAdded, nameRemoved, newBinding, this.context.phase);
        decl.init = decl.init.addScope(scope, this.context.bindings, ALL_PHASES);
      });
    }

    // for syntax declarations we need to load the compiletime value
    // into the environment
    if (isSyntaxDeclaration(term.declaration) ||
    isSyntaxrecDeclaration(term.declaration)) {
      term.declaration.declarators.forEach(decl => {
        // each compiletime value needs to be expanded with a fresh
        // environment and in the next higher phase
        let syntaxExpander = new TermExpander(_.merge(this.context, {
          phase: this.context.phase + 1,
          env: new Env(),
          store: this.context.store
        }));
        let init = syntaxExpander.expand(decl.init);
        let val = evalCompiletimeValue(init.gen(), _.merge(this.context, {
          phase: this.context.phase + 1
        }));

        this.context.env.set(decl.binding.name.resolve(this.context.phase),
        new CompiletimeTransform(val));
      });
    }
    return term;
  }

  expandFunctionDeclaration(term) {
    if (isFunctionWithName(term)) {
      term = term.extend({
        name: removeScope(term.name, this.context.useScope, this.context.phase)
      });
      registerBindings(term.name, this.context);
    }
    return term;
  }

  expandImport(term) {
    let path = term.moduleSpecifier.val();
    let mod = this.context.modules.loadAndCompile(path);
    if (term.forSyntax) {
      this.context.store = this.context.modules.visit(mod, this.context.phase + 1, this.context.store);
      this.context.store = this.context.modules.invoke(mod, this.context.phase + 1, this.context.store);
    } else {
      this.context.store = this.context.modules.visit(mod, this.context.phase, this.context.store);
    }
    let boundNames = bindImports(term, mod, this.context);
    return removeNames(term, boundNames);
  }

  expandExport(term) {
    if (isVariableDeclaration(term.declaration)) {
      return term.extend({
        declaration: this.bindVariableDeclaration(term.declaration)
      });
    } else if (isFunctionDeclaration(term.declaration)) {
      return term.extend({
        declaration: this.bindFunctionDeclaration(term.declaration)
      });
    }
    return term;
  }

  // [isPragma, term => {
  //   let pathStx = term.items.get(0);
  //   if (pathStx.val() === 'base') {
  //     return term;
  //   }
  //   let mod = this.context.modules.loadAndCompile(pathStx.val());
  //   store = this.context.modules.visit(mod, phase, store);
  //   bindAllSyntaxExports(mod, pathStx, this.context);
  //   return term;
  // }],
}
<commit_msg>Cleaning<commit_after>import { List } from 'immutable';
import { enforestExpr, Enforester } from "./enforester";
import TermExpander from "./term-expander.js";
import BindingMap from "./binding-map.js";
import Env from "./env";
import Reader from "./shift-reader";
import * as _ from "ramda";
import Term, {
  isEOF, isBindingIdentifier, isBindingPropertyProperty, isBindingPropertyIdentifier, isObjectBinding, isArrayBinding, isFunctionDeclaration, isFunctionExpression,
  isFunctionTerm, isFunctionWithName, isSyntaxDeclaration, isSyntaxrecDeclaration, isVariableDeclaration,
  isVariableDeclarationStatement, isImport, isExport, isPragma, isExportSyntax
} from "./terms";
import { Maybe } from 'ramda-fantasy';
import { gensym } from './symbol';
import { VarBindingTransform, CompiletimeTransform } from './transforms';
import { expect, assert } from "./errors";
import { evalCompiletimeValue } from './load-syntax';
import { Scope, freshScope } from "./scope";
import Syntax, { ALL_PHASES } from './syntax';
import ASTDispatcher from './ast-dispatcher';

const Just = Maybe.Just;
const Nothing = Maybe.Nothing;

const registerSyntax = (stx, context) => {
  let newBinding = gensym(stx.val());
  context.env.set(newBinding.toString(), new VarBindingTransform(stx));
  context.bindings.add(stx, {
    binding: newBinding,
    phase: context.phase,
    // skip dup because js allows variable redeclarations
    // (technically only for `var` but we can let later stages of the pipeline
    // handle incorrect redeclarations of `const` and `let`)
    skipDup: true
  });
};

function bindImports(impTerm, exModule, context) {
  let names = [];
  let phase = impTerm.forSyntax ? context.phase + 1 : context.phase;
  impTerm.namedImports.forEach(specifier => {
    let name = specifier.binding.name;
    let exportName = findNameInExports(name, exModule.exportEntries);
    if (exportName != null) {
      let newBinding = gensym(name.val());
      context.store.set(newBinding.toString(), new VarBindingTransform(name));
      context.bindings.addForward(name, exportName, newBinding, phase);
      names.push(name);
    }
  });
  return List(names);
}

let registerBindings = _.cond([
  [isBindingIdentifier, ({name}, context) => {
    registerSyntax(name, context);
  }],
  [isBindingPropertyIdentifier, ({binding}, context) => {
    registerBindings(binding, context);
  }],
  [isBindingPropertyProperty, ({binding}, context) => {
    registerBindings(binding, context);
  }],
  [isArrayBinding, ({elements, restElement}, context) => {
    if (restElement != null) {
      registerBindings(restElement, context);
    }
    elements.forEach(el => {
      if (el != null) {
        registerBindings(el, context);
      }
    });
  }],
  [isObjectBinding, ({properties}, context) => {
    // properties.forEach(prop => registerBindings(prop, context));
  }],
  [_.T, binding => assert(false, "not implemented yet for: " + binding.type)]
]);

let removeScope = _.cond([
  [isBindingIdentifier, ({name}, scope, phase) => new Term('BindingIdentifier', {
    name: name.removeScope(scope, phase)
  })],
  [isArrayBinding, ({elements, restElement}, scope, phase) => {
    return new Term('ArrayBinding', {
      elements: elements.map(el => el == null ? null : removeScope(el, scope, phase)),
      restElement: restElement == null ? null : removeScope(restElement, scope, phase)
    });
  }],
  [isBindingPropertyIdentifier, ({binding, init}, scope, phase) => new Term('BindingPropertyIdentifier', {
    binding: removeScope(binding, scope, phase),
    init
  })],
  [isBindingPropertyProperty, ({binding, name}, scope, phase) => new Term('BindingPropertyProperty', {
    binding: removeScope(binding, scope, phase), name
  })],
  [isObjectBinding, ({properties}, scope, phase) => new Term('ObjectBinding', {
    properties: properties.map(prop => removeScope(prop, scope, phase))
  })],
  [_.T, binding => assert(false, "not implemented yet for: " + binding.type)]
]);

function findNameInExports(name, exp) {
  let foundNames = exp.reduce((acc, e) => {
    if (e.declaration) {
      return acc.concat(e.declaration.declarators.reduce((acc, decl) => {
        if (decl.binding.name.val() === name.val()) {
          return acc.concat(decl.binding.name);
        }
        return acc;
      }, List()));
    }
    return acc;
  }, List());
  assert(foundNames.size <= 1, 'expecting no more than 1 matching name in exports');
  return foundNames.get(0);
}

function removeNames(impTerm, names) {
  let namedImports = impTerm.namedImports.filter(specifier => !names.contains(specifier.binding.name));
  return impTerm.extend({ namedImports });
}

function bindAllSyntaxExports(exModule, toSynth, context) {
  let phase = context.phase;
  exModule.exportEntries.forEach(ex => {
    if (isExportSyntax(ex)) {
      ex.declaration.declarators.forEach(decl => {
        let name = decl.binding.name;
        let newBinding = gensym(name.val());
        let storeName = exModule.moduleSpecifier + ":" + name.val() + ":" + phase;
        let synthStx = Syntax.fromIdentifier(name.val(), toSynth);
        let storeStx = Syntax.fromIdentifier(storeName, toSynth);
        context.bindings.addForward(synthStx, storeStx, newBinding, phase);
      });
    }
  });
}

export default class TokenExpander extends ASTDispatcher {
  constructor(context) {
    super(false);
    this.context = context;
  }

  expand(stxl) {
    let result = [];
    if (stxl.size === 0) {
      return List(result);
    }
    let prev = List();
    let enf = new Enforester(stxl, prev, this.context);

    while(!enf.done) {
      result.push(this.dispatch(enf.enforest()));
    }

    return List(result);
  }

  expandVariableDeclarationStatement(term) {
    term = term.extend({
      declaration: this.bindVariableDeclaration(term.declaration)
    });

    // syntax id^{a, b} = <init>^{a, b}
    // ->
    // syntaxrec id^{a,b,c} = function() { return <<id^{a}>> }
    // syntaxrec id^{a,b} = <init>^{a,b,c}
    if (isSyntaxDeclaration(term.declaration)) {
      let scope = freshScope('nonrec');
      term.declaration.declarators.forEach(decl => {
        let name = decl.binding.name;
        let nameAdded = name.addScope(scope, this.context.bindings, ALL_PHASES);
        let nameRemoved = name.removeScope(this.context.currentScope[this.context.currentScope.length - 1], this.context.phase);
        let newBinding = gensym(name.val());
        this.context.bindings.addForward(nameAdded, nameRemoved, newBinding, this.context.phase);
        decl.init = decl.init.addScope(scope, this.context.bindings, ALL_PHASES);
      });
    }

    // for syntax declarations we need to load the compiletime value
    // into the environment
    if (isSyntaxDeclaration(term.declaration) ||
    isSyntaxrecDeclaration(term.declaration)) {
      term.declaration.declarators.forEach(decl => {
        // each compiletime value needs to be expanded with a fresh
        // environment and in the next higher phase
        let syntaxExpander = new TermExpander(_.merge(this.context, {
          phase: this.context.phase + 1,
          env: new Env(),
          store: this.context.store
        }));
        let init = syntaxExpander.expand(decl.init);
        let val = evalCompiletimeValue(init.gen(), _.merge(this.context, {
          phase: this.context.phase + 1
        }));

        this.context.env.set(decl.binding.name.resolve(this.context.phase),
        new CompiletimeTransform(val));
      });
    }
    return term;
  }

  expandFunctionDeclaration(term) {
    if (isFunctionWithName(term)) {
      term = term.extend({
        name: removeScope(term.name, this.context.useScope, this.context.phase)
      });
      registerBindings(term.name, this.context);
    }
    return term;
  }

  expandImport(term) {
    let path = term.moduleSpecifier.val();
    let mod = this.context.modules.loadAndCompile(path);
    if (term.forSyntax) {
      this.context.store = this.context.modules.visit(mod, this.context.phase + 1, this.context.store);
      this.context.store = this.context.modules.invoke(mod, this.context.phase + 1, this.context.store);
    } else {
      this.context.store = this.context.modules.visit(mod, this.context.phase, this.context.store);
    }
    let boundNames = bindImports(term, mod, this.context);
    return removeNames(term, boundNames);
  }

  expandExport(term) {
    if (isVariableDeclaration(term.declaration)) {
      return term.extend({
        declaration: this.bindVariableDeclaration(term.declaration)
      });
    } else if (isFunctionDeclaration(term.declaration)) {
      return term.extend({
        declaration: this.bindFunctionDeclaration(term.declaration)
      });
    }
    return term;
  }

  // [isPragma, term => {
  //   let pathStx = term.items.get(0);
  //   if (pathStx.val() === 'base') {
  //     return term;
  //   }
  //   let mod = this.context.modules.loadAndCompile(pathStx.val());
  //   store = this.context.modules.visit(mod, phase, store);
  //   bindAllSyntaxExports(mod, pathStx, this.context);
  //   return term;
  // }],

  bindFunctionDeclaration(decl) {
    let name = removeScope(decl.name, this.context.useScope, this.context.phase);
    registerBindings(name, this.context);
    return decl.extend({ name });
  }

  bindVariableDeclaration (declaration) {
    let declarators = declaration.declarators.map(decl => {
      let newDecl = decl.extend({
        // first, remove the use scope from each binding
        binding: removeScope(decl.binding, this.context.useScope, this.context.phase)
      });
      // mutate the binding map
      // TODO: make this functional
      registerBindings(newDecl.binding, this.context);
      return newDecl;
    });
    return declaration.extend({ declarators });
  }

}
<|endoftext|>


<commit_before>var fs = require('fs');
var pandoc = require('node-pandoc');

/**
 * file: input bib file
 * enc: encoding of the bib file
 * outfilepath: path of the out files (fkeys.json, fbib.json)
 */
var parseBib = function(file,enc,csl,outfile){
    enc = enc? enc : "utf8";
    var bib_file = fs.readFileSync(file, enc);
    // extract keys from bibtex file
    var regex = /(?:@[^\{]*\{)([^,]*)/g;
    var match = regex.exec(bib_file);
    // create tmp file 'keys.txt' with json structure: {"key_1":"[@key]",...,"key_n":"[@key_n]"}
    var filecontent = "{\n";
    while (match != null){
        filecontent += '"' + match[1] + '":"[@' + match[1] + ']",\n';
        match = regex.exec(bib_file);
    }
    filecontent = filecontent.substr(0,filecontent.length-2) + "\n}";
    if(!fs.existsSync('./tmp')) fs.mkdirSync('./tmp');
    fs.writeFile("./tmp/keys.txt", filecontent, function(err) {if(err) return console.log(err);});

    // pandoc parse keys.txt with csl file and bib file
    var args = "--bibliography "+ file +" --csl " + csl + " -o ./tmp/keys.html"
    var callback = function(err, result){
        if(err) {return console.error('Error: ', err )};
        extractFormatedKeys(outfile);
        extractFormatedBib(outfile);
        return result;
    }
    return pandoc('./tmp/keys.txt',args,callback);
}

var extractFormatedKeys = function(filepath){
    var htmlfile = fs.readFileSync('./tmp/keys.html', 'utf8');
    var regex = /(?:
)(\{[^\}]*\})(?:<\/p>)/m;
    var match = regex.exec(htmlfile);
    var result = match ? match[1] : "";

    result = result.replace(/&#(\d+);/g, function(match, dec) {
        return String.fromCharCode(dec);
    });
    result = result.replace(/"/g, function(match, dec) {
        return '"';
    });
    result = result.replace(/<[^>]+>/g, function(match, dec) {
        return '';
    });
    result = result.replace(/,/g, function(match, dec) {
        return ',\n';
    });
    if(!fs.existsSync(filepath)) fs.mkdirSync(filepath);
    return fs.writeFile(filepath + "/fkeys.json", result, function(err) {if(err) return console.log(err);});
}

var extractFormatedBib = function(filepath){
    var htmlfile = fs.readFileSync('./tmp/keys.html', 'utf8');
    var regex = /(
[\w\W]*<\/div>)/m;
    var match = regex.exec(htmlfile);
    var result = match ? match[0] : "";

    regex = /(?:
)([\W\w]*?)(?:<\/div>)/gm;
    match = regex.exec(result);
    var filecontent = "{\n";
    while (match != null){
        var line = ('"' + match[1] + '":' + JSON.stringify(match[2].trim()) + ',\n').replace(/\n/g, '');
        filecontent += line + '\n';
        match = regex.exec(result);
    }
    filecontent = filecontent.substr(0,filecontent.length-2) + "\n}";

    if(!fs.existsSync(filepath)) fs.mkdirSync(filepath);
    return fs.writeFile(filepath + "/fbib.json", filecontent, function(err) {if(err) return console.log(err);});
}

module.exports = {
    parse: parseBib
}<commit_msg>publish: debug bibtex2json<commit_after>var fs = require('fs');
var pandoc = require('node-pandoc');

/**
 * file: input bib file
 * enc: encoding of the bib file
 * outfilepath: path of the out files (fkeys.json, fbib.json)
 */
var parseBib = function(file,enc,csl,outfile){
    enc = enc? enc : "utf8";
    var bib_file = fs.readFileSync(file, enc);
    // extract keys from bibtex file
    var regex = /(?:@[^\{]*\{)([^,]*)/g;
    var match = regex.exec(bib_file);
    // create tmp file 'keys.txt' with json structure: {"key_1":"[@key]",...,"key_n":"[@key_n]"}
    var filecontent = "{\n";
    while (match != null){
        filecontent += '"' + match[1] + '":"[@' + match[1] + ']",\n';
        match = regex.exec(bib_file);
    }
    filecontent = filecontent.substr(0,filecontent.length-2) + "\n}";
    if(!fs.existsSync('./tmp')) fs.mkdirSync('./tmp');
    fs.writeFile("./tmp/keys.txt", filecontent, function(err) {if(err) return console.log(err);});

    // pandoc parse keys.txt with csl file and bib file
    var args = "--bibliography "+ file +" --csl " + csl + " -o ./tmp/keys.html"
    var callback = function(err, result){
        if(err) {return console.error('Error: ', err )};
        extractFormatedKeys(outfile);
        extractFormatedBib(outfile);
        return result;
    }
    return pandoc('./tmp/keys.txt',args,callback);
}

var extractFormatedKeys = function(filepath){
    var htmlfile = fs.readFileSync('./tmp/keys.html', 'utf8');
    var regex = /(?:
)(\{[^\}]*\})(?:<\/p>)/m;
    var match = regex.exec(htmlfile);
    var result = match ? match[1] : "";

    result = result.replace(/&#(\d+);/g, function(match, dec) {
        return String.fromCharCode(dec);
    });
    result = result.replace(/"/g, function(match, dec) {
        return '"';
    });
    result = result.replace(/<[^>]+>/g, function(match, dec) {
        return '';
    });
    result = result.replace(/,/g, function(match, dec) {
        return ',\n';
    });
    if(!fs.existsSync(filepath)) fs.mkdirSync(filepath);
    return fs.writeFile(filepath + "/fkeys.json", result, function(err) {if(err) return console.log(err);});
}

var extractFormatedBib = function(filepath){
    var htmlfile = fs.readFileSync('./tmp/keys.html', 'utf8');
    console.log(htmlfile);
    var regex = /(
[\w\W]*<\/div>)/m;
    var match = regex.exec(htmlfile);
    var result = match ? match[0] : "";
    console.log(result);
    regex = /(?:
)([\W\w]*?)(?:<\/div>)/gm;
    match = regex.exec(result);
    var filecontent = "{\n";
    while (match != null){
        var line = ('"' + match[1] + '":' + JSON.stringify(match[2].trim()) + ',\n').replace(/\n/g, '');
        filecontent += line + '\n';
        match = regex.exec(result);
    }
    filecontent = filecontent.substr(0,filecontent.length) + "\n}";

    if(!fs.existsSync(filepath)) fs.mkdirSync(filepath);
    return fs.writeFile(filepath + "/fbib.json", filecontent, function(err) {if(err) return console.log(err);});
}

module.exports = {
    parse: parseBib
}<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
 * @fileoverview Handles auth requests to Nacl.
 */

var _ = require('lodash');

var getOrigin = require('./util').getOrigin;
var random = require('../../../src/lib/random');

module.exports = AuthHandler;

function AuthHandler(channel) {
  if (!(this instanceof AuthHandler)) {
    return new AuthHandler(channel);
  }

  this._channel = channel;

  // Map for tabIds to ports.
  this._ports = {};
}

// Get an access token from the chrome.identity API.
// See https://developer.chrome.com/apps/app_identity
AuthHandler.prototype.getAccessToken = function(cb) {
  if (process.env.TEST_ACCESS_TOKEN) {
    return process.nextTick(cb.bind(null, null, process.env.TEST_ACCESS_TOKEN));
  }

  // This will return an access token for the profile that the user is
  // signed in to chrome as.  If the user is not signed in to chrome, an
  // OAuth window will pop up and ask them to sign in.
  //
  // For now, we don't have a way to ask the user which profile they would
  // like to use.  However, once the `chrome.identity.getAccounts` API call
  // gets out of dev/beta channel, we can get a list of accounts and prompt
  // the user for which one they would like to use with vanadium.
  chrome.identity.getAuthToken({
    interactive: true
  }, function(token) {
    // Wrap in process.nextTick so chrome stack traces can use sourceMap.
    process.nextTick(function(){
      if (chrome.runtime.lastError) {
        console.error('Error getting auth token.', chrome.runtime.lastError);
        return cb(chrome.runtime.lastError);
      }

      return cb(null, token);
    });
  });
};

// Get the name of all accounts from wspr.  Will be empty if no root account
// exists.
AuthHandler.prototype.getAccounts = function(cb) {
  this._channel.performRpc('auth:get-accounts', {}, cb);
};

// Get an access token from the user and use it to create the root account on
// wspr.
AuthHandler.prototype.createAccount = function(cb) {
  var ah = this;
  this.getAccessToken(function(err, token) {
    if (err) {
      return cb(err);
    }

    ah._channel.performRpc('auth:create-account', {token: token}, cb);
  });
};

// Check if an origin is already associated with an account on wspr.
AuthHandler.prototype.originHasAccount = function(origin, cb) {
  this._channel.performRpc('auth:origin-has-account', {origin: origin}, cb);
};

// Associate the account with the origin on wspr.
AuthHandler.prototype.associateAccount =
  function(account, origin, caveats, cb) {
    this._channel.performRpc('auth:associate-account', {
      account: account,
      origin: origin,
      caveats: caveats
    }, cb);
};

// Pop up a new tab asking the user to chose their caveats.
AuthHandler.prototype.getCaveats = function(account, origin, port) {
  // Store the account name and a random salt on the port.
  port.account = account;
  port.authState = random.hex();

  // Get  currently active tab in the window.
  var windowId = port.sender.tab.windowId;
  chrome.tabs.query({active: true, windowId: windowId}, function(tabs) {
    // Store the current tab id so we can switch back to it after the addcaveats
    // tab is removed.  Note that the currently active tab might not be the same
    // as the tab that is requesting authentication.
    if (tabs && tabs[0] && tabs[0].id) {
      port.currentTabId = tabs[0].id;
    }

    chrome.tabs.create({
      url: chrome.extension.getURL('html/addcaveats.html') + '?webappId=' +
        port.sender.tab.id + '&origin=' + encodeURIComponent(origin) +
        '&authState=' + port.authState
    });
  });
};

// Handle incoming 'auth' message.
AuthHandler.prototype.handleAuthMessage = function(port) {
  port.postMessage({
    type: 'auth:received'
  });

  this._ports[port.sender.tab.id] = port;

  var origin;
  try {
    origin = getOrigin(port.sender.url);
  } catch (err) {
    return sendErrorToContentScript('auth', port, err);
  }

  var ah = this;

  this.getAccounts(function(err, accounts) {
    if (err) {
      return sendErrorToContentScript('auth', port, err);
    }

    if (!accounts || accounts.length === 0) {
      // No account exists.  Create one and then call getCaveats.
      ah.createAccount(function(err, createdAccount) {
        if (err) {
          return sendErrorToContentScript('auth', port, err);
        }

        ah.getCaveats(createdAccount, origin, port);
      });
    } else {
      // At least one account already exists. Use the first one.
      var account = accounts[0];

      // Check if origin is associated.
      ah.originHasAccount(origin, function(err, hasAccount) {
        if (err) {
          return sendErrorToContentScript('auth', port, err);
        }

        if (hasAccount) {
          // Origin already associated.  Return success.
          port.postMessage({
            type: 'auth:success',
            account: account
          });
        } else {
          // No origin associated.  Get caveats and then associate.
          ah.getCaveats(account, origin, port);
        }
      });
    }
  });
};

AuthHandler.prototype.handleFinishAuth = function(caveatsPort, msg) {
  if (caveatsPort.sender.url.indexOf(chrome.extension.getURL(
      'html/addcaveats.html')) !== 0) {
    console.error('invalid requester for associateAccount:finish');
    return;
  }

  // Remove the caveats tab.
  chrome.tabs.remove(caveatsPort.sender.tab.id);

  var webappPort = this._ports[msg.webappId];
  delete this._ports[msg.webappId];

  if (msg.cancel) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('User declined to bless origin.'));
  }

  if (!webappPort || msg.authState !== webappPort.authState) {
    return console.error('Port not authorized.');
  }

  if (!webappPort.account) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('No port.account.'));
  }

  // Switch back to the last active tab.
  if (webappPort.currentTabId) {
    chrome.tabs.update(webappPort.currentTabId, {active: true});
  }

  if (!msg.caveats || msg.caveats.length === 0) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('No caveats selected'));
  }

  this.associateAccount(webappPort.account, msg.origin, msg.caveats,
    function(err) {
      if (err) {
        return sendErrorToContentScript('auth', webappPort, err);
      }
      webappPort.postMessage({
        type: 'auth:success',
        account: webappPort.account
      });
    });
};

AuthHandler.prototype.getAllPorts = function() {
  return _.values(this._ports);
};

// Convert an Error object into a bare Object with the same properties.  We do
// this because port.postMessage calls JSON.stringify, which ignores the message
// and stack properties on Error objects.
function errorToObject(err) {
  var obj = {};
  Object.getOwnPropertyNames(err).forEach(function(key) {
    obj[key] = err[key];
  });
  return obj;
}

// Helper functions to send error message back to calling content script.
function sendErrorToContentScript(type, port, err) {
  console.error(err);
  port.postMessage({
    type: type + ':error',
    error: errorToObject(err)
  });
}
<commit_msg>auth-handler: Retry when id server fails to grant blessing for token.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
 * @fileoverview Handles auth requests to Nacl.
 */

var _ = require('lodash');

var getOrigin = require('./util').getOrigin;
var random = require('../../../src/lib/random');

module.exports = AuthHandler;

function AuthHandler(channel) {
  if (!(this instanceof AuthHandler)) {
    return new AuthHandler(channel);
  }

  this._channel = channel;

  // Map for tabIds to ports.
  this._ports = {};
}

// Get an access token from the chrome.identity API.
// See https://developer.chrome.com/apps/app_identity
AuthHandler.prototype.getAccessToken = function(cb) {
  if (process.env.TEST_ACCESS_TOKEN) {
    return process.nextTick(cb.bind(null, null, process.env.TEST_ACCESS_TOKEN));
  }

  // This will return an access token for the profile that the user is
  // signed in to chrome as.  If the user is not signed in to chrome, an
  // OAuth window will pop up and ask them to sign in.
  //
  // For now, we don't have a way to ask the user which profile they would
  // like to use.  However, once the `chrome.identity.getAccounts` API call
  // gets out of dev/beta channel, we can get a list of accounts and prompt
  // the user for which one they would like to use with vanadium.
  chrome.identity.getAuthToken({
    interactive: true
  }, function(token) {
    // Wrap in process.nextTick so chrome stack traces can use sourceMap.
    process.nextTick(function(){
      if (chrome.runtime.lastError) {
        console.error('Error getting auth token.', chrome.runtime.lastError);
        return cb(chrome.runtime.lastError);
      }

      return cb(null, token);
    });
  });
};

// Get the name of all accounts from wspr.  Will be empty if no root account
// exists.
AuthHandler.prototype.getAccounts = function(cb) {
  this._channel.performRpc('auth:get-accounts', {}, cb);
};

// Get an access token from the user and use it to create the root account on
// wspr.
AuthHandler.prototype.createAccount = function(cb) {
  var ah = this;
  this.getAccessToken(function(err, token) {
    if (err) {
      return cb(err);
    }

    // If getAccessToken returns an empty token we shouldn't send it to the
    // identity server. Instead we directly pass an error to the callback which
    // will purge the cache and try again.
    if (!token) {
      return cb(new Error('getAccessToken returned an empty token.'), null,
        token);
    }

    ah._channel.performRpc('auth:create-account', {token: token},
      function(err, createdAccount) {
        cb(err, createdAccount, token);
      });
  });
};

// Check if an origin is already associated with an account on wspr.
AuthHandler.prototype.originHasAccount = function(origin, cb) {
  this._channel.performRpc('auth:origin-has-account', {origin: origin}, cb);
};

// Associate the account with the origin on wspr.
AuthHandler.prototype.associateAccount =
  function(account, origin, caveats, cb) {
    this._channel.performRpc('auth:associate-account', {
      account: account,
      origin: origin,
      caveats: caveats
    }, cb);
};

// Pop up a new tab asking the user to chose their caveats.
AuthHandler.prototype.getCaveats = function(account, origin, port) {
  // Store the account name and a random salt on the port.
  port.account = account;
  port.authState = random.hex();

  // Get  currently active tab in the window.
  var windowId = port.sender.tab.windowId;
  chrome.tabs.query({active: true, windowId: windowId}, function(tabs) {
    // Store the current tab id so we can switch back to it after the addcaveats
    // tab is removed.  Note that the currently active tab might not be the same
    // as the tab that is requesting authentication.
    if (tabs && tabs[0] && tabs[0].id) {
      port.currentTabId = tabs[0].id;
    }

    chrome.tabs.create({
      url: chrome.extension.getURL('html/addcaveats.html') + '?webappId=' +
        port.sender.tab.id + '&origin=' + encodeURIComponent(origin) +
        '&authState=' + port.authState
    });
  });
};

// Handle incoming 'auth' message.
AuthHandler.prototype.handleAuthMessage = function(port) {
  port.postMessage({
    type: 'auth:received'
  });

  this._ports[port.sender.tab.id] = port;

  var origin;
  try {
    origin = getOrigin(port.sender.url);
  } catch (err) {
    return sendErrorToContentScript('auth', port, err);
  }

  var ah = this;

  this.getAccounts(function(err, accounts) {
    if (err) {
      return sendErrorToContentScript('auth', port, err);
    }

    if (!accounts || accounts.length === 0) {
      // No account exists.  Create one and then call getCaveats.
      var retry = true;
      var createAccountCallback = function(err, createdAccount, token) {
        if (err) {
          // If the token we received from chrome.identity.getAuthToken failed
          // to authenticate for the identity server, it may because that the
          // cached token has expired.
          // So, we remove the token from the cache and retry once.
          // TODO(suharshs,nlacasse): Filter by a more specific set of errors.
          if (retry && token) {
            retry = false;
            return chrome.identity.removeCachedAuthToken(token, function(){
              ah.createAccount(createAccountCallback);
            });
          }
          return sendErrorToContentScript('auth', port, err);
        }
        ah.getCaveats(createdAccount, origin, port);
      };

      ah.createAccount(createAccountCallback);
    } else {
      // At least one account already exists. Use the first one.
      var account = accounts[0];

      // Check if origin is associated.
      ah.originHasAccount(origin, function(err, hasAccount) {
        if (err) {
          return sendErrorToContentScript('auth', port, err);
        }

        if (hasAccount) {
          // Origin already associated.  Return success.
          port.postMessage({
            type: 'auth:success',
            account: account
          });
        } else {
          // No origin associated.  Get caveats and then associate.
          ah.getCaveats(account, origin, port);
        }
      });
    }
  });
};

AuthHandler.prototype.handleFinishAuth = function(caveatsPort, msg) {
  if (caveatsPort.sender.url.indexOf(chrome.extension.getURL(
      'html/addcaveats.html')) !== 0) {
    console.error('invalid requester for associateAccount:finish');
    return;
  }

  // Remove the caveats tab.
  chrome.tabs.remove(caveatsPort.sender.tab.id);

  var webappPort = this._ports[msg.webappId];
  delete this._ports[msg.webappId];

  if (msg.cancel) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('User declined to bless origin.'));
  }

  if (!webappPort || msg.authState !== webappPort.authState) {
    return console.error('Port not authorized.');
  }

  if (!webappPort.account) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('No port.account.'));
  }

  // Switch back to the last active tab.
  if (webappPort.currentTabId) {
    chrome.tabs.update(webappPort.currentTabId, {active: true});
  }

  if (!msg.caveats || msg.caveats.length === 0) {
    return sendErrorToContentScript('auth', webappPort,
        new Error('No caveats selected'));
  }

  this.associateAccount(webappPort.account, msg.origin, msg.caveats,
    function(err) {
      if (err) {
        return sendErrorToContentScript('auth', webappPort, err);
      }
      webappPort.postMessage({
        type: 'auth:success',
        account: webappPort.account
      });
    });
};

AuthHandler.prototype.getAllPorts = function() {
  return _.values(this._ports);
};

// Convert an Error object into a bare Object with the same properties.  We do
// this because port.postMessage calls JSON.stringify, which ignores the message
// and stack properties on Error objects.
function errorToObject(err) {
  var obj = {};
  Object.getOwnPropertyNames(err).forEach(function(key) {
    obj[key] = err[key];
  });
  return obj;
}

// Helper functions to send error message back to calling content script.
function sendErrorToContentScript(type, port, err) {
  console.error(err);
  port.postMessage({
    type: type + ':error',
    error: errorToObject(err)
  });
}
<|endoftext|>


<commit_before>/*
  This modules adds code mirror code rendering to items on the page that
  contain code. To enable it on your elements add the classname:
  .deck-codemirror to your container and the classname 'codemirror-item'
  to any block that you wish to codemirrorify.
*/
(function($, deck, undefined) {

  var $d = $(document);

  /*
  Extends defaults/options.

  options.classes.codemirror
    This class is added to the deck container when there is code in the
    slide that should be

  options.selectors.codemirror-item
    This class should be added to the element containing code that should
    be highlighted.
  */
  $.extend(true, $[deck].defaults, {
    classes: {
      codemirror: 'deck-codemirror',
      codemirrorresult: 'deck-codemirror-result'
    },

    selectors: {
      codemirroritem: '.code',
    },

    data : {
      codemirrorified: 'codemirrorified'
    },
    codemirror : {
      lineNumbers : true,
      theme : "default",
      mode : "javascript",
      theme : "default",
      indentUnit : 1,
      indentWithTabs : false,
      runnable : false
    }
  });

  // flag to indicate that we are currently in the editor. Required to stop keypress
  // propagation to all other extensions.
  var inEditor = false;

  // a helper private function that can be used to "codemirror" a slide if that slide
  // has any elements with the proper classname.
  var codemirrorify = function(slide) {
    var $container = $[deck]('getContainer'),
        opts = $[deck]('getOptions'),
        codeblocks = $(slide).find(opts.selectors.codemirroritem),
        hiddenScripts  = [],
        cleanupScripts = [];

    // Seek out and cache all hidden scripts
    $("script[type=codemirror]").each(function() {
      hiddenScripts.push({
        selector: $(this).data("selector"),
        src: this.innerHTML
      });
    });

    // Seek out and cache all cleanup scripts
    $("script[type=\"codemirror/cleanup\"]").each(function() {
      cleanupScripts.push({
        selector: $(this).data("selector"),
        src: this.innerHTML
      });
    });

    var real_console_log = console.log;

    // Overwrite the default log behavior to pipe to an output element.
    console.log = function(...args) {
      var output = $.deck('getSlide').find('.deck-codemirror-result');
      if (!output.length) {
        return;
      }
      var messages = [];
      // Convert all arguments to Strings (Objects will be JSONified).
      for (var i = 0; i < args.length; i++) {
        var value = arguments[i];
        messages.push(typeof(value) == 'object' ? JSON.stringify(value) : String(value));
      }
      var msg = messages.join(" ");
      if (output.html() !== "") {
        output.append("
" + msg);
      } else {
        output.html(msg);
      }
    };

    // go through all code blocks
    $.each(codeblocks, function(i, codeblock) {

      // if codeblock hasn't been codemirrorified yet
      if (!$.data(codeblock, opts.data.codemirrorified)) {

        // initialize defaults.
        var codeblock = $(codeblock),
            editor    = null,
            options   = $.extend(opts.codemirror,
              {
                mode : !!codeblock.attr('mode') ? codeblock.attr('mode') : opts.codemirror.mode,
                theme : !!codeblock.attr('theme') ? codeblock.attr('theme') : opts.codemirror.theme,
                onFocus : function(e) {
                  inEditor = true;
                },
                onBlur : function(e) {
                  inEditor = false;
                }
              }
            );

        // if this is a textarea just use the codemirror shorthand.
        if (codeblock.get(0).nodeName.toUpperCase() === "TEXTAREA") {
          editor = CodeMirror.fromTextArea(codeblock[0], options);
        } else {
          // else codemirror the element's content and attach to element parent.
          var parent  = codeblock.parent();
          codeblock.hide();
          editor      = CodeMirror(parent[0],
            $.extend(options, {
              value : codeblock.html()
            })
          );
        }

        // mark that this code block has been codemirrored.
        $.data(codeblock[0], opts.data.codemirrorified, 'true');

        // attach a listener to this event to make sure that all other keybindings
        // don't trigger on keypress.
        $(editor.getWrapperElement()).keydown(function(e) {
          e.stopPropagation();
        });

        if (opts.codemirror.runnable || codeblock.attr("runnable")) {
          // make the code runnable
          var wrapper = editor.getWrapperElement(),
              button  = $('<button>', {
                "class" : "button",
                text : "Run"
              }).prependTo(wrapper),
              clearButton  = $('<button>', {
                "class" : "button clear",
                text : "Clear"
              }).prependTo(wrapper),
              output = $('
', {
                "class" : opts.classes.codemirrorresult
              }).appendTo($(wrapper).parent());

          clearButton.click(function(editor, output){
            return function(event) {
              if (iframe) {
                iframe.remove();
              }
              output.html('');
            };
          }(editor, output));

          var iframe;

          $(document).bind('deck.change', function() {
            if (iframe) {
              iframe.remove();
            }
          });

          button.click(function(editor, output){
            return function(event) {
              // save the default logging behavior.
              // Following Dean Edward's fantastic sandbox code:
              // http://dean.edwards.name/weblog/2006/11/sandbox/+evaluating+js+in+an+iframe
              // create an iframe sandbox for this element.
              if (iframe) {
                iframe.remove();
              }
              iframe = $("")
                .css("display", "none")
                .appendTo($d.find('body'));

              // Overwrite the default log behavior to pipe to an output element.

              var sandBoxMarkup = "


<commit_before>/**
 * Manages insertation and editing of quotes.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2015 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLab/WCF/Ui/Redactor/Quote
 */
define(['EventHandler', 'Language', 'Dom/Util', 'Ui/Dialog'], function(EventHandler, Language, DomUtil, UiDialog) {
	"use strict";

	var _element = null;
	var _insertCallback = null;
	var _quotePaddingTop = 0;
	var _titleHeight = 0;
	var _wysiwygQuoteButton = null;
	var _wysiwygQuoteTitle = null;
	var _wysiwygQuoteUrl = null;

	var UiRedactorQuote = {
		/**
		 * Registers an editor instance.
		 *
		 * @param       {string}        editorId        textarea identifier
		 * @param       {object}        editor          editor element
		 */
		initEditor: function(editorId, editor) {
			EventHandler.add('com.woltlab.wcf.redactor', 'observe_load_' + editorId, (function(data) {
				this.observeAll(data.editor);
			}).bind(this));

			this.observeAll(editor);
		},

		/**
		 * Opens a dialog to insert a quote at caret position.
		 *
		 * @param       {function}      callback        callback invoked with the
 element as parameter
		 */
		insert: function(callback) {
			_insertCallback = callback;

			UiDialog.open(this);
			UiDialog.setTitle(this, Language.get('wcf.wysiwyg.quote.insert'));

			_wysiwygQuoteButton.textContent = Language.get('wcf.global.button.submit');
			_wysiwygQuoteTitle.value = '';
			_wysiwygQuoteUrl.value = '';
		},

		/**
		 * Edits a
 element.
		 *
		 * @param       {Element}       element
 element
		 * @param       {Event=}        event           event object
		 */
		edit: function(element, event) {
			if (_titleHeight === 0) {
				var styles = window.getComputedStyle(element, '::before');
				_titleHeight = DomUtil.styleAsInt(styles, 'height');

				styles = window.getComputedStyle(element);
				_quotePaddingTop = DomUtil.styleAsInt(styles, 'padding-top');
			}

			if (typeof event === 'object') {
				// check if click occured within the ::before pseudo element
				var rect = DomUtil.offset(element);
				if ((event.clientY + window.scrollY) > (rect.top + _quotePaddingTop + _titleHeight)) {
					return;
				}

				event.preventDefault();
			}

			_element = element;

			UiDialog.open(this);
			UiDialog.setTitle(this, Language.get('wcf.wysiwyg.quote.edit'));

			// set values
			_wysiwygQuoteButton.textContent = Language.get('wcf.global.button.save');
			_wysiwygQuoteTitle.value = elData(_element, 'quote-title');
			_wysiwygQuoteUrl.value = elData(_element, 'quote-url');
		},

		/**
		 * Observes all
 elements for clicks on the editable headline
		 * @param       {Element}       editorElement           editor element
		 */
		observeAll: function(editorElement) {
			var elements = elByTag('BLOCKQUOTE', editorElement);
			for (var i = 0, length = elements.length; i < length; i++) {
				this._observe(elements[i], true);
			}
		},

		/**
		 * Observes clicks on a
 element and updates the headline.
		 *
		 * @param       {Element}       element
 element
		 * @param       {boolean}       updateHeader    update quote header
		 */
		_observe: function(element, updateHeader) {
			element.addEventListener('click', this.edit.bind(this, element));

			if (updateHeader) this._updateHeader(element);
		},

		/**
		 * Updates the headline of target
 element.
		 *
		 * @param       {Element}       element
 element
		 */
		_updateHeader: function(element) {
			elData(element, 'quote-header', Language.get('wcf.wysiwyg.quote.header', {
				title: elData(element, 'quote-title') || elData(element, 'quote-url') || ''
			}));
		},

		/**
		 * Adds or edits a
 element on dialog submit.
		 */
		_dialogSubmit: function() {
			if (_insertCallback !== null) {
				// insert a new
 element
				var element = elCreate('blockquote');
				element.className = 'quoteBox';
				element.id = 'quote-' + DomUtil.getUniqueId();

				_insertCallback(element);

				_element = elById(element.id);
				_element.id = '';

				this._observe(_element, false);
			}

			// edit an existing
 element
			elData(_element, 'quote-title', _wysiwygQuoteTitle.value.trim());
			elData(_element, 'quote-url', _wysiwygQuoteUrl.value.trim());

			this._updateHeader(_element);

			UiDialog.close(this);
		},

		_dialogOnSetup: function() {
			_wysiwygQuoteTitle = elById('wysiwygQuoteTitle');
			_wysiwygQuoteUrl = elById('wysiwygQuoteUrl');

			var _keyupCallback = (function(event) {
				if (event.which === 13) {
					this._dialogSubmit(event);
				}
			}).bind(this);

			_wysiwygQuoteTitle.addEventListener('keyup', _keyupCallback);
			_wysiwygQuoteUrl.addEventListener('keyup', _keyupCallback);

			_wysiwygQuoteButton = elById('wysiwygQuoteSubmit');
			_wysiwygQuoteButton.addEventListener('click', this._dialogSubmit.bind(this));
		},

		_dialogOnClose: function() {
			_element = null;
			_insertCallback = null;
		},

		_dialogSetup: function() {
			return {
				id: 'wysiwygQuoteDialog',
				options: {
					onClose: this._dialogOnClose.bind(this),
					onSetup: this._dialogOnSetup.bind(this)
				},
				source: '
'
						+ '
' + Language.get('wcf.wysiwyg.quote.title') + '
'
						+ '
<input type="text" id="wysiwygQuoteTitle" class="long">
'
					+ '
'
					+ '
'
						+ '
' + Language.get('wcf.wysiwyg.quote.url') + '
'
						+ '
<input type="text" id="wysiwygQuoteUrl" class="long">
'
					+ '
'
					+ '
'
						+ '<button class="buttonPrimary" id="wysiwygQuoteSubmit"></button>'
					+ '
'
			};
		}
	};

	return UiRedactorQuote;
});
<commit_msg>Fixed infinite loop<commit_after>/**
 * Manages insertation and editing of quotes.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2015 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLab/WCF/Ui/Redactor/Quote
 */
define(['EventHandler', 'Language', 'Dom/Util', 'Ui/Dialog'], function(EventHandler, Language, DomUtil, UiDialog) {
	"use strict";

	var _callbackEdit = null;
	var _element = null;
	var _insertCallback = null;
	var _quotePaddingTop = 0;
	var _titleHeight = 0;
	var _wysiwygQuoteButton = null;
	var _wysiwygQuoteTitle = null;
	var _wysiwygQuoteUrl = null;

	return {
		/**
		 * Registers an editor instance.
		 *
		 * @param       {string}        editorId        textarea identifier
		 * @param       {object}        editor          editor element
		 */
		initEditor: function(editorId, editor) {
			EventHandler.add('com.woltlab.wcf.redactor', 'observe_load_' + editorId, (function(data) {
				this.observeAll(data.editor);
			}).bind(this));

			this.observeAll(editor);
		},

		/**
		 * Opens a dialog to insert a quote at caret position.
		 *
		 * @param       {function}      callback        callback invoked with the
 element as parameter
		 */
		insert: function(callback) {
			_insertCallback = callback;

			UiDialog.open(this);
			UiDialog.setTitle(this, Language.get('wcf.wysiwyg.quote.insert'));

			_wysiwygQuoteButton.textContent = Language.get('wcf.global.button.submit');
			_wysiwygQuoteTitle.value = '';
			_wysiwygQuoteUrl.value = '';
		},

		/**
		 * Edits a
 element.
		 *
		 * @param       {Event?}        event           event object
		 * @param       {Element=}      element
 element
		 */
		edit: function(event, element) {
			if (event instanceof Event) {
				element = event.currentTarget;
			}

			if (_titleHeight === 0) {
				var styles = window.getComputedStyle(element, '::before');
				_titleHeight = DomUtil.styleAsInt(styles, 'height');

				styles = window.getComputedStyle(element);
				_quotePaddingTop = DomUtil.styleAsInt(styles, 'padding-top');
			}

			if (event instanceof Event) {
				// check if click occured within the ::before pseudo element
				var rect = DomUtil.offset(element);
				if ((event.clientY + window.scrollY) > (rect.top + _quotePaddingTop + _titleHeight)) {
					return;
				}

				event.preventDefault();
			}

			_element = element;

			UiDialog.open(this);
			UiDialog.setTitle(this, Language.get('wcf.wysiwyg.quote.edit'));

			// set values
			_wysiwygQuoteButton.textContent = Language.get('wcf.global.button.save');
			_wysiwygQuoteTitle.value = elData(_element, 'quote-title');
			_wysiwygQuoteUrl.value = elData(_element, 'quote-url');
		},

		/**
		 * Observes all
 elements for clicks on the editable headline
		 * @param       {Element}       editorElement           editor element
		 */
		observeAll: function(editorElement) {
			var elements = elByTag('BLOCKQUOTE', editorElement);
			for (var i = 0, length = elements.length; i < length; i++) {
				this._observe(elements[i], true);
			}
		},

		/**
		 * Observes clicks on a
 element and updates the headline.
		 *
		 * @param       {Element}       element
 element
		 * @param       {boolean}       updateHeader    update quote header
		 */
		_observe: function(element, updateHeader) {
			if (_callbackEdit === null) _callbackEdit = this.edit.bind(this);

			element.removeEventListener(WCF_CLICK_EVENT, _callbackEdit);
			element.addEventListener(WCF_CLICK_EVENT, _callbackEdit);

			if (updateHeader) this._updateHeader(element);
		},

		/**
		 * Updates the headline of target
 element.
		 *
		 * @param       {Element}       element
 element
		 */
		_updateHeader: function(element) {
			var value = Language.get('wcf.wysiwyg.quote.header', {
				title: elData(element, 'quote-title') || elData(element, 'quote-url') || ''
			});

			if (elData(element, 'quote-header') !== value) {
				elData(element, 'quote-header', value);
			}
		},

		/**
		 * Adds or edits a
 element on dialog submit.
		 */
		_dialogSubmit: function() {
			if (_insertCallback !== null) {
				// insert a new
 element
				var element = elCreate('blockquote');
				element.className = 'quoteBox';
				element.id = 'quote-' + DomUtil.getUniqueId();

				_insertCallback(element);

				_element = elById(element.id);
				_element.id = '';

				this._observe(_element, false);
			}

			// edit an existing
 element
			elData(_element, 'quote-title', _wysiwygQuoteTitle.value.trim());
			elData(_element, 'quote-url', _wysiwygQuoteUrl.value.trim());

			this._updateHeader(_element);

			UiDialog.close(this);
		},

		_dialogOnSetup: function() {
			_wysiwygQuoteTitle = elById('wysiwygQuoteTitle');
			_wysiwygQuoteUrl = elById('wysiwygQuoteUrl');

			var _keyupCallback = (function(event) {
				if (event.which === 13) {
					this._dialogSubmit(event);
				}
			}).bind(this);

			_wysiwygQuoteTitle.addEventListener('keyup', _keyupCallback);
			_wysiwygQuoteUrl.addEventListener('keyup', _keyupCallback);

			_wysiwygQuoteButton = elById('wysiwygQuoteSubmit');
			_wysiwygQuoteButton.addEventListener(WCF_CLICK_EVENT, this._dialogSubmit.bind(this));
		},

		_dialogOnClose: function() {
			_element = null;
			_insertCallback = null;
		},

		_dialogSetup: function() {
			return {
				id: 'wysiwygQuoteDialog',
				options: {
					onClose: this._dialogOnClose.bind(this),
					onSetup: this._dialogOnSetup.bind(this)
				},
				source: '
'
						+ '
' + Language.get('wcf.wysiwyg.quote.title') + '
'
						+ '
<input type="text" id="wysiwygQuoteTitle" class="long">
'
					+ '
'
					+ '
'
						+ '
' + Language.get('wcf.wysiwyg.quote.url') + '
'
						+ '
<input type="text" id="wysiwygQuoteUrl" class="long">
'
					+ '
'
					+ '
'
						+ '<button class="buttonPrimary" id="wysiwygQuoteSubmit"></button>'
					+ '
'
			};
		}
	};
});
<|endoftext|>


<commit_before>(function() {
  'use strict';

  function sequoiaTreeDirective(Tree){

    return {
      restrict: 'AE',
      replace: true,
      templateUrl: 'angular-sequoia.html',
      scope: {
        'treeNodes': '=sequoiaTree',
        'model': '=ngModel',
        'template': '=nodeTemplate',
        'options': '='
      },
      link: function(scope) {
        scope.canEdit = scope.options.canEdit ? true : false;

        scope.model = _.isArray(scope.model) ? scope.model : [];
        scope.breadcrumbs = [];

        var tree = new Tree(scope.treeNodes, scope.template);

        scope.load = function(node) {
          scope.onlySelected = false;
          if(tree.isValidNode(node)) {
            tree.setCurrentNodes(node[tree.template.nodes]);
            scope.breadcrumbs = tree.breadcrumbs(node[tree.template.id]);
          } else {
            tree.setCurrentNodes();
            scope.breadcrumbs = [];
          }
        };

        scope.select = function(node) {
          if(node._id) {
            scope.model.push(node[tree.template.id]);
          }
        };

        scope.remove = function(node) {
          var index = node._id ? _.indexOf(scope.model,node[tree.template.id]) : -1;
          if(index !== -1) {
            scope.model.splice(index, 1);
          }
        };

        scope.isSelected = function(node) {
          return _.indexOf(scope.model, node[tree.template.id]) !== -1 ? true : false;
        };

        scope.toggleSelected = function() {
          if(scope.onlySelected) {
            scope.onlySelected = false;
            tree.setCurrentNodes(tree.getNodesInPath());
          } else {
            scope.onlySelected = true;
            var selected = tree.findSelected(scope.model);
            tree.setNodesInPath(tree.nodes);
            tree.setCurrentNodes(selected);
          }
        };

        scope.tree = tree;

        scope.load();
      }
    };

  }

  sequoiaTreeDirective.$inject = ['SequoiaTree'];

  angular.module('ngSequoia')
    .directive('sequoiaTree', sequoiaTreeDirective);

})();<commit_msg>Fix hardcoded _id - template.id instead of _id<commit_after>(function() {
  'use strict';

  function sequoiaTreeDirective(Tree){

    return {
      restrict: 'AE',
      replace: true,
      templateUrl: 'angular-sequoia.html',
      scope: {
        'treeNodes': '=sequoiaTree',
        'model': '=ngModel',
        'template': '=nodeTemplate',
        'options': '='
      },
      link: function(scope) {
        scope.canEdit = scope.options.canEdit ? true : false;

        scope.model = _.isArray(scope.model) ? scope.model : [];
        scope.breadcrumbs = [];

        var tree = new Tree(scope.treeNodes, scope.template);

        scope.load = function(node) {
          scope.onlySelected = false;
          if(tree.isValidNode(node)) {
            tree.setCurrentNodes(node[tree.template.nodes]);
            scope.breadcrumbs = tree.breadcrumbs(node[tree.template.id]);
          } else {
            tree.setCurrentNodes();
            scope.breadcrumbs = [];
          }
        };

        scope.select = function(node) {
          if(node[tree.template.id]) {
            scope.model.push(node[tree.template.id]);
          }
        };

        scope.remove = function(node) {
          var index = node._id ? _.indexOf(scope.model,node[tree.template.id]) : -1;
          if(index !== -1) {
            scope.model.splice(index, 1);
          }
        };

        scope.isSelected = function(node) {
          return _.indexOf(scope.model, node[tree.template.id]) !== -1 ? true : false;
        };

        scope.toggleSelected = function() {
          if(scope.onlySelected) {
            scope.onlySelected = false;
            tree.setCurrentNodes(tree.getNodesInPath());
          } else {
            scope.onlySelected = true;
            var selected = tree.findSelected(scope.model);
            tree.setNodesInPath(tree.nodes);
            tree.setCurrentNodes(selected);
          }
        };

        scope.tree = tree;

        scope.load();
      }
    };

  }

  sequoiaTreeDirective.$inject = ['SequoiaTree'];

  angular.module('ngSequoia')
    .directive('sequoiaTree', sequoiaTreeDirective);

})();<|endoftext|>


<commit_before>// @flow

/**
 * An internal certificate ID value.
 */
export type CertificateId = number;

/**
 * A description of mixed content (HTTP resources on HTTPS pages), as defined by
 * https://www.w3.org/TR/mixed-content/#categories
 */
export type MixiedContentType = "blockable" | "optionally-blockable" | "none";

/**
 * The security level of a page or resource.
 */
export type SecurityState = "unknown" | "neutral" | "insecure" | "warning" | "secure" | "info";
<commit_msg>add security domain type<commit_after>// @flow

/**
 * An internal certificate ID value.
 */
export type CertificateId = number;

/**
 * A description of mixed content (HTTP resources on HTTPS pages), as defined by
 * https://www.w3.org/TR/mixed-content/#categories
 */
export type MixiedContentType = "blockable" | "optionally-blockable" | "none";

/**
 * The security level of a page or resource.
 */
export type SecurityState = "unknown" | "neutral" | "insecure" | "warning" | "secure" | "info";

/**
 * An explanation of an factor contributing to the security state.
 */
export type SecurityStateExplanation = {
  securityState: SecurityState,
  summary: string,
  description: string,
  hasCertificate: boolean,
  mixedContentType: MixiedContentType,
};

/**
 * Information about insecure content on the page.
 */
export type InsecureContentStatus = {
  ranMixedContent: boolean,
  displayedMixedContent: boolean,
  containedMixedForm: boolean,
  ranContentWithCertErrors: boolean,
  displayedContentWithCertErrors: boolean,
  ranInsecureContentStyle: SecurityState,
  displayedInsecureContentStyle: SecurityState,
};

/**
 * The action to take when a certificate error occurs.
 * continue will continue processing the request and cancel will cancel the request.
 */
export type CertificateErrorAction = "continue" | "cancel";

/**
 * Security Domain
 *
 * EXPERIMENTAL
 */
export type Security = {
  /**
   * Enables tracking security state changes.
   */
  enable(): Promise<>;

  /**
   * Disables tracking security state changes.
   */
  disable(): Promise<>;

  /**
   * Displays native dialog with the certificate details.
   */
  showCertificateViewer(): Promise<>;

  /**
   * Handles a certificate error that fired a certificateError event.
   */
  handleCertificateError(arg: {
    eventId: number,
    action: CertificateErrorAction
  }): Promise<>;

  /**
   * Enable/disable overriding certificate errors. If enabled,
   * all certificate error events need to be handled by
   * the DevTools client and should be answered with handleCertificateError commands.
   */
  setOverrideCertificateErrors(arg: {
    override: boolean
  }): Promise<>;

  /* events */

  /**
   * The security state of the page changed.
   */
  securityStateChanged(callback: (
    securityState: SecurityState,
    schemeIsCryptographic: boolean,
    explanations: Array<SecurityStateExplanation>,
    insecureContentStatus: InsecureContentStatus,
    summary?: string
  ) => void): void;

  /**
   * There is a certificate error.
   * If overriding certificate errors is enabled,
   * then it should be handled with the handleCertificateError command.
   *
   * Note: this event does not fire if the certificate error has been allowed internally.
   */
  certificateError(callback: (
    eventId: number,
    errorType: string,
    requestURL: string
  ) => void): void;
};
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngInject
 */
var NpdcBreadcrumbs = function($location, $rootScope) {

  this.breadcrumbs = [];

  this.path = "";

  var self = this;

  var home = { href: "/", title: "Norwegian Polar Data Centre", text: "NPDC" };

  var capitalize = (string) => {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  var link = (crumb, i) => {
    if (i === 0) {
      self.path = "";
      return home;
    }

    if (i > 0) {
      self.path += `/${crumb}`;
    }

    if (i === 2 && (/^\w{8}-\w{4}-/).test(crumb)) {
      return { href: self.path, text: crumb.split("-")[0] };
    }
    return { href: self.path, title: capitalize(crumb), text: capitalize(decodeURIComponent(crumb)) };
  };

  $rootScope.$on("$locationChangeSuccess", function(event, uri) {

    let parts = uri.split("//")[1].split("/").filter(p => { return !(/^$/).test(p); });
    let i = 0;
    self.breadcrumbs = parts.map(
      crumb => {
        return link(crumb, i++);
      }
    );
  });

  return this;
};

module.exports = NpdcBreadcrumbs;<commit_msg>Shorten UUIDs on any level...<commit_after>'use strict';

/**
 * @ngInject
 */
var NpdcBreadcrumbs = function($location, $rootScope) {

  this.breadcrumbs = [];

  this.path = "";

  var self = this;

  var home = { href: "/", title: "Norwegian Polar Data Centre", text: "NPDC" };

  var capitalize = (string) => {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  var link = (crumb, i) => {
    if (i === 0) {
      self.path = "";
      return home;
    }

    if (i > 0) {
      self.path += `/${crumb}`;
    }

    if (i >= 2 && (/^\w{8}-\w{4}-/).test(crumb)) {
      return { href: self.path, text: crumb.split("-")[0] };
    }
    return { href: self.path, title: capitalize(crumb), text: capitalize(decodeURIComponent(crumb)) };
  };

  $rootScope.$on("$locationChangeSuccess", function(event, uri) {

    let parts = uri.split("//")[1].split("/").filter(p => { return !(/^$/).test(p); });
    let i = 0;
    self.breadcrumbs = parts.map(
      crumb => {
        return link(crumb, i++);
      }
    );
  });

  return this;
};

module.exports = NpdcBreadcrumbs;<|endoftext|>


<commit_before>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 * @fileOverview
 * @author Cyril Junod <cyril.junod at gmail.com>
 */
YUI.add("wegas-box", function(Y) {
    "use strict";

    /**
     * @name Y.Wegas.Box
     * @extends Y.Widget
     * @borrows Y.WidgetChild, Y.Wegas.Widget, Y.Wegas.Editable
     * @class Displays a box widget
     * @constructor
     * @description  Display a simple box
     */
    var Box = Y.Base.create("wegas-box", Y.Widget, [Y.WidgetChild, Y.Wegas.Widget, Y.Wegas.Editable], {
        /** @lends Y.Wegas.Box# */
        CONTENT_TEMPLATE: null,
        getEditorLabel: function() {
            return this.get("label");
        }
    }, {
        /** @lends Y.Wegas.Box */
        EDITORNAME: "Box",
        ATTRS: {
            label: {
                type: "string",
                optional: true,
                getter: Y.Wegas.Editable.removeNullValue
            }
        }
    });
    Y.namespace("Wegas").Box = Box;

});
<commit_msg>Revert box modification<commit_after>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 * @fileOverview
 * @author Cyril Junod <cyril.junod at gmail.com>
 */
YUI.add("wegas-box", function(Y) {
    "use strict";

    /**
     * @name Y.Wegas.Box
     * @extends Y.Widget
     * @borrows Y.WidgetChild, Y.Wegas.Widget, Y.Wegas.Editable
     * @class Displays a box widget
     * @constructor
     * @description  Display a simple box
     */
    var Box = Y.Base.create("wegas-box", Y.Widget, [Y.WidgetChild, Y.Wegas.Widget, Y.Wegas.Editable], {
        /** @lends Y.Wegas.Box# */
        CONTENT_TEMPLATE: null,
        getEditorLabel: function() {
            return null;
        }
    }, {
        /** @lends Y.Wegas.Box */
        EDITORNAME: "Box"
    });
    Y.namespace("Wegas").Box = Box;

});
<|endoftext|>


<commit_before>class gltfUserInterface
{
    constructor(
        modelIndexerPath,
        model,
        renderingParameters,
        stats,
        enableModelSelection = true,
        ignoredVariants = ["glTF-Draco", "glTF-Embedded"])
    {
        this.modelIndexerPath = modelIndexerPath;
        this.model = model;
        this.renderingParameters = renderingParameters;
        this.stats = stats;
        this.enableModelSelection = enableModelSelection;
        this.ignoredVariants = ignoredVariants;

        this.modelIndexer = undefined;
        this.gui = undefined;
        this.gltfFolder = undefined;
        this.modelsDictionary = undefined;
        this.modelsPath = undefined;

        this.onLoadModel = undefined;
        this.onLoadNextScene = undefined;
        this.onLoadPreviousScene = undefined;
    }

    initialize()
    {
        const self = this;
        axios.get(this.modelIndexerPath).then(response =>
        {
            self.modelIndexer = response.data;
            self.initializeCallback();
        });
    }

    initializeCallback()
    {
        this.modelsPath = this.modelIndexer !== undefined ? getContainingFolder(this.modelIndexerPath) : "models/";
        this.parseModelIndex(this.modelIndexer);

        this.gui = new dat.GUI({ width: 300 });
        this.gltfFolder = this.gui.addFolder("glTF");

        if (this.enableModelSelection)
        {
            this.initializeModelsDropdown();
        }

        this.initializeSceneSelection();
        this.initializeLightingSettings();
        this.initializeDebugSettings();
        this.initializeMonitoringView();
        this.gltfFolder.open();

        if (this.model.includes("/"))
        {
            this.loadFromPath(this.model);
        }
        else
        {
            this.loadFromKey(this.model);
        }
    }

    parseModelIndex(modelIndexer)
    {
        this.modelsDictionary = {};

        for (const entry of modelIndexer)
        {
            if (entry.variants === undefined)
            {
                continue;
            }

            for (const variant of Object.keys(entry.variants))
            {
                if (this.ignoredVariants.includes(variant))
                {
                    continue;
                }

                const modelPath = entry.name + "/" + variant + "/" + entry.variants[variant];
                let modelKey = getFileNameWithoutExtension(modelPath);
                if (variant !== "glTF")
                {
                    modelKey += " (" + variant.replace("glTF-", "") + ")";
                }
                this.modelsDictionary[modelKey] = modelPath;
            }
        }
    }

    initializeModelsDropdown()
    {
        const modelKeys = Object.keys(this.modelsDictionary);
        if (!modelKeys.includes(this.model))
        {
            this.model = modelKeys[0];
        }

        const self = this;
        this.gltfFolder.add(this, "model", modelKeys).name("Model")
            .onChange(modelKey => self.loadFromKey(modelKey));
    }

    initializeSceneSelection()
    {
        const scenesFolder = this.gltfFolder.addFolder("Scene Index");
        scenesFolder.add(this, "onLoadPreviousScene").name("←");
        scenesFolder.add(this, "onLoadNextScene").name("→");
    }

    initializeLightingSettings()
    {
        const self = this;
        const lightingFolder = this.gui.addFolder("Lighting");
        lightingFolder.add(this.renderingParameters, "useIBL").name("Image-Based Lighting");
        lightingFolder.add(this.renderingParameters, "usePunctual").name("Punctual Lighting");
        lightingFolder.add(this.renderingParameters, "exposure", 0, 2, 0.1).name("Exposure");
        lightingFolder.add(this.renderingParameters, "gamma", 0, 10, 0.1).name("Gamma");
        lightingFolder.add(this.renderingParameters, "toneMap", Object.values(ToneMaps)).name("Tone Map");
        lightingFolder.addColor(this.renderingParameters, "clearColor", [50, 50, 50]).name("Background Color");
        lightingFolder.add(this.renderingParameters, "environment", Environments).name("Environment")
            .onChange(environment => self.loadEnvironment(environment));
    }

    initializeDebugSettings()
    {
        const debugFolder = this.gui.addFolder("Debug");
        debugFolder.add(this.renderingParameters, "debugOutput", Object.values(DebugOutput)).name("Debug Output");
    }

    initializeMonitoringView()
    {
        const monitoringFolder = this.gui.addFolder("Performance");
        this.stats.domElement.height = "48px";
        for (const child of this.stats.domElement.children)
        {
            child.style.display = "";
        }
        this.stats.domElement.style.position = "static";
        const statsList = document.createElement("li");
        statsList.appendChild(this.stats.domElement);
        statsList.classList.add("gui-stats");
        monitoringFolder.__ul.appendChild(statsList);
    }

    loadFromPath(modelPath)
    {
        this.onLoadModel(modelPath);
    }

    loadFromKey(modelKey)
    {
        this.model = modelKey;
        const relativePath = this.modelsDictionary[this.model];
        this.onLoadModel(relativePath, this.modelsPath);
    }

    loadEnvironment(environment)
    {
        this.renderingParameters.environment = environment;
        this.loadFromKey(this.model);
    }
}
<commit_msg>reordered the UI a little<commit_after>class gltfUserInterface
{
    constructor(
        modelIndexerPath,
        model,
        renderingParameters,
        stats,
        enableModelSelection = true,
        ignoredVariants = ["glTF-Draco", "glTF-Embedded"])
    {
        this.modelIndexerPath = modelIndexerPath;
        this.model = model;
        this.renderingParameters = renderingParameters;
        this.stats = stats;
        this.enableModelSelection = enableModelSelection;
        this.ignoredVariants = ignoredVariants;

        this.modelIndexer = undefined;
        this.gui = undefined;
        this.gltfFolder = undefined;
        this.modelsDictionary = undefined;
        this.modelsPath = undefined;

        this.onLoadModel = undefined;
        this.onLoadNextScene = undefined;
        this.onLoadPreviousScene = undefined;
    }

    initialize()
    {
        const self = this;
        axios.get(this.modelIndexerPath).then(response =>
        {
            self.modelIndexer = response.data;
            self.initializeCallback();
        });
    }

    initializeCallback()
    {
        this.modelsPath = this.modelIndexer !== undefined ? getContainingFolder(this.modelIndexerPath) : "models/";
        this.parseModelIndex(this.modelIndexer);

        this.gui = new dat.GUI({ width: 300 });
        this.gltfFolder = this.gui.addFolder("glTF");

        if (this.enableModelSelection)
        {
            this.initializeModelsDropdown();
        }

        this.initializeSceneSelection();
        this.initializeLightingSettings();
        this.initializeDebugSettings();
        this.initializeMonitoringView();
        this.gltfFolder.open();

        if (this.model.includes("/"))
        {
            this.loadFromPath(this.model);
        }
        else
        {
            this.loadFromKey(this.model);
        }
    }

    parseModelIndex(modelIndexer)
    {
        this.modelsDictionary = {};

        for (const entry of modelIndexer)
        {
            if (entry.variants === undefined)
            {
                continue;
            }

            for (const variant of Object.keys(entry.variants))
            {
                if (this.ignoredVariants.includes(variant))
                {
                    continue;
                }

                const modelPath = entry.name + "/" + variant + "/" + entry.variants[variant];
                let modelKey = getFileNameWithoutExtension(modelPath);
                if (variant !== "glTF")
                {
                    modelKey += " (" + variant.replace("glTF-", "") + ")";
                }
                this.modelsDictionary[modelKey] = modelPath;
            }
        }
    }

    initializeModelsDropdown()
    {
        const modelKeys = Object.keys(this.modelsDictionary);
        if (!modelKeys.includes(this.model))
        {
            this.model = modelKeys[0];
        }

        const self = this;
        this.gltfFolder.add(this, "model", modelKeys).name("Model")
            .onChange(modelKey => self.loadFromKey(modelKey));
    }

    initializeSceneSelection()
    {
        const scenesFolder = this.gltfFolder.addFolder("Scene Index");
        scenesFolder.add(this, "onLoadPreviousScene").name("←");
        scenesFolder.add(this, "onLoadNextScene").name("→");
    }

    initializeLightingSettings()
    {
        const self = this;
        const lightingFolder = this.gui.addFolder("Lighting");
        lightingFolder.add(this.renderingParameters, "useIBL").name("Image-Based Lighting");
        lightingFolder.add(this.renderingParameters, "usePunctual").name("Punctual Lighting");
        lightingFolder.add(this.renderingParameters, "environment", Environments).name("Environment")
            .onChange(environment => self.loadEnvironment(environment));
        lightingFolder.add(this.renderingParameters, "exposure", 0, 2, 0.1).name("Exposure");
        lightingFolder.add(this.renderingParameters, "gamma", 0, 10, 0.1).name("Gamma");
        lightingFolder.add(this.renderingParameters, "toneMap", Object.values(ToneMaps)).name("Tone Map");
        lightingFolder.addColor(this.renderingParameters, "clearColor", [50, 50, 50]).name("Background Color");
    }

    initializeDebugSettings()
    {
        const debugFolder = this.gui.addFolder("Debug");
        debugFolder.add(this.renderingParameters, "debugOutput", Object.values(DebugOutput)).name("Debug Output");
    }

    initializeMonitoringView()
    {
        const monitoringFolder = this.gui.addFolder("Performance");
        this.stats.domElement.height = "48px";
        for (const child of this.stats.domElement.children)
        {
            child.style.display = "";
        }
        this.stats.domElement.style.position = "static";
        const statsList = document.createElement("li");
        statsList.appendChild(this.stats.domElement);
        statsList.classList.add("gui-stats");
        monitoringFolder.__ul.appendChild(statsList);
    }

    loadFromPath(modelPath)
    {
        this.onLoadModel(modelPath);
    }

    loadFromKey(modelKey)
    {
        this.model = modelKey;
        const relativePath = this.modelsDictionary[this.model];
        this.onLoadModel(relativePath, this.modelsPath);
    }

    loadEnvironment(environment)
    {
        this.renderingParameters.environment = environment;
        this.loadFromKey(this.model);
    }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
* @author Mitchell Seaton
*/
var fs = require('fs'), path = require('path'), utile = require('utile'), libxml = require('libxmljs'), moment = require('moment');
var argv = require('optimist')
		.usage('Convert eSciDoc SRW query results to JSON for TimelineJS.\nUsage: $0 -f [input]')
		.demand(['f'])
		.alias('f', 'file') // File eSciDoc SRW XML
		.alias('O', 'output') // Output file name
		.alias('d', 'dir') // Target directory for output file
		.boolean('p') // Use JSONP as output format
		.default('d', '_files/')
		.describe('f', 'eSciDoc SRW query (XML)')
		.describe('O', 'Output file name.')
		.describe('d', 'Target directory for output.')
		.describe('p', 'Using JSONP (JSON with padding) format.')
		.check(function(opts) {
		  if(path.extname(opts.f) != '.xml') throw new Error('Input file (-f) must have XML extension.')
		  return true;
		})
		.argv;

var is_json_p = argv.p; // true if we require JSONP (cross-domain, local)
var xml_docs = new Array();
var period_map = {'TEIP5DKCLARIN': {}, 'TEIP5': {}, 'AUDIO': {}, 'VIDEO': {}, 'LEX': {}, 'IMDI-SESSION'}, json_obj = {};
var file_read_length = 1, temp_filename = null;

// eSciDoc 1.3.x SRW
var ns_obj = {'sru-zr':'http://www.loc.gov/zing/srw/',
		'escidocItem':'http://www.escidoc.de/schemas/item/0.10',
		'escidocMetadataRecords':'http://www.escidoc.de/schemas/metadatarecords/0.5',
		'escidocContentStreams':'http://www.escidoc.de/schemas/contentstreams/0.7',
		'escidocComponents':'http://www.escidoc.de/schemas/components/0.9',
		'version':'http://escidoc.de/core/01/properties/version/',
		'release':'http://escidoc.de/core/01/properties/release/',
		'prop':'http://escidoc.de/core/01/properties/',
		'srel':'http://escidoc.de/core/01/structural-relations/',
		'xlink':'http://www.w3.org/1999/xlink' };

// read a File in as input SRW query XML data
var readFile = function(file) {
  fs.readFile(file, 'utf8', function (err, data) {
    if (err) throw err;
    file_read_length--;
    parse(libxml.parseXmlString(data));
  });
}

// Parse and pull data from the XMLDocument
var parse = function(doc) {
    var totalRecords = doc.get('//sru-zr:numberOfRecords', ns_obj).text();
    console.log('Total records in query: ' + totalRecords);

    var items = doc.find('//escidocItem:item', ns_obj);
    if(utile.isArray(items)) console.log('Found ' + items.length + ' items.');
    else console.error('Found 0 items in XMLDocument.');

    // Add the timeline items
    utile.each(items, function(val, key) {
      var creation_date = new Date(val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/created', ns_obj).text());
      var creation_date_str = moment(creation_date).format('yyyy,mm,dd');

      var tag = val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/conformsTo', ns_obj).text();
      if(tag.indexOf('IMDI') != -1) tag = tag.substring(0, tag.lastIndexOf('-')-1); // test data date: 2010-02-23
      if(!period_map[tag][creation_date_str]) {
    	var title = val.attr('title').value();
    	var description = val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/description', ns_obj).text();
	var href_attr = val.attr('href').value().split('/');
	var link_tag = 'Vis ressource';

	var date_obj = {headline: title, startDate: creation_date_str, endDate: creation_date_str, text: description + '
' + link_tag + '
'};
	if(tag != null) date_obj.tag = tag;
	date_obj = addOptImage(date_obj, val);

	json_obj.timeline.date.push(date_obj);
	period_map[tag][creation_date_str] = 1; // flag example as set
      }
    });

    if(file_read_length == 0)
      process.nextTick(save);
}

// Look for any existing images to use (TEIP5DKCLARIN)
var addOptImage = function(obj, item) {
	var image = item.find('escidocComponents:components/escidocComponents:component/escidocComponents:properties[prop:mime-type="image/jpeg"]', ns_obj)[0];
	if(image != null) {
	  var href = image.attr('href').value().split('/');
	  var itemID = href[3];
	  var componentID = href[6];
	  var publisher = item.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/publisher', ns_obj);
	  var subject = item.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/subject', ns_obj);
	  var credit = (publisher != null) ? publisher.text() : '';
	  var search_url = 'https://clarin.dk/clarindk/list.jsp?check_list_text=on&check_list_access_public=on&check_list_access_academic=on&check_list_access_restricted=on&fullsearch=&fullsearch-hidden=Title%2CPublisher+%28CopyrightOwner%29%2CCreator%2CDescription%2CSourceTitle%2CSubject&metadata-1=CreationDate&equals-1=%3D&searchtext-1=' + obj.startDate;
	  var caption = 'Eksempel. \"Søg Alle\" fra denne periode.';
	  var url = 'https://clarin.dk/clarindk/download-proxy.jsp?item=' + itemID + '&component=' + componentID + '&.jpg';

	  // add credit, caption, thumbnail(optional)
	  obj.asset = {media: url, credit: credit, caption: caption};
	  console.log('Image found: ' + image.attr('href').value());
	} else {
	  console.log('No image found: ' + obj.headline);
	}

	return obj;
}

/* Save JSON format file for TimelineJS */
var save = function() {
  var file_dir = path.normalize(argv.d);
  var file_name = (argv.O) ? argv.O : temp_filename;
  var json_str = JSON.stringify(json_obj, null, 4);
  var json_data = (is_json_p) ? 'storyjs_jsonp_data = ' + json_str : json_str;

  fs.exists(file_dir, function(exists) {
    var file_path = (is_json_p) ? path.join(file_dir, file_name + '.jsonp') : path.join(file_dir, file_name + '.json');
    if(exists)
      fs.writeFile(file_path, json_data, 'utf8', function(err) {
        if (err) throw err;
        console.log('File saved:' + file_path);
    });
    else console.log('Target directory doesn\'t exist: ' + file_dir);
  });
}

// main execution function
var main = function() {
  // TimelineJS heading (JSON config file or from data range?)
  json_obj.timeline =  {type: 'default', headline: '', text: '', startDate: '', date: []};

  if(utile.isArray(argv.f)) {
    file_read_length = argv.f.length;
    temp_filename = path.basename(argv.f[0], path.extname(argv.f[0]))
    for(var i=0; i<file_read_length; i++) readFile(argv.f[i]); // read multiple files
  } else {
    temp_filename = path.basename(argv.f, path.extname(argv.f));
    readFile(argv.f); // read single file input
  }
}

main(); // execute thread
<commit_msg>static var JSON object fix.<commit_after>#!/usr/bin/env node
/**
* @author Mitchell Seaton
*/
var fs = require('fs'), path = require('path'), utile = require('utile'), libxml = require('libxmljs'), moment = require('moment');
var argv = require('optimist')
		.usage('Convert eSciDoc SRW query results to JSON for TimelineJS.\nUsage: $0 -f [input]')
		.demand(['f'])
		.alias('f', 'file') // File eSciDoc SRW XML
		.alias('O', 'output') // Output file name
		.alias('d', 'dir') // Target directory for output file
		.boolean('p') // Use JSONP as output format
		.default('d', '_files/')
		.describe('f', 'eSciDoc SRW query (XML)')
		.describe('O', 'Output file name.')
		.describe('d', 'Target directory for output.')
		.describe('p', 'Using JSONP (JSON with padding) format.')
		.check(function(opts) {
		  if(path.extname(opts.f) != '.xml') throw new Error('Input file (-f) must have XML extension.')
		  return true;
		})
		.argv;

var is_json_p = argv.p; // true if we require JSONP (cross-domain, local)
var xml_docs = new Array();
var period_map = {'TEIP5DKCLARIN': {}, 'TEIP5': {}, 'AUDIO': {}, 'VIDEO': {}, 'LEX': {}, 'IMDI-SESSION':{}}, json_obj = {};
var file_read_length = 1, temp_filename = null;

// eSciDoc 1.3.x SRW
var ns_obj = {'sru-zr':'http://www.loc.gov/zing/srw/',
		'escidocItem':'http://www.escidoc.de/schemas/item/0.10',
		'escidocMetadataRecords':'http://www.escidoc.de/schemas/metadatarecords/0.5',
		'escidocContentStreams':'http://www.escidoc.de/schemas/contentstreams/0.7',
		'escidocComponents':'http://www.escidoc.de/schemas/components/0.9',
		'version':'http://escidoc.de/core/01/properties/version/',
		'release':'http://escidoc.de/core/01/properties/release/',
		'prop':'http://escidoc.de/core/01/properties/',
		'srel':'http://escidoc.de/core/01/structural-relations/',
		'xlink':'http://www.w3.org/1999/xlink' };

// read a File in as input SRW query XML data
var readFile = function(file) {
  fs.readFile(file, 'utf8', function (err, data) {
    if (err) throw err;
    file_read_length--;
    parse(libxml.parseXmlString(data));
  });
}

// Parse and pull data from the XMLDocument
var parse = function(doc) {
    var totalRecords = doc.get('//sru-zr:numberOfRecords', ns_obj).text();
    console.log('Total records in query: ' + totalRecords);

    var items = doc.find('//escidocItem:item', ns_obj);
    if(utile.isArray(items)) console.log('Found ' + items.length + ' items.');
    else console.error('Found 0 items in XMLDocument.');

    // Add the timeline items
    utile.each(items, function(val, key) {
      var creation_date = new Date(val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/created', ns_obj).text());
      var creation_date_str = moment(creation_date).format('yyyy,mm,dd');

      var tag = val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/conformsTo', ns_obj).text();
      if(tag.indexOf('IMDI') != -1) tag = tag.substring(0, tag.lastIndexOf('-')-1); // test data date: 2010-02-23
      if(!period_map[tag][creation_date_str]) {
    	var title = val.attr('title').value();
    	var description = val.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/description', ns_obj).text();
	var href_attr = val.attr('href').value().split('/');
	var link_tag = 'Vis ressource';

	var date_obj = {headline: title, startDate: creation_date_str, endDate: creation_date_str, text: description + '
' + link_tag + '
'};
	if(tag != null) date_obj.tag = tag;
	date_obj = addOptImage(date_obj, val);

	json_obj.timeline.date.push(date_obj);
	period_map[tag][creation_date_str] = 1; // flag example as set
      }
    });

    if(file_read_length == 0)
      process.nextTick(save);
}

// Look for any existing images to use (TEIP5DKCLARIN)
var addOptImage = function(obj, item) {
	var image = item.find('escidocComponents:components/escidocComponents:component/escidocComponents:properties[prop:mime-type="image/jpeg"]', ns_obj)[0];
	if(image != null) {
	  var href = image.attr('href').value().split('/');
	  var itemID = href[3];
	  var componentID = href[6];
	  var publisher = item.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/publisher', ns_obj);
	  var subject = item.get('escidocMetadataRecords:md-records/escidocMetadataRecords:md-record/CMD/Components/olac/subject', ns_obj);
	  var credit = (publisher != null) ? publisher.text() : '';
	  var search_url = 'https://clarin.dk/clarindk/list.jsp?check_list_text=on&check_list_access_public=on&check_list_access_academic=on&check_list_access_restricted=on&fullsearch=&fullsearch-hidden=Title%2CPublisher+%28CopyrightOwner%29%2CCreator%2CDescription%2CSourceTitle%2CSubject&metadata-1=CreationDate&equals-1=%3D&searchtext-1=' + obj.startDate;
	  var caption = 'Eksempel. \"Søg Alle\" fra denne periode.';
	  var url = 'https://clarin.dk/clarindk/download-proxy.jsp?item=' + itemID + '&component=' + componentID + '&.jpg';

	  // add credit, caption, thumbnail(optional)
	  obj.asset = {media: url, credit: credit, caption: caption};
	  console.log('Image found: ' + image.attr('href').value());
	} else {
	  console.log('No image found: ' + obj.headline);
	}

	return obj;
}

/* Save JSON format file for TimelineJS */
var save = function() {
  var file_dir = path.normalize(argv.d);
  var file_name = (argv.O) ? argv.O : temp_filename;
  var json_str = JSON.stringify(json_obj, null, 4);
  var json_data = (is_json_p) ? 'storyjs_jsonp_data = ' + json_str : json_str;

  fs.exists(file_dir, function(exists) {
    var file_path = (is_json_p) ? path.join(file_dir, file_name + '.jsonp') : path.join(file_dir, file_name + '.json');
    if(exists)
      fs.writeFile(file_path, json_data, 'utf8', function(err) {
        if (err) throw err;
        console.log('File saved:' + file_path);
    });
    else console.log('Target directory doesn\'t exist: ' + file_dir);
  });
}

// main execution function
var main = function() {
  // TimelineJS heading (JSON config file or from data range?)
  json_obj.timeline =  {type: 'default', headline: '', text: '', startDate: '', date: []};

  if(utile.isArray(argv.f)) {
    file_read_length = argv.f.length;
    temp_filename = path.basename(argv.f[0], path.extname(argv.f[0]))
    for(var i=0; i<file_read_length; i++) readFile(argv.f[i]); // read multiple files
  } else {
    temp_filename = path.basename(argv.f, path.extname(argv.f));
    readFile(argv.f); // read single file input
  }
}

main(); // execute thread
<|endoftext|>