Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Thursday, February 5, 2009

Erro do AJAX .Net no Internet Explorer, comédia!

Bem que o IE é uma porcaria todo mundo sabe. Tirando a lentidão do coitado ainda é cheio de bugs, e cá vai mais um.

Em aplicações .Net ASPX com AJAX, pode acontecer de algum sortudo ter o seguinte erro de JavaScript após algum tempo de execução:

Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.
Details: Error parsing near '


E o melhor deste erro é que só acontece no IE, no Firefox funciona sempre perfeitamente. Basicamente um problema exclusivo do IE, ainda não sei por que não colocam o Firefox nas empresas, a desculpa de que não é corporativo não cola.

Para resolver isto a "melhor" maneira para o usuário é, limpar os arquivos temporários e reiniciar o browser :D

Andei procurando a algumas semanas uma solução para isto e a única que me ajudou foi neste link, lá em baixo:

http://weblogs.asp.net/leftslipper/archive/2007/02/26/sys-webforms-pagerequestmanagerparsererrorexception-what-it-is-and-how-to-avoid-it.aspx#6815054

# re: Sys.WebForms.PageRequestManagerParserErrorException - what it is and how to avoid it
Friday, January 02, 2009 1:20 PM by Arjan Douwes
I am experiencing the same issue with my Ajax.net website. After adding <customErrors mode="Off"/> to the web.config file at the problem seems to be that the site is being hosted on a webfarm and the SessionState is being encrypted using the MAC Address. The issue with webfarms is that the EnableViewStateMac is by default set to True which causes problems.
In the web.config I changed the <Page> tag to <Page EnableViewStateMac="False">
I also added
EnableEventValidation="false" EnableViewStateMac="false"
to the <%@ Page ... directive of the aspx pages.
These two changes to the website solved my issue.


Ou seja, mudar no web.config o customErrors:


<customErrors mode="Off"/>


E colocar nos ASPX que trabalham com AJAX:


<%@ Page Language="C#" EnableEventValidation="false" EnableViewStateMac="false" ...


Pronto, no meu caso resolveu, e se tiveres sorte também poderá resolver.

Wednesday, December 17, 2008

Chamando Web Services sobre HTTPS

Utilizar web service sobre HTTPS é da mesma forma que um web service HTTP.

Adicionar a referência web ao projeto, com a url HTTPS.

O uso do web service a nível de código é a mesma coisa.

Só que ao tentar chamar o web service poderá acontecer de obter esta mensagem erro:

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

Colocando este código antes da chamada ao web sersvice provavelmente irá resolver o problema:


System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate
{
return true;
};


Basicamente é por que o .Net esta rejeitando o certificado por não ser um certificado válido, com o código acima, mesmo não sendo um certificado válido ele irá aceitar o certificado, e conseguirá comunicar com o web service.

Thursday, November 27, 2008

Script Python para consumir Web Services em .Net

Tive um desafio a poucos dias. Que foi consumir Web Services feitos em .Net a partir de um servidor Solaris 10 via processo.

De todas as soluções possíveis que estive a ver, a melhor foi usar Python.

Encontrei este exemplo:

http://users.skynet.be/pascalbotte/rcx-ws-doc/postxmlpython.htm

Assim fiz o WebServiceGenericClientNet.py:

#!/usr/bin/python

# by eduveks

import sys, httplib, array

try:
    host = ""
    url = ""
    namespace = ""
    header = ""
    method = ""
    params = {}

    for arg in sys.argv[1:]:
        if host == "" and arg.find("host=") == 0:
            host = arg[len("host="):]
        elif url  == "" and arg.find("url=") == 0:
            url  = arg[len("url="):]
        elif namespace == "" and arg.find("namespace=") == 0:
            namespace = arg[len("namespace="):]
        elif header == "" and arg.find("header=") == 0:
            header = arg[len("header="):]
        elif method == "" and arg.find("method=") == 0:
            method = arg[len("method="):]
        elif arg.find("param_") == 0:
            params[arg[len("param_"):arg.find("=")]] = arg[arg.find("=") + 1:]

    SOAP_Request = ""
    SOAP_Request += "<soap:Envelope"
    SOAP_Request += " soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
    SOAP_Request += " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""
    SOAP_Request += " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
    SOAP_Request += " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
    if header != "":
        SOAP_Request += "<soap:Header>"
        SOAP_Request += header
        SOAP_Request += "</soap:Header>"
    SOAP_Request += "<soap:Body>"
    SOAP_Request += "<"+ method +" xmlns=\""+ namespace +"\">"
    for param in params.keys():
        SOAP_Request += "<"+ param +">"+ params[param] +"</"+ param +">"
    SOAP_Request += "</"+ method +">"
    SOAP_Request += "</soap:Body>"
    SOAP_Request += "</soap:Envelope>"

    http = httplib.HTTP(host)
    http.putrequest("POST", url)
    http.putheader("Host", host)
    http.putheader("User-Agent", "Python")
    http.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
    http.putheader("Content-length", "%d" % len(SOAP_Request))
    http.putheader("SOAPAction", "\""+ namespace + method +"\"")
    http.endheaders()
    http.send(SOAP_Request)

    http_response_statuscode, http_response_statusmessage, http_response_header = http.getreply()
    SOAP_Response = http.getfile().read()
    if http_response_statuscode == 200 and http_response_statusmessage == "OK":
        print SOAP_Response[SOAP_Response.find("<"+ method +"Result>") + len("<"+ method +"Result>"):SOAP_Response.find("</"+ method +"Result>")]
    else:
        print "### ERROR ###############"
        if SOAP_Response.find("<faultstring>") > -1:
            print SOAP_Response[SOAP_Response.find("<faultstring>")  + len("<faultstring>"):SOAP_Response.find("</faultstring>")]
        print "Response: ", http_response_statuscode, http_response_statusmessage
        print http_response_header
        print SOAP_Response

except:
    print "### ERROR ###############"
    for err in sys.exc_info():
        print err


Para executar o script basta dar permissões de execução e executar:

chmod +x WebServiceGenericClientNet.py
./WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld


O output é:

HelloWorld


Os parâmetros do WebServiceGenericClientNet.py são:

host: Endereço do servidor
url: Endereço do web service
namespace: Namespace do web service, que pode ser encontrado vendo o WSDL, http://localhost/HelloWorld.asmx?WSDL
method: Método do web service a ser chamado
param_*NOME_DO_PARAMETRO*: Caso o método precise de parâmetros, podem ser definidos assim, atenção a ordem.

Além de usar este script no Solaris, também acabei por usar este script para chamar web services apartir do .Net/C#, pois são web services que serão atualizados constantemente, com novos métodos e talz, e em vez de ficar atualizando o WSDL, basta chamar diretamente com o script a queima-roupa, e a configuração da chamada dos web services pode ser feita a partir de configurações em base de dados. Para fazer isto no .Net/C# foi só lançar um processo assim:

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "C:\Python26\python.exe";
process.StartInfo.Arguments = "WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld";
process.StartInfo.WorkingDirectory = "C:\Python26\";
process.Start();
string output = process.StandardOutput.ReadToEnd();

O script suporta a configuração do header, passando o argumento header=... para o script.

Para explorar e ver fácilmente os SOAPs enviados e recebidos na chamada de um web service, existe o WebServiceStudio:

Friday, January 11, 2008

TextBoxRevolution

Precisei fazer uma TextBox com fundo transparente e também imagem de fundo, totalmente customizada, procurei na net e encontrei uma base, então resolvi melhorar e organizar bem o código, e esta ai o resultado.

Uma coisa que as vezes faz falta no Windows.Form, é o Attributes nos Controls, algo que temos no Asp.Net mas não no Windows.Form, e como eu também precisava deste recurso na TextBox então resolvi implementar isto também, por isso esta TextBox também suporta o Attributes, TextBoxRevolution.Attributes, assim já é possível anexar outros objetos ao Control.

[CODE]
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace TextBoxRevolutionTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form form = new Form();
form.Text = "TextBoxRevolution";
form.Width = 450;
form.Height = 250;
string text = @"
The Foundations of the GPL
Nobody should be restricted by the software they use. There are four freedoms that every user should have:
* the freedom to use the software for any purpose,
* the freedom to share the software with your friends and neighbors,
* the freedom to change the software to suit your needs, and
* the freedom to share the changes you make.
When a program offers users all of these freedoms, we call it free software.
Developers who write software can release it under the terms of the GNU GPL. When they do, it will be free software and stay free software, no matter who changes or distributes the program. We call this copyleft: the software is copyrighted, but instead of using those rights to restrict users like proprietary software does, we use them to ensure that every user has freedom.
";
TextBoxRevolution textBoxRevolution = new TextBoxRevolution();
textBoxRevolution.Name = "textBoxRevolution";
textBoxRevolution.Dock = DockStyle.Fill;
textBoxRevolution.Control.Name = "textBoxRevolutionOut";
textBoxRevolution.Transparent = true;
textBoxRevolution.Height = 0;
textBoxRevolution.TopMargin = 5;
textBoxRevolution.BorderStyle = BorderStyle.None;
textBoxRevolution.Multiline = true;
textBoxRevolution.ForeColor = Color.FromArgb(0, 0, 0);
textBoxRevolution.Text = text;
textBoxRevolution.Select(0, 0);
textBoxRevolution.Background += new TextBoxRevolution.OnBackground(textBoxRevolution_Background);
form.Controls.Add(textBoxRevolution);
Application.Run(form);
}
static Image textBoxRevolution_Background(TextBoxRevolution textBoxRevolution)
{
Color topColor = Color.FromArgb(235, 237, 241);
Color bottomColor = Color.FromArgb(225, 229, 232);
if (textBoxRevolution.Control.Name.EndsWith("Over"))
{
topColor = Color.FromArgb(249, 247, 255);
bottomColor = Color.FromArgb(238, 234, 255);
}
Bitmap img = new Bitmap(textBoxRevolution.Width, textBoxRevolution.Height);
Graphics g = Graphics.FromImage(img);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillRectangle(new SolidBrush(topColor), 0, 0, textBoxRevolution.Width, textBoxRevolution.Height);
g.FillRectangle(new SolidBrush(bottomColor), 0, textBoxRevolution.Height / 2, textBoxRevolution.Width - 50, textBoxRevolution.Height / 2);
g.FillEllipse(new SolidBrush(bottomColor), textBoxRevolution.Width - 100, textBoxRevolution.Height / 2, 100, 20);
g.FillRectangle(new SolidBrush(bottomColor), textBoxRevolution.Width - 50, (textBoxRevolution.Height / 2) + 10, textBoxRevolution.Width, textBoxRevolution.Height / 2);
return img;
}
}
}

namespace System.Windows.Forms
{
public class TextBoxRevolution : TextBox
{

public delegate Image OnBackground(TextBoxRevolution textBoxRevolution);
public event OnBackground Background;

PictureBox pictureBox = null;
Dictionary<string, object> attributes = new Dictionary<string, object>();

public TextBoxRevolution()
{
pictureBox = new PictureBox();
pictureBox.Dock = DockStyle.Fill;
this.ShortcutsEnabled = false;
this.Cursor = Cursors.Arrow;
this.Controls.Add(pictureBox);
}

public Dictionary<string, object> Attributes
{
get
{
return attributes;
}
set
{
attributes = value;
}
}

bool transparent = false;
public bool Transparent
{
get
{
return transparent;
}
set
{
transparent = value;
}
}

public PictureBox Control
{
get
{
return pictureBox;
}
}

int topMargin = 0;
public int TopMargin
{
get
{
return topMargin * -1;
}
set
{
topMargin = value;
}
}

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case Win32.WM_PAINT:
Draw();
break;
case Win32.WM_HSCROLL:

case Win32.WM_VSCROLL:
this.Invalidate();
break;
}
}

public void Draw()
{
Bitmap bmpCaptured = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
Bitmap bmpResult = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
Rectangle r = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
Win32.CaptureWindow(this, ref bmpCaptured);
if (Transparent)
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
}
ImageAttributes imgAttrib = new ImageAttributes();

if (Transparent)
{
ColorMap[] colorMap = new ColorMap[1];
colorMap[0] = new ColorMap();
colorMap[0].OldColor = Color.White;
colorMap[0].NewColor = Color.Transparent;
imgAttrib.SetRemapTable(colorMap);
}
Graphics g = Graphics.FromImage(bmpResult);


try
{
g.DrawImage(Background(this), r, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, GraphicsUnit.Pixel, imgAttrib);
}
catch
{
}
g.DrawImage(bmpCaptured, r, 0, TopMargin, this.ClientRectangle.Width, this.ClientRectangle.Height, GraphicsUnit.Pixel, imgAttrib);
g.Dispose();
pictureBox.Image = (Image)bmpResult.Clone();
}

public int ContentHeight
{
get
{
return LinesCount * base.Font.Height;
}
}

public int LinesCount
{
get
{
const int EM_GETLINECOUNT = 186;
int lineCount = Win32.SendMessage(base.Handle, EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero);
return lineCount + 1;
}
}
}

public class Win32
{
public const int WM_MOUSEMOVE = 0x0200;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_RBUTTONDOWN = 0x0204;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_MOUSELEAVE = 0x02A3;
public const int WM_PAINT = 0x000F;
public const int WM_ERASEBKGND = 0x0014;
public const int WM_PRINT = 0x0317;
public const int EN_HSCROLL = 0x0601;
public const int EN_VSCROLL = 0x0602;
public const int WM_HSCROLL = 0x0114;
public const int WM_VSCROLL = 0x0115;
public const int EM_GETSEL = 0x00B0;
public const int EM_LINEINDEX = 0x00BB;
public const int EM_LINEFROMCHAR = 0x00C9;
public const int EM_POSFROMCHAR = 0x00D6;
[DllImport("USER32.DLL", EntryPoint = "PostMessage")]
public static extern bool PostMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("USER32.DLL", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("USER32.DLL", EntryPoint = "GetCaretBlinkTime")]
public static extern uint GetCaretBlinkTime();
public const int WM_PRINTCLIENT = 0x0318;
public const long PRF_CHECKVISIBLE = 0x00000001L;
public const long PRF_NONCLIENT = 0x00000002L;
public const long PRF_CLIENT = 0x00000004L;
public const long PRF_ERASEBKGND = 0x00000008L;
public const long PRF_CHILDREN = 0x00000010L;
public const long PRF_OWNED = 0x00000020L;
public static bool CaptureWindow(System.Windows.Forms.Control control, ref System.Drawing.Bitmap bitmap)
{
Graphics g2 = Graphics.FromImage(bitmap);
int meint = (int)(PRF_CLIENT | PRF_ERASEBKGND);
System.IntPtr meptr = new System.IntPtr(meint);
System.IntPtr hdc = g2.GetHdc();
Win32.SendMessage(control.Handle, Win32.WM_PRINT, hdc, meptr);
g2.ReleaseHdc(hdc);
g2.Dispose();
return true;
}
}
}
[/CODE]

Monday, June 4, 2007

Cache

Por razões de desempenho, para fazer menos requisições e execuções de querys na DB, surgio a necessidade de fazer cache, mas como manter os filtros e os resultado de diversas querys distintas? Tive a idéia de fazer serialização dos DataTable, e para isto fiz uma classe, que pode além de DataTable, fazer serialização de qualquer objecto que suporte serialization.

Exemplo do uso da classe Cache:

[CODE]
Cache cache = new Cache(WebConfigurationManager.AppSettings["CacheFolder"]);
if (cache.PleaseSaveMe(query))
{
cache.Save(query, dv.Table, WebConfigurationManager.AppSettings["CacheTime"]);
}
else
{
(DataTable)cache.Load(query);
}
[/CODE]

Neste caso usei a query para servir de ID para o Cache, ou seja sempre que for uma query diferente é gravado em Cache o DataTable gerado por esta query, ou se for uma query já executada então o DataTable é recuperado.

Descrição:

[CODE]
new Cache("CACHE_FOLDER");
if (cache.PleaseSaveMe("CACHE_ID"))
{
cache.Save("CACHE_ID", CACHE_OBJECT, "CACHE_TIME");
}
else
{
(CACHE_OBJECT)cache.Load("CACHE_ID")
}
[/CODE]

CACHE_FOLDER é o caminho para a pasta que vai conter os arquivos de cache.

CACHE_ID é o ID de referência de um objeto em cache, é a chave para poder recupera-lo.

CACHE_OBJECT é o objecto que será gravado em cache, lembrando que tem o objeto tem que suportar serialization.

CACHE_TIME define o tempo em que o objeto ficará em cache, pode ser passado no seguinte formato (também é possível em long):
  - "2W" = 2 semanas
  - "5D" = 5 dias
  - "1H" = 1 hora
  - "15M" = 15 minutos
  - "50S" = 50 segundos

cache.PleaseSaveMe verifica se é necessário gravar o cache.

cache.Save grava um novo ou sobrepõe o objeto em cache.

cache.Load recupera o objeto que esta em cache.

Para cada objeto em cache é gerado 3 arquivos.

  - [GUID].id.cache identificador do cache, o tal ID que é passado no save, e que é usado para recuperar o objeto.

  - [GUID].obj.cache arquivo do objeto serializado.

  - [GUID].time.cache tempo que esta em cache.

Código da Class Cache:

[CODE]
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
 
public class Cache
{
public const string ID_EXT = ".id.cache";
public const string TIME_EXT = ".time.cache";
public const string OBJ_EXT = ".obj.cache";
 
private string folder = "";
 
public const long WEEK = 6048000000000L;
public const long DAY = 864000000000L;
public const long HOUR = 36000000000L;
public const long MINUTE = 600000000L;
public const long SECOND = 10000000L;
 
public Cache(string _folder)
{
folder = _folder;
}
 
public string GetGuid(string id)
{
string[] files = Directory.GetFiles(folder);
string guid = "";
foreach (string file_id in files)
{
if (file_id.EndsWith(ID_EXT))
{
StreamReader srID = new StreamReader(file_id);
if (id == srID.ReadToEnd())
{
guid = file_id.Replace(folder, "").Replace(ID_EXT, "");
}
srID.Close();
if (guid != "")
{
break;
}
}
}
return guid;
}
 
public object Load(string id)
{
string fileOBJ = folder + GetGuid(id) + OBJ_EXT;
FileStream fsOBJ = new FileStream(fileOBJ, FileMode.Open);
object obj = new BinaryFormatter().Deserialize(fsOBJ);
fsOBJ.Close();
return obj;
}
 
public void Save(string id, object obj, long lifeTime)
{
Save(id, obj, lifeTime.ToString(), true);
}
 
public void Save(string id, object obj, string lifeTime)
{
Save(id, obj, lifeTime, false);
}
 
private void Save(string id, object obj, string lifeTime, bool lifeTimeIsLong)
{
Clear(id);
if (!lifeTimeIsLong)
{
string timeType = lifeTime.Substring(lifeTime.Length - 1);
long time = Convert.ToInt64(lifeTime.Substring(0, lifeTime.Length - 1));
switch (timeType.ToUpper())
{
case "W":
lifeTime = ""+ (time * WEEK);
break;
case "D":
lifeTime = ""+ (time * DAY);
break;
case "H":
lifeTime = ""+ (time * HOUR);
break;
case "M":
lifeTime = ""+ (time * MINUTE);
break;
case "S":
lifeTime = ""+ (time * SECOND);
break;
default:
break;
}
}
string file = folder + Guid.NewGuid().ToString();
string file_id = file + ID_EXT;
string file_time = file + TIME_EXT;
string file_obj = file + OBJ_EXT;
StreamWriter swID = File.CreateText(file_id);
swID.Write(id);
swID.Close();
StreamWriter swTIME = File.CreateText(file_time);
swTIME.WriteLine(DateTime.Now.Ticks.ToString());
swTIME.WriteLine(lifeTime);
swTIME.Close();
 
MemoryStream msOBJ = new MemoryStream();
new BinaryFormatter().Serialize(msOBJ, obj);
FileStream fsOBJECT = File.Create(file_obj);
fsOBJECT.Write(msOBJ.ToArray(), 0, (int)msOBJ.Length);
fsOBJECT.Flush();
fsOBJECT.Close();
msOBJ.Close();
}
 
public bool PleaseSaveMe(string id)
{
 
string[] files = Directory.GetFiles(folder);
bool found = false;
bool result = false;
foreach (string file_id in files)
{
if (file_id.EndsWith(ID_EXT))
{
string file_time = file_id.Replace(ID_EXT, TIME_EXT);
StreamReader srID = new StreamReader(file_id);
StreamReader srTIME = new StreamReader(file_time);
string _id = srID.ReadToEnd();
long createTime = Convert.ToInt64(srTIME.ReadLine());
long lifeTime = Convert.ToInt64(srTIME.ReadLine());
srID.Close();
srTIME.Close();
if (id == _id)
{
found = true;
if (DateTime.Now.Ticks - lifeTime > createTime)
{
result = true;
}
break;
}
}
}
if (found == false)
{
return true;
}
return result;
}
 
public void Clear()
{
Clear("");
}
 
public void Clear(string id)
{
string[] files = Directory.GetFiles(folder);
foreach (string file_id in files)
{
if (file_id.EndsWith(ID_EXT))
{
string file_time = file_id.Replace(ID_EXT, TIME_EXT);
StreamReader srID = new StreamReader(file_id);
StreamReader srTIME = new StreamReader(file_time);
string _id = srID.ReadToEnd();
long createTime = Convert.ToInt64(srTIME.ReadLine());
long lifeTime = Convert.ToInt64(srTIME.ReadLine());
srID.Close();
srTIME.Close();
if (id == _id)
{
File.Delete(file_id);
File.Delete(file_time);
File.Delete(file_id.Replace(ID_EXT, OBJ_EXT));
}
else
{
if (DateTime.Now.Ticks - lifeTime > createTime)
{
File.Delete(file_id);
File.Delete(file_time);
File.Delete(file_id.Replace(ID_EXT, OBJ_EXT));
}
}
}
}
}
}

[/CODE]