text:
package org.mcisb.kinetics.novostar;

import java.io.*;
import java.text.*;
import java.util.*;
import org.mcisb.kinetics.*;
import org.mcisb.ontology.sbo.*;
import org.mcisb.sbml.*;
import org.mcisb.tracking.*;
import org.mcisb.util.*;
import org.sbml.jsbml.*;

/**
 *
 * @author Neil Swainston
 */
public class NovostarExcelReader extends KineticsExcelReader
{
	/**
	 *
	 */
	private final KineticsExperimentSet experimentSet;

	/**
	 *
	 * @param excelFile
	 * @param experimentSet
	 * @throws Exception
	 */
	public NovostarExcelReader( final File excelFile, final KineticsExperimentSet experimentSet ) throws Exception
	{
		super( excelFile );
		this.experimentSet = experimentSet;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mcisb.kinetics.KineticsExcelReader#getMetaData()
	 */
	@Override
	protected void getMetaData() throws Exception
	{
		final String META_DATA_WORKSHEET_NAME = "Sheet1"; //$NON-NLS-1$
		final int NAME_COLUMN = 0;
		final int EXPERIMENT_NAME_ROW = 0;
		final int EXPERIMENT_NAME_COLUMN = 5;
		final int EXPERIMENT_DATE_ROW = 0;
		final int EXPERIMENT_DATE_COLUMN = 10;
		final int EXPERIMENT_DESCRIPTION_ROW = 4;
		final int EXPERIMENT_DESCRIPTION_COLUMN = 0;
		final String DATE_PATTERN = "yyyy/MM/dd  HH:mm:ss"; //$NON-NLS-1$
		final String SPACE = " "; //$NON-NLS-1$
		final String NOVOSTAR = "NOVOstar"; //$NON-NLS-1$
		final String BMG_LABTECHNOLOGIES = "BMG Labtechnologies"; //$NON-NLS-1$
		final String TEMPERATURE = "Target temperature"; //$NON-NLS-1$
		final String USER = "User"; //$NON-NLS-1$
		final String COMMENT = "Comment"; //$NON-NLS-1$

		final UniqueObject instrument = new UniqueObject( StringUtils.getUniqueId(), BMG_LABTECHNOLOGIES + SPACE + NOVOSTAR );
		final History modelHistory = new History();
		final StringBuffer notes = new StringBuffer();

		int row = 0;

		for( Iterator<List<Object>> iterator = getData( META_DATA_WORKSHEET_NAME ).iterator(); iterator.hasNext(); )
		{
			final List<Object> rowData = iterator.next();
			String name = null;

			for( int column = 0; column < rowData.size(); column++ )
			{
				final Object data = rowData.get( column );

				if( data != null )
				{
					final String cell = data.toString().trim();

					if( row == EXPERIMENT_NAME_ROW && column == EXPERIMENT_NAME_COLUMN )
					{
						experimentSet.setName( cell );
					}
					else if( row == EXPERIMENT_DATE_ROW && column == EXPERIMENT_DATE_COLUMN )
					{
						final Calendar calendar = Calendar.getInstance();
						calendar.setTime( new SimpleDateFormat( DATE_PATTERN ).parse( cell ) );
						final Date date = calendar.getTime();
						modelHistory.setCreatedDate( date );
						modelHistory.setModifiedDate( date );
					}
					else if( row == EXPERIMENT_DESCRIPTION_ROW && column == EXPERIMENT_DESCRIPTION_COLUMN )
					{
						notes.append( cell );
					}
					else if( column == NAME_COLUMN )
					{
						name = cell;
					}
					else if( name != null && !name.equals( NOVOSTAR ) && !name.equals( BMG_LABTECHNOLOGIES ) )
					{
						if( name.equals( USER ) )
						{
							final String organisation = System.getProperty( "org.mcisb.kinetics.Organisation" ); //$NON-NLS-1$
							final Creator person = new Creator();
							person.setGivenName( cell );
							person.setFamilyName( cell );
							person.setEmail( cell );
							person.setOrganisation( organisation );
							modelHistory.addCreator( person );
						}
						else if( name.equals( TEMPERATURE ) && NumberUtils.isDecimal( cell ) )
						{
							experimentSet.getExperimentProtocol().setProperty( org.mcisb.tracking.PropertyNames.TEMPERATURE, Float.valueOf( cell ) );
						}
						else if( name.equals( COMMENT ) )
						{
							experimentSet.setDescription( cell );
						}
						else if( name.equals( org.mcisb.tracking.PropertyNames.SERIAL_NUMBER ) )
						{
							instrument.setProperty( name, cell );
						}
						else
						{
							experimentSet.getExperimentProtocol().setProperty( name, cell );
						}

						name = null;
					}
				}
			}

			row++;
		}

		instrument.setProperty( org.mcisb.tracking.PropertyNames.MANUFACTURER, BMG_LABTECHNOLOGIES );
		instrument.setProperty( org.mcisb.tracking.PropertyNames.MODEL, NOVOSTAR );

		experimentSet.getExperimentProtocol().setDescription( notes.toString() );
		experimentSet.setInstrument( instrument );
		experimentSet.setModelHistory( modelHistory );
	}

	/*
	 * (non-Javadoc)
	 * @see org.mcisb.kinetics.KineticsExcelReader#getData()
	 */
	@Override
	protected void getData()
	{
		final int CELL_COLUMN = 0;
		final int SAMPLE_NAME_COLUMN = 1;
		final int SECOND_COLUMN = 2;
		final String RAW_DATA_WORKSHEET_NAME = "Sheet2"; //$NON-NLS-1$
		final double DEFAULT_CONCENTRATION = 0.0;

		final Collection<Spot> spots = new ArrayList<>();
		final List<Double> timepoints = new ArrayList<>();
		boolean timepointsSet = false;
		int rows = 0;
		int columns = 0;

		for( Iterator<List<Object>> iterator = getData( RAW_DATA_WORKSHEET_NAME ).iterator(); iterator.hasNext(); )
		{
			final List<Object> rowData = iterator.next();
			int row = NumberUtils.UNDEFINED;
			int column  = NumberUtils.UNDEFINED;
			List<Double> absorbanceData = null;
			Spot spot = null;

			for( int i = 0; i < rowData.size(); i++ )
			{
				final Object data = rowData.get( i );

				if( data != null )
				{
					if( i == CELL_COLUMN )
					{
						String cell = (String)data;
						row = cell.charAt( 0 ) - 'A';
						column = Integer.parseInt( cell.substring( 1 ) );
						rows = Math.max( row + 1, rows );
						columns = Math.max( column + 1, columns );
					}
					else if( i == SAMPLE_NAME_COLUMN )
					{
						absorbanceData = new ArrayList<>();

						final String id = Character.valueOf( (char)( 'A' + row ) ).toString() + column;
						final Species species = new Species( SbmlUtils.DEFAULT_LEVEL, SbmlUtils.DEFAULT_VERSION );
						species.setNamespace( SbmlUtils.getDefaultSBMLNamespace() );
						species.setId( id );
						species.setName( id );
						species.setInitialConcentration( DEFAULT_CONCENTRATION );
	    				species.setUnits( org.mcisb.kinetics.PropertyNames.CONCENTRATION_UNIT );
	    				species.setSBOTerm( SboUtils.SUBSTRATE );
						spot = new Spot( new SpotReading( species, absorbanceData ) );
						spot.setRow( row );
						spot.setColumn( column );
					}
					else if( i > SECOND_COLUMN )
					{
						if( !timepointsSet && data instanceof Double )
						{
							timepoints.add( (Double)data );
						}
						else if( absorbanceData != null && data instanceof Double )
						{
							absorbanceData.add( (Double)data );
						}
					}
				}
			}

			if( spot != null )
			{
				spots.add( spot );
			}

			timepointsSet = true;
		}

		final Plate plate = new Plate( rows, columns );

		for( Iterator<Spot> iterator = spots.iterator(); iterator.hasNext(); )
		{
			final Spot spot = iterator.next();
			plate.setValueAt( spot, spot.getRow(), spot.getColumn() );
		}

		experimentSet.setPlate( plate );
		experimentSet.setTimepoints( CollectionUtils.toDoubleArray( timepoints ) );
	}
}


text:
CREATE EXTENSION pgcrypto;
CREATE EXTENSION citext;
CREATE EXTENSION "uuid-ossp";

-- shared stored procedures

CREATE FUNCTION on_record_insert() RETURNS trigger AS $$
  BEGIN
    NEW.id         := uuid_generate_v4();
    NEW.created_at := now();
    NEW.updated_at := now();
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION on_record_update() RETURNS trigger AS $$
  BEGIN
    -- ensure IDs aren't altered on updates
    NEW.id         := OLD.id;
    -- ensure date-created isn't altered on updates
    NEW.created_at := OLD.created_at;
    NEW.updated_at := now();
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION insert_user(addr TEXT, pass TEXT) RETURNS SETOF users AS $$
  BEGIN
    RETURN QUERY
      INSERT INTO users (email, password)
      VALUES (addr, crypt(pass, gen_salt('bf', 8)))
      RETURNING id, email, password, created_at, updated_at;
    EXCEPTION WHEN unique_violation THEN
  END;
$$ LANGUAGE plpgsql;

-- the User resource

CREATE TABLE users (
  id           UUID         PRIMARY KEY,
  email        CITEXT       NULL UNIQUE,
  password     VARCHAR      NOT NULL,
  created_at   TIMESTAMP    NOT NULL,
  updated_at   TIMESTAMP    NOT NULL
);

-- the Status resource

CREATE TABLE statuses (
  id           UUID          PRIMARY KEY,
  author_id    UUID          NOT NULL REFERENCES users (id) ON DELETE CASCADE,
  content      VARCHAR(144)  NOT NULL,
  created_at   TIMESTAMP     NOT NULL,
  updated_at   TIMESTAMP     NOT NULL
);

CREATE TRIGGER users_insert
  BEFORE INSERT ON users
  FOR EACH ROW
  EXECUTE PROCEDURE on_record_insert();

CREATE TRIGGER users_update
  BEFORE UPDATE ON users
  FOR EACH ROW
  EXECUTE PROCEDURE on_record_update();

CREATE TRIGGER statuses_insert
  BEFORE INSERT ON statuses
  FOR EACH ROW
  EXECUTE PROCEDURE on_record_insert();

CREATE TRIGGER statuses_update
  BEFORE UPDATE ON statuses
  FOR EACH ROW
  EXECUTE PROCEDURE on_record_update();

redpajama_set_name: RedPajamaGithub


text:
(function() {
    $(function() {

        var _userService = abp.services.app.user;
        var _$modal = $('#UserCreateModal');
        var _$form = _$modal.find('form');

        _$form.validate();

        _$form.find('button[type="submit"]').click(function (e) {
            e.preventDefault();

            if (!_$form.valid()) {
                return;
            }

            abp.ui.setBusy(_$modal);
            var user = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js

            _userService.createUser(user).done(function () {
                // _$modal.find("[data-dismiss=modal]:first").click();
                _$modal.modal('hide');
                // Model hide animation will takes some time, we have to reload until it is hidden(in its hidden event).
                _$modal.on('hidden.bs.modal', function () {
                    $('body').data('lobiAdmin').reload();
                });
            }).always(function () {
                abp.ui.clearBusy(_$modal);
            });

        });
        _$modal.on('shown.bs.modal', function () {
            _$modal.find('input:not([type=hidden]):first').focus();
        });
    });
})();


text:
import React from 'react';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import DateUtils from 'matrix-react-sdk/lib/DateUtils';

function getdaysArray() {
	return [
        _t('Sunday'),
        _t('Monday'),
        _t('Tuesday'),
        _t('Wednesday'),
        _t('Thursday'),
        _t('Friday'),
        _t('Saturday'),
    ];
}

module.exports = React.createClass({
    displayName: 'DateSeparator',
    render: function() {
        var date = new Date(this.props.ts);
        var today = new Date();
        var yesterday = new Date();
        var days = getdaysArray();
        yesterday.setDate(today.getDate() - 1);
        var label;
        if (date.toDateString() === today.toDateString()) {
            label = _t('Today');
        }
        else if (date.toDateString() === yesterday.toDateString()) {
            label = _t('Yesterday');
        }
        else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
            label = days[date.getDay()];
        }
        else {
            label = DateUtils.formatFullDate(date, this.props.showTwelveHour);
        }

        return (

{ label }

        );
    }
});


text:
import { computed, get, observer, set } from '@ember/object';
import { guidFor } from '@ember/object/internals';
import { DEBUG } from '@glimmer/env';

import { module, test } from 'qunit';
import { reject, resolve } from 'rsvp';

import { gte } from 'ember-compatibility-helpers';
import { setupTest } from 'ember-qunit';

import { InvalidError } from '@ember-data/adapter/error';
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import Model, { attr, attr as DSattr } from '@ember-data/model';
import JSONSerializer from '@ember-data/serializer/json';
import JSONAPISerializer from '@ember-data/serializer/json-api';
import { recordDataFor } from '@ember-data/store/-private';
import testInDebug from '@ember-data/unpublished-test-infra/test-support/test-in-debug';

module('unit/model - Model', function (hooks) {
  setupTest(hooks);
  let store, adapter;

  hooks.beforeEach(function () {
    let { owner } = this;

    class Person extends Model {
      @attr('string')
      name;
      @attr('boolean')
      isDrugAddict;
      @attr()
      isArchived;
    }

    owner.register('model:person', Person);
    owner.register(
      'adapter:application',
      JSONAPIAdapter.extend({
        shouldBackgroundReloadRecord: () => false,
      })
    );
    owner.register('serializer:-default', JSONAPISerializer);
    owner.register('serializer:application', JSONAPISerializer.extend());

    store = owner.lookup('service:store');
    adapter = store.adapterFor('application');
  });

  module('currentState', function () {
    test('supports pushedData in root.deleted.uncommitted', async function (assert) {
      let record = store.push({
        data: {
          type: 'person',
          id: '1',
        },
      });

      record.deleteRecord();

      store.push({
        data: {
          type: 'person',
          id: '1',
        },
      });

      assert.strictEqual(
        get(record, 'currentState.stateName'),
        'root.deleted.uncommitted',
        'record accepts pushedData is in root.deleted.uncommitted state'
      );
    });

    test('supports canonical updates via pushedData in root.deleted.saved', async function (assert) {
      adapter.deleteRecord = () => {
        return resolve({ data: null });
      };

      let record = store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            isArchived: false,
          },
        },
      });

      record.deleteRecord();
      await record.save();

      let currentState = record._internalModel.currentState;

      assert.strictEqual(currentState.stateName, 'root.deleted.saved', 'record is in a persisted deleted state');
      assert.true(get(record, 'isDeleted'));
      assert.notStrictEqual(
        store.peekRecord('person', '1'),
        null,
        'the deleted person is not removed from store (no unload called)'
      );

      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            isArchived: true,
          },
        },
      });

      currentState = record._internalModel.currentState;

      assert.strictEqual(currentState.stateName, 'root.deleted.saved', 'record is still in a persisted deleted state');
      assert.true(get(record, 'isDeleted'), 'The record is still deleted');
      assert.true(get(record, 'isArchived'), 'The record reflects the update to canonical state');
    });

    test('Does not support dirtying in root.deleted.saved', async function (assert) {
      adapter.deleteRecord = () => {
        return resolve({ data: null });
      };

      let record = store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            isArchived: false,
          },
        },
      });

      record.deleteRecord();
      await record.save();

      let currentState = record._internalModel.currentState;

      assert.strictEqual(currentState.stateName, 'root.deleted.saved', 'record is in a persisted deleted state');
      assert.true(get(record, 'isDeleted'));
      assert.notStrictEqual(
        store.peekRecord('person', '1'),
        null,
        'the deleted person is not removed from store (no unload called)'
      );

      if (DEBUG) {
        assert.throws(
          () => {
            set(record, 'isArchived', true);
          },
          /Attempted to set 'isArchived' to 'true' on the deleted record <person:1>/,
          'Assertion includes more context when in DEBUG'
        );
      } else {
        assert.throws(
          () => {
            set(record, 'isArchived', true);
          },
          /Attempted to set 'isArchived' on the deleted record <person:1>/,
          "Assertion does not leak the 'value'"
        );
      }

      currentState = record._internalModel.currentState;

      assert.strictEqual(currentState.stateName, 'root.deleted.saved', 'record is still in a persisted deleted state');
      assert.true(get(record, 'isDeleted'), 'The record is still deleted');
      assert.false(get(record, 'isArchived'), 'The record reflects canonical state');
    });

    test('currentState is accessible when the record is created', async function (assert) {
      let record = store.push({
        data: {
          type: 'person',
          id: '1',
        },
      });

      assert.strictEqual(
        get(record, 'currentState.stateName'),
        'root.loaded.saved',
        'records pushed into the store start in the loaded state'
      );
    });
  });

  module('ID', function () {
    test('a record reports its unique id via the `id` property', async function (assert) {
      store.push({
        data: {
          type: 'person',
          id: '1',
        },
      });

      let record = await store.findRecord('person', '1');

      assert.strictEqual(get(record, 'id'), '1', 'reports id as id by default');
    });

    test("a record's id is included in its toString representation", async function (assert) {
      let person = store.push({
        data: {
          type: 'person',
          id: '1',
        },
      });

      assert.strictEqual(
        person.toString(),
        `<dummy@model:${person.constructor.modelName}::${guidFor(person)}:1>`,
        'reports id in toString'
      );
    });

    testInDebug('trying to use `id` as an attribute should raise', async function (assert) {
      class TestModel extends Model {
        @attr('number')
        id;
        @attr('string')
        name;
      }

      this.owner.register('model:test-model', TestModel);

      assert.expectAssertion(() => {
        let ModelClass = store.modelFor('test-model');
        get(ModelClass, 'attributes');
      }, /You may not set `id` as an attribute on your model/);

      assert.expectAssertion(() => {
        store.push({
          data: {
            id: '1',
            type: 'test-model',
            attributes: {
              id: 'foo',
              name: 'bar',
            },
          },
        });
      }, /You may not set 'id' as an attribute on your model/);
    });

    test(`a collision of a record's id with object function's name`, async function (assert) {
      // see https://github.com/emberjs/ember.js/issues/4792 for an explanation of this test
      //   and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
      // this effectively tests that our identityMap does not choke on IDs that are method names
      // such as `watch` which is particularly problematic
      assert.expect(1);

      let hasWatchMethod = Object.prototype.watch;
      try {
        if (!hasWatchMethod) {
          Object.prototype.watch = function () {};
        }

        store.push({
          data: {
            type: 'person',
            id: 'watch',
          },
        });

        let record = await store.findRecord('person', 'watch');

        assert.strictEqual(get(record, 'id'), 'watch', 'record is successfully created and could be found by its id');
      } finally {
        if (!hasWatchMethod) {
          delete Object.prototype.watch;
        }
      }
    });

    test('can ask if record with a given id is loaded', async function (assert) {
      store.push({
        data: [
          {
            type: 'person',
            id: '1',
            attributes: {
              name: 'Scumbag Dale',
            },
          },
          {
            type: 'person',
            id: '2',
            attributes: {
              name: 'Scumbag Katz',
            },
          },
          {
            type: 'person',
            id: '3',
            attributes: {
              name: 'Scumbag Bryn',
            },
          },
        ],
      });

      assert.true(store.hasRecordForId('person', 1), 'should have person with id 1');
      assert.true(store.hasRecordForId('person', 1), 'should have person with id 1');
      assert.false(store.hasRecordForId('person', 4), 'should not have person with id 4');
      assert.false(store.hasRecordForId('person', 4), 'should not have person with id 4');
    });

    test('setting the id during createRecord should correctly update the id', async function (assert) {
      let person = store.createRecord('person', { id: 'john' });

      assert.strictEqual(person.get('id'), 'john', 'new id should be correctly set.');

      let record = store.peekRecord('person', 'john');

      assert.strictEqual(person, record, 'The cache has an entry for john');
    });

    test('setting the id after createRecord should correctly update the id', async function (assert) {
      let person = store.createRecord('person');

      assert.strictEqual(person.get('id'), null, 'initial created model id should be null');

      person.set('id', 'john');

      assert.strictEqual(person.get('id'), 'john', 'new id should be correctly set.');

      let record = store.peekRecord('person', 'john');

      assert.strictEqual(person, record, 'The cache has an entry for john');
    });

    testInDebug('mutating the id after createRecord but before save works', async function (assert) {
      let person = store.createRecord('person', { id: 'chris' });

      assert.strictEqual(person.get('id'), 'chris', 'initial created model id should be null');

      try {
        person.set('id', 'john');
        assert.ok(false, 'we should have thrown an error during mutation');
      } catch (e) {
        assert.ok(true, 'we did throw');
      }

      let chris = store.peekRecord('person', 'chris');
      let john = store.peekRecord('person', 'john');

      assert.ok(chris === person, 'The cache still has an entry for chris');
      assert.ok(john === null, 'The cache has no entry for john');
    });

    test('updating the id with store.setRecordId should work correctly when the id property is watched', async function (assert) {
      const OddPerson = Model.extend({
        name: DSattr('string'),
        idComputed: computed('id', function () {
          return this.get('id');
        }),
      });
      this.owner.register('model:odd-person', OddPerson);

      let person = store.createRecord('odd-person');
      let oddId = person.get('idComputed');

      assert.strictEqual(oddId, null, 'initial computed get is null');
      // test .get access of id
      assert.strictEqual(person.get('id'), null, 'initial created model id should be null');

      store.setRecordId('odd-person', 'john', person._internalModel.clientId);

      oddId = person.get('idComputed');
      assert.strictEqual(oddId, 'john', 'computed get is correct');
      // test direct access of id
      assert.strictEqual(person.id, 'john', 'new id should be correctly set.');
    });

    test('ID mutation (complicated)', async function (assert) {
      let idChange = 0;
      let compChange = 0;
      const OddPerson = Model.extend({
        name: DSattr('string'),
        idComputed: computed('id', function () {
          // we intentionally don't access the id here
          return 'not-the-id:' + compChange++;
        }),
        idDidChange: observer('id', function () {
          idChange++;
        }),
      });
      this.owner.register('model:odd-person', OddPerson);

      let person = store.createRecord('odd-person');
      assert.strictEqual(person.get('idComputed'), 'not-the-id:0');
      assert.strictEqual(idChange, 0, 'we have had no changes initially');

      let personId = person.get('id');
      assert.strictEqual(personId, null, 'initial created model id should be null');
      assert.strictEqual(idChange, 0, 'we should still have no id changes');

      // simulate an update from the store or RecordData that doesn't
      // go through the internalModelFactory
      person._internalModel.setId('john');
      assert.strictEqual(idChange, 1, 'we should have one change after updating id');
      let recordData = recordDataFor(person);
      assert.strictEqual(
        recordData.getResourceIdentifier().id,
        'john',
        'new id should be set on the identifier on record data.'
      );
      assert.strictEqual(recordData.id, 'john', 'new id should be correctly set on the record data itself.');
      assert.strictEqual(person.get('id'), 'john', 'new id should be correctly set.');
    });

    test('an ID of 0 is allowed', async function (assert) {
      store.push({
        data: {
          type: 'person',
          id: 0, // explicit number 0 to make this as risky as possible
          attributes: {
            name: 'Tom Dale',
          },
        },
      });

      // we peek it instead of getting the return of push to make sure
      // we can locate it in the identity map
      let record = store.peekRecord('person', 0);

      assert.strictEqual(record.get('name'), 'Tom Dale', 'found record with id 0');
    });
  });

  module('@attr()', function () {
    test('a Model does not require an attribute type', async function (assert) {
      class NativeTag extends Model {
        @attr()
        name;
      }
      const LegacyTag = Model.extend({
        name: DSattr(),
      });

      this.owner.register('model:native-tag', NativeTag);
      this.owner.register('model:legacy-tag', LegacyTag);

      let nativeTag = store.createRecord('native-tag', { name: 'test native' });
      let legacyTag = store.createRecord('legacy-tag', { name: 'test legacy' });

      assert.strictEqual(get(nativeTag, 'name'), 'test native', 'the value is persisted');
      assert.strictEqual(get(legacyTag, 'name'), 'test legacy', 'the value is persisted');
    });

    test('a Model can have a defaultValue without an attribute type', async function (assert) {
      class NativeTag extends Model {
        @attr({ defaultValue: 'unknown native tag' })
        name;
      }
      const LegacyTag = Model.extend({
        name: DSattr({ defaultValue: 'unknown legacy tag' }),
      });

      this.owner.register('model:native-tag', NativeTag);
      this.owner.register('model:legacy-tag', LegacyTag);

      let nativeTag = store.createRecord('native-tag');
      let legacyTag = store.createRecord('legacy-tag');

      assert.strictEqual(get(nativeTag, 'name'), 'unknown native tag', 'the default value is found');
      assert.strictEqual(get(legacyTag, 'name'), 'unknown legacy tag', 'the default value is found');
    });

    test('a defaultValue for an attribute can be a function', async function (assert) {
      class Tag extends Model {
        @attr('string', {
          defaultValue() {
            return 'le default value';
          },
        })
        createdAt;
      }
      this.owner.register('model:tag', Tag);

      let tag = store.createRecord('tag');
      assert.strictEqual(get(tag, 'createdAt'), 'le default value', 'the defaultValue function is evaluated');
    });

    test('a defaultValue function gets the record, options, and key', async function (assert) {
      assert.expect(2);
      class Tag extends Model {
        @attr('string', {
          defaultValue(record, options, key) {
            assert.deepEqual(record, tag, 'the record is passed in properly');
            assert.strictEqual(key, 'createdAt', 'the attribute being defaulted is passed in properly');
            return 'le default value';
          },
        })
        createdAt;
      }
      this.owner.register('model:tag', Tag);

      let tag = store.createRecord('tag');

      get(tag, 'createdAt');
    });

    testInDebug('We assert when defaultValue is a constant non-primitive instance', async function (assert) {
      class Tag extends Model {
        @attr({ defaultValue: [] })
        tagInfo;
      }
      this.owner.register('model:tag', Tag);

      let tag = store.createRecord('tag');

      assert.expectAssertion(() => {
        get(tag, 'tagInfo');
      }, /Non primitive defaultValues are not supported/);
    });
  });

  module('Attribute Transforms', function () {
    function converts(testName, type, provided, expected, options = {}) {
      test(testName, async function (assert) {
        let { owner } = this;
        class TestModel extends Model {
          @attr(type, options)
          name;
        }

        owner.register('model:model', TestModel);
        owner.register('serializer:model', JSONSerializer);
        store.push(store.normalize('model', { id: 1, name: provided }));
        store.push(store.normalize('model', { id: 2 }));

        let record = store.peekRecord('model', 1);

        assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected);
      });
    }

    function convertsFromServer(testName, type, provided, expected) {
      test(testName, async function (assert) {
        let { owner } = this;
        class TestModel extends Model {
          @attr(type)
          name;
        }

        owner.register('model:model', TestModel);
        owner.register('serializer:model', JSONSerializer);

        let record = store.push(
          store.normalize('model', {
            id: '1',
            name: provided,
          })
        );

        assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected);
      });
    }

    function convertsWhenSet(testName, type, provided, expected) {
      test(testName, async function (assert) {
        let { owner } = this;
        class TestModel extends Model {
          @attr(type)
          name;
        }

        owner.register('model:model', TestModel);
        owner.register('serializer:model', JSONSerializer);

        let record = store.push({
          data: {
            type: 'model',
            id: '2',
          },
        });

        set(record, 'name', provided);
        assert.deepEqual(record.serialize().name, expected, type + ' saves ' + provided + ' as ' + expected);
      });
    }

    module('String', function () {
      converts('string-to-string', 'string', 'Scumbag Tom', 'Scumbag Tom');
      converts('number-to-string', 'string', 1, '1');
      converts('empty-string-to-empty-string', 'string', '', '');
      converts('null-to-null', 'string', null, null);
    });

    module('Number', function () {
      converts('string-1-to-number-1', 'number', '1', 1);
      converts('string-0-to-number-0', 'number', '0', 0);
      converts('1-to-1', 'number', 1, 1);
      converts('0-to-0', 'number', 0, 0);
      converts('empty-string-to-null', 'number', '', null);
      converts('null-to-null', 'number', null, null);
      converts('boolean-true-to-1', 'number', true, 1);
      converts('boolean-false-to-0', 'number', false, 0);
    });

    module('Boolean', function () {
      converts('string-1-to-true', 'boolean', '1', true);
      converts('empty-string-to-false', 'boolean', '', false);
      converts('number-1-to-true', 'boolean', 1, true);
      converts('number-0-to-false', 'boolean', 0, false);

      converts('null-to-null { allowNull: true }', 'boolean', null, null, { allowNull: true });
      converts('null-to-false { allowNull: false }', 'boolean', null, false, { allowNull: false });
      converts('null-to-false', 'boolean', null, false);

      converts('boolean-true-to-true', 'boolean', true, true);
      converts('boolean-false-to-false', 'boolean', false, false);
    });

    module('Date', function () {
      converts('null-to-null', 'date', null, null);
      converts('undefined-to-undefined', 'date', undefined, undefined);

      let dateString = '2011-12-31T00:08:16.000Z';
      let date = new Date(dateString);

      convertsFromServer('string-to-Date', 'date', dateString, date);
      convertsWhenSet('Date-to-string', 'date', date, dateString);
    });
  });

  module('Reserved Props', function () {
    testInDebug(`don't allow setting of readOnly state props`, async function (assert) {
      let record = store.createRecord('person');

      assert.expectAssertion(() => {
        record.set('isLoaded', true);
      }, /Cannot set property isLoaded of \[object Object\] which has only a getter/);
    });

    class NativePostWithInternalModel extends Model {
      @attr('string')
      _internalModel;
      @attr('string')
      name;
    }
    class NativePostWithCurrentState extends Model {
      @attr('string')
      currentState;
      @attr('string')
      name;
    }
    const PROP_MAP = {
      _internalModel: NativePostWithInternalModel,
      currentState: NativePostWithCurrentState,
    };

    function testReservedProperty(prop) {
      let testName = `A subclass of Model cannot use the reserved property '${prop}'`;

      testInDebug(testName, async function (assert) {
        const NativePost = PROP_MAP[prop];
        const LegacyPost = Model.extend({
          [prop]: DSattr('string'),
          name: DSattr('string'),
        });
        this.owner.register('model:native-post', NativePost);
        this.owner.register('model:legacy-post', LegacyPost);

        const msg = `'${prop}' is a reserved property name on instances of classes extending Model.`;

        assert.throws(
          () => {
            store.createRecord('native-post', { name: 'TomHuda' });
          },
          function (e) {
            return e.message.indexOf(msg) === 0;
          },
          'We throw for native-style classes'
        );

        assert.throws(
          () => {
            store.createRecord('legacy-post', { name: 'TomHuda' });
          },
          function (e) {
            return e.message.indexOf(msg) === 0;
          },
          'We throw for legacy-style classes'
        );
      });
    }

    ['_internalModel', 'currentState'].forEach(testReservedProperty);

    testInDebug('A subclass of Model throws an error when calling create() directly', async function (assert) {
      class NativePerson extends Model {}
      const LegacyPerson = Model.extend({});

      assert.throws(
        () => {
          NativePerson.create();
        },
        /You should not call `create` on a model/,
        'Throws an error when calling create() on model'
      );

      assert.throws(
        () => {
          LegacyPerson.create();
        },
        /You should not call `create` on a model/,
        'Throws an error when calling create() on model'
      );
    });
  });

  module('init()', function () {
    test('ensure model exits loading state, materializes data and fulfills promise only after data is available', async function (assert) {
      assert.expect(2);
      adapter.findRecord = () =>
        resolve({
          data: {
            id: 1,
            type: 'person',
            attributes: { name: 'John' },
          },
        });

      let person = await store.findRecord('person', 1);

      assert.strictEqual(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state');
      assert.true(get(person, 'isLoaded'), 'model is loaded');
    });

    test('Pushing a record into the store should transition new records to the loaded state', async function (assert) {
      let person = store.createRecord('person', { id: 1, name: 'TomHuda' });

      assert.true(person.isNew, 'createRecord should put records into the new state');

      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'TomHuda',
          },
        },
      });

      assert.false(person.isNew, 'push should put move the record into the loaded state');
      assert.strictEqual(person.currentState.stateName, 'root.loaded.saved', 'model is in loaded state');
    });

    test('internalModel is ready by `init`', async function (assert) {
      let nameDidChange = 0;

      class OddNativePerson extends Model {
        @attr('string')
        name;
        init() {
          super.init(...arguments);
          this.set('name', 'my-name-set-in-init');
        }
      }
      const OddLegacyPerson = Model.extend({
        name: DSattr('string'),

        init() {
          this._super(...arguments);
          this.set('name', 'my-name-set-in-init');
        },

        nameDidChange: observer('name', () => nameDidChange++),
      });
      this.owner.register('model:native-person', OddNativePerson);
      this.owner.register('model:legacy-person', OddLegacyPerson);

      assert.strictEqual(nameDidChange, 0, 'observer should not trigger on create');
      let person = store.createRecord('legacy-person');
      assert.strictEqual(nameDidChange, 0, 'observer should not trigger on create');
      assert.strictEqual(person.get('name'), 'my-name-set-in-init');

      person = store.createRecord('native-person');
      assert.strictEqual(person.get('name'), 'my-name-set-in-init');
    });

    test('accessing attributes during init should not throw an error', async function (assert) {
      const Person = Model.extend({
        name: DSattr('string'),

        init() {
          this._super(...arguments);
          assert.strictEqual(this.get('name'), 'bam!', 'We all good here');
        },
      });
      this.owner.register('model:odd-person', Person);

      store.createRecord('odd-person', { name: 'bam!' });
    });
  });

  module('Updating', function () {
    test('a Model can update its attributes', async function (assert) {
      assert.expect(1);

      let person = store.push({
        data: {
          type: 'person',
          id: '2',
          attributes: {
            name: 'Scumbag Katz',
          },
        },
      });

      set(person, 'name', 'Brohuda Katz');
      assert.strictEqual(get(person, 'name'), 'Brohuda Katz', 'setting took hold');
    });

    test(`clearing the value when a Model's defaultValue was in use works`, async function (assert) {
      class Tag extends Model {
        @attr('string', { defaultValue: 'unknown' })
        name;
      }

      this.owner.register('model:tag', Tag);

      let tag = store.createRecord('tag');
      assert.strictEqual(get(tag, 'name'), 'unknown', 'the default value is found');

      set(tag, 'name', null);
      assert.strictEqual(get(tag, 'name'), null, `null doesn't shadow defaultValue`);
    });

    test(`a Model can define 'setUnknownProperty'`, async function (assert) {
      class NativeTag extends Model {
        @attr('string')
        name;

        setUnknownProperty(key, value) {
          if (key === 'title') {
            this.set('name', value);
          }
        }
      }
      const LegacyTag = Model.extend({
        name: DSattr('string'),

        setUnknownProperty(key, value) {
          if (key === 'title') {
            this.set('name', value);
          }
        },
      });
      this.owner.register('model:native-tag', NativeTag);
      this.owner.register('model:legacy-tag', LegacyTag);

      let legacyTag = store.createRecord('legacy-tag', { name: 'old' });
      assert.strictEqual(get(legacyTag, 'name'), 'old', 'precond - name is correct');

      set(legacyTag, 'name', 'edited');
      assert.strictEqual(get(legacyTag, 'name'), 'edited', 'setUnknownProperty was not triggered');

      set(legacyTag, 'title', 'new');
      assert.strictEqual(get(legacyTag, 'name'), 'new', 'setUnknownProperty was triggered');

      let nativeTag = store.createRecord('native-tag', { name: 'old' });
      assert.strictEqual(get(nativeTag, 'name'), 'old', 'precond - name is correct');

      set(nativeTag, 'name', 'edited');
      assert.strictEqual(get(nativeTag, 'name'), 'edited', 'setUnknownProperty was not triggered');

      set(nativeTag, 'title', 'new');
      assert.strictEqual(get(nativeTag, 'name'), 'new', 'setUnknownProperty was triggered');
    });

    test('setting a property to undefined on a newly created record should not impact the current state', async function (assert) {
      class Tag extends Model {
        @attr('string')
        tagInfo;
      }
      this.owner.register('model:tag', Tag);

      let tag = store.createRecord('tag');

      set(tag, 'name', 'testing');

      assert.strictEqual(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted');

      set(tag, 'name', undefined);

      assert.strictEqual(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted');

      tag = store.createRecord('tag', { name: undefined });

      assert.strictEqual(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted');
    });

    test('setting a property back to its original value removes the property from the `_attributes` hash', async function (assert) {
      let person = store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Scumbag Dale',
          },
        },
      });

      let recordData = recordDataFor(person);
      assert.strictEqual(recordData._attributes.name, undefined, 'the `_attributes` hash is clean');

      set(person, 'name', 'Niceguy Dale');

      assert.strictEqual(
        recordData._attributes.name,
        'Niceguy Dale',
        'the `_attributes` hash contains the changed value'
      );

      set(person, 'name', 'Scumbag Dale');

      assert.strictEqual(recordData._attributes.name, undefined, 'the `_attributes` hash is reset');
    });
  });

  module('Mutation', function () {
    test('can have properties and non-specified properties set on it', async function (assert) {
      let record = store.createRecord('person', { isDrugAddict: false, notAnAttr: 'my value' });
      set(record, 'name', 'bar');
      set(record, 'anotherNotAnAttr', 'my other value');

      assert.strictEqual(get(record, 'notAnAttr'), 'my value', 'property was set on the record');
      assert.strictEqual(get(record, 'anotherNotAnAttr'), 'my other value', 'property was set on the record');
      assert.false(get(record, 'isDrugAddict'), 'property was set on the record');
      assert.strictEqual(get(record, 'name'), 'bar', 'property was set on the record');
    });

    test('setting a property on a record that has not changed does not cause it to become dirty', async function (assert) {
      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Peter',
            isDrugAddict: true,
          },
        },
      });

      let person = await store.findRecord('person', '1');

      assert.false(person.get('hasDirtyAttributes'), 'precond - person record should not be dirty');

      person.set('name', 'Peter');
      person.set('isDrugAddict', true);

      assert.false(
        person.get('hasDirtyAttributes'),
        'record does not become dirty after setting property to old value'
      );
    });

    test('resetting a property on a record cause it to become clean again', async function (assert) {
      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Peter',
            isDrugAddict: true,
          },
        },
      });

      let person = await store.findRecord('person', '1');

      assert.false(person.get('hasDirtyAttributes'), 'precond - person record should not be dirty');

      person.set('isDrugAddict', false);

      assert.true(person.get('hasDirtyAttributes'), 'record becomes dirty after setting property to a new value');

      person.set('isDrugAddict', true);

      assert.false(person.get('hasDirtyAttributes'), 'record becomes clean after resetting property to the old value');
    });

    test('resetting a property to the current in-flight value causes it to become clean when the save completes', async function (assert) {
      adapter.updateRecord = function () {
        return resolve();
      };

      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Tom',
          },
        },
      });

      let person = store.peekRecord('person', 1);
      person.set('name', 'Thomas');

      let saving = person.save();

      assert.strictEqual(person.get('name'), 'Thomas');

      person.set('name', 'Tomathy');
      assert.strictEqual(person.get('name'), 'Tomathy');

      person.set('name', 'Thomas');
      assert.strictEqual(person.get('name'), 'Thomas');

      await saving;

      assert.false(person.get('hasDirtyAttributes'), 'The person is now clean');
    });

    test('a record becomes clean again only if all changed properties are reset', async function (assert) {
      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Peter',
            isDrugAddict: true,
          },
        },
      });

      let person = await store.findRecord('person', 1);

      assert.false(person.get('hasDirtyAttributes'), 'precond - person record should not be dirty');
      person.set('isDrugAddict', false);
      assert.true(person.get('hasDirtyAttributes'), 'record becomes dirty after setting one property to a new value');
      person.set('name', 'Mark');
      assert.true(person.get('hasDirtyAttributes'), 'record stays dirty after setting another property to a new value');
      person.set('isDrugAddict', true);
      assert.true(
        person.get('hasDirtyAttributes'),
        'record stays dirty after resetting only one property to the old value'
      );
      person.set('name', 'Peter');
      assert.false(
        person.get('hasDirtyAttributes'),
        'record becomes clean after resetting both properties to the old value'
      );
    });

    test('an invalid record becomes clean again if changed property is reset', async function (assert) {
      adapter.updateRecord = () => {
        return reject(
          new InvalidError([
            {
              source: {
                pointer: '/data/attributes/name',
              },
            },
          ])
        );
      };

      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Peter',
            isDrugAddict: true,
          },
        },
      });

      let person = store.peekRecord('person', 1);

      assert.false(person.get('hasDirtyAttributes'), 'precond - person record should not be dirty');
      person.set('name', 'Wolf');
      assert.true(person.get('hasDirtyAttributes'), 'record becomes dirty after setting one property to a new value');

      await person
        .save()
        .then(() => {
          assert.ok(false, 'We should reject the save');
        })
        .catch(() => {
          assert.false(person.get('isValid'), 'record is not valid');
          assert.true(person.get('hasDirtyAttributes'), 'record still has dirty attributes');

          person.set('name', 'Peter');

          assert.true(person.get('isValid'), 'record is valid after resetting attribute to old value');
          assert.false(
            person.get('hasDirtyAttributes'),
            'record becomes clean after resetting property to the old value'
          );
        });
    });

    test('an invalid record stays dirty if only invalid property is reset', async function (assert) {
      adapter.updateRecord = () => {
        return reject(
          new InvalidError([
            {
              source: {
                pointer: '/data/attributes/name',
              },
            },
          ])
        );
      };

      store.push({
        data: {
          type: 'person',
          id: '1',
          attributes: {
            name: 'Peter',
            isDrugAddict: true,
          },
        },
      });

      let person = store.peekRecord('person', 1);

      assert.false(person.get('hasDirtyAttributes'), 'precond - person record should not be dirty');
      person.set('name', 'Wolf');
      person.set('isDrugAddict', false);
      assert.true(person.get('hasDirtyAttributes'), 'record becomes dirty after setting one property to a new value');

      await person
        .save()
        .then(() => {
          assert.ok(false, 'save should have rejected');
        })
        .catch(() => {
          assert.false(person.get('isValid'), 'record is not valid');
          assert.true(person.get('hasDirtyAttributes'), 'record still has dirty attributes');

          person.set('name', 'Peter');

          assert.true(person.get('isValid'), 'record is valid after resetting invalid attribute to old value');
          assert.true(person.get('hasDirtyAttributes'), 'record still has dirty attributes');
        });
    });

    test('it should cache attributes', async function (assert) {
      class Post extends Model {
        @attr('string')
        updatedAt;
      }
      this.owner.register('model:post', Post);

      let dateString = 'Sat, 31 Dec 2011 00:08:16 GMT';
      let date = new Date(dateString);

      store.push({
        data: {
          type: 'post',
          id: '1',
        },
      });

      let record = await store.findRecord('post', '1');

      record.set('updatedAt', date);

      assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date');
      assert.strictEqual(
        get(record, 'updatedAt'),
        get(record, 'updatedAt'),
        'second get still returns the same object'
      );
    });

    test('changedAttributes() return correct values', async function (assert) {
      class Mascot extends Model {
        @attr('string')
        name;
        @attr('string')
        likes;
        @attr('boolean')
        isMascot;
      }

      this.owner.register('model:mascot', Mascot);

      let mascot = store.push({
        data: {
          type: 'mascot',
          id: '1',
          attributes: {
            likes: 'JavaScript',
            isMascot: true,
          },
        },
      });

      assert.strictEqual(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes');

      mascot.set('name', 'Tomster'); // new value
      mascot.set('likes', 'Ember.js'); // changed value
      mascot.set('isMascot', true); // same value

      let changedAttributes = mascot.changedAttributes();

      assert.deepEqual(changedAttributes.name, [undefined, 'Tomster']);
      assert.deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']);

      mascot.rollbackAttributes();

      assert.strictEqual(
        Object.keys(mascot.changedAttributes()).length,
        0,
        'after rollback attributes there are no changes'
      );
    });

    test('changedAttributes() works while the record is being saved', async function (assert) {
      assert.expect(1);
      class Mascot extends Model {
        @attr('string')
        name;
        @attr('string')
        likes;
        @attr('boolean')
        isMascot;
      }

      this.owner.register('model:mascot', Mascot);
      adapter.createRecord = function () {
        assert.deepEqual(cat.changedAttributes(), {
          name: [undefined, 'Argon'],
          likes: [undefined, 'Cheese'],
        });

        return resolve({ data: { id: 1, type: 'mascot' } });
      };

      let cat;

      cat = store.createRecord('mascot');
      cat.setProperties({
        name: 'Argon',
        likes: 'Cheese',
      });

      await cat.save();
    });

    test('changedAttributes() works while the record is being updated', async function (assert) {
      assert.expect(1);
      let cat;

      class Mascot extends Model {
        @attr('string')
        name;
        @attr('string')
        likes;
        @attr('boolean')
        isMascot;
      }

      this.owner.register('model:mascot', Mascot);
      adapter.updateRecord = function () {
        assert.deepEqual(cat.changedAttributes(), {
          name: ['Argon', 'Helia'],
          likes: ['Cheese', 'Mussels'],
        });

        return { data: { id: '1', type: 'mascot' } };
      };

      cat = store.push({
        data: {
          type: 'mascot',
          id: '1',
          attributes: {
            name: 'Argon',
            likes: 'Cheese',
          },
        },
      });

      cat.setProperties({
        name: 'Helia',
        likes: 'Mussels',
      });

      await cat.save();
    });

    if (gte('3.10.0')) {
      test('@attr decorator works without parens', async function (assert) {
        assert.expect(1);
        let cat;

        class Mascot extends Model {
          @attr name;
        }

        this.owner.register('model:mascot', Mascot);
        adapter.updateRecord = function () {
          assert.deepEqual(cat.changedAttributes(), {
            name: ['Argon', 'Helia'],
          });

          return { data: { id: '1', type: 'mascot' } };
        };

        cat = store.push({
          data: {
            type: 'mascot',
            id: '1',
            attributes: {
              name: 'Argon',
            },
          },
        });

        cat.setProperties({
          name: 'Helia',
        });

        await cat.save();
      });
    }
  });

  module('Misc', function () {
    testInDebug('Calling record.attr() asserts', async function (assert) {
      let person = store.createRecord('person', { id: 1, name: 'TomHuda' });

      assert.expectAssertion(() => {
        person.attr();
      }, /Assertion Failed: The `attr` method is not available on Model, a Snapshot was probably expected\. Are you passing a Model instead of a Snapshot to your serializer\?/);
    });
  });
});


text:
module Clusters
  module Applications
    class PrometheusUpdateService < BaseHelmService
      attr_accessor :project

      def initialize(app, project)
        super(app)
        @project = project
      end

      def execute
        app.make_updating!

        helm_api.update(patch_command(values))

        ::ClusterWaitForAppUpdateWorker.perform_in(::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id)
      rescue ::Kubeclient::HttpError => ke
        app.make_update_errored!("Kubernetes error: #{ke.message}")
      rescue StandardError => e
        app.make_update_errored!(e.message)
      end

      private

      def values
        PrometheusConfigService
          .new(project, cluster, app)
          .execute
          .to_yaml
      end
    end
  end
end


text:
package net.bytebuddy.dynamic.scaffold.inline;

import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.asm.ClassVisitorWrapper;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.BridgeMethodResolver;
import net.bytebuddy.dynamic.scaffold.FieldRegistry;
import net.bytebuddy.dynamic.scaffold.MethodRegistry;
import net.bytebuddy.instrumentation.Instrumentation;
import net.bytebuddy.instrumentation.LoadedTypeInitializer;
import net.bytebuddy.instrumentation.attribute.FieldAttributeAppender;
import net.bytebuddy.instrumentation.attribute.MethodAttributeAppender;
import net.bytebuddy.instrumentation.attribute.TypeAttributeAppender;
import net.bytebuddy.instrumentation.field.FieldDescription;
import net.bytebuddy.instrumentation.method.MethodDescription;
import net.bytebuddy.instrumentation.method.MethodList;
import net.bytebuddy.instrumentation.method.MethodLookupEngine;
import net.bytebuddy.instrumentation.method.bytecode.ByteCodeAppender;
import net.bytebuddy.instrumentation.method.bytecode.stack.constant.TextConstant;
import net.bytebuddy.instrumentation.type.InstrumentedType;
import net.bytebuddy.instrumentation.type.TypeDescription;
import net.bytebuddy.instrumentation.type.TypeList;
import net.bytebuddy.modifier.Visibility;
import net.bytebuddy.test.utility.MockitoRule;
import net.bytebuddy.test.utility.ObjectPropertyAssertion;
import net.bytebuddy.utility.RandomString;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.asm.Type;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static net.bytebuddy.matcher.ElementMatchers.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;

public class InlineDynamicTypeBuilderTest {

    private static final String FOOBAR = "foo.Bar", FOO = "foo", BAR = "bar", QUX = "qux", BAZ = "baz";

    @Rule
    public TestRule mockitoRule = new MockitoRule(this);

    @Mock
    private Instrumentation simpleInstrumentation, preparingInstrumentation, typeInitializerInstrumentation, fieldCacheInstrumentation;

    @Mock
    private ByteCodeAppender byteCodeAppender, typeInitializerAppender, fieldCacheAppender;

    @Mock
    private LoadedTypeInitializer loadedTypeInitializer;

    @Before
    public void setUp() throws Exception {
        when(simpleInstrumentation.prepare(any(InstrumentedType.class))).then(new Answer<InstrumentedType>() {
            @Override
            public InstrumentedType answer(InvocationOnMock invocation) throws Throwable {
                return (InstrumentedType) invocation.getArguments()[0];
            }
        });
        when(simpleInstrumentation.appender(any(Instrumentation.Target.class))).thenReturn(byteCodeAppender);
        when(byteCodeAppender.appendsCode()).thenReturn(true);
        when(byteCodeAppender.apply(any(MethodVisitor.class), any(Instrumentation.Context.class), any(MethodDescription.class)))
                .thenAnswer(new Answer<ByteCodeAppender.Size>() {
                    @Override
                    public ByteCodeAppender.Size answer(InvocationOnMock invocation) throws Throwable {
                        MethodVisitor methodVisitor = (MethodVisitor) invocation.getArguments()[0];
                        MethodDescription methodDescription = (MethodDescription) invocation.getArguments()[2];
                        methodVisitor.visitInsn(Opcodes.ICONST_0);
                        methodVisitor.visitInsn(Opcodes.IRETURN);
                        return new ByteCodeAppender.Size(1, methodDescription.getStackSize());
                    }
                });
        when(preparingInstrumentation.prepare(any(InstrumentedType.class))).then(new Answer<InstrumentedType>() {
            @Override
            public InstrumentedType answer(InvocationOnMock invocation) throws Throwable {
                return ((InstrumentedType) invocation.getArguments()[0])
                        .withField(BAZ, new TypeDescription.ForLoadedType(Object.class), 0)
                        .withMethod(QUX, new TypeDescription.ForLoadedType(int.class), Collections.<TypeDescription>emptyList(), Collections.<TypeDescription>emptyList(), 0)
                        .withInitializer(loadedTypeInitializer);
            }
        });
        when(preparingInstrumentation.appender(any(Instrumentation.Target.class))).thenReturn(byteCodeAppender);
        when(typeInitializerInstrumentation.prepare(any(InstrumentedType.class))).then(new Answer<InstrumentedType>() {
            @Override
            public InstrumentedType answer(InvocationOnMock invocation) throws Throwable {
                return (InstrumentedType) invocation.getArguments()[0];
            }
        });
        when(typeInitializerInstrumentation.appender(any(Instrumentation.Target.class))).thenReturn(typeInitializerAppender);
        when(typeInitializerAppender.appendsCode()).thenReturn(true);
        when(typeInitializerAppender.apply(any(MethodVisitor.class), any(Instrumentation.Context.class), any(MethodDescription.class)))
                .thenAnswer(new Answer<ByteCodeAppender.Size>() {
                    @Override
                    public ByteCodeAppender.Size answer(InvocationOnMock invocation) throws Throwable {
                        MethodVisitor methodVisitor = (MethodVisitor) invocation.getArguments()[0];
                        MethodDescription methodDescription = (MethodDescription) invocation.getArguments()[2];
                        methodVisitor.visitInsn(Opcodes.ICONST_1);
                        methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, Type.getInternalName(Foo.class), FOO, Type.getDescriptor(int.class));
                        methodVisitor.visitInsn(Opcodes.RETURN);
                        return new ByteCodeAppender.Size(1, methodDescription.getStackSize());
                    }
                });
        when(fieldCacheInstrumentation.prepare(any(InstrumentedType.class))).then(new Answer<InstrumentedType>() {
            @Override
            public InstrumentedType answer(InvocationOnMock invocation) throws Throwable {
                return (InstrumentedType) invocation.getArguments()[0];
            }
        });
        when(fieldCacheInstrumentation.appender(any(Instrumentation.Target.class))).thenReturn(fieldCacheAppender);
        when(fieldCacheAppender.appendsCode()).thenReturn(true);
        when(fieldCacheAppender.apply(any(MethodVisitor.class), any(Instrumentation.Context.class), any(MethodDescription.class)))
                .thenAnswer(new Answer<ByteCodeAppender.Size>() {
                    @Override
                    public ByteCodeAppender.Size answer(InvocationOnMock invocation) throws Throwable {
                        MethodVisitor methodVisitor = (MethodVisitor) invocation.getArguments()[0];
                        Instrumentation.Context instrumentationContext = (Instrumentation.Context) invocation.getArguments()[1];
                        MethodDescription methodDescription = (MethodDescription) invocation.getArguments()[2];
                        FieldDescription fieldDescription = instrumentationContext.cache(new TextConstant(BAR),
                                new TypeDescription.ForLoadedType(String.class));
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC,
                                fieldDescription.getDeclaringType().getInternalName(),
                                fieldDescription.getInternalName(),
                                fieldDescription.getDescriptor());
                        methodVisitor.visitInsn(Opcodes.ARETURN);
                        return new ByteCodeAppender.Size(1, methodDescription.getStackSize());
                    }
                });
    }

    @Test
    public void testPlainRebasing() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                new InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation(new MethodRebaseResolver.MethodNameTransformer.Suffixing()))
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(2));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(not(named(FOO)).and(isMethod()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(2));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(takesArguments(1).and(isConstructor()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testPlainRedefinition() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.INSTANCE)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(1));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(1));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRebasingWithDefinedField() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                new InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation(new MethodRebaseResolver.MethodNameTransformer.Suffixing()))
                .defineField(BAR, long.class, Visibility.PUBLIC)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(2));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredField(BAR).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertEquals(long.class, loaded.getDeclaredField(BAR).getType());
        assertThat(loaded.getDeclaredMethods().length, is(2));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(not(named(FOO)).and(isMethod()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(2));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(takesArguments(1).and(isConstructor()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRedefinitionWithDefinedField() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.INSTANCE)
                .defineField(BAR, long.class, Visibility.PUBLIC)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(2));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredField(BAR).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertEquals(long.class, loaded.getDeclaredField(BAR).getType());
        assertThat(loaded.getDeclaredMethods().length, is(1));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(1));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRebasingWithDefinedMethod() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                new InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation(new MethodRebaseResolver.MethodNameTransformer.Suffixing()))
                .defineMethod(BAR, int.class, Arrays.<Class<?>>asList(long.class, Object.class), Visibility.PUBLIC)
                .intercept(simpleInstrumentation)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(3));
        Method method = loaded.getDeclaredMethod(BAR, long.class, Object.class);
        assertThat(method.getName(), is(BAR));
        assertThat(method.getDeclaredAnnotations().length, is(0));
        assertEquals(int.class, method.getReturnType());
        assertThat(method.getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(not(named(FOO).or(named(BAR))).and(isMethod()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(2));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(takesArguments(1).and(isConstructor()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRedefinitionWithDefinedMethod() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.INSTANCE)
                .defineMethod(BAR, int.class, Arrays.<Class<?>>asList(long.class, Object.class), Visibility.PUBLIC)
                .intercept(simpleInstrumentation)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(2));
        Method method = loaded.getDeclaredMethod(BAR, long.class, Object.class);
        assertThat(method.getName(), is(BAR));
        assertThat(method.getDeclaredAnnotations().length, is(0));
        assertEquals(int.class, method.getReturnType());
        assertThat(method.getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(1));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRebasingWithDefinedAbstractMethod() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                new InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation(new MethodRebaseResolver.MethodNameTransformer.Suffixing()))
                .defineMethod(BAR, int.class, Arrays.<Class<?>>asList(long.class, Object.class), Visibility.PUBLIC)
                .throwing(IOException.class)
                .withoutCode()
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(3));
        Method method = loaded.getDeclaredMethod(BAR, long.class, Object.class);
        assertThat(method.getName(), is(BAR));
        assertThat(method.getExceptionTypes().length, is(1));
        assertThat(Arrays.asList(method.getExceptionTypes()), hasItem(IOException.class));
        assertThat(method.getDeclaredAnnotations().length, is(0));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(not(named(FOO).or(named(BAR))).and(isMethod()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(2));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(new MethodList.ForLoadedType(loaded).filter(takesArguments(1).and(isConstructor()))
                .getOnly().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER));
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testRedefinitionWithDefinedAbstractMethod() throws Exception {
        Class<?> loaded = new InlineDynamicTypeBuilder<Foo>(ClassFileVersion.forCurrentJavaVersion(),
                new NamingStrategy.Fixed(FOOBAR),
                new TypeDescription.ForLoadedType(Foo.class),
                new TypeList.ForLoadedType(Collections.<Class<?>>singletonList(Serializable.class)),
                Opcodes.ACC_PUBLIC,
                TypeAttributeAppender.NoOp.INSTANCE,
                isDeclaredBy(Object.class),
                BridgeMethodResolver.Simple.Factory.FAIL_FAST,
                new ClassVisitorWrapper.Chain(),
                new FieldRegistry.Default(),
                new MethodRegistry.Default(),
                MethodLookupEngine.Default.Factory.INSTANCE,
                FieldAttributeAppender.NoOp.INSTANCE,
                MethodAttributeAppender.NoOp.INSTANCE,
                ClassFileLocator.ForClassLoader.ofClassPath(),
                InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.INSTANCE)
                .defineMethod(BAR, int.class, Arrays.<Class<?>>asList(long.class, Object.class), Visibility.PUBLIC)
                .throwing(IOException.class)
                .withoutCode()
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        assertThat(loaded.getName(), is(FOOBAR));
        assertThat(loaded.getModifiers(), is(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)); // Static is implicit due to inner class inheritance.
        assertThat(loaded.getAnnotation(Bar.class), notNullValue());
        assertThat(Serializable.class.isAssignableFrom(loaded), is(true));
        assertThat(loaded.getDeclaredFields().length, is(1));
        assertThat(loaded.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL));
        assertThat(loaded.getDeclaredField(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredField(FOO).getType());
        assertThat(loaded.getDeclaredMethods().length, is(2));
        Method method = loaded.getDeclaredMethod(BAR, long.class, Object.class);
        assertThat(method.getName(), is(BAR));
        assertThat(method.getExceptionTypes().length, is(1));
        assertThat(Arrays.asList(method.getExceptionTypes()), hasItem(IOException.class));
        assertThat(method.getDeclaredAnnotations().length, is(0));
        assertThat(loaded.getDeclaredMethod(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredMethod(FOO).getAnnotation(Bar.class), notNullValue());
        assertEquals(String.class, loaded.getDeclaredMethod(FOO).getReturnType());
        assertThat(loaded.getDeclaredConstructors().length, is(1));
        assertThat(loaded.getDeclaredConstructor().getModifiers(), is(Opcodes.ACC_PUBLIC));
        assertThat(loaded.getDeclaredConstructor().getAnnotation(Bar.class), notNullValue());
        assertThat(loaded.getDeclaredMethod(FOO).invoke(loaded.newInstance()), is((Object) FOO));
    }

    @Test
    public void testObjectProperties() throws Exception {
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.class).create(new ObjectPropertyAssertion.Creator<List<?>>() {
            @Override
            public List<?> create() {
                return Collections.singletonList(new Object());
            }
        }).apply();
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.TargetHandler.Prepared.ForRebaseInstrumentation.class).refine(new ObjectPropertyAssertion.Refinement<DynamicType>() {
            @Override
            public void apply(DynamicType mock) {
                when(mock.getTypeDescription()).thenReturn(Mockito.mock(TypeDescription.class));
            }
        }).refine(new ObjectPropertyAssertion.Refinement<RandomString>() {
            @Override
            public void apply(RandomString mock) {
                when(mock.nextString()).thenReturn(FOO + System.identityHashCode(mock));
            }
        }).apply();
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.class).apply();
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation.class).apply();
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.TargetHandler.Prepared.ForRebaseInstrumentation.MethodRebaseDelegation.class).apply();
        ObjectPropertyAssertion.of(InlineDynamicTypeBuilder.TargetHandler.Prepared.ForRebaseInstrumentation.MethodRebaseDelegation.Factory.class).apply();
    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Bar {
        /* example annotation */
    }

    @Bar
    public static class Foo {

        @Bar
        private final String foo;

        @Bar
        public Foo() {
            foo = FOO;
        }

        @Bar
        public String foo() {
            return FOO;
        }
    }
}


text:
<?php
#root
const VIDEOCENTRO = 'videocentro/';
# acciones
const CREATE = 		'create';
const READ = 			'read';
const UPDATE = 		'update';
const DELETE = 		'delete';
const DETAIL = 		'detail';
const LIST_ALL = 	'list_all';

# vistas
const VIEW_CREATE = 	'agregar';
const VIEW_READ = 		'buscar';
const VIEW_UPDATE = 	'modificar';
const VIEW_DELETE = 	'borrar';
const VIEW_LIST_ALL = 'listar';
const VIEW_DETAIL =		'detalle';

# resultados por página
const PAGE_SIZE = 5;
?>


text:
<?php

namespace Floppy\Server\RequestHandler\Exception;

use Exception;
use Floppy\Common\Exception\StorageException;

class FileSourceNotFoundException extends Exception implements StorageException
{
}


text:
'use strict';

const MonitoringModule = require('./module').MonitoringModule;
const logger = require('../core').logger;

module.exports = (agent, options) => {
    let module = new MonitoringModule(agent, options);

    logger.info(`Init "${module.name.toUpperCase()}" module. Version - ${module.version}`);

    return {
        module: module,
        middlewares: require('./middlewares')(module)
    };
};


text:
namespace Twin.Forms
{
	using System;
	using System.Drawing;
	using System.Windows.Forms;
	using System.Collections.Generic;
	using Twin.Bbs;
	using Twin.Properties;

	/// <summary>
	/// ƒ^ƒuŠÖ˜A'̃†[ƒeƒBƒŠƒeƒBŒQ
	/// </summary>
	public class TabUtility
	{
		private static TabPage lastSelectedTab;
		private static bool isDraging;

		// ƒ^ƒu'ðˆÚ"®'·'éæ'É' 'éA‹'²•\Ž¦'³'ê'éƒ^ƒu
		private static TabPage dropPositionTab = null;
		private static Rectangle prevDrawRect = Rectangle.Empty;

		/// <summary>
		/// ÅŒã'É'I'ð'³'ê'½ƒ^ƒu'ðŽæ"¾'µ'Ü'·B
		/// </summary>
		public static TabPage SelectedTab
		{
			get
			{
				return lastSelectedTab;
			}
		}

		public static event EventHandler ChangedPosition;

		static TabUtility()
		{
		}

		/// <summary>
		/// Žw'肵'½ƒ^ƒuƒRƒ"ƒgƒ[ƒ‹'̃}ƒEƒXƒNƒŠƒbƒN'ðŠÄŽ‹'·'éƒCƒxƒ"ƒgƒnƒ"ƒhƒ‰'ðÝ'肵'Ü'·B
		/// </summary>
		/// <param name="tabctrl"></param>
		public static void SetTabControl(TabControl tabctrl)
		{
			tabctrl.MouseDown += new MouseEventHandler(OnMouseDown);
			tabctrl.MouseMove += new MouseEventHandler(OnMouseMove);
			tabctrl.MouseUp += new MouseEventHandler(OnMouseUp);
		}

		/// <summary>
		/// ƒ}ƒEƒX'ªƒNƒŠƒbƒN'³'ꂽ'Æ'«'ɍÀ•WˆÊ'u'É' 'éƒ^ƒu'ðŽæ"¾'µ'Ü'·B
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void OnMouseDown(object sender, MouseEventArgs e)
		{
			TabControl tabctrl = (TabControl)sender;

			lastSelectedTab = GetItemAt(tabctrl, e.X, e.Y);

			if (lastSelectedTab != null && e.Button != MouseButtons.Left)
			{
				tabctrl.SelectedTab = lastSelectedTab;
			}
		}

		private static void OnMouseMove(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				isDraging = true;

				TabControl tabctrl = (TabControl)sender;

				// ˆÚ"®æ'̈ʒu'ð'í'©'è'â'·''·'邽'߁Aƒ}ƒEƒX'¼‰º'̃^ƒu'ð‹'²•\Ž¦'·'é
				TabPage currentTab = GetItemAt(tabctrl, e.X, e.Y);

				if (currentTab == null)
					return;

				if (lastSelectedTab == currentTab || dropPositionTab == currentTab)
					return;

				HighlightTab(tabctrl, currentTab);

				dropPositionTab = currentTab;
			}
			else if (e.Button == MouseButtons.None)
			{
			}
		}

		/// <summary>
		/// ƒ}ƒEƒX'ªƒNƒŠƒbƒN'³'ꂽ'Æ'«'ɍÀ•WˆÊ'u'É' 'éƒ^ƒu'ðŽæ"¾
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void OnMouseUp(object sender, MouseEventArgs e)
		{
			TabControl tabctrl = (TabControl)sender;

			if (e.Button == MouseButtons.Left)
			{
				TabPage target = GetItemAt(tabctrl, e.X, e.Y);
				if (isDraging && target != null && lastSelectedTab != target)
				{
					ChangePosition(tabctrl,
						tabctrl.TabPages.IndexOf(lastSelectedTab),
						tabctrl.TabPages.IndexOf(target));
				}
				isDraging = false;
			}

			dropPositionTab = null;

			if (prevDrawRect != Rectangle.Empty)
			{
				tabctrl.Invalidate(prevDrawRect);
				prevDrawRect = Rectangle.Empty;
			}
		}

		/// <summary>
		/// ƒ^ƒu'̈ʒu'ð•ÏX
		/// </summary>
		/// <param name="ctrl">ƒ^ƒuƒRƒ"ƒgƒ[ƒ‹</param>
		/// <param name="from">•ÏX'·'éƒ^ƒuƒy[ƒW'̃Cƒ"ƒfƒbƒNƒX</param>
		/// <param name="to">ˆÚ"®æ'̃^ƒuƒy[ƒWƒRƒŒƒNƒVƒ‡ƒ""àƒCƒ"ƒfƒbƒNƒX</param>
		public static void ChangePosition(TabControl ctrl, int from, int to)
		{
			if (ctrl == null)
			{
				throw new ArgumentNullException("ctrl");
			}

			if (from < 0 || from >= ctrl.TabCount ||
				to < 0 || to > ctrl.TabCount)
			{
				return;
			}

			TabPage target = ctrl.TabPages[from];
			ctrl.Enabled = false;
			ctrl.SuspendLayout();
			ctrl.SelectedTab = null;
			ctrl.TabPages.Remove(target);
			ctrl.TabPages.Insert(to, target);
			ctrl.SelectedTab = null;
			ctrl.SelectedTab = target;
			ctrl.ResumeLayout();
			ctrl.Enabled = true;

			OnChangedPosition(ctrl);
		}

		/// <summary>
		/// Žw'肵'½À•W'É' 'éƒ^ƒuƒy[ƒW'ðŽæ"¾
		/// </summary>
		/// <param name="tabctrl"></param>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public static TabPage GetItemAt(TabControl tabctrl, int x, int y)
		{
			if (tabctrl == null)
			{
				throw new ArgumentNullException("tabctrl");
			}
			for (int i = 0; i < tabctrl.TabCount; i++)
			{
				Rectangle rect = tabctrl.GetTabRect(i);
				if (rect.Contains(x, y))
				{
					return tabctrl.TabPages[i];
				}
			}
			return null;
		}

		public static TabPage GetItemAt(TabControl tabctrl, Point location)
		{
			return GetItemAt(tabctrl, location.X, location.Y);
		}

		/// <summary>
		/// Žw'肵'½ƒ^ƒu'ð‹'²•\Ž¦
		/// </summary>
		/// <param name="tab"></param>
		public static void HighlightTab(TabControl ctrl, TabPage tab)
		{
			if (tab == null)
				return;

			int index = ctrl.TabPages.IndexOf(tab);

			if (index == -1)
				return;

			Rectangle rc = ctrl.GetTabRect(index);

			// 'O‰ñ•`‰æ'µ'½ƒ^ƒu'ðÄ•`‰æ
			if (prevDrawRect != Rectangle.Empty)
			{
				ctrl.Invalidate(prevDrawRect);
			}

			// ƒ^ƒu'ÌŽw'肵'½ˆÊ'u (style) 'Ƀ‰ƒCƒ"'ðˆø'
			using (Graphics g = ctrl.CreateGraphics())
			{
				Color baseColor = Color.FromArgb(100, ControlPaint.Light(SystemColors.Highlight));
				Brush brush = new SolidBrush(baseColor);

				g.FillRectangle(brush, rc);

				brush.Dispose();
			}

			prevDrawRect = rc;
		}

		/// <summary>
		/// Žw'肵'½ƒ^ƒu'ð•`‰æ
		/// </summary>
		/// <param name="control"></param>
		/// <param name="e"></param>
		public static void DrawItem<THeader, TControl>(TabControl control,
			DrawItemEventArgs e) where TControl : ClientBase//Ex<THeader>
		{
			if (control == null)
			{
				throw new ArgumentNullException("control");
			}
			if (e == null)
			{
				throw new ArgumentNullException("e");
			}
			if (e.Index < 0 || e.Index >= control.TabCount)
				return;

			TabPage tab = control.TabPages[e.Index];
			Image image = null;
			int imgheight = 0;
			int imgwidth = 0;

			if (tab.Tag == null)
				throw new NullReferenceException("tab.Tag is null");

			TwinWindow<THeader, TControl> window =
				(TwinWindow<THeader, TControl>)tab.Tag;

			StringFormat format = new StringFormat();
			format.Alignment = StringAlignment.Center;
			format.LineAlignment = StringAlignment.Center;
			format.FormatFlags = StringFormatFlags.NoWrap;

			if (control.Alignment == TabAlignment.Left ||
				control.Alignment == TabAlignment.Right)
			{
				format.FormatFlags |= StringFormatFlags.DirectionVertical;
			}

			// 'È'º'©•`‰æˆÊ'u'ª'¸'ê'é'̂ŕ␳
			if (control.Alignment == TabAlignment.Top &&
				control.SelectedTab != tab)
			{
				imgheight = 3;
			}

			if (tab.ImageIndex != -1)
			{
				image =
					control.ImageList.Images[tab.ImageIndex];

				if (control.Alignment == TabAlignment.Left ||
					control.Alignment == TabAlignment.Right)
				{
					imgheight += image.Height + 5;
				}
				else
				{
					imgwidth = image.Width + 5;
				}
			}

			Rectangle rect = new Rectangle(
				imgwidth + e.Bounds.X, imgheight + e.Bounds.Y,
				e.Bounds.Width - imgwidth, e.Bounds.Height - imgheight);

			Brush backBrush, foreBrush;
			bool isColoring = !window.ColorSet.IsDefaultColor;

			if (e.State == DrawItemState.Selected)
			{
				backBrush = new SolidBrush(
					isColoring ? window.ColorSet.ActiveBackColor : SystemColors.Control);

				foreBrush = new SolidBrush(
					isColoring ? window.ColorSet.ActiveForeColor : SystemColors.ControlText);
			}
			else
			{
				backBrush = new SolidBrush(
					isColoring ? window.ColorSet.DeactiveBackColor : SystemColors.ControlDark);

				foreBrush = new SolidBrush(
					isColoring ? window.ColorSet.DeactiveForeColor : SystemColors.ControlLightLight);
			}

			e.Graphics.FillRectangle(backBrush, e.Bounds);
			e.Graphics.DrawString(tab.Text, e.Font, foreBrush, rect, format);

			backBrush.Dispose();
			foreBrush.Dispose();

			// 'I'𒆂̃^ƒu'ð‹'²•\Ž¦'·'é
			Color c = Twinie.Settings.Design.TabHighlightColor;
			if (! c.IsEmpty && e.State == DrawItemState.Selected)
			{
				Rectangle rc = e.Bounds;
				rc.Inflate(-1, -1);

				using (Pen pen = new Pen(c, 2))
					e.Graphics.DrawRectangle(pen, rc);
			}

			if (image != null)
			{
				int left = (image.Width + 5) / 2;

				e.Graphics.DrawImage(image,
					e.Bounds.X + left, e.Bounds.Y + left,
					image.Width, image.Height);
			}

			// "d‹CƒAƒCƒRƒ"'ð•`‰æ
			if (window.Referenced)
			{
				using (var denki = (Bitmap)Resources.denki.Clone())
				{
					denki.MakeTransparent(Color.White);
					int y = e.Bounds.Top + 3;//(e.Bounds.Height - denki.Height) / 2;
					int x = e.Bounds.Left;
					e.Graphics.DrawImage(denki, x, y);
				}
			}
		}

		private static void OnChangedPosition(TabControl tab)
		{
			if (ChangedPosition != null)
				ChangedPosition(tab, EventArgs.Empty);
		}
	}

}