text:
const {expect} = require('chai');
const {importFromFilePath} = require('../../lib/text/import');
const {Namespace, DataElement, Group, Concept, Value, CodeFromValueSetValue, CodeFromAncestorValue, RefValue, OrValues, QuantifiedValue, PrimitiveIdentifier} = require('../../lib/models');

describe('#importFromFilePath()', () => {
  it('should correctly import a simple entry', () => {
    const {namespaces, errors} = importFixture('Simple');
    expect(errors).is.empty;
    const simple = expectAndGetSingleEntry(namespaces, 'shr.test', 'Simple');
    expect(simple.concepts).to.have.length(1);
    expectConcept(simple.concepts[0], 'http://foo.org', 'bar', 'Foobar');
    expect(simple.description).to.equal('It is a simple entry');
    expectPrimitiveValue(simple.value, 'string');
  });

  it('should correctly import a simple element', () => {
    const {namespaces, errors} = importFixture('SimpleElement');
    expect(errors).is.empty;
    const simple = expectAndGetSingleElement(namespaces, 'shr.test', 'Simple');
    expect(simple.concepts).to.have.length(1);
    expectConcept(simple.concepts[0], 'http://foo.org', 'bar');
    expect(simple.description).to.equal('It is a simple element');
    expectPrimitiveValue(simple.value, 'string');
  });

  it('should correctly import a coded entry', () => {
    const {namespaces, errors} = importFixture('Coded');
    expect(errors).is.empty;
    const coded = expectAndGetSingleEntry(namespaces, 'shr.test', 'Coded');
    expect(coded.description).to.equal('It is a coded entry');
    expectCodeValue(coded.value);
  });

  it('should correctly import an entry with a code from a valueset', () => {
    const {namespaces, errors} = importFixture('CodedFromValueSet');
    expect(errors).is.empty;
    const coded = expectAndGetSingleEntry(namespaces, 'shr.test', 'CodedFromValueSet');
    expect(coded.description).to.equal('It is a coded entry');
    expectCodeValue(coded.value, 'http://standardhealthrecord.org/test/vs/Coded');
  });

  it('should correctly import an entry with a code descending from a concept', () => {
    const {namespaces, errors} = importFixture('CodedDescendent');
    expect(errors).is.empty;
    const coded = expectAndGetSingleEntry(namespaces, 'shr.test', 'CodedDescendent');
    expect(coded.description).to.equal('It is a coded entry');
    expectCodeValue(coded.value, 'http://standardhealthrecord.org/test/vs/Coded', 'grandpa', 'Grandfather');
  });

  it('should correctly import a reference to simple element', () => {
    const {namespaces, errors} = importFixture('SimpleReference');
    expect(errors).is.empty;
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');
    const simple = expectAndGetEntry(ns, 0, 'SimpleReference');
    expect(simple.description).to.equal('It is a reference to a simple element');
    expectRefValue(simple.value, 'shr.test', 'Simple');
  });

  it('should correctly import an entry with a list value', () => {
    const {namespaces, errors} = importFixture('MultiString');
    expect(errors).is.empty;
    const simple = expectAndGetSingleEntry(namespaces, 'shr.test', 'MultiString');
    expect(simple.description).to.equal('It is a multi-string entry');
    expectMinMax(simple.value, 1);
    expectPrimitiveValue(simple.value.value, 'string');
  });

  it('should correctly import a choice entry', () => {
    const {namespaces, errors} = importFixtureFolder('choice');
    expect(errors).is.empty;
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');
    const choice = expectAndGetEntry(ns, 0, 'Choice');
    expect(choice.description).to.equal('It is an entry with a choice');
    expectOrValues(choice.value, 3);
    expectOrValue(choice.value, 0, 'primitive', 'date');
    expectOrValue(choice.value, 1, 'other.ns', 'Period');
    expectOrValue(choice.value, 2, 'shr.test', 'Simple');
  });

  it('should correctly import a complex choice entry', () => {
    const {namespaces, errors} = importFixtureFolder('complexChoice');
    expect(errors).is.empty;
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');
    const choice = expectAndGetEntry(ns, 0, 'ComplexChoice');
    expect(choice.description).to.equal('It is an entry with a complex choice');
    const or = choice.value;
    expectOrValues(or, 2);
    const or0 = or.values[0];
    expectMinMax(or0, 1, 2);
    expectOrValues(or0.value, 2);
    expectOrValue(or0.value, 0, 'primitive', 'date');
    expectOrValue(or0.value, 1, 'other.ns', 'Period');
    const or1 = or.values[1];
    expectMinMax(or1, 3, 4);
    expectValue(or1.value, 'shr.test', 'Simple');
  });

  it('should correctly import a group entry', () => {
    const {namespaces, errors} = importFixtureFolder('group');
    expect(errors).is.empty;
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');
    const group = expectAndGetEntry(ns, 0, 'SimpleGroup', Group);
    expect(group.concepts).to.have.length(3);
    expectConcept(group.concepts[0], 'http://foo.org', 'bar');
    expectConcept(group.concepts[1], 'http://boo.org', 'far');
    expectConcept(group.concepts[2], 'http://zoo.org', 'bear');
    expect(group.description).to.equal('It is a group entry');
    expect(group.elements).to.have.length(4);
    expectGroupElement(group, 0, 'shr.test', 'Simple', 0, 1);
    expectGroupElement(group, 1, 'shr.test', 'Coded', 0);
    expectGroupElement(group, 2, 'shr.test', 'Simple2', 1);
    expectGroupElement(group, 3, 'other.ns', 'Thing', 1, 1);
  });

  it('should correctly import a group element', () => {
    const {namespaces, errors} = importFixtureFolder('groupElement');
    expect(errors).is.empty;
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');
    const group = expectAndGetElement(ns, 0, 'SimpleGroup', Group);
    expect(group.concepts).to.have.length(3);
    expectConcept(group.concepts[0], 'http://foo.org', 'bar');
    expectConcept(group.concepts[1], 'http://boo.org', 'far');
    expectConcept(group.concepts[2], 'http://zoo.org', 'bear');
    expect(group.description).to.equal('It is a group element');
    expect(group.elements).to.have.length(4);
    expectGroupElement(group, 0, 'shr.test', 'Simple', 0, 1);
    expectGroupElement(group, 1, 'shr.test', 'Coded', 0);
    expectGroupElement(group, 2, 'shr.test', 'Simple2', 1);
    expectGroupElement(group, 3, 'other.ns', 'Thing', 1, 1);
  });

  it('should correctly import multiple elements in a single namespace', () => {
    const {namespaces, errors} = importFixture('MultipleElementNamespace');
    expect(errors).is.empty;
    expect(namespaces).to.have.length(1);
    const ns = expectAndGetNamespace(namespaces, 0, 'shr.test');

    const simple = expectAndGetEntry(ns, 0, 'SimpleDate');
    expect(simple.description).to.equal('It is a simple date entry');
    expectPrimitiveValue(simple.value, 'date');

    const coded = expectAndGetElement(ns, 1, 'Coded');
    expect(coded.description).to.equal('It is a coded element');
    expectCodeValue(coded.value, 'http://standardhealthrecord.org/test/vs/Coded');
  });

  it('should correctly resolve elements and vocabularies from other namespaces', () => {
    const {namespaces, errors} = importFixtureFolder('uses');
    expect(errors).is.empty;
    expect(namespaces).to.have.length(3);

    const ns1 = expectAndGetNamespace(namespaces, 0, 'shr.test.one');
    expect(ns1.definitions).to.have.length(1);
    const one = expectAndGetEntry(ns1, 0, 'One');
    expect(one.concepts).to.have.length(2);
    expectConcept(one.concepts[0], 'http://foo.org', 'bar');
    expectConcept(one.concepts[1], 'http://moo.org', 'car');
    expect(one.description).to.equal('It is an entry that uses other namespaces');
    expectValue(one.value, 'shr.test.two', 'Two');

    const ns2 = expectAndGetNamespace(namespaces, 1, 'shr.test.two');
    expect(ns2.definitions).to.have.length(1);
    const two = expectAndGetEntry(ns2, 0, 'Two');
    expect(two.concepts).to.have.length(1);
    expectConcept(two.concepts[0], 'http://zoo.org', 'bear');
    expect(two.description).to.equal('It is an entry that uses other namespaces too');
    expectPrimitiveValue(two.value, 'string');

    const ns3 = expectAndGetNamespace(namespaces, 2, 'shr.test.three');
    expect(ns3.definitions).to.have.length(0);
  });

  it('should return errors when there are invalid vocabulary references', () => {
    const {namespaces, errors} = importFixture('InvalidVocabularyReference');
    expect(errors).has.length(1);
    const simple = expectAndGetSingleEntry(namespaces, 'shr.test', 'Simple');
    expect(simple.concepts).to.have.length(1);
    expectConcept(simple.concepts[0], 'ZOO', 'bear'); // Defaults to vocabulary alias
    expect(simple.description).to.equal('It is a simple entry with invalid vocab');
    expectPrimitiveValue(simple.value, 'string');
  });

  it('should return errors when there are invalid element references', () => {
    const {namespaces, errors} = importFixture('InvalidElementReference');
    expect(errors).has.length(1);
    const simple = expectAndGetSingleEntry(namespaces, 'shr.test', 'Simple');
    expect(simple.concepts).to.have.length(1);
    expectConcept(simple.concepts[0], 'http://foo.org', 'bar');
    expect(simple.description).to.equal('It is a simple entry with invalid element reference');
    expectValue(simple.value, 'shr.test', 'Complex'); // Defaults to current namespace
  });

  it('should return errors when there are invalid fully qualified element references', () => {
    const {namespaces, errors} = importFixture('InvalidFQElementReference');
    expect(errors).has.length(1);
    const simple = expectAndGetSingleEntry(namespaces, 'shr.test', 'Simple');
    expect(simple.concepts).to.have.length(1);
    expectConcept(simple.concepts[0], 'http://foo.org', 'bar');
    expect(simple.description).to.equal('It is a simple entry with invalid fully qualified element reference');
    expectValue(simple.value, 'other.ns', 'Complex'); // Defaults to current namespace
  });

  it('should return errors when there are ambiguous element references', () => {
    const {namespaces, errors} = importFixtureFolder('ambiguousResolution');
    expect(errors).has.length(1);
    const ns1 = expectAndGetNamespace(namespaces, 0, 'shr.test.one');
    expect(ns1.definitions).to.have.length(1);
    const amb = expectAndGetEntry(ns1, 0, 'Ambiguous');
    expect(amb.concepts).to.be.empty;
    expect(amb.description).to.equal('It is an entry that uses an ambiguous reference');
    expectValue(amb.value, 'shr.test.two', 'Foo'); // Defaults to first encountered namespace
  });

  it('should return errors when there are conflicting vocab references', () => {
    const {namespaces, errors} = importFixtureFolder('conflictingVocab');
    expect(errors).to.have.length(1);
    expect(errors[0]).to.contain('FOO');
    expect(errors[0]).to.not.contain('MOO');
    expect(namespaces).to.have.length(2);

    const ns1 = expectAndGetNamespace(namespaces, 0, 'shr.test.one');
    expect(ns1.definitions).to.have.length(1);
    const conflicting = expectAndGetEntry(ns1, 0, 'Conflicting');
    expect(conflicting.concepts).to.have.length(2);
    expectConcept(conflicting.concepts[0], 'http://foo.org', 'bar'); // Default to the first encountered vocab
    expectConcept(conflicting.concepts[1], 'http://moo.org', 'car');
    expect(conflicting.description).to.equal('It is an entry that uses a conflicting vocab reference');
    expectPrimitiveValue(conflicting.value, 'string');
  });
});

function expectAndGetNamespace(results, namespaceIndex, expectedNamespace) {
  const ns = results[namespaceIndex];
  expect(ns).to.be.instanceof(Namespace);
  expect(ns.namespace).to.equal(expectedNamespace);
  return ns;
}

function expectAndGetElement(namespace, defIndex, expectedName, expectedClass=DataElement) {
  return expectAndGetBaseElement(namespace, defIndex, expectedName, expectedClass, false);
}

function expectAndGetEntry(namespace, defIndex, expectedName, expectedClass=DataElement) {
  return expectAndGetBaseElement(namespace, defIndex, expectedName, expectedClass, true);
}

function expectAndGetBaseElement(namespace, defIndex, expectedName, expectedClass, isEntry) {
  const def = namespace.definitions[defIndex];
  expect(def).to.be.instanceof(expectedClass);
  expect(def.isEntry).to.equal(isEntry);
  expect(def.identifier.namespace).to.equal(namespace.namespace);
  expect(def.identifier.name).to.equal(expectedName);
  return def;
}

function expectAndGetSingleElement(results, expectedNamespace, expectedName, expectedClass=DataElement) {
  return expectAndGetSingleBaseElement(results, expectedNamespace, expectedName, expectedClass, false);
}

function expectAndGetSingleEntry(results, expectedNamespace, expectedName, expectedClass=DataElement) {
  return expectAndGetSingleBaseElement(results, expectedNamespace, expectedName, expectedClass, true);
}

function expectAndGetSingleBaseElement(results, expectedNamespace, expectedName, expectedClass, isEntry) {
  expect(results).to.have.length(1);
  const ns = expectAndGetNamespace(results, 0, expectedNamespace);
  expect(ns.definitions).to.have.length(1);
  return expectAndGetBaseElement(ns, 0, expectedName, expectedClass, isEntry);
}

function expectValue(value, expectedNamespace, expectedName) {
  expect(value).to.be.instanceof(Value);
  expect(value.identifier.namespace).to.equal(expectedNamespace);
  expect(value.identifier.name).to.equal(expectedName);
}

function expectPrimitiveValue(value, expectedName) {
  expect(value).to.be.instanceof(Value);
  expect(value.identifier).to.be.instanceof(PrimitiveIdentifier);
  expect(value.identifier.namespace).to.equal('primitive');
  expect(value.identifier.name).to.equal(expectedName);
}

function expectCodeValue(value, expectedUrl, expectedAncestor, expectedLabel) {
  if (typeof expectedUrl == 'undefined') {
    expect(value).to.be.instanceof(Value);
    expect(value.valueset).to.be.undefined;
  } else if (typeof expectedAncestor == 'undefined') {
    expect(value).to.be.instanceof(CodeFromValueSetValue);
    expect(value.valueset).to.equal(expectedUrl);
  } else {
    expect(value).to.be.instanceof(CodeFromAncestorValue);
    expectConcept(value.ancestor, expectedUrl, expectedAncestor, expectedLabel);
  }
  expect(value.identifier).to.be.instanceof(PrimitiveIdentifier);
  expect(value.identifier.namespace).to.equal('primitive');
  expect(value.identifier.name).to.equal('code');
}

function expectRefValue(value, expectedNamespace, expectedName) {
  expect(value).to.be.instanceof(RefValue);
  expect(value.identifier.namespace).to.equal(expectedNamespace);
  expect(value.identifier.name).to.equal(expectedName);
}

function expectOrValues(value, size) {
  expect(value).to.be.instanceof(OrValues);
  expect(value.values).to.have.length(size);
}

function expectMinMax(quantifiedValue, expectedMin, expectedMax) {
  expect(quantifiedValue).to.be.instanceof(QuantifiedValue);
  expect(quantifiedValue.min).to.equal(expectedMin);
  if (typeof quantifiedValue.max != 'undefined') {
    expect(quantifiedValue.max).to.equal(expectedMax);
    expect(quantifiedValue.isMaxUnbounded()).to.be.false;
  } else {
    expect(quantifiedValue.max).to.be.undefined;
    expect(quantifiedValue.isMaxUnbounded()).to.be.true;
  }
}

function expectOrValue(or, componentIndex, expectedNamespace, expectedName, expectedMin, expectedMax) {
  let value = or.values[componentIndex];
  if (typeof expectedMin != 'undefined') {
    expectMinMax(value, expectedMin, expectedMax);
    value = value.value;
  }
  expectValue(value, expectedNamespace, expectedName);
}

function expectGroupElement(group, elementIndex, expectedNamespace, expectedName, expectedMin, expectedMax) {
  const element = group.elements[elementIndex];
  expectMinMax(element, expectedMin, expectedMax);
  expectValue(element.value, expectedNamespace, expectedName);
}

function expectConcept(concept, codesystem, code, label) {
  expect(concept.codesystem).equals(codesystem);
  expect(concept.code).equals(code);
  expect(concept.label).equals(label);
}

function importFixture(name) {
  return importFromFilePath(`${__dirname}/fixtures/${name}.txt`);
}

function importFixtureFolder(name) {
  return importFromFilePath(`${__dirname}/fixtures/${name}`);
}


text:
describe Person do
  subject(:person) { Person.new }

  it "says hello" do
    expect(person.greet).to eq("Hello!")
  end
end

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="DaemonCodeAnalyzer">
    <disable_hints />
  </component>
  <component name="EntryPointsManager">
    <entry_points version="2.0" />
  </component>
  <component name="ProjectInspectionProfilesVisibleTreeState">
    <entry key="Project Default">
      <profile-state>
        <expanded-state>
          <State>
            <id />
          </State>
        </expanded-state>
        <selected-state>
          <State>
            <id>Class metrics</id>
          </State>
        </selected-state>
      </profile-state>
    </entry>
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="Android API 21 Platform" project-jdk-type="Android SDK">
    <output url="file://$PROJECT_DIR$/out" />
  </component>
  <component name="RunManager">
    <configuration default="true" type="Remote" factoryName="Remote">
      <option name="USE_SOCKET_TRANSPORT" value="true" />
      <option name="SERVER_MODE" value="false" />
      <option name="SHMEM_ADDRESS" value="javadebug" />
      <option name="HOST" value="localhost" />
      <option name="PORT" value="5005" />
      <method />
    </configuration>
    <configuration default="true" type="Application" factoryName="Application">
      <option name="MAIN_CLASS_NAME" />
      <option name="VM_PARAMETERS" />
      <option name="PROGRAM_PARAMETERS" />
      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" />
      <option name="ENABLE_SWING_INSPECTOR" value="false" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <module name="" />
      <envs />
      <method />
    </configuration>
    <configuration default="true" type="JUnit" factoryName="JUnit">
      <module name="" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" />
      <option name="PACKAGE_NAME" />
      <option name="MAIN_CLASS_NAME" />
      <option name="METHOD_NAME" />
      <option name="TEST_OBJECT" value="class" />
      <option name="VM_PARAMETERS" value="-ea" />
      <option name="PARAMETERS" />
      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <option name="TEST_SEARCH_SCOPE">
        <value defaultName="moduleWithDependencies" />
      </option>
      <envs />
      <patterns />
      <method />
    </configuration>
    <list size="0" />
    <configuration name="<template>" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" default="true" selected="false">
      <option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
    </configuration>
    <configuration name="<template>" type="WebApp" default="true" selected="false">
      <Host>localhost</Host>
      <Port>5050</Port>
    </configuration>
  </component>
  <component name="masterDetails">
    <states>
      <state key="Copyright.UI">
        <settings>
          <last-edited>appPlant License</last-edited>
          <splitter-proportions>
            <option name="proportions">
              <list>
                <option value="0.2" />
              </list>
            </option>
          </splitter-proportions>
        </settings>
      </state>
      <state key="ProjectJDKs.UI">
        <settings>
          <last-edited>Android API 21 Platform</last-edited>
          <splitter-proportions>
            <option name="proportions">
              <list>
                <option value="0.2" />
              </list>
            </option>
          </splitter-proportions>
        </settings>
      </state>
      <state key="ScopeChooserConfigurable.UI">
        <settings>
          <splitter-proportions>
            <option name="proportions">
              <list>
                <option value="0.2" />
              </list>
            </option>
          </splitter-proportions>
        </settings>
      </state>
    </states>
  </component>
</project>


text:
package org.asteriskjava.manager;

import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.util.DaemonThreadFactory;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Proxies a ManagerEventListener and dispatches events asynchronously by using
 * a single threaded executor.

 * Use this proxy to prevent the reader thread from being blocked while your
 * application processes {@link org.asteriskjava.manager.event.ManagerEvent}s.
 * If you want to use the {@link org.asteriskjava.manager.ManagerConnection} for
 * sending actions in your {@link org.asteriskjava.manager.ManagerEventListener}
 * using a proxy like this one is mandatory; otherwise you will always run into
 * a timeout because the reader thread that is supposed to read the response to
 * your action is still blocked processing the event.

 * If in doubt use the proxy as it won't hurt.

 * Example:
 *

 * ManagerConnection connection;
 * ManagerEventListener myListener;
 * ...
 * connection.addEventListener(new ManagerEventListenerProxy(myListener));
 *

 *
 * @author srt
 * @author fink
 * @since 0.3
 */
public class ManagerEventListenerProxy implements ManagerEventListener {
		private final ThreadPoolExecutor executor;
    private final ManagerEventListener target;

    /**
     * Creates a new ManagerEventListenerProxy that notifies the given target
     * asynchronously when new events are received.
     *
     * @param target the target listener to invoke.
     * @see Executors#newSingleThreadExecutor(ThreadFactory)
     */
    public ManagerEventListenerProxy(ManagerEventListener target) {
	    executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory());
	    this.target = target;
	    if (target == null) {
		    throw new NullPointerException("ManagerEventListener target is null!");
	    }
    }//new

    @Override public void onManagerEvent(final ManagerEvent event) {
			executor.execute(new Runnable() {
					@Override public void run() {
							target.onManagerEvent(event);
					}
			});
    }//onManagerEvent

    public void shutdown() {
        executor.shutdown();
    }

		public static class Access {
			public static int getThreadQueueSize (ManagerEventListenerProxy proxy) {
				return proxy.executor.getQueue().size();
			}
		}//Access
}


text:
import lrparsing
from lrparsing import Keyword, List, Prio, Ref, Token, Opt
from arithmeticExpressions import ALitteral, Addition, Subtraction, Product, Division, EuclideanDivision, Modulo, \
    Power, Func, UndefinedLitteral, Min, Max, globalsHeightExpression, globalsWidthExpression, globalsFpsExpression
from triggerExpressions import BLitteral, Timer, eLock, \
    Equals, GreaterThan, LowerThan, GeqThan, LeqThan, \
    NotEquals, And, Or, Not, Is, AnyEval, RandomEval, Del, \
    SelectMinEval, SelectMaxEval, UniqueEval, PropertyTriggerExpression, \
    EventTriggerExpression, SpriteTriggerExpression, TextTriggerExpression, \
    LineTriggerExpression, OvalTriggerExpression, RectTriggerExpression, PolygonTriggerExpression
from database import Variable
from keywords import KEYWORD_ID, KEYWORD_FILENAME, KEYWORD_COLOR, KEYWORD_FONT_NAME, KEYWORD_FONT_SIZE, KEYWORD_H, \
    KEYWORD_TEXT, KEYWORD_WIDTH, KEYWORD_W, KEYWORD_X_INT, KEYWORD_X, KEYWORD_Y_INT, KEYWORD_Y, KEYWORD_Z, \
    KEYWORD_ROTATE, KEYWORD_SCALE
from utils.mathutils import sign
from random import random, randint
from math import cos, sin, tan, exp, log, floor, ceil, acos, asin, atan, cosh, sinh, tanh, acosh, atanh, asinh

class TriggerParser(lrparsing.Grammar):
    class T(lrparsing.TokenRegistry):
        integer = Token(re='[0-9]+')
        float = Token(re='[0-9]+\.[0-9]+')
        string = Token(re='\'[^\']*\'')
        true = Token('true')
        false = Token('false')

        variable = Token(re='[A-Z][A-Z_0-9]*')
        uvariable = Token('_')

        prop = Token(re='p[A-Z][A-Za-z_0-9]*')
        event = Token(re='e[A-Z][A-Za-z_0-9]*')
        graphicsSprite = Token(re='gs[A-Z][A-Za-z_0-9]*')
        graphicsLine = Token(re='gl[A-Z][A-Za-z_0-9]*')
        graphicsOval = Token(re='go[A-Z][A-Za-z_0-9]*')
        graphicsRect = Token(re='gr[A-Z][A-Za-z_0-9]*')
        graphicsPolygon = Token(re='gp[A-Z][A-Za-z_0-9]*')
        graphicsText = Token(re='gt[A-Z][A-Za-z_0-9]*')

        idkw = Token('id')

        coordX = Token('x')
        coordY = Token('y')
        coordZ = Token('z')
        coordXInt = Token(re='x[1-9][0-9]*')
        coordYInt = Token(re='y[1-9][0-9]*')
        coordW = Token('w')
        coordH = Token('h')
        rotate = Token('rotate')
        scale = Token('scale')

        fileName = Token('fileName')
        color = Token('color')
        width = Token('width')
        text = Token('text')
        fontName = Token('fontName')
        fontSize = Token('fontSize')

        cosf = Token('cos')
        sinf = Token('sin')
        tanf = Token('tan')
        expf = Token('exp')
        logf = Token('log')
        absf = Token('abs')
        signf = Token('sign')
        floorf = Token('floor')
        ceilf = Token('ceil')
        roundf = Token('round')
        acosf = Token('acos')
        asinf = Token('asin')
        atanf = Token('atan')
        chf = Token('ch')
        shf = Token('sh')
        thf = Token('th')
        achf = Token('ach')
        ashf = Token('ash')
        athf = Token('ath')
        rand = Token('rand')
        randint = Token('randint')

        lenf = Token('len')
        minf = Token('min')
        maxf = Token('max')

        globalsKw = Token('globals')
        globalsFpsKw = Token('fps')
        globalsHeightKw = Token('screenHeight')
        globalsWidthKw = Token('screenWidth')

        elock = Keyword('eLock')
        timer = Token('timer')
        iskw = Token('is')
        delkw = Token('del')
        andkw = Token('and')
        orkw = Token('or')
        notkw = Token('not')

        anyEval = Token('anyEval')
        randomEval = Token('randomEval')
        minEvalKw = Token('minEval')
        maxEvalKw = Token('maxEval')
        uniqueEval = Token('uniqueEval')

    arithmExpr = Ref('arithmExpr')
    boolExpr = Ref('boolExpr')

    litExpr = T.true | T.false

    timerExpr = T.timer + '(' + arithmExpr + ')'

    eLockParameters = List(arithmExpr, Token(','), min=1)
    eLockExpr = T.elock + '(' + arithmExpr + Opt(',' + eLockParameters) + ')'

    parameter = Prio(T.variable, arithmExpr) | T.uvariable

    namedParameterKW = arithmExpr | T.idkw | \
                       T.coordX | T.coordY | T.coordZ | \
                       T.coordXInt | T.coordYInt | \
                       T.coordH | T.coordW | \
                       T.rotate | T.scale | \
                       T.fileName | \
                       T.color | T.width | \
                       T.text | T.fontName | T.fontSize
    namedParameter = namedParameterKW + '=' + parameter
    parameters = \
        Prio(List(parameter, Token(',')) + Opt(',' + List(namedParameter, Token(','))),
             List(namedParameter, Token(',')))

    parameterizedType = T.prop | T.event | T.graphicsSprite | T.graphicsText | T.graphicsLine | \
                        T.graphicsOval | T.graphicsRect | T.graphicsPolygon
    parameterizedExpr = parameterizedType + '(' + parameters + ')'

    compareArithmExpr = arithmExpr << (Token('==') | Token('>') | Token('<') | Token('<=') |
                                       Token('>=') | Token('!=')) << arithmExpr

    andExpr = boolExpr >> T.andkw >> boolExpr
    orExpr = boolExpr >> T.orkw >> boolExpr
    notExpr = T.notkw + boolExpr
    isExpr = T.variable + T.iskw + arithmExpr
    delExpr = T.delkw + T.variable

    parExpr = '(' + boolExpr + ')'

    anyEvalExpr = T.anyEval + parExpr
    randomEvalExpr = T.randomEval + parExpr
    minEvalExpr = T.minEvalKw + '[' + arithmExpr + ']' + parExpr
    maxEvalExpr = T.maxEvalKw + '[' + arithmExpr + ']' + parExpr
    uniqueEvalExpr = T.uniqueEval + parExpr

    boolExpr = Prio(litExpr,
                    timerExpr,
                    eLockExpr,
                    parameterizedExpr,
                    parExpr,
                    isExpr,
                    delExpr,
                    compareArithmExpr,
                    notExpr,
                    andExpr,
                    orExpr,
                    anyEvalExpr,
                    randomEvalExpr,
                    minEvalExpr,
                    maxEvalExpr,
                    uniqueEvalExpr
                    )

    addArithmExpr = arithmExpr << Token('+') << arithmExpr
    minusArithmExpr = Opt(arithmExpr) << Token('-') << arithmExpr
    multArithmExpr = arithmExpr << (Token('*') | Token('/') | Token('//') | Token('%')) << arithmExpr
    powerArithmExpr = arithmExpr << Token('**') << arithmExpr
    constantArithmExpr = Token('pi') | Token('e')

    parArithmExpr = '(' + arithmExpr + ')'

    unaryFuncArithmExpr = (T.cosf | T.sinf | T.tanf | T.expf | T.logf | T.absf | T.signf | T.floorf | T.ceilf | T.roundf
                           | T.acosf | T.asinf | T.atanf | T.shf | T.chf | T.thf | T.ashf | T.achf | T.athf | T.lenf
                           | T.rand | T.randint) \
                           + parArithmExpr
    binaryFuncArithmExpr = (T.minf | T.maxf) + '(' + arithmExpr + ',' + arithmExpr + ')'

    globalsKeyWord = T.globalsFpsKw | T.globalsHeightKw | T.globalsWidthKw
    globalsExpr = T.globalsKw + '(' + globalsKeyWord + ')'

    arithmExpr = Prio(T.integer, T.float, T.variable, T.string, constantArithmExpr,
                      globalsExpr, parArithmExpr,
                      unaryFuncArithmExpr, binaryFuncArithmExpr,
                      powerArithmExpr, multArithmExpr, minusArithmExpr, addArithmExpr)

    START = boolExpr
    COMMENTS = (                      # Allow C and Python comments
        Token(re="#(?:[^\r\n]*(?:\r\n?|\n\r?))") |
        Token(re="/[*](?:[^*]|[*][^/])*[*]/"))

    @classmethod
    def parse(cls, expr, tree_factory=None, on_error=None, log=None):
        tree = super(TriggerParser, cls).parse(expr, tree_factory, on_error, log)
        return cls.buildExpression(tree)

    @classmethod
    def buildExpression(cls, tree):
        rootName = tree[0]

        def buildAnd():
            a1 = cls.buildExpression((tree[1]))
            a2 = cls.buildExpression((tree[3]))
            return And(a1, a2)

        def buildAnyEval():
            expr = cls.buildExpression(tree[2])
            return AnyEval(expr)

        def buildArithmetic():
            return cls.buildArithmeticExpression(tree)

        def buildCompare():
            a1 = cls.buildExpression(tree[1])
            a2 = cls.buildExpression(tree[3])
            if tree[2][1] == '==':
                return Equals(a1, a2)
            elif tree[2][1] == '>':
                return GreaterThan(a1, a2)
            elif tree[2][1] == '<':
                return LowerThan(a1, a2)
            elif tree[2][1] == '>=':
                return GeqThan(a1, a2)
            elif tree[2][1] == '<=':
                return LeqThan(a1, a2)
            elif tree[2][1] == '!=':
                return NotEquals(a1, a2)

        def buildDel():
            variable = cls.buildExpression(tree[2])
            return Del(variable)

        def buildDoubleNext():
            return cls.buildExpression(tree[2])

        def buildElock():
            priority = cls.buildExpression(tree[3])
            if len(tree) >= 6:
                args = cls.buildExpression(tree[5])
            else:
                args = []
            return eLock(priority, args)

        def buildELockParameters():
            return [cls.buildExpression(arg) for arg in tree[1::2]]

        def buildIs():
            variable = cls.buildExpression(tree[1])
            function = cls.buildExpression(tree[3])
            return Is(variable, function)

        def buildLitteral():
            return BLitteral(tree[1][1] == 'true')

        def buildMaxEvalExpr():
            arithmExpr = cls.buildExpression(tree[3])
            expr = cls.buildExpression(tree[5])
            return SelectMaxEval(expr, arithmExpr)

        def buildMinEvalExpr():
            arithmExpr = cls.buildExpression(tree[3])
            expr = cls.buildExpression(tree[5])
            return SelectMinEval(expr, arithmExpr)

        def buildNamedParameter():
            name = cls.buildExpression(tree[1])
            parameter = cls.buildExpression(tree[3])
            return name, parameter

        def buildNext():
            return cls.buildExpression(tree[1])

        def buildNot():
            a1 = cls.buildExpression((tree[2]))
            return Not(a1)

        def buildOr():
            a1 = cls.buildExpression((tree[1]))
            a2 = cls.buildExpression((tree[3]))
            return Or(a1, a2)

        def buildParameterized():
            exprType, exprValue = cls.buildExpression(tree[1])

            exprTypeAction = {
                TriggerParser.T.prop: (PropertyTriggerExpression, 1),
                TriggerParser.T.event: (EventTriggerExpression, 1),
                TriggerParser.T.graphicsSprite: (SpriteTriggerExpression, 2),
                TriggerParser.T.graphicsLine: (LineTriggerExpression, 2),
                TriggerParser.T.graphicsOval: (OvalTriggerExpression, 2),
                TriggerParser.T.graphicsRect: (RectTriggerExpression, 2),
                TriggerParser.T.graphicsPolygon: (PolygonTriggerExpression, 2),
                TriggerParser.T.graphicsText: (TextTriggerExpression, 2)
            }

            clsCons, offset = exprTypeAction[exprType]
            args, kwargs = cls.buildExpression(tree[3])

            if offset > 0:
                name = exprValue[offset:]
                return clsCons(name, args, kwargs)
            else:
                return clsCons(args, kwargs)

        def buildParameterizedType():
            return tree[1][0], tree[1][1]

        def buildParameters():
            buildArgs = [cls.buildExpression(arg) for arg in tree[1::2]]
            args = [arg for arg in buildArgs if not isinstance(arg, tuple)]
            kwargs = {kwarg[0]: kwarg[1] for kwarg in buildArgs if isinstance(kwarg, tuple)}
            return args, kwargs

        def buildRandomEval():
            expr = cls.buildExpression(tree[2])
            return RandomEval(expr)

        def buildTimer():
            nbFrames = cls.buildExpression((tree[3]))
            return Timer(nbFrames)

        def buildUniqueEvalExpr():
            expr = cls.buildExpression(tree[2])
            return UniqueEval(expr)

        def keywordColorValue():
            return KEYWORD_COLOR

        def keywordFileNameValue():
            return KEYWORD_FILENAME

        def keywordFontNameValue():
            return KEYWORD_FONT_NAME

        def keywordFontSizeValue():
            return KEYWORD_FONT_SIZE

        def keywordHValue():
            return KEYWORD_H

        def keywordIdValue():
            return KEYWORD_ID

        def keywordRotateValue():
            return KEYWORD_ROTATE

        def keywordScaleValue():
            return KEYWORD_SCALE

        def keywordTextValue():
            return KEYWORD_TEXT

        def keywordWidthValue():
            return KEYWORD_WIDTH

        def keywordWValue():
            return KEYWORD_W

        def keywordXIntValue():
            value = int(tree[1][1:])
            return KEYWORD_X_INT[value]

        def keywordXValue():
            return KEYWORD_X

        def keywordYIntValue():
            value = int(tree[1][1:])
            return KEYWORD_Y_INT[value]

        def keywordYValue():
            return KEYWORD_Y

        def keywordZValue():
            return KEYWORD_Z

        def unnamedVariableValue():
            return UndefinedLitteral()

        def value():
            return tree[1]

        def variableValue():
            return Variable(tree[1])

        booleanSymbols = {
            TriggerParser.T.variable: variableValue,
            TriggerParser.T.uvariable: unnamedVariableValue,

            TriggerParser.T.idkw: keywordIdValue,

            TriggerParser.T.coordX: keywordXValue,
            TriggerParser.T.coordY: keywordYValue,
            TriggerParser.T.coordZ: keywordZValue,
            TriggerParser.T.coordXInt: keywordXIntValue,
            TriggerParser.T.coordYInt: keywordYIntValue,
            TriggerParser.T.coordW: keywordWValue,
            TriggerParser.T.coordH: keywordHValue,
            TriggerParser.T.rotate: keywordRotateValue,
            TriggerParser.T.scale: keywordScaleValue,

            TriggerParser.T.fileName: keywordFileNameValue,
            TriggerParser.T.color: keywordColorValue,
            TriggerParser.T.width: keywordWidthValue,
            TriggerParser.T.text: keywordTextValue,
            TriggerParser.T.fontName: keywordFontNameValue,
            TriggerParser.T.fontSize: keywordFontSizeValue,

            TriggerParser.arithmExpr: buildArithmetic,

            TriggerParser.boolExpr: buildNext,
            TriggerParser.litExpr: buildLitteral,
            TriggerParser.timerExpr: buildTimer,

            TriggerParser.eLockParameters: buildELockParameters,
            TriggerParser.eLockExpr: buildElock,

            TriggerParser.parameter: buildNext,
            TriggerParser.namedParameterKW: buildNext,
            TriggerParser.namedParameter: buildNamedParameter,
            TriggerParser.parameters: buildParameters,
            TriggerParser.parameterizedType: buildParameterizedType,

            TriggerParser.parameterizedExpr: buildParameterized,

            TriggerParser.compareArithmExpr: buildCompare,
            TriggerParser.andExpr: buildAnd,
            TriggerParser.orExpr: buildOr,
            TriggerParser.notExpr: buildNot,
            TriggerParser.isExpr: buildIs,
            TriggerParser.delExpr: buildDel,

            TriggerParser.parExpr: buildDoubleNext,

            TriggerParser.anyEvalExpr: buildAnyEval,
            TriggerParser.randomEvalExpr: buildRandomEval,
            TriggerParser.minEvalExpr: buildMinEvalExpr,
            TriggerParser.maxEvalExpr: buildMaxEvalExpr,
            TriggerParser.uniqueEvalExpr: buildUniqueEvalExpr,

            TriggerParser.parArithmExpr: buildArithmetic,

            TriggerParser.START: buildNext,

        }

        return booleanSymbols[rootName]()

    @classmethod
    def buildArithmeticExpression(cls, tree):
        rootName = tree[0]

        def buildBinaryExpression():
            a1 = cls.buildArithmeticExpression(tree[1])
            a3 = cls.buildArithmeticExpression(tree[3])
            if tree[2][1] == '+':
                return Addition(a1, a3)
            elif tree[2][1] == '-':
                return Subtraction(a1, a3)
            elif tree[2][1] == '*':
                return Product(a1, a3)
            elif tree[2][1] == '/':
                return Division(a1, a3)
            elif tree[2][1] == '//':
                return EuclideanDivision(a1, a3)
            elif tree[2][1] == '%':
                return Modulo(a1, a3)
            elif tree[2][1] == '**':
                return Power(a1, a3)

        def buildBinaryFunctionExpression():
            x1 = cls.buildArithmeticExpression(tree[3])
            x2 = cls.buildArithmeticExpression(tree[5])
            if tree[1][1] == 'min':
                return Min(x1, x2)
            elif tree[1][1] == 'max':
                return Max(x1, x2)

        def buildConstant():
            from math import pi, e
            if tree[1][1] == 'pi':
                value = pi
            else:
                value = e
            return ALitteral(value)

        def buildGlobalFpsKeyWord():
            return globalsFpsExpression

        def buildGlobalWidthKeyWord():
            return globalsWidthExpression

        def buildGlobalHeightKeyWord():
            return globalsHeightExpression

        def buildMinusExpression():
            if len(tree) == 4:
                return buildBinaryExpression()
            else:
                a1 = cls.buildArithmeticExpression(tree[2])
                return Subtraction(ALitteral(0), a1)

        def buildNext(i):
            def _buildNext():
                return cls.buildArithmeticExpression(tree[i])
            return _buildNext

        def buildUnaryFunctionExpression():
            a = cls.buildArithmeticExpression(tree[2])
            if tree[1][1] == 'cos':
                return Func(a, cos)
            elif tree[1][1] == 'sin':
                return Func(a, sin)
            elif tree[1][1] == 'tan':
                return Func(a, tan)
            elif tree[1][1] == 'acos':
                return Func(a, acos)
            elif tree[1][1] == 'asin':
                return Func(a, asin)
            elif tree[1][1] == 'atan':
                return Func(a, atan)
            elif tree[1][1] == 'ch':
                return Func(a, cosh)
            elif tree[1][1] == 'sh':
                return Func(a, sinh)
            elif tree[1][1] == 'th':
                return Func(a, tanh)
            elif tree[1][1] == 'ash':
                return Func(a, acosh)
            elif tree[1][1] == 'ash':
                return Func(a, asinh)
            elif tree[1][1] == 'ath':
                return Func(a, atanh)
            elif tree[1][1] == 'exp':
                return Func(a, exp)
            elif tree[1][1] == 'log':
                return Func(a, log)
            elif tree[1][1] == 'abs':
                return Func(a, abs)
            elif tree[1][1] == 'sign':
                return Func(a, sign)
            elif tree[1][1] == 'ceil':
                return Func(a, ceil)
            elif tree[1][1] == 'floor':
                return Func(a, floor)
            elif tree[1][1] == 'round':
                return Func(a, round)
            elif tree[1][1] == 'len':
                return Func(a, len)
            elif tree[1][1] == 'rand':
                def _random(x):
                    return random() * x
                return Func(a, _random)
            elif tree[1][1] == 'randint':
                def _randint(x):
                    return randint(0, x - 1)
                return Func(a, _randint)

        def intvalue():
            return ALitteral(int(tree[1]))

        def floatvalue():
            return ALitteral(float(tree[1]))

        def stringWithoutQuotes():
            return ALitteral(tree[1][1:-1])

        def variableValue():
            return ALitteral(Variable(tree[1]))

        arithmeticSymbols = {
            TriggerParser.T.integer: intvalue,
            TriggerParser.T.float: floatvalue,
            TriggerParser.T.string: stringWithoutQuotes,
            TriggerParser.T.variable: variableValue,

            TriggerParser.T.globalsFpsKw: buildGlobalFpsKeyWord,
            TriggerParser.T.globalsHeightKw: buildGlobalHeightKeyWord,
            TriggerParser.T.globalsWidthKw: buildGlobalWidthKeyWord,

            TriggerParser.arithmExpr: buildNext(1),
            TriggerParser.addArithmExpr: buildBinaryExpression,
            TriggerParser.minusArithmExpr: buildMinusExpression,
            TriggerParser.multArithmExpr: buildBinaryExpression,
            TriggerParser.powerArithmExpr: buildBinaryExpression,
            TriggerParser.constantArithmExpr: buildConstant,
            TriggerParser.parArithmExpr: buildNext(2),
            TriggerParser.unaryFuncArithmExpr: buildUnaryFunctionExpression,
            TriggerParser.binaryFuncArithmExpr: buildBinaryFunctionExpression,
            TriggerParser.globalsKeyWord: buildNext(1),
            TriggerParser.globalsExpr: buildNext(3)
        }

        return arithmeticSymbols[rootName]()

if __name__ == '__main__':
    # print BooleanExpressionParser.pre_compile_grammar()

    # from database import Property
    # from triggerExpressions import BExpression
    #
    # Property.add('Test', [1, 2], {})
    # Property.add('Test', [1, 3], {})
    # Property.add('Test', [2, 4], {})
    # Property.add('Test', [1, 5], {})
    #
    # expr = 'pTest(X,Y)'
    # expr = BExpression(TriggerParser.parse(expr))
    # print expr
    # for evaluation in expr.eval(None):
    #     print evaluation
    #
    # print
    #
    # expr = 'anyEval(pTest(X,Y))'
    # expr = BExpression(TriggerParser.parse(expr))
    # print expr
    # for evaluation in expr.eval(None):
    #     print evaluation
    #
    # print
    #
    # expr = 'randomEval(pTest(X,Y))'
    # expr = BExpression(TriggerParser.parse(expr))
    # print expr
    # for evaluation in expr.eval(None):
    #     print evaluation
    #
    # print
    #
    # expr = 'minEval(pTest(X,Y) or Z is 3 and X is 2 or Z is 2 and X is 1)[X + Z]'
    # expr = BExpression(TriggerParser.parse(expr))
    # print expr
    # for evaluation in expr.eval(None):
    #     print evaluation
    #
    # print
    #
    # expr = 'maxEval(pTest(X,Y) or Z is 8 and X is 2 or Z is 2 and X is 1)[X + Y]'
    # expr = BExpression(TriggerParser.parse(expr))
    # print expr
    # for evaluation in expr.eval(None):
    #     print evaluation

    from database import Property
    from triggerExpressions import BExpression

    expr = '(A + B ** 2) != (A + B ** 2)'
    expr = BExpression(TriggerParser.parse(expr))
    print expr


text:
import { pull } from "lodash";
export = pull;


text: dml xworker.tools.GenerateXsd run %1 %2


text:
package graphTheory.algorithms.steinerProblems.eolienneApproximationAlgorithms;

import graphTheory.algorithms.steinerProblems.steinerArborescenceApproximation.SteinerArborescenceApproximationAlgorithm;
import graphTheory.graph.Arc;
import graphTheory.utils.*;

import java.util.*;

/**
 *
 * Implementation of the G_F algorithm.
 *

 * This algorithm returns a feasible solution for the Directed Steiner Tree
 * problem. It is a greedy algorihm which uses a sub-algorihthm named FLAC.
 *

 * FLAC is designed to returns a feasible solution for the minimum Density
 * Directed Steiner Tree problem: it searches for a tree rooted in the root of
 * the instance which spans a part of the terminal. It try to minimize the total
 * cost of the tree divided by the number of terminals.
 *

 * Gf uses FLAC to span some terminals, delete those terminals, and repeat FLAC
 * to span other terminals. It continues until all the terminals are reached.
 *

 * To span the terminals, FLAC grows a flow from the terminals: we call them
 * sources. That flow is send through the entering arcs, with a flow rate equals
 * to 1 L/s, considering the volume of an arc is its weight. Then, when an arc
 * is full (we say saturated), the source feeds its entering arcs. If two
 * sources reach the same arc with a path of saturated arcs, the flow rate is 2
 * L/s. And if more sources reaches the arc, the flow rate increases again: the
 * flow rate inside an arc is equals to the number of sources it can reach with
 * paths of saturated arcs
 *

 * FLAC continue until the root is reached, and we return the set of saturated
 * arcs linked to the root. As we want to return a tree, each time an arc is
 * saturated, if a node is connected to the same source with two paths of
 * saturated arcs, we delete that last saturated arc.
 *

 *
 *
 *
 * @author Watel Dimitri
 *
 */
public class GFLAC2EolienneAlgorithm extends EolienneApproximationAlgorithm {

	// --------------------   Directed Steiner Tree Part --------------------//

	/**
	 * Copy of the costs of the instance. It let the algorithm modify the costs
	 * withouth modifying the instance it self.
	 */
	private HashMap<Arc, Integer> costs;

	/**
	 * Copy of the required vertices of the instance. It let the algorithm
	 * modify this set without modifiying the instance.
	 */
	private HashSet<Integer> requiredVertices;

	private HashMap<Arc, Integer> leftCapacities;

	/**
	 * For each node, this map sorts its input arcs by cost.
	 */
	private HashMap<Integer, TreeSet<Arc>> sortedInputArcs;

	/**
	 * A comparator used to sort arcs by costs.
	 */
	private Comparator<Arc> comp;

	@Override
	protected void computeWithoutTime() {

		// Copy the required vertices
		requiredVertices = new HashSet<Integer>(instance.getRequiredVertices());
		// Remove the root, if it is a terminal, otherwise, this algorithm could start
		// a infinite loop
		requiredVertices.remove(instance.getRoot());

		// This set will merge the trees returned by FLAC
		HashSet<Arc> currentSol = new HashSet<Arc>();

		this.costs = instance.getCosts();
		comp = getArcsComparator();

		sortedInputArcs = new HashMap<Integer, TreeSet<Arc>>();

		leftCapacities = this.getInstance().getCapacities();

		// Initialize parameters
		this.init();

		// Until all the terminals are reached

		while (requiredVertices.size() > 0) {
			Triplet<HashSet<Arc>, HashSet<Integer>, HashSet<Integer>> result = applyFLAC(); // Search a low Density Directed Steiner Tree with the FLAC algorithm

			if (result == null) {
				this.arborescence = null;
				this.cost = null;
				return;
			}

			// This is the tree returned by FLAC
			HashSet<Arc> tbest = result.first;

			// Those are the terminals reached by the previous tree
			HashSet<Integer> reachedNodes = result.second;

			HashSet<Integer> reachedTerminals = result.third;

			/*
			 * For each arc in the tree set the cost of that arc to 0 As a
			 * consequence, the next tree returned by FLAC is preferentially
			 * merged by the current partial solution. In addition, this loop
			 * add the arc to the current partial solution.
			 */

			currentSol.addAll(tbest);
			requiredVertices.removeAll(reachedTerminals); // Remove the reached terminals from the required vertices of the instance
		}

		// Set the output of this algorithm : the returned tree and its cost

		arborescence = currentSol;
		int c = 0;
		if (arborescence != null)
			for (Arc a : arborescence)
				c += instance.getCost(a);

		cost = c;
	}

	private Comparator<Arc> getArcsComparator() {
		return new Comparator<Arc>() {

			@Override
			public int compare(Arc o1, Arc o2) {
				if (o1 == null)
					return 1;
				else if (o2 == null)
					return -1;
				else if (o1.equals(o2))
					return 0;
				else {
					Integer i1 = costs.get(o1);
					Integer i2 = costs.get(o2);
					int comp = i1.compareTo(i2);
					if (comp != 0)
						return comp;
					comp = o1.getInput().compareTo(o2.getInput());
					if (comp != 0)
						return comp;
					return o1.getOutput().compareTo(o2.getOutput());
				}
			}
		};
	}

	private TreeSet<Arc> getSortedInputArcs(Integer v){
		TreeSet<Arc> tree = sortedInputArcs.get(v);
		if(tree == null)
			tree = sortInputArcs(v);
		return tree;
	}

	/**
	 * Sort the input arcs of v by cost
	 *
	 * @param v
	 */
	private TreeSet<Arc> sortInputArcs(Integer v) {
		Iterator<Arc> it = instance.getGraph().getInputArcsIterator(v);

		TreeSet<Arc> ts = new TreeSet<Arc>(comp);
		while (it.hasNext()) {
			ts.add(it.next());
		}

		sortedInputArcs.put(v, ts);
		return ts;
	}

	// ---------- density Directed Steiner Tree part ---------

	/**
	 * @return a tree rooted in the root of the instance spanning a part of the
	 *         terminals, and the set of those terminals.
	 */
	private Triplet<HashSet<Arc>, HashSet<Integer>, HashSet<Integer>> applyFLAC() {

		// Reinitialize the parameters to let FLAC restart normally
		reinit();
		while (true) {

			// Check which arc will be the next saturated one
			Arc a = nextSaturatedArc();
            if(a == null)
                return null;
			System.out.println(a);

			Integer u = a.getInput();
			Integer v = a.getOutput();

			// If the root is reached by the terminals, we can return a tree
			if (u.equals(instance.getRoot())) {
				saturated.add(a);
				return buildTree(u);
			}

			// We now check if a node is linked to the root with two paths of saturated arcs: it is called a conflict
			boolean conflict = findConflict(u, v);
            System.out.println(conflict);

			// Whatever the case, we have to check which arc of v will be its next saturated entering arc, and when
			// it will be saturated
			updateNextSaturatedArc(v);

			// If there is a conflict, we just ignore the arc saturation, as if it was never added to the arc
			if (!conflict)
				// If there is no conflict, we have to update the flow rate of other arcs as a new arc is
				// saturated.
				saturateArcAndUpdate(a);
		}
	}

	/**
	 * Set of saturated arcs (ie full of fluid)
	 */
	private HashSet<Arc> saturated;

	/**
	 * For each node, this map saves the sources this node is linked to with a
	 * path of saturated arcs
	 */
	private HashMap<Integer, Integer> flowRates;

	/**
	 * Set of nodes for which one entering arc is saturating. The key of each
	 * node in the Fibonacci Heap is the physical time when its next saturating
	 * arc will be saturated.
	 */
	private CustomFibonacciHeap<Integer, DoubleBoolean> sortedSaturating;

	/**
	 * Set of nodes associated with the next saturated entering arc of this
	 * node.
	 */
	private HashMap<Integer, Iterator<Arc>> nextSaturatedEnteringArcIterators;

	/**
	 * Set of nodes associated with the next saturated entering arc of this
	 * node.
	 */
	private HashMap<Integer, Arc> nextSaturatedEnteringArcs;

	/**
	 * The actual physical time since the beginning of saturation
	 */
	private double time;

	/**
	 * This maps each node to the node of the fibonacci heap containing it.
	 */
	private HashMap<Integer, CustomFibonacciHeapNode<Integer, DoubleBoolean>> n2fbn;

	private WeightedQuickUnionPathCompressionUF unionFind;

	/**
	 * Initialize the maps, sets and lists used by the algorithm FLAC
	 */
	private void init() {
		saturated = new HashSet<Arc>();
		flowRates = new HashMap<Integer, Integer>();
		sortedSaturating = new CustomFibonacciHeap<Integer, DoubleBoolean>();
		nextSaturatedEnteringArcIterators = new HashMap<Integer, Iterator<Arc>>();
		nextSaturatedEnteringArcs = new HashMap<Integer, Arc>();
		n2fbn = new HashMap<Integer, CustomFibonacciHeapNode<Integer, DoubleBoolean>>();
		unionFind = new WeightedQuickUnionPathCompressionUF(instance.getGraph().getNumberOfVertices());
	}

	/**
	 * Clear the maps, sets and lists used by the algorithm FLAC. Reinitialize
	 * the parameters used by FLAC.
	 */
	private void reinit() {
		saturated.clear();
		flowRates.clear();
		sortedSaturating.clear();
		nextSaturatedEnteringArcIterators.clear();
		nextSaturatedEnteringArcs.clear();
		n2fbn.clear();
		unionFind.reinit();

		// The saturation begin at 0 seconds
		time = 0D;

		// Init parameters for each terminal
		Iterator<Integer> it = instance.getGraph().getVerticesIterator();
		while (it.hasNext()) {
			Integer v = it.next();
			if (requiredVertices.contains(v)) {

				// define the sources feeding that terminal as the terminal itself
				setFlowRate(v, 1);

				// define the next saturated arc entering v, and compute the time
				// in seconds needed to saturate it.
				updateNextSaturatedArc(v);
			}
		}
	}

	/**
	 * Assuming an entering arc of v is saturated, the next one is the next in
	 * the list of entering arcs of v sorted by weigths.

	 * This method find this arc and compute when it will be saturated
	 *
	 * @param v
	 */
	private void updateNextSaturatedArc(Integer v) {

		// Iterator over the entering arcs of v sorted by weights
		Iterator<Arc> it = nextSaturatedEnteringArcIterators.get(v);

		if (it == null) {
			// Init the iterator, if it was not the case
			it = getSortedInputArcs(v).iterator();
			nextSaturatedEnteringArcIterators.put(v, it);
		}

		// Last saturated arc entering v
		Arc b = nextSaturatedEnteringArc(v);

		// Next saturated arc entering v
		Arc a = null;
		if (it.hasNext()) {
			// If b was not the arc entering v with biggest cost
			// a exists
			a = it.next();
			nextSaturatedEnteringArcs.put(v, a);
		} else {
			// Else, all arcs entering v are already saturated
			nextSaturatedEnteringArcs.remove(v);
			n2fbn.remove(v);
			return;
		}

		// Saturated time of a
		Double satTime;

		if (b == null)
			// No arc entering v start to saturate
			satTime = getVolume(a) / ((double)getFlowRate(v));
		else
			// All arc entering v start to saturate, including a
			satTime = (getVolume(a) - getVolume(b)) / ((double)getFlowRate(v));

		// Reinsert v in the list with the saturated time of a
		CustomFibonacciHeapNode<Integer, DoubleBoolean> fbn = sortedSaturating
				.insert(v, new DoubleBoolean(time + satTime, !a.getInput()
						.equals(instance.getRoot())));
		n2fbn.put(v, fbn);

	}

	/**
	 * @param v
	 * @return the next saturated time entering v
	 */
	private Arc nextSaturatedEnteringArc(Integer v) {
		return nextSaturatedEnteringArcs.get(v);
	}

	/**
	 *
	 * @return the next saturated time entering the first node if the fibonnacci
	 *         heap
	 */
	private Arc nextSaturatedArc() {
		CustomFibonacciHeapNode<Integer, DoubleBoolean> fbn = sortedSaturating
				.removeMin();
        if(fbn == null)
            return null;
		time = fbn.getKey().getDoubleValue();
		return nextSaturatedEnteringArc(fbn.getData());
	}

	/**
	 *
	 * @param u
	 * @param v
	 * @return true if the saturation of arc (u,v) implies a conflict
	 */
	private boolean findConflict(Integer u, Integer v) {
		if (unionFind.connected(u-1, v-1))
			return true;
		return !checkCapacities(u, getFlowRate(v));
	}

	private boolean checkCapacities(Integer u, int k){
		LinkedList<Integer> toCheck  = new LinkedList<Integer>();
		toCheck.add(u);

		while(!toCheck.isEmpty()){
			Integer w = toCheck.pollFirst();
			Iterator<Arc> it = this.getInstance().getGraph().getInputArcsIterator(w);
			while(it.hasNext()) {
				Arc b = it.next();
				Integer capacity = leftCapacities.get(b);
                System.out.println(b+" "+capacity+" "+getFlowRate(w)+" "+k);
				if(capacity != null && capacity < getFlowRate(w) + k)
					return false;
				if(isSaturated(b))
					toCheck.add(b.getInput());
			}
		}
		return true;
	}

	/**
	 * Add the arc a to the set of saturated arcs, and update the flow rate of
	 * all the arcs affected by this saturation
	 *
	 * @param a
	 */
	private void saturateArcAndUpdate(Arc a) {
		Integer u = a.getInput();
		Integer v = a.getOutput();

		// This list will contain the set of node for which the flow rate will change
		// after the saturation of a...
		LinkedList<Integer> toUpdate = new LinkedList<Integer>();
		// ...including u
		toUpdate.add(u);

		// The sources of v we have to add to update the affected nodes

		Integer vFlowRate = getFlowRate(v);

		while (!toUpdate.isEmpty()) {
			Integer w = toUpdate.pollFirst();

			// The current flow rate inside each entering arc of w, before a is saturated
			Integer prevFlowRate = getFlowRate(w);
			Integer newFlowRate = prevFlowRate + vFlowRate;
			setFlowRate(w, newFlowRate); // sources disjoint union, because there is no conflict

			if (prevFlowRate != 0) {

				Double prevFlowRateD = (double)prevFlowRate;

				// if w already received flow before a became saturated
				// the time the next entering arc of w is saturated is accelerated like this:
				CustomFibonacciHeapNode<Integer, DoubleBoolean> fbn = n2fbn
						.get(w);
				// by the following test, we test if there is an entering arc of w which is not fully saturated
				// in the other case we do nothing
				if (fbn != null) {
					double prevNextSaturatedEnteringArcTime = fbn.getKey()
							.getDoubleValue();
					double newVolFlowRateD = newFlowRate;

					double newNextSaturatedEnteringArcTime = time
							+ (prevNextSaturatedEnteringArcTime - time)
							* (prevFlowRateD / newVolFlowRateD);
					sortedSaturating.decreaseKey(fbn, new DoubleBoolean(
							newNextSaturatedEnteringArcTime, fbn.getKey()
									.getBooleanValue()));
				}
			} else
				// if w did not receive any flow from the source, we initialize its saturation like this
				updateNextSaturatedArc(w);

			Arc saturatingInputArc = nextSaturatedEnteringArc(w);

			// For each node linked to w with a saturated arc, we insert it in the list
			// of nodes we have to update
			for (Arc inputArc : getSortedInputArcs(w)) {
				if (inputArc.equals(saturatingInputArc))
					break;
				if (isSaturated(inputArc))
					toUpdate.add(inputArc.getInput());
			}
		}

		saturated.add(a);
	}

	/**
	 *
	 * @return the set of saturated arcs linked to the root, and the terminals
	 *         this set of arcs reach.
	 */
	private Triplet<HashSet<Arc>, HashSet<Integer>, HashSet<Integer>> buildTree(Integer u) {
		LinkedList<Integer> toList = new LinkedList<Integer>();
		toList.add(u);

		HashSet<Arc> tree = new HashSet<Arc>();
		HashSet<Integer> reached = new HashSet<Integer>();
 		HashSet<Integer> leaves = new HashSet<Integer>();

		while (!toList.isEmpty()) {
			Integer v = toList.pollFirst();
			reached.add(v);
			if (requiredVertices.contains(v))
				leaves.add(v);

			Iterator<Arc> it = instance.getGraph().getOutputArcsIterator(v);
			while (it.hasNext()) {
				Arc a = it.next();
				if (!isSaturated(a))
					continue;

				tree.add(a);
				Integer capacity = leftCapacities.get(a);
				if(capacity != null)
					leftCapacities.put(a, capacity-getFlowRate(a.getOutput()));
				toList.add(a.getOutput());
			}
		}
		return new Triplet<HashSet<Arc>, HashSet<Integer>, HashSet<Integer>> (tree, reached, leaves);
	}

	/**
	 *
	 * @param a
	 * @return the maximum value of flow an arc a can contain: its cost
	 */
	private double getVolume(Arc a) {
		return (double) costs.get(a);
	}

	/**
	 *
	 * @param v
	 * @return the current flow rate entering v: the sources it can reach with
	 *         saturated arcs
	 */
	private Integer getFlowRate(Integer v) {
		Integer flowRate = flowRates.get(v);
		if (flowRate == null) {
			return 0;
		}
		return flowRate;
	}

	private void setFlowRate(Integer v, Integer flowRate){
		flowRates.put(v, flowRate);
	}

	/**
	 *
	 * @param a
	 * @return true if a is full of flow
	 */
	private boolean isSaturated(Arc a) {
		return saturated.contains(a);
	}
}


text:
package org.wildfly.extras.creaper.commands.elytron.credentialstore;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.jboss.arquillian.junit.Arquillian;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.wildfly.extras.creaper.commands.elytron.CredentialRef;
import org.wildfly.extras.creaper.core.CommandFailedException;
import org.wildfly.extras.creaper.core.online.OnlineCommand;
import org.wildfly.extras.creaper.core.online.OnlineCommandContext;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.operations.Address;
import org.wildfly.extras.creaper.core.online.operations.Operations;
import org.wildfly.extras.creaper.core.online.operations.Values;

@RunWith(Arquillian.class)
public class AddCredentialStoreAliasOnlineTest extends AbstractCredentialStoreOnlineTest {

    private static final String TEST_CREDENTIAL_STORE_NAME = "CreaperTestCredentialStore";
    private static final Address TEST_CREDENTIAL_STORE_ADDRESS = SUBSYSTEM_ADDRESS
            .and("credential-store", TEST_CREDENTIAL_STORE_NAME);

    private static final String TEST_CREDENTIAL_STORE_ALIAS_NAME = "creapertestcredentialstorealias";
    private static final String TEST_CREDENTIAL_STORE_ALIAS_NAME2 = "creapertestcredentialstorealias2";

    private static final String PATH = "path";
    private static final String TMP = "tmp";
    private static final Address TEST_PATH_TMP_ADDRESS = Address.root()
            .and(PATH, TMP);

    @ClassRule
    public static TemporaryFolder tmp = new TemporaryFolder();

    @BeforeClass
    public static void createTmpPath() throws Exception {
        try (OnlineManagementClient client = createManagementClient()) {
            AddTmpDirectoryToPath addTargetToPath = new AddTmpDirectoryToPath();
            client.apply(addTargetToPath);
        }
    }

    @Before
    public void createCredentialStore() throws Exception {
        AddCredentialStore addCredentialStore = new AddCredentialStore.Builder(TEST_CREDENTIAL_STORE_NAME)
                .create(true)
                .credentialReference(new CredentialRef.CredentialRefBuilder()
                        .clearText("somePassword")
                        .build())
                .relativeTo("tmp")
                .build();

        client.apply(addCredentialStore);
    }

    @After
    public void cleanup() throws Exception {
        // ops.removeIfExists(TEST_CREDENTIAL_STORE_ALIAS_ADDRESS);
        // ops.removeIfExists(TEST_CREDENTIAL_STORE_ALIAS_ADDRESS2);
        ops.removeIfExists(TEST_CREDENTIAL_STORE_ADDRESS);
        administration.reloadIfRequired();
    }

    @AfterClass
    public static void removeTmpPath() throws Exception {
        try (OnlineManagementClient client = createManagementClient()) {
            Operations operations = new Operations(client);
            operations.removeIfExists(TEST_PATH_TMP_ADDRESS);
        }
    }

    @Test
    public void addSimpleCredentialStoreAlias() throws Exception {
        AddCredentialStoreAlias addCredentialStoreAlias
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .replaceExisting()
                .build();

        client.apply(addCredentialStoreAlias);

        assertTrue("Credential store alias should be created",
                aliasExists(TEST_CREDENTIAL_STORE_ADDRESS, TEST_CREDENTIAL_STORE_ALIAS_NAME));
    }

    @Test
    public void addFullCredentialStoreAlias() throws Exception {
        AddCredentialStoreAlias addCredentialStoreAlias
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .entryType(AddCredentialStoreAlias.EntryType.PASSWORD_CREDENTIAL)
                .replaceExisting()
                .build();

        client.apply(addCredentialStoreAlias);
        assertTrue("Credential store alias should be created",
            aliasExists(TEST_CREDENTIAL_STORE_ADDRESS, TEST_CREDENTIAL_STORE_ALIAS_NAME));
    }

    @Test
    public void addTwoCredentialStoreAliases() throws Exception {
        AddCredentialStoreAlias addCredentialStoreAlias
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .replaceExisting()
                .build();

        AddCredentialStoreAlias addCredentialStoreAlias2
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME2)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someOtherValue")
                .replaceExisting()
                .build();

        client.apply(addCredentialStoreAlias);
        client.apply(addCredentialStoreAlias2);

        assertTrue("Credential store alias should be created",
            aliasExists(TEST_CREDENTIAL_STORE_ADDRESS, TEST_CREDENTIAL_STORE_ALIAS_NAME));
        assertTrue("Credential store alias should be created",
            aliasExists(TEST_CREDENTIAL_STORE_ADDRESS, TEST_CREDENTIAL_STORE_ALIAS_NAME2));
    }

    @Test(expected = CommandFailedException.class)
    public void addExistCredentialStoreAliasNotAllowed() throws Exception {
        AddCredentialStoreAlias addCredentialStoreAlias
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .build();

        AddCredentialStoreAlias addCredentialStoreAlias2
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someOtherValue")
                .build();

        client.apply(addCredentialStoreAlias);
        assertTrue("Credential store alias should be created", ops.exists(TEST_CREDENTIAL_STORE_ADDRESS));
        client.apply(addCredentialStoreAlias2);
        fail("Credential store alias creapertestcredentialstorealias already exists in configuration, exception should be thrown");
    }

    @Test
    public void addExistCredentialStoreAliasAllowed() throws Exception {
        AddCredentialStoreAlias addCredentialStoreAlias
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .build();

        AddCredentialStoreAlias addCredentialStoreAlias2
                = new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someOtherValue")
                .replaceExisting()
                .build();

        client.apply(addCredentialStoreAlias);
        assertTrue("Credential store alias should be created", ops.exists(TEST_CREDENTIAL_STORE_ADDRESS));
        client.apply(addCredentialStoreAlias2);
        assertTrue("Credential store alias should be created", ops.exists(TEST_CREDENTIAL_STORE_ADDRESS));
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_nullName() throws Exception {
        new AddCredentialStoreAlias.Builder(null)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .build();

        fail("Creating command with null name should throw exception");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_emptyName() throws Exception {
        new AddCredentialStoreAlias.Builder("")
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("someSecretValue")
                .build();

        fail("Creating command with empty name should throw exception");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_nullCredentialStore() throws Exception {
        new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(null)
                .secretValue("someSecretValue")
                .build();

        fail("Creating command with null credential-store should throw exception");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_emptyCredentialStore() throws Exception {
        new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore("")
                .secretValue("someSecretValue")
                .build();

        fail("Creating command with empty credential-store should throw exception");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_nullSecretValue() throws Exception {
        new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue(null)
                .build();

        fail("Creating command with null secret-value should throw exception");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addCredentialStoreAlias_emptySecretValue() throws Exception {
        new AddCredentialStoreAlias.Builder(TEST_CREDENTIAL_STORE_ALIAS_NAME)
                .credentialStore(TEST_CREDENTIAL_STORE_NAME)
                .secretValue("")
                .build();

        fail("Creating command with empty secret-value should throw exception");
    }

    private static final class AddTmpDirectoryToPath implements OnlineCommand {

        @Override
        public void apply(OnlineCommandContext ctx) throws Exception {
            Operations ops = new Operations(ctx.client);
            Address pathAddress = Address.root()
                    .and(PATH, TMP);

            ops.add(pathAddress, Values.empty()
                    .and(PATH, tmp.getRoot().getAbsolutePath()));
        }
    }
}


text:
package com.swayzetrain.inventory.api.service.instance;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.swayzetrain.inventory.api.service.userrole.UserRoleWriter;
import com.swayzetrain.inventory.auth.model.UserAuthorizationDetails;
import com.swayzetrain.inventory.common.model.Instance;
import com.swayzetrain.inventory.common.repository.InstanceRepository;
import com.swayzetrain.inventory.common.service.CommonService;

@Service
public class InstanceWriter {

	@Autowired
	private InstanceRepository instanceRepository;

	@Autowired
	private CommonService commonService;

	@Autowired
	private UserRoleWriter userRoleWriter;

	public ResponseEntity<?> SaveNewInstance(Instance instance, UserAuthorizationDetails userAuthorizationDetails) {

		instance.setCreationuserid(userAuthorizationDetails.getUserid());
		instance.setDatemodified(commonService.setTimestamp());
		instance.setDatecreated(commonService.setTimestamp());

		Instance instanceResponse = instanceRepository.save(instance);

		userRoleWriter.establishNewInstanceUserRole(userAuthorizationDetails.getUsername(), instanceResponse.getInstanceid());

		return new ResponseEntity<Instance>(instanceResponse, HttpStatus.OK);

	}

}


text:
@implementation MBAccountTool

static MBAccount *_account;

+ (void)saveAccount:(MBAccount *)account{
    [NSKeyedArchiver archiveRootObject:account toFile:MBAccountFileName];
}

+ (MBAccount *)account{
    if (nil == _account) {
        _account = [NSKeyedUnarchiver unarchiveObjectWithFile:MBAccountFileName];
        if ([[NSDate date] compare:_account.expires_date] != NSOrderedAscending) {
            return nil;
        }
    }
    return _account;
}

@end


text:
{% extends "futuschedule/base.html" %}
{% load staticfiles %}

{% block title %}Schedule{% endblock %}

{% block body %}
<script type="text/javascript">
var s_id = {{s_id}};
</script>
<script src="{% static 'futuschedule/js/build/page-schedule-detail.js' %}"></script>
{% endblock %}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Grevillea 9(no. 52): 127 (1881)

#### Original name
Sphaeronaema eucalypti Cooke & Harkn.

### Remarks
null


text:
<!doctype html>

  <meta charset="utf-8">
  <title>mark.js manual test (dev purposes)</title>


text:
@interface TLCategory : UIViewController

@property (nonatomic,strong)NSString *businessName;

@property (nonatomic)NSInteger count;
@property (nonatomic)NSInteger flag;
@property (nonatomic)NSInteger sflag;
@property (nonatomic)NSInteger myTag;

@property (nonatomic,strong)NSString *businessId;

-(IBAction)mentou_click:(id)sender;
-(IBAction)shouyintai_click:(id)sender;
-(IBAction)jinyingchangsuo_click:(id)sender;
-(IBAction)gongdanzhengmian_click:(id)sender;
-(IBAction)gongdanfanmian_click:(id)sender;
-(IBAction)qita_click:(id)sender;

-(IBAction)submit:(id)sender;

@end


text:
<?php
include "includes/config.php";
session_start();
if(!isset($_SESSION['nama_lengkap'])){
	echo "";
}
$config = new Config();
$db = $config->getConnection();
?>
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Analytic Hierarchy Process</title>
	<link href="images/favicon.ico" rel="shortcut icon" />

    <link href="css/bootstrap.min.css" rel="stylesheet">
    <link href="css/dataTables.bootstrap.min.css" rel="stylesheet">
    <link type="text/css" href="css/jquery.toastmessage.css" rel="stylesheet"/>
	<link rel="stylesheet" href="css/font-awesome.min.css">

		  <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
			Toggle navigation

		  </button>
		   Tugas Besar Manajemen Sains

<?php echo $_SESSION['nama_lengkap'] ?>

 Profil

 Data Pengguna

 Logout


text:
---
layout: post
title: 解决修改arsc同名文件导致apktool反编译失败
categories: Reverse_Engineering
description: 解决修改arsc同名文件导致apktool反编译失败
keywords:
---

# 解决修改arsc同名文件导致apktool反编译失败

## 背景

  有些软件,会修改apk的resources.arsc文件,做成同名资源,导致apktool出现崩溃:

```Txt
Exception in thread "main" brut.androlib.AndrolibException: Multiple res specs: drawable/
  at brut.androlib.res.data.ResTypeSpec.addResSpec(ResTypeSpec.java:78)
  at brut.androlib.res.decoder.ARSCDecoder.readEntry(ARSCDecoder.java:248)
  at brut.androlib.res.decoder.ARSCDecoder.readTableType(ARSCDecoder.java:212)
  at brut.androlib.res.decoder.ARSCDecoder.readTableTypeSpec(ARSCDecoder.java:154)
  at brut.androlib.res.decoder.ARSCDecoder.readTablePackage(ARSCDecoder.java:116)
  at brut.androlib.res.decoder.ARSCDecoder.readTableHeader(ARSCDecoder.java:78)
  at brut.androlib.res.decoder.ARSCDecoder.decode(ARSCDecoder.java:47)
  at brut.androlib.res.AndrolibResources.getResPackagesFromApk(AndrolibResources.java:544)
  at brut.androlib.res.AndrolibResources.loadMainPkg(AndrolibResources.java:63)
  at brut.androlib.res.AndrolibResources.getResTable(AndrolibResources.java:55)
  at brut.androlib.Androlib.getResTable(Androlib.java:66)
  at brut.androlib.ApkDecoder.setTargetSdkVersion(ApkDecoder.java:198)
  at brut.androlib.ApkDecoder.decode(ApkDecoder.java:96)
  at brut.apktool.Main.cmdDecode(Main.java:165)
  at brut.apktool.Main.main(Main.java:81)
```

## 代码

  为了解决这个问题,就要修改apktool,编译过程如上一篇帖子所述http://www.0xaa55.com/thread-1659-1-1.html,发生异常后,程序断在:

```Java
    public void addResSpec(ResResSpec spec) throws AndrolibException {
        if (mResSpecs.put(spec.getName(), spec) != true) {
            throw new AndrolibException(String.format(
                    "Multiple res specs: %s/%s", getName(), spec.getName()));
        }
    }
```

再看ApkTool源码

```Java
//ResType.java
package brut.androlib.res.data;

import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject;
import java.util.*;

/**
 * @author Ryszard Wiśniewski <[email]brut.alll@gmail.com[/email]>
 */
public final class ResType {
    private final String mName;
    private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();

    private final ResTable mResTable;
    private final ResPackage mPackage;

    public ResType(String name, ResTable resTable, ResPackage package_) {
        this.mName = name;
        this.mResTable = resTable;
        this.mPackage = package_;
    }

    public String getName() {
        return mName;
    }

    public boolean isString() {
        return mName.equalsIgnoreCase("string");
    }

    public Set<ResResSpec> listResSpecs() {
        return new LinkedHashSet<ResResSpec>(mResSpecs.values());
    }

    public ResResSpec getResSpec(String name) throws AndrolibException {
        ResResSpec spec = mResSpecs.get(name);
        if (spec == null) {
            throw new UndefinedResObject(String.format("resource spec: %s/%s",
                    getName(), name));
        }
        return spec;
    }

    public void addResSpec(ResResSpec spec) throws AndrolibException {
        if (mResSpecs.put(spec.getName(), spec) != null) {
            throw new AndrolibException(String.format(
                    "Multiple res specs: %s/%s", getName(), spec.getName()));
        }
    }

    @Override
    public String toString() {
        return mName;
    }
```

  可以发现mResSpecs是map结构的,键值一一对应,所以对方如果在arsc中放了2个同名资源的话,apktool不会继续处理,那么比较好的方法是将mResSpecs做成multimap结构,因此改动如下:

```Java
package brut.androlib.res.data;
import com.google.common.collect.HashMultimap;
import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject;
import java.util.*;

/**
 * @author Ryszard Wiśniewski <[email]brut.alll@gmail.com[/email]>
 */
public final class ResType {
    private final String mName;
    //private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
    private static HashMultimap<String,ResResSpec> mResSpecs = null;
    private final ResTable mResTable;
    private final ResPackage mPackage;

    public ResType(String name, ResTable resTable, ResPackage package_) {
        this.mName = name;
        this.mResTable = resTable;
        this.mPackage = package_;
        mResSpecs = HashMultimap.create();
    }

    public String getName() {
        return mName;
    }

    public boolean isString() {
        return mName.equalsIgnoreCase("string");
    }

    public Set<ResResSpec> listResSpecs() {
        return new LinkedHashSet<ResResSpec>(mResSpecs.values());
    }

    public ResResSpec getResSpec(String name) throws AndrolibException {
        //ResResSpec spec = mResSpecs.get(name);
        Set<ResResSpec> spec = mResSpecs.get(name);
        if (spec.size() == 0) {
            throw new UndefinedResObject(String.format("resource spec: %s/%s",
                    getName(), name));
        }
        //return spec;
        return spec.iterator().next();
    }

    public void addResSpec(ResResSpec spec) throws AndrolibException {
        //if (mResSpecs.put(spec.getName(), spec) != null) {
        if (mResSpecs.put(spec.getName(), spec) != true) {
            throw new AndrolibException(String.format(
                    "Multiple res specs: %s/%s", getName(), spec.getName()));
        }
    }

    @Override
    public String toString() {
        return mName;
    }
}
```

## 结论
  在android studio中调试成功解密出文件之后替换 安卓改之理 中的apktool,完美恢复!


text:
<?php  include_once "Shared/header.php" ?>

<?php include_once "Shared/menu.php";
    include_once "controller/cargoController.php";
    include_once "controller/setorController.php";
    $setorCtrl = new setorController();
    $controller = new cargoController();
?>

Cadastro de Cargos

                    <form class="form-inline" method="POST" action="../controllers/cargoController.php">
                        <input type="hidden" id="id" name="id" value="" />
                        <select name="setor" id="setor" class="form-control">
                        <?php
                        foreach($setorCtrl->retornarTodos() as $setor){
                        ?>
                            <option value="<?= $setor["id"]?>"><?= $setor["Setor"]?></option>
                        <?php } ?>
                        </select>
                        <input type="text" name="txtcargo" id="txtcargo" class="form-control" class="form-control" />
                        <input type="submit" name="inserir" value="Cadastrar" id="btnCadastrar" class="form-control btn-primary" />
                        <input type="reset" value="Cancelar" id="btnCancelar" class="form-control btn-danger" />
                    </form>

Setores

                    <form class="form-inline" method="POST" action="../controllers/cargoController.php">

                            Selecionar
                            Cargo
                            Setor
                            Editar

                        <?php
                        foreach($controller->retornarTodos() as $cargo){ ?>
                            <tr id="<?= $cargo["id"]?>">

                                    <input type="checkbox" name="ids[]" value="<?= $cargo["id"]?>"/>

                                    <?= $cargo["nomeCargo"]?>

                                <td id="<?= $cargo["idsetor"]?>">
                                    <?= $cargo["setor"]?>

                                <a class="edit" data-obj="<?= $cargo["id"]?>;<?= $cargo["nomeCargo"]?>;<?= $cargo["idsetor"]?>">

                        <?php } ?>

                        <input type="submit" name="excluir" value="Excluir" class="btn-success" />
                    </form

<?php  include_once "Shared/footer.php" ?>


text:
name: addmultisigaddress
btcversion: 0.16.3
btcgroup: wallet
permalink: en/doc/0.16.3/rpc/wallet/addmultisigaddress/
---

addmultisigaddress nrequired ["key",...] ( "account" "address_type" )

Add a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.
Each key is a Bitcoin address or hex-encoded public key.
This functionality is only intended for use with non-watchonly addresses.
See `importaddress` for watchonly p2sh address support.
If 'account' is specified (DEPRECATED), assign address to that account.

Arguments:
1. nrequired                      (numeric, required) The number of required signatures out of the n keys or addresses.
2. "keys"                         (string, required) A json array of bitcoin addresses or hex-encoded public keys
     [
       "address"                  (string) bitcoin address or hex-encoded public key
       ...,
     ]
3. "account"                      (string, optional) DEPRECATED. An account to assign the addresses to.
4. "address_type"                 (string, optional) The address type to use. Options are "legacy", "p2sh-segwit", and "bech32". Default is set by -addresstype.

Result:
{
  "address":"multisigaddress",    (string) The value of the new multisig address.
  "redeemScript":"script"         (string) The string value of the hex-encoded redemption script.
}

Result (DEPRECATED. To see this result in v0.16 instead, please start bitcoind with -deprecatedrpc=addmultisigaddress).
        clients should transition to the new output api before upgrading to v0.17.
"address"                         (string) A bitcoin address associated with the keys.

Examples:

Add a multisig address from 2 addresses
> bitcoin-cli addmultisigaddress 2 "[\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\",\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\"]"

As json rpc call
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "addmultisigaddress", "params": [2, "[\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\",\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\"]"] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/


text:
require "optparse"

class Dirtree

  MAX_DEPTH = 8
  STORAGE_UNITS = %w[B KB MB GB TB]
  STORAGE_BASE = 1024
  DEFAULT_OPTIONS = { depth: MAX_DEPTH, hidden: false, filecount: false, diskusage: false }

  def initialize(root_dir = Dir.pwd, opts)
    options = DEFAULT_OPTIONS.merge(opts)
    @rundir = Dir.pwd
    @root_dir = root_dir
    @depth = options[:depth]
    @include_hidden = options[:hidden]
    @filecount = options[:filecount]
    @diskusage = options[:diskusage]
    @tree_str = ""
  end

  def print_tree(dir = @root_dir, level = 0)
    create_tree(dir, level)
    puts @tree_str
  end

  def create_tree(dir, level)
    # show but don't follow directory symlinks
    if File.symlink?(dir)
      @tree_str << row_string_for_link(dir, level)
      return
    end

    # for normal directories, recursively create the tree until
    # specified depth reached
    Dir.chdir(dir) do
      @tree_str <<  row_string_for_dir(dir, level)
      child_directories.each { |d| create_tree(d, level + 1) } if level < @depth
    end
  rescue Errno::EACCES
    @tree_str << row_string_for_noaccess(dir, level)
  end

  def child_directories
    @include_hidden ? pattern = "{*,.*}" : pattern = "*"
    Dir.glob(pattern).select { |f| File.directory?(f) && f != "." && f != ".." }
  end

  def row_string_for_dir(dir, level)
    if dir == "/"
      dirname = "/"
    elsif dir == @rundir
      dirname = "."
    else
      dirname = dir.split('/').last
    end

    row_str = ""
    row_str << level_header_for_row(level)
    row_str << dirname
    row_str << "\033[34m [%d]\033[0m" % file_count if @filecount
    row_str << "\033[35m [%s]\033[0m" % disk_usage if @diskusage
    row_str << "\n"
  end

  def row_string_for_noaccess(dir, level)
    dirname = dir + "\033[31m <no access>\033[0m"
    row_str = ""
    row_str << level_header_for_row(level)
    row_str << dirname
    row_str << "\n"
  end

  def row_string_for_link(dir, level)
    dirname = dir + "\033[33m <symlink>\033[0m"
    row_str = ""
    row_str << level_header_for_row(level)
    row_str << dirname
    row_str << "\n"
  end

  def level_header_for_row(level)
    header_str = ""
    if level > 0
      header_str << "   " * (level - 1)
      header_str << "└─ "
    end
    header_str
  end

  def all_files
    Dir.glob('*').select { |f| File.file?(f) }
  end

  def file_count
    all_files.size
  end

  def disk_usage
    bytes = all_files.map { |f| File.size(f) }.reduce(:+) || 0
    if bytes < STORAGE_BASE
      size_str = bytes.to_s + STORAGE_UNITS[0]
    else
      disk_usage = human_rep(bytes)
      size_str = format_size(disk_usage[:size], disk_usage[:unit])
    end
    size_str
  end

  # set the preferred presentation for file size human representation;
  # show one digit after decimal point, unless it's zero or the unit is < MB
  def format_size(disk_usage, unit)
    if STORAGE_UNITS.index(unit) > 1
      size_str = "%.1f" % disk_usage
    else
      size_str = "%.0f" % disk_usage
    end
    size_str + unit
  end

  # return human-readable number + unit for file size in bytes;
  # adapted from Active Support's number helpers (but without translation, option handling etc)
  def human_rep(bytes)
    number = Float(bytes)
    max_exp = STORAGE_UNITS.size - 1
    exponent = (Math.log(bytes) / Math.log(STORAGE_BASE)).to_i
    exponent = max_exp if exponent > max_exp
    number /= STORAGE_BASE ** exponent
    unit = STORAGE_UNITS[exponent]
    { size: number, unit: unit }
  end
end

options = {}
parser = OptionParser.new do |opts|
  opts.banner = "Usage: dirtree [options] [directory_name]"

  opts.on("-a", "--include-hidden", "include hidden directories") do |a|
    options[:hidden] = true
  end

  opts.on("-dN", "--depth N", "maximum tree depth to show") do |d|
    options[:depth] = Integer(d)
  end

  opts.on("-c", "--file-count", "show file count per directory") do
    options[:filecount] = true
  end

  opts.on("-s", "--disk-usage", "show disk usage per directory") do
    options[:diskusage] = true
  end

  opts.on("-h", "--help", "Show this message") do
    puts opts
    exit
  end
end

parser.parse!

# main

if ARGV[0] && !File.directory?(ARGV[0])
  $stderr.puts "#{ARGV[0]} is not a directory!"
  $stderr.puts parser
  abort
end

Dirtree.new(ARGV[0] || Dir.pwd, options).print_tree


text:
    <java-class-file name="D:\Experiments\Analisi di Sopravvivenza\Progetto16715\ProgettiDaAnalizzare\jhotdraw\JHotDraw 7.4.1\JHotDraw 7.4.1\Source\jhotdraw7\src\main\java\org\jhotdraw\draw\action\DrawingColorChooserAction.java">
        <package-decl name="org.jhotdraw.draw.action"/>
        <class name="DrawingColorChooserAction" visibility="public">
            <constructor visibility="public" name="DrawingColorChooserAction">
            </constructor>
            <constructor visibility="public" name="DrawingColorChooserAction">
            </constructor>
            <constructor visibility="public" name="DrawingColorChooserAction">
            </constructor>
            <constructor visibility="public" name="DrawingColorChooserAction">
            </constructor>
            <constructor visibility="public" name="DrawingColorChooserAction">
            </constructor>
            <method name="actionPerformed" visibility="public">
            </method>
            <method name="getInitialColor" visibility="protected">
            </method>
            <method name="updateEnabledState" visibility="protected">
            </method>
        </class>
    </java-class-file>


text:
@implementation TGModernMediaListItemContentView

- (void)prepareForReuse
{
}

- (void)updateItem
{
}

- (void)setItem:(id<TGModernMediaListItem>)item
{
    [self setItem:item synchronously:false];
}

- (void)setItem:(id<TGModernMediaListItem>)item synchronously:(bool)__unused synchronously
{
    _item = item;
}

@end


text:
package dyff

import (
	"fmt"

	"github.com/gonvenience/bunt"
	colorful "github.com/lucasb-eyer/go-colorful"
)

var (
	additionGreen      = color("#58BF38")
	modificationYellow = color("#C7C43F")
	removalRed         = color("#B9311B")
)

func color(hex string) colorful.Color {
	color, _ := colorful.Hex(hex)
	return color
}

func green(format string, a ...interface{}) string {
	return colored(additionGreen, format, a...)
}

func red(format string, a ...interface{}) string {
	return colored(removalRed, format, a...)
}

func yellow(format string, a ...interface{}) string {
	return colored(modificationYellow, format, a...)
}

func lightgreen(format string, a ...interface{}) string {
	return colored(bunt.LightGreen, format, a...)
}

func lightred(format string, a ...interface{}) string {
	return colored(bunt.LightSalmon, format, a...)
}

func bold(format string, a ...interface{}) string {
	return bunt.Style(
		fmt.Sprintf(format, a...),
		bunt.EachLine(),
		bunt.Bold(),
	)
}

func italic(format string, a ...interface{}) string {
	return bunt.Style(
		fmt.Sprintf(format, a...),
		bunt.EachLine(),
		bunt.Italic(),
	)
}

func colored(color colorful.Color, format string, a ...interface{}) string {
	return bunt.Style(
		fmt.Sprintf(format, a...),
		bunt.EachLine(),
		bunt.Foreground(color),
	)
}


text:
const stubString = () => {
  var result = ''
  return result
}

export default stubString


text:
package tls

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/sha256"
	"crypto/subtle"
	"errors"
	"io"

	"golang.org/x/crypto/cryptobyte"
)

// sessionState contains the information that is serialized into a session
// ticket in order to later resume a connection.
type sessionState struct {
	vers         uint16
	cipherSuite  uint16
	createdAt    uint64
	masterSecret []byte // opaque master_secret<1..2^16-1>;
	// struct { opaque certificate<1..2^24-1> } Certificate;
	certificates [][]byte // Certificate certificate_list<0..2^24-1>;

	// usedOldKey is true if the ticket from which this session came from
	// was encrypted with an older key and thus should be refreshed.
	usedOldKey bool
}

func (m *sessionState) marshal() []byte {
	var b cryptobyte.Builder
	b.AddUint16(m.vers)
	b.AddUint16(m.cipherSuite)
	addUint64(&b, m.createdAt)
	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
		b.AddBytes(m.masterSecret)
	})
	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
		for _, cert := range m.certificates {
			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
				b.AddBytes(cert)
			})
		}
	})
	return b.BytesOrPanic()
}

func (m *sessionState) unmarshal(data []byte) bool {
	*m = sessionState{usedOldKey: m.usedOldKey}
	s := cryptobyte.String(data)
	if ok := s.ReadUint16(&m.vers) &&
		s.ReadUint16(&m.cipherSuite) &&
		readUint64(&s, &m.createdAt) &&
		readUint16LengthPrefixed(&s, &m.masterSecret) &&
		len(m.masterSecret) != 0; !ok {
		return false
	}
	var certList cryptobyte.String
	if !s.ReadUint24LengthPrefixed(&certList) {
		return false
	}
	for !certList.Empty() {
		var cert []byte
		if !readUint24LengthPrefixed(&certList, &cert) {
			return false
		}
		m.certificates = append(m.certificates, cert)
	}
	return s.Empty()
}

// sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
// version (revision = 0) doesn't carry any of the information needed for 0-RTT
// validation and the nonce is always empty.
type sessionStateTLS13 struct {
	// uint8 version  = 0x0304;
	// uint8 revision = 0;
	cipherSuite      uint16
	createdAt        uint64
	resumptionSecret []byte      // opaque resumption_master_secret<1..2^8-1>;
	certificate      Certificate // CertificateEntry certificate_list<0..2^24-1>;
}

func (m *sessionStateTLS13) marshal() []byte {
	var b cryptobyte.Builder
	b.AddUint16(VersionTLS13)
	b.AddUint8(0) // revision
	b.AddUint16(m.cipherSuite)
	addUint64(&b, m.createdAt)
	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
		b.AddBytes(m.resumptionSecret)
	})
	marshalCertificate(&b, m.certificate)
	return b.BytesOrPanic()
}

func (m *sessionStateTLS13) unmarshal(data []byte) bool {
	*m = sessionStateTLS13{}
	s := cryptobyte.String(data)
	var version uint16
	var revision uint8
	return s.ReadUint16(&version) &&
		version == VersionTLS13 &&
		s.ReadUint8(&revision) &&
		revision == 0 &&
		s.ReadUint16(&m.cipherSuite) &&
		readUint64(&s, &m.createdAt) &&
		readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
		len(m.resumptionSecret) != 0 &&
		unmarshalCertificate(&s, &m.certificate) &&
		s.Empty()
}

func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
	if len(c.ticketKeys) == 0 {
		return nil, errors.New("tls: internal error: session ticket keys unavailable")
	}

	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
	keyName := encrypted[:ticketKeyNameLen]
	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
	macBytes := encrypted[len(encrypted)-sha256.Size:]

	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
		return nil, err
	}
	key := c.ticketKeys[0]
	copy(keyName, key.keyName[:])
	block, err := aes.NewCipher(key.aesKey[:])
	if err != nil {
		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
	}
	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state)

	mac := hmac.New(sha256.New, key.hmacKey[:])
	mac.Write(encrypted[:len(encrypted)-sha256.Size])
	mac.Sum(macBytes[:0])

	return encrypted, nil
}

func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
	if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
		return nil, false
	}

	keyName := encrypted[:ticketKeyNameLen]
	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
	macBytes := encrypted[len(encrypted)-sha256.Size:]
	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]

	keyIndex := -1
	for i, candidateKey := range c.ticketKeys {
		if bytes.Equal(keyName, candidateKey.keyName[:]) {
			keyIndex = i
			break
		}
	}
	if keyIndex == -1 {
		return nil, false
	}
	key := &c.ticketKeys[keyIndex]

	mac := hmac.New(sha256.New, key.hmacKey[:])
	mac.Write(encrypted[:len(encrypted)-sha256.Size])
	expected := mac.Sum(nil)

	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
		return nil, false
	}

	block, err := aes.NewCipher(key.aesKey[:])
	if err != nil {
		return nil, false
	}
	plaintext = make([]byte, len(ciphertext))
	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)

	return plaintext, keyIndex > 0
}