text:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package graphics;

import controlegastos.*;

import bd.Conection;
import java.awt.Graphics;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JScrollPane;
import javax.swing.JTable;

/**
 *
 * @author maxx
 */
public class mainMenu extends javax.swing.JFrame {

    /**
     * Creates new form mainMenu
     */
    public mainMenu() {
        new Conection();
        initComponents();
        run();
    }

    public void run() {
        String query = "SELECT `descricao`, `valor`, `necessário` FROM `gastos` WHERE `mes` = " + jComboBox1.getSelectedItem().toString();
        ResultSet rs = Conection.sql(query);
        jTable1.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        try {
            jTable1.setModel(new ResultSetTable(rs));

            query = "SELECT SUM(`valor`) AS `sum` FROM `gastos` WHERE `mes` = " + jComboBox1.getSelectedItem().toString();
            rs = Conection.sql(query);
            if(rs.next() && rs.getString("sum") != null)
                jLabelec.setText(String.valueOf(ControleGastos.salario-Double.parseDouble(rs.getString("sum"))));
            else
                jLabelec.setText("0");

            query = "SELECT SUM(`valor`) AS `sum` FROM `gastos` WHERE `mes` = " + jComboBox1.getSelectedItem().toString() + " AND `necessário` = 1";
            rs = Conection.sql(query);
            if(rs.next() && rs.getString("sum") != null)
                jLabelnec.setText(rs.getString("sum"));
            else
                jLabelnec.setText("0");

            query = "SELECT SUM(`valor`) AS `sum` FROM `gastos` WHERE `mes` = " + jComboBox1.getSelectedItem().toString() + " AND `necessário` = 0";
            rs = Conection.sql(query);
            if(rs.next() && rs.getString("sum") != null)
                jLabeldes.setText(rs.getString("sum"));
            else
                jLabeldes.setText("0");

            Fuzzy f1 = new Fuzzy(Double.parseDouble(jLabelnec.getText()), Double.parseDouble(jLabeldes.getText()));
            jLabel3.setText(f1.getRank());
            jLabel3.setForeground(f1.getColour());
        } catch (SQLException | ClassNotFoundException ex) {
            Logger.getLogger(mainMenu.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jMenu3 = new javax.swing.JMenu();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jComboBox1 = new javax.swing.JComboBox();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        jLabelnec = new javax.swing.JLabel();
        jLabeldes = new javax.swing.JLabel();
        jLabelec = new javax.swing.JLabel();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jTextField1 = new javax.swing.JTextField();
        jTextField2 = new javax.swing.JTextField();
        jSeparator1 = new javax.swing.JSeparator();
        jLabel7 = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();
        jCheckBox1 = new javax.swing.JCheckBox();
        jLabel9 = new javax.swing.JLabel();
        jLabel10 = new javax.swing.JLabel();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenu2 = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();

        jMenu3.setText("jMenu3");

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Gerenciador de Dispesas");
        setResizable(false);

        jTable1.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jTable1.setName(""); // NOI18N
        jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jTable1.getTableHeader().setReorderingAllowed(false);
        jTable1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTable1MouseClicked(evt);
            }
        });
        jTable1.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                jTable1PropertyChange(evt);
            }
        });
        jTable1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jTable1KeyPressed(evt);
            }
        });
        jScrollPane1.setViewportView(jTable1);

        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }));
        jComboBox1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jComboBox1ActionPerformed(evt);
            }
        });
        jComboBox1.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                jComboBox1PropertyChange(evt);
            }
        });

        jLabel1.setText("Mês");

        jLabel2.setText("Gastos");

        jLabel3.setForeground(new java.awt.Color(255, 61, 61));
        jLabel3.setText("Sovino");

        jLabel4.setText("Total necessários:");

        jLabel5.setText("Total desnecessários:");

        jLabel6.setText("Economia:");

        jLabelnec.setText("0");

        jLabeldes.setText("0");

        jLabelec.setText("0");

        jButton2.setText("Inserir");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jButton3.setText("Remover");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        jLabel7.setText("Descrição");

        jLabel8.setText("Valor");

        jLabel9.setText("Necessário");

        jLabel10.setText("Nova Dispesa");

        jMenu1.setText("Arquivo");

        jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK));
        jMenuItem2.setText("Sair");
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem2ActionPerformed(evt);
            }
        });
        jMenu1.add(jMenuItem2);

        jMenuBar1.add(jMenu1);

        jMenu2.setText("Editar");

        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.ALT_MASK));
        jMenuItem1.setText("Configuração");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        jMenu2.add(jMenuItem1);

        jMenuBar1.add(jMenu2);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel6)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jLabelec))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel4)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jLabelnec))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel5)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jLabeldes))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel7)
                            .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jCheckBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel8)
                                .addGap(18, 18, 18)
                                .addComponent(jLabel9)
                                .addGap(0, 0, Short.MAX_VALUE))))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel1)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(83, 83, 83)
                                .addComponent(jLabel3))
                            .addComponent(jLabel10))
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGap(0, 0, Short.MAX_VALUE)
                        .addComponent(jButton3, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1)
                    .addComponent(jLabel3))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 98, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(jLabelnec))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(jLabeldes))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(jLabelec))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jLabel10)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(jLabel8)
                    .addComponent(jLabel9))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jCheckBox1)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jComboBox1ActionPerformed
        // TODO add your handling code here:
        run();
    }//GEN-LAST:event_jComboBox1ActionPerformed

    private void jComboBox1PropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_jComboBox1PropertyChange

    }//GEN-LAST:event_jComboBox1PropertyChange

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
        // TODO add your handling code here:
        this.dispose();
    }//GEN-LAST:event_jMenuItem2ActionPerformed

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        // TODO add your handling code here:
        configMenu cfg = new configMenu(this);
        cfg.setVisible(true);
        cfg.setLocation(600, 400);
        this.setEnabled(false);
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
        // TODO add your handling code here:
        Object valueAt = jTable1.getValueAt(jTable1.getSelectedRow(), 0);
        String query = "DELETE FROM `gastos` WHERE `mes` = "+ jComboBox1.getSelectedItem().toString() + " AND `descricao` LIKE '" + valueAt.toString() + "'";
        Conection.update(query);
        run();
    }//GEN-LAST:event_jButton3ActionPerformed

    private void jTable1PropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_jTable1PropertyChange
        // TODO add your handling code here:
        jButton3.setEnabled(true);
        if(jTable1.getSelectedRow() == -1)
            jButton3.setEnabled(false);
    }//GEN-LAST:event_jTable1PropertyChange

    private void jTable1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTable1KeyPressed
        // TODO add your handling code here:
        jButton3.setEnabled(true);
        if(jTable1.getSelectedRow() == -1)
            jButton3.setEnabled(false);
    }//GEN-LAST:event_jTable1KeyPressed

    private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTable1MouseClicked
        // TODO add your handling code here:
        jButton3.setEnabled(true);
        if(jTable1.getSelectedRow() == -1)
            jButton3.setEnabled(false);
    }//GEN-LAST:event_jTable1MouseClicked

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        // TODO add your handling code here:
        if(jTextField1.getText().length() > 1 && jTextField2.getText().length() > 1){
            String query = "INSERT INTO `gastos` (`mes`, `descricao`, `valor`, `necessário`) VALUES ("
                    + jComboBox1.getSelectedItem().toString() +", '"
                    +jTextField1.getText()+"', '"
                    +jTextField2.getText()+"', "+jCheckBox1.isSelected() +");";
            Conection.update(query);
        run();
        }
    }//GEN-LAST:event_jButton2ActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JCheckBox jCheckBox1;
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JLabel jLabeldes;
    private javax.swing.JLabel jLabelec;
    private javax.swing.JLabel jLabelnec;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField jTextField1;
    private javax.swing.JTextField jTextField2;
    // End of variables declaration//GEN-END:variables
}


text:
import { symbol, toString } from '@ember/-internals/utils';
import { assert } from '@ember/debug';
import { isDestroyed } from '@glimmer/destroyable';
import { DEBUG } from '@glimmer/env';
import { Revision, UpdatableTag } from '@glimmer/validator';

type ObjMap<T> = { [key: string]: T };

const objectPrototype = Object.prototype;

export interface MetaCounters {
  peekCalls: number;
  peekPrototypeWalks: number;
  setCalls: number;
  deleteCalls: number;
  metaCalls: number;
  metaInstantiated: number;
  matchingListenersCalls: number;
  observerEventsCalls: number;
  addToListenersCalls: number;
  removeFromListenersCalls: number;
  removeAllListenersCalls: number;
  listenersInherited: number;
  listenersFlattened: number;
  parentListenersUsed: number;
  flattenedListenersCalls: number;
  reopensAfterFlatten: number;
  readableLazyChainsCalls: number;
  writableLazyChainsCalls: number;
}

let counters: MetaCounters | undefined;
if (DEBUG) {
  counters = {
    peekCalls: 0,
    peekPrototypeWalks: 0,
    setCalls: 0,
    deleteCalls: 0,
    metaCalls: 0,
    metaInstantiated: 0,
    matchingListenersCalls: 0,
    observerEventsCalls: 0,
    addToListenersCalls: 0,
    removeFromListenersCalls: 0,
    removeAllListenersCalls: 0,
    listenersInherited: 0,
    listenersFlattened: 0,
    parentListenersUsed: 0,
    flattenedListenersCalls: 0,
    reopensAfterFlatten: 0,
    readableLazyChainsCalls: 0,
    writableLazyChainsCalls: 0,
  };
}

/**
@module ember
*/

export const UNDEFINED = symbol('undefined');

const enum ListenerKind {
  ADD = 0,
  ONCE = 1,
  REMOVE = 2,
}

interface StringListener {
  event: string;
  target: null;
  method: string;
  kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE;
  sync: boolean;
}

interface FunctionListener {
  event: string;
  target: object | null;
  method: Function;
  kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE;
  sync: boolean;
}

type Listener = StringListener | FunctionListener;

let currentListenerVersion = 1;

export class Meta {
  _descriptors: Map<string, any> | undefined;
  _mixins: any | undefined;
  _isInit: boolean;
  _lazyChains: ObjMap<[UpdatableTag, unknown][]> | undefined;
  _values: ObjMap<unknown> | undefined;
  _revisions: ObjMap<Revision> | undefined;
  source: object;
  proto: object | undefined;
  _parent: Meta | undefined | null;

  _listeners: Listener[] | undefined;
  _listenersVersion = 1;
  _inheritedEnd = -1;
  _flattenedVersion = 0;

  // DEBUG
  constructor(obj: object) {
    if (DEBUG) {
      counters!.metaInstantiated++;
    }
    this._parent = undefined;
    this._descriptors = undefined;
    this._mixins = undefined;
    this._lazyChains = undefined;
    this._values = undefined;
    this._revisions = undefined;

    // initial value for all flags right now is false
    // see FLAGS const for detailed list of flags used
    this._isInit = false;

    // used only internally
    this.source = obj;
    this.proto = obj.constructor === undefined ? undefined : obj.constructor.prototype;

    this._listeners = undefined;
  }

  get parent() {
    let parent = this._parent;
    if (parent === undefined) {
      let proto = getPrototypeOf(this.source);
      this._parent = parent = proto === null || proto === objectPrototype ? null : meta(proto);
    }
    return parent;
  }

  setInitializing() {
    this._isInit = true;
  }

  unsetInitializing() {
    this._isInit = false;
  }

  isInitializing() {
    return this._isInit;
  }

  isPrototypeMeta(obj: object) {
    return this.proto === this.source && this.source === obj;
  }

  _getOrCreateOwnMap(key: string) {
    return this[key] || (this[key] = Object.create(null));
  }

  _getOrCreateOwnSet(key: string) {
    return this[key] || (this[key] = new Set());
  }

  _findInheritedMap(key: string, subkey: string): any | undefined {
    let pointer: Meta | null = this;
    while (pointer !== null) {
      let map: Map<string, any> = pointer[key];
      if (map !== undefined) {
        let value = map.get(subkey);
        if (value !== undefined) {
          return value;
        }
      }
      pointer = pointer.parent;
    }
  }

  _hasInInheritedSet(key: string, value: any) {
    let pointer: Meta | null = this;
    while (pointer !== null) {
      let set = pointer[key];
      if (set !== undefined && set.has(value)) {
        return true;
      }
      pointer = pointer.parent;
    }
    return false;
  }

  valueFor(key: string): unknown {
    let values = this._values;

    return values !== undefined ? values[key] : undefined;
  }

  setValueFor(key: string, value: unknown) {
    let values = this._getOrCreateOwnMap('_values');

    values[key] = value;
  }

  revisionFor(key: string): Revision | undefined {
    let revisions = this._revisions;

    return revisions !== undefined ? revisions[key] : undefined;
  }

  setRevisionFor(key: string, revision: Revision | undefined) {
    let revisions = this._getOrCreateOwnMap('_revisions');

    revisions[key] = revision;
  }

  writableLazyChainsFor(key: string): [UpdatableTag, unknown][] {
    if (DEBUG) {
      counters!.writableLazyChainsCalls++;
    }

    let lazyChains = this._getOrCreateOwnMap('_lazyChains');

    let chains = lazyChains[key];

    if (chains === undefined) {
      chains = lazyChains[key] = [];
    }

    return chains;
  }

  readableLazyChainsFor(key: string): [UpdatableTag, unknown][] | undefined {
    if (DEBUG) {
      counters!.readableLazyChainsCalls++;
    }

    let lazyChains = this._lazyChains;

    if (lazyChains !== undefined) {
      return lazyChains[key];
    }

    return undefined;
  }

  addMixin(mixin: any) {
    assert(
      isDestroyed(this.source)
        ? `Cannot add mixins of \`${toString(mixin)}\` on \`${toString(
            this.source
          )}\` call addMixin after it has been destroyed.`
        : '',
      !isDestroyed(this.source)
    );
    let set = this._getOrCreateOwnSet('_mixins');
    set.add(mixin);
  }

  hasMixin(mixin: any) {
    return this._hasInInheritedSet('_mixins', mixin);
  }

  forEachMixins(fn: Function) {
    let pointer: Meta | null = this;
    let seen: Set<any> | undefined;
    while (pointer !== null) {
      let set = pointer._mixins;
      if (set !== undefined) {
        seen = seen === undefined ? new Set() : seen;
        // TODO cleanup typing here
        set.forEach((mixin: any) => {
          if (!seen!.has(mixin)) {
            seen!.add(mixin);
            fn(mixin);
          }
        });
      }
      pointer = pointer.parent;
    }
  }

  writeDescriptors(subkey: string, value: any) {
    assert(
      isDestroyed(this.source)
        ? `Cannot update descriptors for \`${subkey}\` on \`${toString(
            this.source
          )}\` after it has been destroyed.`
        : '',
      !isDestroyed(this.source)
    );
    let map = this._descriptors || (this._descriptors = new Map());
    map.set(subkey, value);
  }

  peekDescriptors(subkey: string) {
    let possibleDesc = this._findInheritedMap('_descriptors', subkey);
    return possibleDesc === UNDEFINED ? undefined : possibleDesc;
  }

  removeDescriptors(subkey: string) {
    this.writeDescriptors(subkey, UNDEFINED);
  }

  forEachDescriptors(fn: Function) {
    let pointer: Meta | null = this;
    let seen: Set<any> | undefined;
    while (pointer !== null) {
      let map = pointer._descriptors;
      if (map !== undefined) {
        seen = seen === undefined ? new Set() : seen;
        map.forEach((value, key) => {
          if (!seen!.has(key)) {
            seen!.add(key);
            if (value !== UNDEFINED) {
              fn(key, value);
            }
          }
        });
      }
      pointer = pointer.parent;
    }
  }

  addToListeners(
    eventName: string,
    target: object | null,
    method: Function | string,
    once: boolean,
    sync: boolean
  ) {
    if (DEBUG) {
      counters!.addToListenersCalls++;
    }

    this.pushListener(eventName, target, method, once ? ListenerKind.ONCE : ListenerKind.ADD, sync);
  }

  removeFromListeners(eventName: string, target: object | null, method: Function | string): void {
    if (DEBUG) {
      counters!.removeFromListenersCalls++;
    }

    this.pushListener(eventName, target, method, ListenerKind.REMOVE);
  }

  private pushListener(
    event: string,
    target: object | null,
    method: Function | string,
    kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE,
    sync = false
  ): void {
    let listeners = this.writableListeners();

    let i = indexOfListener(listeners, event, target, method!);

    // remove if found listener was inherited
    if (i !== -1 && i < this._inheritedEnd) {
      listeners.splice(i, 1);
      this._inheritedEnd--;
      i = -1;
    }

    // if not found, push. Note that we must always push if a listener is not
    // found, even in the case of a function listener remove, because we may be
    // attempting to add or remove listeners _before_ flattening has occurred.
    if (i === -1) {
      assert(
        'You cannot add function listeners to prototypes. Convert the listener to a string listener, or add it to the instance instead.',
        !(this.isPrototypeMeta(this.source) && typeof method === 'function')
      );

      assert(
        'You attempted to remove a function listener which did not exist on the instance, which means you may have attempted to remove it before it was added.',
        !(
          !this.isPrototypeMeta(this.source) &&
          typeof method === 'function' &&
          kind === ListenerKind.REMOVE
        )
      );

      listeners.push({
        event,
        target,
        method,
        kind,
        sync,
      } as Listener);
    } else {
      let listener = listeners[i];

      // If the listener is our own listener and we are trying to remove it, we
      // want to splice it out entirely so we don't hold onto a reference.
      if (kind === ListenerKind.REMOVE && listener.kind !== ListenerKind.REMOVE) {
        listeners.splice(i, 1);
      } else {
        assert(
          `You attempted to add an observer for the same method on '${
            event.split(':')[0]
          }' twice to ${target} as both sync and async. Observers must be either sync or async, they cannot be both. This is likely a mistake, you should either remove the code that added the observer a second time, or update it to always be sync or async. The method was ${method}.`,
          !(
            listener.kind === ListenerKind.ADD &&
            kind === ListenerKind.ADD &&
            listener.sync !== sync
          )
        );

        // update own listener
        listener.kind = kind;
        listener.sync = sync;
      }
    }
  }

  private writableListeners(): Listener[] {
    // Check if we need to invalidate and reflatten. We need to do this if we
    // have already flattened (flattened version is the current version) and
    // we are either writing to a prototype meta OR we have never inherited, and
    // may have cached the parent's listeners.
    if (
      this._flattenedVersion === currentListenerVersion &&
      (this.source === this.proto || this._inheritedEnd === -1)
    ) {
      if (DEBUG) {
        counters!.reopensAfterFlatten++;
      }

      currentListenerVersion++;
    }

    // Inherited end has not been set, then we have never created our own
    // listeners, but may have cached the parent's
    if (this._inheritedEnd === -1) {
      this._inheritedEnd = 0;
      this._listeners = [];
    }

    return this._listeners!;
  }

  /**
    Flattening is based on a global revision counter. If the revision has
    bumped it means that somewhere in a class inheritance chain something has
    changed, so we need to reflatten everything. This can only happen if:

    1. A meta has been flattened (listener has been called)
    2. The meta is a prototype meta with children who have inherited its
       listeners
    3. A new listener is subsequently added to the meta (e.g. via `.reopen()`)

    This is a very rare occurrence, so while the counter is global it shouldn't
    be updated very often in practice.
  */
  private flattenedListeners(): Listener[] | undefined {
    if (DEBUG) {
      counters!.flattenedListenersCalls++;
    }

    if (this._flattenedVersion < currentListenerVersion) {
      if (DEBUG) {
        counters!.listenersFlattened++;
      }

      let parent = this.parent;

      if (parent !== null) {
        // compute
        let parentListeners = parent.flattenedListeners();

        if (parentListeners !== undefined) {
          if (this._listeners === undefined) {
            // If this instance doesn't have any of its own listeners (writableListeners
            // has never been called) then we don't need to do any flattening, return
            // the parent's listeners instead.
            if (DEBUG) {
              counters!.parentListenersUsed++;
            }

            this._listeners = parentListeners;
          } else {
            let listeners = this._listeners;

            if (this._inheritedEnd > 0) {
              listeners.splice(0, this._inheritedEnd);
              this._inheritedEnd = 0;
            }

            for (let i = 0; i < parentListeners.length; i++) {
              let listener = parentListeners[i];
              let index = indexOfListener(
                listeners,
                listener.event,
                listener.target,
                listener.method
              );

              if (index === -1) {
                if (DEBUG) {
                  counters!.listenersInherited++;
                }

                listeners.unshift(listener);
                this._inheritedEnd++;
              }
            }
          }
        }
      }

      this._flattenedVersion = currentListenerVersion;
    }

    return this._listeners;
  }

  matchingListeners(eventName: string): (string | boolean | object | null)[] | undefined {
    let listeners = this.flattenedListeners();
    let result;

    if (DEBUG) {
      counters!.matchingListenersCalls++;
    }

    if (listeners !== undefined) {
      for (let index = 0; index < listeners.length; index++) {
        let listener = listeners[index];

        // REMOVE listeners are placeholders that tell us not to
        // inherit, so they never match. Only ADD and ONCE can match.
        if (
          listener.event === eventName &&
          (listener.kind === ListenerKind.ADD || listener.kind === ListenerKind.ONCE)
        ) {
          if (result === undefined) {
            // we create this array only after we've found a listener that
            // matches to avoid allocations when no matches are found.
            result = [] as any[];
          }

          result.push(listener.target!, listener.method, listener.kind === ListenerKind.ONCE);
        }
      }
    }

    return result;
  }

  observerEvents() {
    let listeners = this.flattenedListeners();
    let result;

    if (DEBUG) {
      counters!.observerEventsCalls++;
    }

    if (listeners !== undefined) {
      for (let index = 0; index < listeners.length; index++) {
        let listener = listeners[index];

        // REMOVE listeners are placeholders that tell us not to
        // inherit, so they never match. Only ADD and ONCE can match.
        if (
          (listener.kind === ListenerKind.ADD || listener.kind === ListenerKind.ONCE) &&
          listener.event.indexOf(':change') !== -1
        ) {
          if (result === undefined) {
            // we create this array only after we've found a listener that
            // matches to avoid allocations when no matches are found.
            result = [] as any[];
          }

          result.push(listener);
        }
      }
    }

    return result;
  }
}

const getPrototypeOf = Object.getPrototypeOf;
const metaStore = new WeakMap();

export function setMeta(obj: object, meta: Meta) {
  assert('Cannot call `setMeta` on null', obj !== null);
  assert('Cannot call `setMeta` on undefined', obj !== undefined);
  assert(
    `Cannot call \`setMeta\` on ${typeof obj}`,
    typeof obj === 'object' || typeof obj === 'function'
  );

  if (DEBUG) {
    counters!.setCalls++;
  }
  metaStore.set(obj, meta);
}

export function peekMeta(obj: object): Meta | null {
  assert('Cannot call `peekMeta` on null', obj !== null);
  assert('Cannot call `peekMeta` on undefined', obj !== undefined);
  assert(
    `Cannot call \`peekMeta\` on ${typeof obj}`,
    typeof obj === 'object' || typeof obj === 'function'
  );

  if (DEBUG) {
    counters!.peekCalls++;
  }

  let meta = metaStore.get(obj);

  if (meta !== undefined) {
    return meta;
  }

  let pointer = getPrototypeOf(obj);

  while (pointer !== null) {
    if (DEBUG) {
      counters!.peekPrototypeWalks++;
    }

    meta = metaStore.get(pointer);

    if (meta !== undefined) {
      if (meta.proto !== pointer) {
        // The meta was a prototype meta which was not marked as initializing.
        // This can happen when a prototype chain was created manually via
        // Object.create() and the source object does not have a constructor.
        meta.proto = pointer;
      }
      return meta;
    }

    pointer = getPrototypeOf(pointer);
  }

  return null;
}

/**
  Retrieves the meta hash for an object. If `writable` is true ensures the
  hash is writable for this object as well.

  The meta object contains information about computed property descriptors as
  well as any watched properties and other information. You generally will
  not access this information directly but instead work with higher level
  methods that manipulate this hash indirectly.

  @method meta
  @for Ember
  @private

  @param {Object} obj The object to retrieve meta for
  @param {Boolean} [writable=true] Pass `false` if you do not intend to modify
    the meta hash, allowing the method to avoid making an unnecessary copy.
  @return {Object} the meta hash for an object
*/
export const meta: {
  (obj: object): Meta;
  _counters?: MetaCounters;
} = function meta(obj: object) {
  assert('Cannot call `meta` on null', obj !== null);
  assert('Cannot call `meta` on undefined', obj !== undefined);
  assert(
    `Cannot call \`meta\` on ${typeof obj}`,
    typeof obj === 'object' || typeof obj === 'function'
  );

  if (DEBUG) {
    counters!.metaCalls++;
  }

  let maybeMeta = peekMeta(obj);

  // remove this code, in-favor of explicit parent
  if (maybeMeta !== null && maybeMeta.source === obj) {
    return maybeMeta;
  }

  let newMeta = new Meta(obj);
  setMeta(obj, newMeta);
  return newMeta;
};

if (DEBUG) {
  meta._counters = counters;
}

export { counters };

function indexOfListener(
  listeners: Listener[],
  event: string,
  target: object | null,
  method: Function | string | null
) {
  for (let i = listeners.length - 1; i >= 0; i--) {
    let listener = listeners[i];

    if (listener.event === event && listener.target === target && listener.method === method) {
      return i;
    }
  }
  return -1;
}

redpajama_set_name: RedPajamaGithub


text:
//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

#ifndef trans_RangeMap_INCL_
#define trans_RangeMap_INCL_

/*! \file
\brief Declarations for trans::RangeMap
*/

#include "libdat/Range.h"

#include <functional>
#include <string>
#include <utility>

namespace trans
{

/*! \brief Transformation function mapping one range onto another.

NOTE: the mapping function is assumed to map the unit input range
[0,1) onto the unit output range [0,1).

The input range values are first transformed into a fraction. The unit
map is applied to that fraction. The results are transformed to fill the
output range.

\par Example
\dontinclude testtrans/uRangeMap.cpp
\skip ExampleStart
\until ExampleEnd
*/

class RangeMap
{

public: // data

	dat::Range<double> theDomain;
	std::function<double(double const &)> theUnitMap;
	dat::Range<double> theRange;

public: // methods

	//! default null constructor
	inline
	RangeMap
		();

	//! Value constructor
	inline
	explicit
	RangeMap
		( dat::Range<double> const & domain
		, std::function<double(double const &)> const & unitMapping
		, dat::Range<double> const & range = dat::Range<double>()
			//!< If null, set to same as domain
		);

	// copy constructor -- compiler provided
	// assignment operator -- compiler provided
	// destructor -- compiler provided

	//! Check if instance is valid
	inline
	bool
	isValid
		() const;

	//! RangeMap value associated with arg (or null if arg out of range)
	inline
	double
	operator()
		( double const & arg
		) const;

	//! Descriptive information about this instance.
	inline
	std::string
	infoString
		( std::string const & title = std::string()
		) const;
};

}

// Inline definitions
#include "libtrans/RangeMap.inl"

#endif // trans_RangeMap_INCL_


text:
using namespace LepusEngine;
using namespace Lepus3D;
using namespace Assets;
using namespace std;

// Default constructor
ModelImporter::ModelImporter()
{
	// Initialise filestreams to null
	mObjFile = nullptr;
	mMtlFile = nullptr;
}

// Opens file after constructor
ModelImporter::ModelImporter(string fn, string dir)
{
	// Initialise filestreams to null
	mObjFile = nullptr;
	mMtlFile = nullptr;

	// Open model file using the provided filename and directory path
	Init(fn, dir);
}

// Opens model file
bool ModelImporter::Init(string fn, string dir)
{
	// Combine directory path and filename together to get filepath
	fn = dir + "/" + fn;

	// Filename for the .obj file
	string objFN = fn;

	// Filename for the .mtl material library file
	string mtlFN = fn.substr(0, fn.length() - string(".obj").length()) + ".mtl";

	// Remove any existing geometry data from possible previous import operations using this instance
	mGeometry.clear();

	// Create filestreams
	mObjFile = new ifstream(objFN);
	mMtlFile = new ifstream(mtlFN);

	return true;
}

// Actual .obj parsing
bool ModelImporter::_ReadOBJ()
{
	// Currently read line
	string line = "";

	// .obj indexes normals and assigns them to vertices, so they have to be loaded into a separate array first.
	// A separate array is also used for final set of vertices, as we ignore indexing; all vertices (duplicate or unique) are placed together,
	// and normals are recalculated.
	VertexArray verts, normals, uvs, finalVerts;

	vector<unsigned long long> indices, finalIndices; // finalIndices will just be an array of indices with the size of n total vertices
	int indexCounter = 0; // TODO: an incrementing index to write for each vertex (as in, ignoring indexing altogether and just writing an index for each vertex). Might consider getting rid of drawing elements altogether and just draw arrays instead.
	while(mObjFile->good()) // check if file is still readable
	{
		getline(*mObjFile, line); // read next line
		if(line[0] == '#') // ignore comments
			continue;

		string keyword = ""; // current keyword, like "o" for object, "v" for vertex, etc.
		string data = ""; // current data, like coordinates when keyword is "v", or material name when keyword is "usemtl"
		int firstSpace = line.find(" "); // first whitespace character in the line
		keyword = line.substr(0, firstSpace); // skip till first whitespace
		if(keyword == "o") // object (mesh) has been found
		{
			// Add last read mesh to model geometry
			if (verts.size() > 0)
			{
				Mesh loadedMesh(finalVerts, true); // temporary mesh, don't index vertices
				loadedMesh.SetIndices(finalIndices); // pass vertex indices (TODO: these don't actually perform index so could remove this to save memory)
				mGeometry.push_back(loadedMesh); // add mesh to geometry set
			}

			// Reset data & state to prepare for next mesh
			verts.clear();
			normals.clear();
			indices.clear();
			finalVerts.clear();
			finalIndices.clear();
			indexCounter = 0;
		}
		else if(keyword == "v" || keyword == "vn" || keyword == "vt") // a vertex coordinate (position, normal or texture uv) is found
		{
			Vertex v;
			data = line.substr(firstSpace+1); // skip the keyword and first whitespace
			string xyz[3] = { "", "", "" }; // XYZ (or XY if keyword is vt) coordinates from the line
			for(int i = 0; i < 3 || (keyword == "vt" && i < 2); i++) // read all 3 (or 2 if vt) coordinates from the line
			{
				xyz[i] = data.substr(0, data.find(" "));
				data = data.substr(data.find(" ")+1);
			}
			// Assign coordinates to the Vertex in accordance to coordinate type (pos/normal/uv)
			// TODO: Wasting memory here. In case of vt, there are 6 unused floats - that's 24 bytes per vertex. Should get rid of separate vectors too.
			if(keyword == "v")
			{
				v.x = stof(xyz[0]);
				v.y = stof(xyz[1]);
				v.z = stof(xyz[2]);
				verts.push_back(v);
			}
			else if(keyword == "vn")
			{
				v.nX = stof(xyz[0]);
				v.nY = stof(xyz[1]);
				v.nZ = stof(xyz[2]);
				normals.push_back(v);
			}
			else if(keyword == "vt")
			{
				v.s = stof(xyz[0]);
				v.t = stof(xyz[1]);
				uvs.push_back(v);
			}
		}
		else if(keyword == "f") // a face (triangle) has been found, this is where indices are taken from
		{
			data = line + " "; // current line + extra whitespace (a quick hack that will be used for loading normals further below, search "normalIndex")
			for(int i = 0; i < 3; i++) // The .obj file should be storing faces as triangles (NOT quads) for this to work
			{
				data = data.substr(data.find(" ")+1); // skips "f " to start reading the integers
				string vertexIndex = data.substr(0, data.find("/")); // copy position index
				data = data.substr(data.find("/")+1); // skips till after slash to read next index type
				// next up should be the vertex UV coord index, which might be empty
				string uvIndex = "";
				if(data.find("/") != 0) // UV coord index is NOT empty (e.g. `f 1/1/1`)
				{
					uvIndex = data.substr(0, data.find("/")); // copy uv index
					data = data.substr(data.find("/")+1); // skips to next index type
				}
				else // UV coord index is empty (e.g. `f 1//1`)
					data = data.substr(1); // skips to next index type
				// next up is the vertex normal index, which is the last one for this vertex. The first two vertices for this face will be separated by a whitespace, while the last one ends with a newline, so that's why there was an extra whitespace added to data earlier.
				string normalIndex = data.substr(0, data.find(" "));

				// Convert all indices from strings to integers
				unsigned long long vIdx = stoll(vertexIndex);
				unsigned long long uvIdx = 0;
				if(uvIndex != "") // check if uv index was even found before converting
					uvIdx = stoll(uvIndex);
				unsigned long long nIdx = stoll(normalIndex);

				indices.push_back(indexCounter++); // add incrementing index

				// finalVerts will store each vertex (no matter if it's duplicated - it ignores indexing)
				// the indices are zero-based (hence the v/n/uvIdx - 1). indexCounter was just incremented hence -1
				// The reason why indexing code is even here is to find out which vertex is the normal/UV coordinate is associated with
				// the .obj file stores vertex positions, normals and uv separately yet they're linked together by indices
				// TODO: this is not the most efficient way of doing things (and certainly not an elegant one) but it works for now
				finalVerts.push_back(verts[vIdx-1]);
				finalVerts[indexCounter-1].nX = normals[nIdx-1].nX;
				finalVerts[indexCounter-1].nY = normals[nIdx-1].nY;
				finalVerts[indexCounter-1].nZ = normals[nIdx-1].nZ;
				if(uvIdx != 0)
				{
					finalVerts[indexCounter-1].s = uvs[uvIdx-1].s;
					finalVerts[indexCounter-1].t = uvs[uvIdx-1].t;
				}
			}
		}
	}

	// Add last mesh found in the file (as there is no "o" keyword afterwards to trigger the adding code)
	Mesh loadedMesh(finalVerts, true);
	loadedMesh.SetIndices(indices);
	mGeometry.push_back(loadedMesh);

	// Remove all data from vectors
	verts.clear();
	normals.clear();
	uvs.clear();
	indices.clear();
	return true;
}

bool ModelImporter::Read()
{
	return _ReadOBJ();
}

Mesh ModelImporter::GetSubMesh(int idx)
{
	return mGeometry[idx];
}

bool ModelImporter::Close()
{
	// close file handles
	mObjFile->close();
	mMtlFile->close();

	// delete pointers
	delete mObjFile;
	delete mMtlFile;

	// reinit pointers
	mObjFile = nullptr;
	mMtlFile = nullptr;

	return true;
}

ModelImporter::~ModelImporter()
{
	// Makes sure file handles are closed
	if(mObjFile != nullptr && mMtlFile != nullptr)
		Close();
}


text:
<?php

namespace ModelForm\Test;

use ModelForm\Fields\CharField;
use ModelForm\Form;

class FieldsTest extends TestCase
{
    public function testFieldAcceptNameAndLabel()
    {
        $form = new Form();
        $form->name = new CharField(['label'=>'Testing']);
        $this->assertEquals('name', $form->name->name);
        $this->assertEquals($form, $form->name->form);
        $this->assertEquals('Testing', $form->name->label);
    }

    public function testFieldRenderHtmlOptions() {
        $form = new Form();
        $form->description = new CharField(['label'=>'Description']);
        $htmlOptions = [
            'maxlength' => 10,
        ];
        $this->assertEquals(
            '<input maxlength="10" name="Form-description" type="text">',
            $form->description->text($htmlOptions)
        );
    }
}


text:
<!DOCTYPE html>

		<title>Le Défi du challenge - SensCritique</title>

				<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
							<meta name="description" content="Deux joueurs s'affrontent sur trois défis pour déterminer un seul perdant. Émission de divertissement mettant en scène la compétition des joueurs.... Jeu - Durée : 25..." />
									<meta property="og:image" content="http://media.senscritique.com/media/000009934206/1200/Le_Defi_du_challenge.jpg" />

		<link rel="publisher" href="https://plus.google.com/+senscritique">

		<link rel="apple-touch-icon" sizes="57x57" href="http://static.senscritique.com/img/favicon/apple-touch-icon-57x57.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="60x60" href="http://static.senscritique.com/img/favicon/apple-touch-icon-60x60.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="72x72" href="http://static.senscritique.com/img/favicon/apple-touch-icon-72x72.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="76x76" href="http://static.senscritique.com/img/favicon/apple-touch-icon-76x76.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="114x114" href="http://static.senscritique.com/img/favicon/apple-touch-icon-114x114.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="120x120" href="http://static.senscritique.com/img/favicon/apple-touch-icon-120x120.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="144x144" href="http://static.senscritique.com/img/favicon/apple-touch-icon-144x144.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="152x152" href="http://static.senscritique.com/img/favicon/apple-touch-icon-152x152.png?v=eELP384vde">
		<link rel="apple-touch-icon" sizes="180x180" href="http://static.senscritique.com/img/favicon/apple-touch-icon-180x180.png?v=eELP384vde">
		<link rel="icon" type="image/png" href="http://static.senscritique.com/img/favicon/favicon-32x32.png?v=eELP384vde" sizes="32x32">
		<link rel="icon" type="image/png" href="http://static.senscritique.com/img/favicon/favicon-194x194.png?v=eELP384vde" sizes="194x194">
		<link rel="icon" type="image/png" href="http://static.senscritique.com/img/favicon/favicon-96x96.png?v=eELP384vde" sizes="96x96">
		<link rel="icon" type="image/png" href="http://static.senscritique.com/img/favicon/android-chrome-192x192.png?v=eELP384vde" sizes="192x192">
		<link rel="icon" type="image/png" href="http://static.senscritique.com/img/favicon/favicon-16x16.png?v=eELP384vde" sizes="16x16">
		<link rel="manifest" href="http://static.senscritique.com/img/favicon/manifest.json?v=eELP384vde">
		<link rel="shortcut icon" href="http://static.senscritique.com/img/favicon/favicon.ico?v=eELP384vde">

						<link rel="stylesheet" type="text/css" href="http://static.senscritique.com/lib/optimized_ln/7ab3b18d6080a19c9bbe308986fbd666.css"/>

	<link rel="stylesheet" type="text/css" href="http://static.senscritique.com/lib/optimized_ln/8f3c454da1cf0c109ee2d54bfac9eb15.css"/>

		<link rel="apple-touch-icon" href="/img/favicon/57.png">
		<link rel="apple-touch-icon" sizes="72x72" href="/img/favicon/72.png">
		<link rel="apple-touch-icon" sizes="114x114" href="/img/favicon/114.png">
		<link rel="publisher" href="https://plus.google.com/+senscritique">

							<button type="button" data-rel="btn-register" data-scmodal-type="login" class="d-link-alt">Déjà inscrit</button> ?
							<form action="/" method="POST" class="lahe-userSubmenu lahe-signin" data-rel="sc-headerSignin">

Connectez-vous avec

								Facebook
								Twitter

ou

								<input type="text" class="lahe-signin-field" name="email" placeholder="Adresse email" data-rel="sc-headerSignin-email" />
								<input type="password" class="lahe-signin-field" name="password" placeholder="Mot de passe" data-rel="sc-headerSignin-password" />
								Mot de passe oublié ?
								<fieldset class="lahe-signin-clear">

									<input type="submit" class="d-button lahe-signin-confirm" value="Connexion" />
								</fieldset>
							</form>

						<button type="button" data-rel="btn-register" data-scmodal-type="register" class="lahe-userMenu-connect">Créer mon compte</button>

					SensCritique

							Films

Au cinéma

																																														Sorties de la semaine
															À l'affiche
															Mes cinémas
															Meilleurs films 2015

TV / VOD

																																														EveryMovie
															A la télé
															En VOD

Guide

																																														Vos films préférés
															Top 111 films
															Sondages

							Séries

Actualité

																																														Séries du moment
															Meilleures séries 2015

Guide

																																														Vos séries préférées
															Top 111 séries
															Sondages

							Jeux

Actualité

																																														Jeux du moment
															Agenda
															Jeux les plus attendus
															Meilleurs jeux 2015

Guide

																																														Vos jeux préférés
															Top 111 jeux
															Sondages

							Livres

Actualité

																																														Livres du moment
															Meilleures ventes
															Meilleurs livres 2015
															Prix littéraires 2014

Guide

																																														Vos livres préférés
															Top 111 livres
															Sondages

							BD

Actualité

																																														Franco-belge
															Comics
															Mangas
															Meilleures BD 2015

Guide

																																														Vos BD préférées
															Top 111 BD
															Sondages

							Musique

Actualité

																																														Albums du moment
															Prochaines sorties
															Meilleurs albums 2015

Guide

																																														Vos albums préférés
															Top 111 albums
															Sondages

						Posts

			<form action="/recherche?" method="GET" class="lahe-searchBar-content" data-rel="sc-headerSearch">

					 Chercher une œuvre, un artiste, une liste, un cinéma ou un membre

						Tout

Tout

Films

Séries

Livres

BD

Jeux vidéo

Albums de musique

Morceaux de musique

Listes d'oeuvres

Sondages

Sagas

Artistes et sociétés

Membres

Cinémas

					<input type="text" name="query" value="" class="unfocus lahe-searchBar-query" data-rel="sc-headerSearch-query" />
					<button type="button" class="lahe-searchBar-close" data-rel="sc-headerSearch-close">

					</button>

			</form>

SensCritique

Séries

Jeu

Le Défi du challenge

				Bande-annonce

							Le Défi du challenge

																								(2014)

12345678910

																															<button type="button" data-sc-action="current"
									data-sc-product-id="12751021"
									data-sc-tooltip="true"
									title="Je suis cette série"
									class="d-button pvi-product-scaction ">

								En cours
							</button>

												<button type="button" data-sc-action="recommend"
								data-sc-product-id="12751021"
								class="d-button pvi-product-scaction "
								style="display:none;">
							 Coup de coeur
						</button>
																			<button type="button" data-rel="bt-review sc-button-modal-sc"
									data-sc-product-id="12751021"
									data-scmodal-type="review"
									class="d-button pvi-product-scaction"
									style="display:none;">
								 Critiquer
							</button>

												<button type="button" data-sc-action="wish-list"
								data-sc-product-id="12751021"
								class="d-button pvi-product-scaction "
								>

								Envie de la voir

						</button>

												<button type="button" data-rel="sc-button"
								data-sc-product-id="12751021"
								class="d-button pvi-product-contextmenu">

						</button>

															6.2

							10
							1
							248
							2

2

2

2

15

36

83

81

19

6

2

					2

2

					1

					2

2

					2

					2

2

					3

					15

15

					4

					36

36

					5

					83

83

					6

					81

81

					7

					19

19

					8

					6

6

					9

					2

2

					10

									248

									5

									2

										7

					<button type="button" class="pco-social-action" data-rel="sc-share-tooltip" data-sc-product-id="12751021">Partager</button>

					<button type="button" class="pco-social-action" data-rel="sc-buy-tooltip" data-sc-product-id="12751021">Acheter</button>

					Accueil

					Saisons

					Critiques

					Listes

				Casting

					Vidéos

					Photos

Emission Web

					 de   Sylvain NES et   Nicolas Sénac (6coups6mouches)

							Jeu

					jeuxvideo.com

					25 min

<time datetime="2014-05-04" >4 mai 2014</time>

Deux joueurs s'affrontent sur trois défis pour déterminer un seul perdant. Émission de divertissement mettant en scène la compétition des joueurs. Successeur du 3615 Turbo.

			Premiers épisodes

								S01E26

																					Rufio vs Zouzou

								S01E27

																					CdV vs Medhi

								S01E28

																					Asfarth vs Kilaye

																			Dernier épisode diffusé : S01E33

					PostsLe Défi du challenge

				Vous avez une anecdote, une vidéo/photo ou une simple question sur cette série ?

				<button type="button" data-rel="js-link" data-sc-link="/post/12751021" class="d-button-success-xl d-more pvi-emptyTopic-btn">
					Créer un post
				</button>
				<button type="button" data-rel="js-link" data-sc-link="/posts" class="d-button-xl d-more pvi-emptyTopic-btn">
					Tous les posts
				</button>

				IntervenantsLe Défi du challenge

					Sylvain NES
											Réalisateur/candidat

					Nicolas Sénac (6coups6mouches)
											présentateur/candidat

					Ronan Letoqueux (RealMyop)
											présentateur/candidat

					Dorian Chandelier
											présentateur/candidat

					Yann Chauvière (CoeurDeVandale)
											présentateur/candidat

			 Intervenants de l'émission Web Le Défi du challenge

Bande-annonce

				Le Défi du challenge

			<div class="" data-rel="external-video" data-sc-no-preroll="" data-sc-video-mode="player" data-sc-video-start="{:start_at}" data-sc-video-id="YsyXkDORsA8" data-sc-param-index-id="175251878" data-sc-video-type="1" data-sc-video-width="700" data-sc-video-height="484" data-sc-video-poster="http://media.senscritique.com/media/000009934206/1200/Le_Defi_du_challenge.jpg" data-sc-video-autoplay="" data-sc-video-disablerebound="" data-sc-video-delay="{:delay}" data-sc-video-hidecontrols="" data-sc-video-mute="{:mute}">

				Sélection de listesLe Défi du challenge

			Le merveilleux monde de Youtube

Youtube est un merveilleux monde, et Dieu sait si j'ai écumé cette plateforme et exploré ses entrailles. Récapitulatif de tout...

				 46

			Internet, ton univers impitoyable

Parce que moi aussi je vais sur Youtube.

Liste-classement de ce qu'il y a de mieux, et de pire, sur la toile.
Avec des...

				 29

			Chroniques JeuxVideo.com

/// VOIR AUSSI
http://www.senscritique.com/liste/Chroniques_Gamekult/911290

				 15

			Une phrase suffit (La corbeille à séries de Johnny Laconique)

Parce que Johnny Laconique se doit d'écrire une phrase sur ces séries avant d'oublier le peu qu'il avait à dire.

				 11

			Bref résumé de ce qui se fait de mieux sur YouTube FR

----------------------------------------------------------------------------------------------------------------------------------...

				 13

			 Toutes les listes

				InfosLe Défi du challenge

										Producteurs

								NESblog

			Vous pourriez également aimer...

		8.4

					Crossed (2013)

		7.3

					3615 Usul (2011)

		7.4

					Joueur du Grenier (2009)

		6.2

					Merci Dorian (2014)

		6.5

					Hard Corner (2012)

		6.3

					Papy Grenier (2012)

		7.5

					Le Fossoyeur de Films (2012)

		7.6

					Mes chers contemporains (2014)

		6.7

					What the Cut?! (2012)

		6.1

					Le Fond de l'affaire (2013)

				Dernières actions sur cette émission Web

			Le Défi du challenge

		 Plus d'actualité

				Le bouche à oreille

L'avis de vos amis en 1 clic

				S'inscrire avec FB

										Saisons

						Saison 1

						-

							-

-

				Lab

				Changelog

				À propos

				Aide

				Blog

				Publicité

				Emploi

				Conditions d'utilisation

Séances de cinéma

Programme TV ce soir

Programme TV aujourd'hui

Programme TV demain

Programme TV cette semaine

					Avis films

					Avis séries

					Avis livres

					Avis BD

					Avis jeux vidéo

					Avis musique

		© 2015 SensCritique


text:
package com.vmware.vim25;

/**
* @author Steve Jin (http://www.doublecloud.org)
* @version 5.1
*/

@SuppressWarnings("all")
public class RemoteTSMEnabledEvent extends HostEvent {
}