refactoring various pieces of the framework.
This commit is contained in:
parent
e985057b4c
commit
9fc9f88a41
|
@ -50,13 +50,16 @@
|
|||
|
||||
'after' => function($response)
|
||||
{
|
||||
// Do stuff after every request to your application.
|
||||
if (Config::get('session.driver') !== '')
|
||||
{
|
||||
Session::flash(Input::old_input, Input::old());
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'auth' => function()
|
||||
{
|
||||
if ( ! Auth::check()) return Redirect::to('login');
|
||||
if ( ! Auth::check()) return Redirect::to_login();
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
define('EXT', '.php');
|
||||
define('BLADE_EXT', '.blade.php');
|
||||
|
||||
function constants($constants)
|
||||
{
|
||||
foreach ($constants as $key => $value)
|
||||
{
|
||||
if ( ! defined($key)) define($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$constants = array(
|
||||
'APP_PATH' => realpath($application).'/',
|
||||
'BASE_PATH' => realpath("$laravel/..").'/',
|
||||
'PACKAGE_PATH' => realpath($packages).'/',
|
||||
'PUBLIC_PATH' => realpath($public).'/',
|
||||
'STORAGE_PATH' => realpath($storage).'/',
|
||||
'SYS_PATH' => realpath($laravel).'/',
|
||||
);
|
||||
|
||||
constants($constants);
|
||||
|
||||
$constants = array(
|
||||
'CACHE_PATH' => STORAGE_PATH.'cache/',
|
||||
'CONFIG_PATH' => APP_PATH.'config/',
|
||||
'CONTROLLER_PATH' => APP_PATH.'controllers/',
|
||||
'DATABASE_PATH' => STORAGE_PATH.'database/',
|
||||
'LANG_PATH' => APP_PATH.'language/',
|
||||
'LIBRARY_PATH' => APP_PATH.'libraries/',
|
||||
'MODEL_PATH' => APP_PATH.'models/',
|
||||
'ROUTE_PATH' => APP_PATH.'routes/',
|
||||
'SESSION_PATH' => STORAGE_PATH.'sessions/',
|
||||
'SYS_CONFIG_PATH' => SYS_PATH.'config/',
|
||||
'SYS_LANG_PATH' => SYS_PATH.'language/',
|
||||
'SYS_VIEW_PATH' => SYS_PATH.'views/',
|
||||
'VIEW_PATH' => APP_PATH.'views/',
|
||||
);
|
||||
|
||||
|
||||
constants($constants);
|
||||
|
||||
unset($constants);
|
|
@ -1,43 +1,15 @@
|
|||
<?php namespace Laravel;
|
||||
|
||||
/**
|
||||
* Define a multitude of framework constants. Mainly, we define
|
||||
* various file paths to core locations of the framework, as well
|
||||
* as a couple of file extensions.
|
||||
*/
|
||||
define('EXT', '.php');
|
||||
define('BLADE_EXT', '.blade.php');
|
||||
|
||||
define('APP_PATH', realpath($application).'/');
|
||||
define('BASE_PATH', realpath("$laravel/..").'/');
|
||||
define('PACKAGE_PATH', realpath($packages).'/');
|
||||
define('PUBLIC_PATH', realpath($public).'/');
|
||||
define('STORAGE_PATH', realpath($storage).'/');
|
||||
define('SYS_PATH', realpath($laravel).'/');
|
||||
define('CACHE_PATH', STORAGE_PATH.'cache/');
|
||||
define('CONFIG_PATH', APP_PATH.'config/');
|
||||
define('CONTROLLER_PATH', APP_PATH.'controllers/');
|
||||
define('DATABASE_PATH', STORAGE_PATH.'database/');
|
||||
define('LANG_PATH', APP_PATH.'language/');
|
||||
define('LIBRARY_PATH', APP_PATH.'libraries/');
|
||||
define('MODEL_PATH', APP_PATH.'models/');
|
||||
define('ROUTE_PATH', APP_PATH.'routes/');
|
||||
define('SESSION_PATH', STORAGE_PATH.'sessions/');
|
||||
define('SYS_CONFIG_PATH', SYS_PATH.'config/');
|
||||
define('SYS_LANG_PATH', SYS_PATH.'language/');
|
||||
define('SYS_VIEW_PATH', SYS_PATH.'views/');
|
||||
define('VIEW_PATH', APP_PATH.'views/');
|
||||
|
||||
unset($laravel, $application, $config, $packages, $public, $storage);
|
||||
require 'constants.php';
|
||||
|
||||
/**
|
||||
* Load the classes that can't be resolved through the auto-loader.
|
||||
* These are typically classes that are used by the auto-loader or
|
||||
* configuration classes, and therefore cannot be auto-loaded.
|
||||
*/
|
||||
require SYS_PATH.'arr'.EXT;
|
||||
require SYS_PATH.'config'.EXT;
|
||||
require SYS_PATH.'loader'.EXT;
|
||||
require SYS_PATH.'arr'.EXT;
|
||||
|
||||
/**
|
||||
* If a Laravel environment has been specified on the server, we will
|
||||
|
|
|
@ -109,8 +109,8 @@ public function first($sql, $bindings = array())
|
|||
*/
|
||||
public function query($sql, $bindings = array())
|
||||
{
|
||||
// First we need to remove all expressions from the bindings since
|
||||
// they will be placed into the query as raw strings.
|
||||
// First we need to remove all expressions from the bindings
|
||||
// since they will be placed into the query as raw strings.
|
||||
foreach ($bindings as $key => $value)
|
||||
{
|
||||
if ($value instanceof Expression) unset($bindings[$key]);
|
||||
|
|
|
@ -43,10 +43,10 @@ class Form {
|
|||
*/
|
||||
public static function open($action = null, $method = 'POST', $attributes = array(), $https = false)
|
||||
{
|
||||
$attributes['action'] = static::action($action, $https);
|
||||
|
||||
$attributes['method'] = static::method($method);
|
||||
|
||||
$attributes['action'] = static::action($action, $https);
|
||||
|
||||
if ( ! array_key_exists('accept-charset', $attributes))
|
||||
{
|
||||
$attributes['accept-charset'] = Config::get('application.encoding');
|
||||
|
@ -207,7 +207,9 @@ public static function input($type, $name, $value = null, $attributes = array())
|
|||
|
||||
$id = static::id($name, $attributes);
|
||||
|
||||
return '<input'.HTML::attributes(array_merge($attributes, compact('type', 'name', 'value', 'id'))).'>'.PHP_EOL;
|
||||
$attributes = array_merge($attributes, compact('type', 'name', 'value', 'id'));
|
||||
|
||||
return '<input'.HTML::attributes($attributes).'>'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,20 +365,37 @@ public static function textarea($name, $value = '', $attributes = array())
|
|||
*/
|
||||
public static function select($name, $options = array(), $selected = null, $attributes = array())
|
||||
{
|
||||
$attributes = array_merge($attributes, array('id' => static::id($name, $attributes), 'name' => $name));
|
||||
$attributes['id'] = static::id($name, $attributes);
|
||||
|
||||
$attributes['name'] = $name;
|
||||
|
||||
$html = array();
|
||||
|
||||
foreach ($options as $value => $display)
|
||||
{
|
||||
$option_attributes = array('value' => HTML::entities($value), 'selected' => ($value == $selected) ? 'selected' : null);
|
||||
|
||||
$html[] = '<option'.HTML::attributes($option_attributes).'>'.HTML::entities($display).'</option>';
|
||||
$html[] = static::option($value, $display, $selected);
|
||||
}
|
||||
|
||||
return '<select'.HTML::attributes($attributes).'>'.implode('', $html).'</select>'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTML select element option.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $display
|
||||
* @return string $selected
|
||||
* @return string
|
||||
*/
|
||||
protected static function option($value, $display, $selected)
|
||||
{
|
||||
$selected = ($value === $selected) ? 'selected' : null;
|
||||
|
||||
$attributes = array('value' => HTML::entities($value), 'selected' => $selected);
|
||||
|
||||
return '<option'.HTML::attributes($attributes).'>'.HTML::entities($display).'</option>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTML checkbox input element.
|
||||
*
|
||||
|
|
|
@ -34,7 +34,7 @@ public static function script($url, $attributes = array())
|
|||
{
|
||||
$url = static::entities(URL::to_asset($url));
|
||||
|
||||
return '<script type="text/javascript" src="'.$url.'"'.static::attributes($attributes).'></script>'.PHP_EOL;
|
||||
return '<script src="'.$url.'"'.static::attributes($attributes).'></script>'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -241,7 +241,7 @@ public static function image($url, $alt = '', $attributes = array())
|
|||
*/
|
||||
public static function ol($list, $attributes = array())
|
||||
{
|
||||
return static::list_elements('ol', $list, $attributes);
|
||||
return static::listing('ol', $list, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,7 +253,7 @@ public static function ol($list, $attributes = array())
|
|||
*/
|
||||
public static function ul($list, $attributes = array())
|
||||
{
|
||||
return static::list_elements('ul', $list, $attributes);
|
||||
return static::listing('ul', $list, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,13 +264,13 @@ public static function ul($list, $attributes = array())
|
|||
* @param array $attributes
|
||||
* @return string
|
||||
*/
|
||||
private static function list_elements($type, $list, $attributes = array())
|
||||
private static function listing($type, $list, $attributes = array())
|
||||
{
|
||||
$html = '';
|
||||
|
||||
foreach ($list as $key => $value)
|
||||
{
|
||||
$html .= (is_array($value)) ? static::list_elements($type, $value) : '<li>'.static::entities($value).'</li>';
|
||||
$html .= (is_array($value)) ? static::elements($type, $value) : '<li>'.static::entities($value).'</li>';
|
||||
}
|
||||
|
||||
return '<'.$type.static::attributes($attributes).'>'.$html.'</'.$type.'>';
|
||||
|
@ -279,6 +279,9 @@ private static function list_elements($type, $list, $attributes = array())
|
|||
/**
|
||||
* Build a list of HTML attributes from an array.
|
||||
*
|
||||
* Numeric-keyed attributes will be assigned the same key and value to handle
|
||||
* attributes such as "autofocus" and "required".
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return string
|
||||
*/
|
||||
|
@ -288,8 +291,6 @@ public static function attributes($attributes)
|
|||
|
||||
foreach ((array) $attributes as $key => $value)
|
||||
{
|
||||
// Assume numeric-keyed attributes to have the same key and value.
|
||||
// Example: required="required", autofocus="autofocus", etc.
|
||||
if (is_numeric($key)) $key = $value;
|
||||
|
||||
if ( ! is_null($value))
|
||||
|
|
|
@ -2,6 +2,20 @@
|
|||
|
||||
return array(
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the pagination links. They may be easily changed by the developer to
|
||||
| anything they wish.
|
||||
|
|
||||
| The "status" line has two place-holders, :current and :last, for which
|
||||
| the current and last page numbers are substituted, respectively.
|
||||
|
|
||||
*/
|
||||
|
||||
'first' => 'First',
|
||||
'previous' => '← Previous',
|
||||
'status' => 'Page :current of :last',
|
||||
|
|
|
@ -2,6 +2,38 @@
|
|||
|
||||
return array(
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Attribute Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap attribute place-holders
|
||||
| with something more reader friendly, such as "E-Mail Address" instead
|
||||
| of "email".
|
||||
|
|
||||
| The Validator class will automatically search this array of lines when
|
||||
| attempting to replace the :attribute place-holder in error messages.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => array(),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used
|
||||
| by the validator class. Some of the rules contain multiple versions,
|
||||
| such as the size (max, min, between) rules. These versions are used
|
||||
| for different input types such as strings and files.
|
||||
|
|
||||
| These language lines may be easily changed by the developer to provide
|
||||
| custom error messages in their application. Error messages for custom
|
||||
| validation rules may also be added to this file.
|
||||
|
|
||||
*/
|
||||
|
||||
"accepted" => "The :attribute must be accepted.",
|
||||
"active_url" => "The :attribute is not a valid URL.",
|
||||
"alpha" => "The :attribute may only contain letters.",
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
* Manually load some core classes that are used on every request
|
||||
* This allows to avoid using the loader for these classes.
|
||||
*/
|
||||
require SYS_PATH.'input'.EXT;
|
||||
require SYS_PATH.'request'.EXT;
|
||||
require SYS_PATH.'response'.EXT;
|
||||
require SYS_PATH.'routing/route'.EXT;
|
||||
require SYS_PATH.'routing/router'.EXT;
|
||||
require SYS_PATH.'routing/loader'.EXT;
|
||||
|
@ -117,7 +119,7 @@
|
|||
*/
|
||||
if (Config::$items['session']['driver'] !== '')
|
||||
{
|
||||
Session\Manager::close(array(Input::old_input => Input::get()));
|
||||
Session\Manager::close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<?php namespace Laravel;
|
||||
|
||||
/**
|
||||
* The Proxy class, like the File class, is primarily intended to get rid of
|
||||
* the testability problems introduced by PHP's global functions.
|
||||
*
|
||||
* For instance, the APC cache driver calls the APC global functions. Instead of
|
||||
* calling those functions directory in the driver, we inject a Proxy instance into
|
||||
* the class, which allows us to stub the global functions.
|
||||
*/
|
||||
class Proxy {
|
||||
|
||||
/**
|
||||
* Magic Method for calling any global function.
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
return call_user_func_array($method, $parameters);
|
||||
}
|
||||
|
||||
}
|
|
@ -160,14 +160,11 @@ public static function ip($default = '0.0.0.0')
|
|||
/**
|
||||
* Get the HTTP protocol for the request.
|
||||
*
|
||||
* This method will return either "https" or "http", depending on whether HTTPS
|
||||
* is being used for the current request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function protocol()
|
||||
{
|
||||
return (isset($_SERVER['HTTPS']) and strtolower($_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';
|
||||
return Arr::get($_SERVER, 'SERVER_PROTOCOL', 'HTTP/1.1');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,7 +174,7 @@ public static function protocol()
|
|||
*/
|
||||
public static function secure()
|
||||
{
|
||||
return static::protocol() == 'https';
|
||||
return isset($_SERVER['HTTPS']) and strtolower($_SERVER['HTTPS']) !== 'off';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -227,7 +227,7 @@ public function render()
|
|||
/**
|
||||
* Send the response to the browser.
|
||||
*
|
||||
* All of the response header will be sent to the browser first, followed by
|
||||
* All of the response headers will be sent to the browser first, followed by
|
||||
* the content of the response instance, which will be evaluated and rendered
|
||||
* by the render method.
|
||||
*
|
||||
|
@ -235,26 +235,33 @@ public function render()
|
|||
*/
|
||||
public function send()
|
||||
{
|
||||
if ( ! isset($this->headers['Content-Type']))
|
||||
{
|
||||
$this->header('Content-Type', 'text/html; charset=utf-8');
|
||||
}
|
||||
|
||||
if ( ! headers_sent()) $this->send_headers();
|
||||
if ( ! headers_sent()) $this->headers();
|
||||
|
||||
echo $this->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the response headers to the browser.
|
||||
* Send all of the response headers to the browser.
|
||||
*
|
||||
* The develop may set any response headers they wish using the "header" method.
|
||||
* All of the headers set by the developer will be automatically sent to the
|
||||
* browser when the response is sent via the "send" method. There is no need
|
||||
* to call this method before calling the "send" method.
|
||||
*
|
||||
* The protocol and status header will be set automatically, as well as the
|
||||
* content-type and charset, unless those headers have been set explicitly.
|
||||
* The content-type charset used will be the application encoding.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_headers()
|
||||
public function headers()
|
||||
{
|
||||
$protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
|
||||
if ( ! isset($this->headers['Content-Type']))
|
||||
{
|
||||
$this->header('Content-Type', 'text/html; charset='.Config::$items['application']['encoding']);
|
||||
}
|
||||
|
||||
header($protocol.' '.$this->status.' '.$this->statuses[$this->status]);
|
||||
header(Request::protocol().' '.$this->status.' '.$this->statuses[$this->status]);
|
||||
|
||||
foreach ($this->headers as $name => $value)
|
||||
{
|
||||
|
|
|
@ -92,6 +92,9 @@ public function everything()
|
|||
|
||||
$routes = array();
|
||||
|
||||
// First, we'll grab the base routes from the application directory.
|
||||
// Once we have these, we'll merge all of the nested routes in the
|
||||
// routes directory into this array of routes.
|
||||
if (file_exists($path = $this->base.'routes'.EXT))
|
||||
{
|
||||
$routes = array_merge($routes, require $path);
|
||||
|
|
|
@ -72,25 +72,29 @@ public static function encrypt($value)
|
|||
*/
|
||||
public static function decrypt($value)
|
||||
{
|
||||
// Since all encrypted strings generated by this class are base64
|
||||
// encoded, we will first attempt to base64 decode the string.
|
||||
// If we can't do it, we'll bail out.
|
||||
if ( ! is_string($value = base64_decode($value, true)))
|
||||
{
|
||||
throw new \Exception('Decryption error. Input value is not valid base64 data.');
|
||||
}
|
||||
|
||||
// Extract the input vector and the encrypted string from the value.
|
||||
// These will be used by Mcrypt to properly decrypt the value.
|
||||
$iv = substr($value, 0, static::iv_size());
|
||||
|
||||
$value = substr($value, static::iv_size());
|
||||
list($iv, $value) = static::parse($value);
|
||||
|
||||
$key = Config::$items['application']['key'];
|
||||
|
||||
return rtrim(mcrypt_decrypt(static::$cipher, $key, $value, static::$mode, $iv), "\0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an encrypted value into the input vector and the actual value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
protected static function parse($value)
|
||||
{
|
||||
return array(substr($value, 0, static::iv_size()), substr($value, static::iv_size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input vector size for the cipher and mode.
|
||||
*
|
||||
|
|
|
@ -269,18 +269,12 @@ protected static function replace($search, $replace, $keys)
|
|||
/**
|
||||
* Close the session handling for the request.
|
||||
*
|
||||
* @param array $flash
|
||||
* @return void
|
||||
*/
|
||||
public static function close($flash = array())
|
||||
public static function close()
|
||||
{
|
||||
$config = Config::$items['session'];
|
||||
|
||||
foreach ($flash as $key => $value)
|
||||
{
|
||||
static::flash($key, $value);
|
||||
}
|
||||
|
||||
static::$driver->save(static::age(), $config, static::$exists);
|
||||
|
||||
static::$transporter->put(static::$session['id'], $config);
|
||||
|
|
|
@ -563,7 +563,9 @@ protected function replace($message, $attribute, $rule, $parameters)
|
|||
// Except for "between" every replacement should be the first parameter.
|
||||
$max = ($rule == 'between') ? $parameters[1] : $parameters[0];
|
||||
|
||||
$message = str_replace(array(':size', ':min', ':max'), array($parameters[0], $parameters[0], $max), $message);
|
||||
$replace = array($parameters[0], $parameters[0], $max);
|
||||
|
||||
$message = str_replace(array(':size', ':min', ':max'), $replace, $message);
|
||||
}
|
||||
elseif (in_array($rule, $this->inclusion_rules))
|
||||
{
|
||||
|
|
|
@ -133,12 +133,16 @@ protected static function name($name)
|
|||
{
|
||||
if (is_null(static::$composers)) static::$composers = require APP_PATH.'composers'.EXT;
|
||||
|
||||
// The view's name may specified in several different ways in the composers file.
|
||||
// The composer may simple have a string value, which is the name. Or, it may
|
||||
// an array value in which a "name" key exists.
|
||||
// The view's name may specified in several different ways in the
|
||||
// composers file. The composer may simple have a string value,
|
||||
// which is the name. Or, it may an array value in which a
|
||||
// "name" key exists.
|
||||
foreach (static::$composers as $key => $value)
|
||||
{
|
||||
if ($name === $value or (is_array($value) and $name === Arr::get($value, 'name'))) return $key;
|
||||
if ($name === $value or (is_array($value) and $name === Arr::get($value, 'name')))
|
||||
{
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,10 +174,10 @@ public function render()
|
|||
{
|
||||
static::compose($this);
|
||||
|
||||
// All nested views and responses are evaluated before the main view.
|
||||
// This allows the assets used by these views to be added to the asset
|
||||
// container before the
|
||||
// main view is evaluated and dumps the links to the assets.
|
||||
// All nested views and responses are evaluated before the
|
||||
// main view. This allows the assets used by these views to
|
||||
// be added to the asset container before the main view is
|
||||
// evaluated and dumps the links to the assets.
|
||||
foreach ($this->data as &$data)
|
||||
{
|
||||
if ($data instanceof View or $data instanceof Response)
|
||||
|
@ -184,9 +188,9 @@ public function render()
|
|||
|
||||
ob_start() and extract($this->data, EXTR_SKIP);
|
||||
|
||||
// If the view is a "Blade" view, we need to check the view for modifications
|
||||
// and get the path to the compiled view file. Otherwise, we'll just use the
|
||||
// regular path to the view.
|
||||
// If the view is a "Blade" view, we need to check the view for
|
||||
// modifications and get the path to the compiled view file.
|
||||
// Otherwise, we'll just use the regular path to the view.
|
||||
$view = (strpos($this->path, BLADE_EXT) !== false) ? $this->compile() : $this->path;
|
||||
|
||||
try { include $view; } catch (Exception $e) { ob_get_clean(); throw $e; }
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
| Tick... Tock... Tick... Tock
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
define('START_TIME', microtime(true));
|
||||
|
||||
/*
|
||||
|
@ -43,6 +44,7 @@
|
|||
| 3... 2... 1... Lift-off!
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
require $laravel.'/laravel.php';
|
||||
|
||||
//echo number_format((microtime(true) - START_TIME) * 1000, 2);
|
||||
echo number_format((microtime(true) - START_TIME) * 1000, 2);
|
Loading…
Reference in New Issue