Popular Posts
Enable SSL connection for Jsoup import org.jsoup.Connection; import org.jsoup.Jsoup; import javax.net.ssl.*; import java.io.IOException; import java.security.KeyManagement... Word break tag : <wbr/> (HTML5) The  HTML  <wbr>  tag  is  used  defines  a  potential  line  break  point  if  needed.  This  stands  for  Word  BReak. This  is  u... Build an OpenVPN server on android device Preparation An android device, in this case, Sony xperia Z is used Root permission required Linux Deploy for deploy i...
Blog Archive
Stats
ADD ... THEN ... UNTIL ...
data: begin of SERIES,
         N1 type I value 10,
         N2 type I value 20,
         N3 type I value 30,
         N4 type I value 40,
         N5 type I value 50,
         N6 type I value 60,
      end of SERIES.
data SUM type I.
add SERIES-N1 then SERIES-N2 until SERIES-N5 giving SUM.
write SUM.
add SERIES-N2 then SERIES-N3 until SERIES-N6 to SUM.
write / SUM.
output:
       150
       350
Horizontal, vertical line and space
* Horizontal line
write sy-uline.
write '------'.
uline.

* Vertical line
write sy-vline.
write '|'.

* space
skip 3.
skip to line 10.
WRITE: format option
通用格式化選項
選項 用途選項
LEFT-JUSTIFIED 輸出對左對齊
CENTERED 輸出置中對齊
RIGHT-JUSTIFIED 輸出對右對齊
UNDER <g> 輸出至<g>下方
NO-GAP 忽略輸出後方的間格空格
USING EDIT MASK <m> 指定輸出格式
USING NO EDIT MASK 取消abap dictionary中定義的輸出格式
NO-ZERO 取消前導的'0'以空格替代

數值格式化選項
選項 用途選項
NO-SIGN 取消前置符號
DECIMALS <d> 定義小數位數
EXPONENT <e> 定義資料類型F中的冪數
ROUND <r> 四拾五入至指定位數
CURRENCY <c> 以TCURX表中定義的貨幣格式化
UNIT <u> 按表格T006中為類型P欄位所指定的單位<u>固定小數位數

日期格式化選項
選項 用途選項
DD/MM/YY 以系統設定的分隔符號格式化
MM/DD/YY 以系統設定的分隔符號格式化
DD/MM/YYYY 以系統設定的分隔符號格式化
MM/DD/YYYY 以系統設定的分隔符號格式化
DDMMYY 無分隔符號格式化
MMDDYY 無分隔符號格式化
YYMMDD 無分隔符號格式化
Data type
資料類型 預設大小 大小 初始值 輸出長度 輸出定位 說明
C 1 1-65535 SPACE 字串長度 LEFT-JUSTIFIED 字元,字串
D 8 8 '00000000' 8 LEFT-JUSTIFIED 日期
F 8 8 0 24 RIGHT-JUSTIFIED 浮點數
I 4 4 0 11 RIGHT-JUSTIFIED 整數
N 1 1-65535 '000...0' 字串長度 LEFT-JUSTIFIED 數值字串
P 8 1-16 0 2*字串長度+1 RIGHT-JUSTIFIED 壓縮號
T 6 6 '000000' 6 LEFT-JUSTIFIED 時間
X 1 1-65536 X'00' 2*字串長度 LEFT-JUSTIFIED 16進制
abap naming rule
命名規則
  • 報表程式(以列表格式輸出資料分析):Yaxxxxxx或Zaxxxxxx。用應用程式區的分類字母替換a。
    任何有效字元替換x。注意SAP報表程式遵守相似的命名約定:Raxxxxxx。
  • 任何其他ABAP/4程式(培訓程式或事務程式):SAPMYxxx或SAPMZxxx。用有效字元替換x。
    注意標準SAPABAP/4程式遵守相似的命名約定:SAPMaxxx,其中a代表某應用程式區。
for xml usage
SELECT
p.[product_name],
p.[product_imgstyle],
p.[product_color],
p.[product_size],
p.[product_weight],
p.[product_desc],
(
 SELECT l.[purchase_url], s.[store_name], s.[display_order]
 FROM [Product_StoreLink] l, [Store] s
 WHERE l.[store_id] = s.[store_id] AND l.[product_id] = p.[product_id]
 FOR XML RAW
) store
FROM Product p
Tab control using url hash variant
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>anchor test with tab design</title>
    <style type="text/css">
        ul.tab
        {
            margin: 1px 0px;
            padding: 0px;
        }
        ul.tab li
        {
            display: inline;
        }
        ul.tab li a
        {
            padding: 3px;
            margin-right: 2px;
            background-color: #eee;
            border: 1px outset gray;
            font-size: small;
            color: Blue;
        }
        ul.tab li a:hover
        {
            background-color: gold;
        }
        ul.tab li a.active_tab
        {
            background-color: Orange;
        }
        
        div.tab_container
        {
            border: 1px solid gray;
            padding: 10px;
        }
        
        a
        {
            text-decoration: none;
        }
        a:hover
        {
            text-decoration: underline;
        }
    </style>
    <script src="Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        function tab_change() {
            // 頁籤序號
            var index = location.hash.substring(1);
            if (!index) index = '0';
            index = parseInt(index);

            // 變更頁籤css
            $('ul.tab li a').removeClass('active_tab').eq(index).addClass('active_tab');

            // postback, 以觸發update panel更新
            //$('<%=hdnTabIndex.ClientID%>').val(index);
            __doPostBack('hdnTabIndex', index);
        }
        $(function () {
            // 頁籤變更觸發
            $(window).bind('hashchange', tab_change);
            // 載入頁面時更新
            tab_change();
        });
        
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="smPage" runat="server">
    </asp:ScriptManager>
    <ul class="tab">
        <li><a href="#0" class="active_tab">第一頁</a></li>
        <li><a href="#1">第二頁</a></li>
        <li><a href="#2">第三頁</a></li>
        <li><a href="#3">第四頁</a></li>
        <li><a href="#4">第五頁</a></li>
    </ul>
    <div class="tab_container">
        <asp:UpdatePanel ID="upTabContainer" runat="server" UpdateMode="Conditional" RenderMode="Block">
            <ContentTemplate>
                <asp:HiddenField ID="hdnTabIndex" runat="server" />
                <asp:Panel ID="plTabContainer0" runat="server" Visible="false">
                    第一頁內容
                </asp:Panel>
                <asp:Panel ID="plTabContainer1" runat="server" Visible="false">
                    第二頁內容
                </asp:Panel>
                <asp:Panel ID="plTabContainer2" runat="server" Visible="false">
                    第三頁內容
                </asp:Panel>
                <asp:Panel ID="plTabContainer3" runat="server" Visible="false">
                    第四頁內容
                </asp:Panel>
                <asp:Panel ID="plTabContainer4" runat="server" Visible="false">
                    第五頁內容
                </asp:Panel>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Tab_Load();
        }

        protected void Tab_Load()
        {
            // postback參數
            string _index = Request.Form["__EVENTARGUMENT"];
            if (string.IsNullOrEmpty(_index)) _index = "0";

            plTabContainer0.Visible = false;
            plTabContainer1.Visible = false;
            plTabContainer2.Visible = false;
            plTabContainer3.Visible = false;
            plTabContainer4.Visible = false;
            upTabContainer.FindControl("plTabContainer" + _index).Visible = true;
        }
    }
}
Speed up VisualStudio using RAMDisk
STEP:
  1. Install RAMDisk and create a ramdisk r:
  2. Create a batch file and setting temp variant:
    @echo off
    set tmp=r:\
    set temp=r:\
    call "C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"
  3. edit web.config
    <compilation debug="true" tempDirectory="r:\">
String.replaceAll()
String.prototype.replaceAll = function(oldValue, newValue) {
    return this.split(oldValue).join(newValue);
}
Register User Controls and Custom Controls in Web.config
<system.web>
    <pages>
        <controls>
            <add tagPrefix="scottgu" src="~/Controls/Header.ascx" tagName="header"/>
            <add tagPrefix="scottgu" src="~/Controls/Footer.ascx" tagName="footer"/>
            <add tagPrefix="ControlVendor" assembly="ControlVendorAssembly"/>
        </controls>
    </pages>
</system.web>
Parse query string
Uri url = new Uri("http://www.google.com.tw/search?sourceid=chrome&ie=UTF-8&q=uri");

System.Collections.Specialized.NameValueCollection queryString
    = System.Web.HttpUtility.ParseQueryString(url.Query);

Console.WriteLine(queryString.Get("sourceid"));
Console.WriteLine(queryString.Get("ie"));
script path in master page
use script manager (script will appear in body section)
<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <asp:ScriptReference Path="~/jquery.js" />
    </Scripts>
</asp:ScriptManager>
use ResolveClientUrl method
<script type="text/javascript" src="<%= Page.ResolveClientUrl("~/jquery.js") %>"></script>
asp.net form validate
// 確認更新
function confirmUpdate(
    confirmMessage, /* 確認訊息 */
    validateGroup, /* validate group*/
    fn /* 自訂欄位檢查function */
) {
    if ('undefined' != typeof (tinyMCE)) tinyMCE.triggerSave(); // 觸發tinyMCE儲存值
    if ('undefined' != typeof (validateGroup)) validateGroup = null;
    if ('function' != typeof (fn)) fn = function () { return true; }  // 自訂驗證的function, 若無則回傳true
    if ('function' != typeof (Page_ClientValidate)) var Page_ClientValidate = function (group) { return true; } // validate control驗證
    if ($(document.forms[0]).valid2() && Page_ClientValidate(validateGroup)) {
        return fn() && confirm(confirmMessage);
    } else {
        return false;
    }
}
Retire value from tinyMCE when jQuery validate valid() invoked
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="superspace.usercontrols.WebForm2" ValidateRequest="false" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>tinyMCE + jQuery validate</title>
    <!-- jQuery -->
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/jquery-1.6.2.min.js" type="text/javascript"></script>
    <!-- jQuery validate + metadata -->
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/jquery.validate/jquery.metadata.min.js" type="text/javascript"></script>
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/jquery.validate/jquery.validate.min.js" type="text/javascript"></script>
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/jquery.validate/jquery.validate.ext.min.js" type="text/javascript"></script>
    <!-- tinyMCE Editor -->
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/tiny_mce/tiny_mce.js" type="text/javascript"></script>
    <script src="<%=VirtualPathUtility.ToAbsolute("~/")%>js/tiny_mce/jquery.tinymce.js" type="text/javascript"></script>
    <style type="text/css">
        body
        {
            font-size: smaller;
        }
    </style>
    <script type="text/javascript">
        $(function () {
            $('.txtContent').tinymce({
                theme: "advanced",
                language: "zh",
                theme_advanced_toolbar_location: "top",
                theme_advanced_toolbar_align: "left",
                theme_advanced_statusbar_location: "bottom",
                theme_advanced_resizing: true
            });
            $(document.forms).validate();
        });
        function confirmUpdate() {
            if (typeof (tinyMCE) != 'undefined') tinyMCE.triggerSave();
            if (!$(document.forms).valid()) return false;
            return true;
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <h3>
        Force tinyMCE editor to save content to control, avoid validate error when valid() has been invoked;</h3>
    <table border="0">
        <tr>
            <td>
                <b style="color: Red;">*</b>標題
            </td>
            <td>
                <asp:TextBox ID="txtTitle" runat="server" CssClass="{required:true,messages:{required:'請填寫標題!'}}" />
            </td>
        </tr>
        <tr>
            <td valign="top">
                <b style="color: Red;">*</b>內容
            </td>
            <td>
                <asp:TextBox ID="txtContent" runat="server" TextMode="MultiLine" Width="100%" Rows="15" CssClass="txtContent {required:true,messages:{required:'請填寫內容!'}}" />
            </td>
        </tr>
        <tr>
            <td align="center" colspan="2">
                <asp:Button ID="btnSubmit" runat="server" Text="儲存" OnClientClick="return confirmUpdate();" />
            </td>
        </tr>
    </table>
    </form>
</body>
</html>
jQuery validator: focus invalid field when calling valid()
/*
 * 在validate呼叫valid()驗證方法式, 加上focusInValid的動件
 */
(function($) {
    $.extend($.fn, {
        valid2 : function() {
            var valid = true;
            var validator;
            if ($(this[0]).is('form')) {
                validator = this.validate();
                valid = this.validate().form();
            } else {
                validator = $(this[0].form).validate();
                this.each(function() {
                    valid &= validator.element(this);
                });
            }
            if (!valid)
                validator.focusInvalid();
            return valid;
        }
    });

    // 新增一個 regex 的驗證方式
    $.validator.methods.regex = function(value, element, param) {
        return this.optional(element) || ((typeof(param) == 'function' && typeof(param.test) == 'function') ? param.test(value) : new RegExp(param).test(value));
    };
    $.validator.messages.regex = 'Please enter a valid value.';
})(jQuery);
Add a event to Outlook calendar dymatically
protected void btnAddEventToOutlook_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.AddHeader("content-disposition", string.Format("attachment;filename={0}.ics", HttpUtility.UrlEncode(EventName, Response.HeaderEncoding)));

    Response.Write(string.Format(@"BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:-//{0}//NONSGML iCalcreator 2.6//ZH_TW
VERSION:2.0
X-WR-CALNAME;LANGUAGE=zh_tw:有 {1} 筆相關活動
BEGIN:VEVENT
UID:{2}
DTSTAMP:{3:yyyyMMddTHHmmss}Z
DESCRIPTION;LANGUAGE=zh_tw:{4}
DTSTART;TZID=TAIWAN:{5:yyyyMMddTHHmmss}
DTEND;TZID=TAIWAN:{6:yyyyMMddTHHmmss}
LOCATION;LANGUAGE=zh_tw:{7}
SUMMARY;LANGUAGE=zh_tw:{8}
URL;VALUE=URI:{9}
END:VEVENT
END:VCALENDAR",
        Request.Url.Host,
        PlaceCount,
        Request.QueryString["oid"],
        DateTime.Now,
        Description,
        Convert.ToDateTime(FromDate),
        Convert.ToDateTime(ToDate),
        Location,
        EventName,
        Request.Url));
    Response.End();
}
about ics file
Add a event to Google Calendar dynamically
hlGoogle.NavigateUrl = string.Format(
    "https://www.google.com/calendar/render?action=TEMPLATE&text={0}&dates={1:yyyyMMddTHHmmss}/{2:yyyyMMddTHHmmss}&sprop=website:{3}&location={4}&details={5}",
    EventName,
    Convert.ToDateTime(FromDate),
    Convert.ToDateTime(ToDate),
    Request.Url.Host,
    Location,
    Details
);
ObjectDataSource
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ObjectDataSourceSample.aspx.cs"
    Inherits="superspace.control.info.ObjectDataSourceSample" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:HiddenField ID="hdnContentId" runat="server" />
        <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
            DeleteMethod="Delete"
            InsertMethod="Insert"
            SelectMethod="Select"
            UpdateMethod="Update"
            OldValuesParameterFormatString="{0}"
            TypeName="SuperspaceLib.VoteOption">
            <DeleteParameters>
                <asp:Parameter Name="ContentId" Type="String" />
                <asp:Parameter Name="OptionID" Type="String" />
            </DeleteParameters>
            <InsertParameters>
                <asp:Parameter Name="ContentId" Type="String" />
                <asp:Parameter Name="OptionID" Type="String" />
                <asp:Parameter Name="OptionName" Type="String" />
            </InsertParameters>
            <SelectParameters>
                <asp:ControlParameter ControlID="hdnContentId" Name="ContentId" PropertyName="Value"
                    Type="String" />
            </SelectParameters>
            <UpdateParameters>
                <asp:Parameter Name="ContentId" Type="String" />
                <asp:Parameter Name="OptionID" Type="String" />
                <asp:Parameter Name="OptionName" Type="String" />
            </UpdateParameters>
        </asp:ObjectDataSource>
        <asp:TextBox ID="txtVoteOption" runat="server" MaxLength="50" Style="width: 100%;" />
        <asp:Button ID="btnAddOption" runat="server" Text="新增" OnClick="btnAddOption_Click" />
        <asp:GridView ID="gvOptions" runat="server" AutoGenerateColumns="False" GridLines="None"
            ShowHeader="False" DataKeyNames="ContentId,OptionID" EnableModelValidation="True"
            DataSourceID="ObjectDataSource1">
            <Columns>
                <asp:BoundField DataField="OptionName" HeaderText="OptionName" SortExpression="OptionName" />
                <asp:TemplateField ShowHeader="False">
                    <ItemTemplate>
                        <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" CommandName="Edit"
                            Text="編輯"></asp:LinkButton>
                        &nbsp;<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Delete"
                            Text="刪除"></asp:LinkButton>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" CommandName="Update"
                            Text="更新"></asp:LinkButton>
                        &nbsp;<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel"
                            Text="取消"></asp:LinkButton>
                    </EditItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Web;

namespace SuperspaceLib
{
    [DataObject(true)]
    public class VoteOption
    {
        [DataObjectMethod(DataObjectMethodType.Select)]
        public DataTable Select(string ContentId)
        {
            DataTable dtOption = null;
            if (HttpContext.Current.Session[ContentId] == null)
            {
                dtOption = new DataTable("VoteOption");
                dtOption.Columns.Add("ContentId");
                dtOption.Columns.Add("OptionID");
                dtOption.Columns.Add("OptionName");
            }
            else
            {
                dtOption = HttpContext.Current.Session[ContentId] as DataTable;
            }
            return dtOption;
        }

        [DataObjectMethod(DataObjectMethodType.Update)]
        public int Update(string ContentId, string OptionID, string OptionName)
        {
            DataTable dtOption = null;
            if (HttpContext.Current.Session[ContentId] == null)
            {
                dtOption = new DataTable("VoteOption");
                dtOption.Columns.Add("ContentId");
                dtOption.Columns.Add("OptionID");
                dtOption.Columns.Add("OptionName");
            }
            else
            {
                dtOption = HttpContext.Current.Session[ContentId] as DataTable;
            }

            int afftected = 0;
            foreach (DataRow row in dtOption.Rows)
            {
                if (row["ContentId"].Equals(ContentId) && row["OptionID"].Equals(OptionID))
                {
                    row["OptionName"] = OptionName;
                    afftected++;
                }
            }
            HttpContext.Current.Session[ContentId] = dtOption;

            return afftected;
        }

        [DataObjectMethod(DataObjectMethodType.Insert)]
        public int Insert(string ContentId, string OptionID, string OptionName)
        {
            DataTable dtOption = null;
            if (HttpContext.Current.Session[ContentId] == null)
            {
                dtOption = new DataTable("VoteOption");
                dtOption.Columns.Add("ContentId");
                dtOption.Columns.Add("OptionID");
                dtOption.Columns.Add("OptionName");
            }
            else
            {
                dtOption = HttpContext.Current.Session[ContentId] as DataTable;
            }

            DataRow row = dtOption.Rows.Add(ContentId, OptionID, OptionName);
            HttpContext.Current.Session[ContentId] = dtOption;

            return 1;
        }

        [DataObjectMethod(DataObjectMethodType.Delete)]
        public int Delete(string ContentId, string OptionID)
        {
            DataTable dtOption = null;
            if (HttpContext.Current.Session[ContentId] == null)
            {
                dtOption = new DataTable("VoteOption");
                dtOption.Columns.Add("ContentId");
                dtOption.Columns.Add("OptionID");
                dtOption.Columns.Add("OptionName");
            }
            else
            {
                dtOption = HttpContext.Current.Session[ContentId] as DataTable;
            }

            int afftected = 0;
            for (int i = dtOption.Rows.Count - 1; i >= 0; i--)
            {
                DataRow row = dtOption.Rows[i];
                if (row["ContentId"].Equals(ContentId) && row["OptionID"].Equals(OptionID))
                {
                    dtOption.Rows.Remove(row);
                    afftected++;
                }
            }
            HttpContext.Current.Session[ContentId] = dtOption;

            return afftected;
        }
    }
}
HINT:
  • OldValuesParameterFormatString="{0}" means parameter will take value of old value by this name format
  • Parameter name must compeletly match the param of method
UpdatePanel in Formview occurs duplicate component id error
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="InnerUpdatePanel.aspx.cs"
    Inherits="superspace.control.info.InnerUpdatePanel" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:FormView ID="fvVote" runat="server" DefaultMode="Insert">
            <InsertItemTemplate>
                <asp:TextBox ID="txtVoteName" runat="server" />
                <asp:UpdatePanel ID="upOption" runat="server" UpdateMode="Conditional">
                    <ContentTemplate>
                        <table border="0" width="100%">
                            <tr>
                                <td>
                                    <asp:TextBox ID="txtOption" runat="server" />
                                </td>
                                <td>
                                    <asp:Button ID="btnAddOption" runat="server" Text="新增選項" />
                                </td>
                            </tr>
                        </table>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </InsertItemTemplate>
            <EditItemTemplate>
                <asp:TextBox ID="txtVoteName" runat="server" />
                <asp:UpdatePanel ID="upOption" runat="server" UpdateMode="Conditional">
                    <ContentTemplate>
                        <table border="0" width="100%">
                            <tr>
                                <td>
                                    <asp:TextBox ID="txtOption" runat="server" />
                                </td>
                                <td>
                                    <asp:Button ID="btnAddOption" runat="server" Text="新增選項" />
                                </td>
                            </tr>
                        </table>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </EditItemTemplate>
        </asp:FormView>
    </div>
    </form>
</body>
</html>
Solutions:
  1. Remove update panel
  2. Create a user control wrapping update panel
Test mail sender
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import bruce.lib.swing.SwingWrench;
import bruce.lib.util.DateTime;
import bruce.lib.util.PostCenter;

public class PostMan extends JFrame {

    JTextField txtIP;
    JTextField txtPort;
    JTextField txtAccount;
    JPasswordField txtPassword;

    JTextField txtSenderMail;
    JTextField txtSednerName;
    JTextField txtReceiverMail;

    JCheckBox cbIsHtml;
    JTextField txtSubject;
    JTextArea txtBody;

    JButton btnSubmit;

    JTextArea txtConsole;

    public PostMan() {
        setLayout(new GridBagLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("發信測試");

        JPanel control = new JPanel(new GridBagLayout());
        control.setMinimumSize(new Dimension(350, 100));

        control.add(new JLabel("主機ip"), new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtIP = new JTextField("ms2.ccic.com.tw", 10), new GridBagConstraints(2, 1, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));
        control.add(new JLabel("通訊埠"), new GridBagConstraints(3, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtPort = new JTextField("25", 3), new GridBagConstraints(4, 1, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));

        control.add(new JLabel("帳號"), new GridBagConstraints(1, 2, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtAccount = new JTextField("gp_report", 10), new GridBagConstraints(2, 2, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));
        control.add(new JLabel("密碼"), new GridBagConstraints(3, 2, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtPassword = new JPasswordField("29952666", 10), new GridBagConstraints(4, 2, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));

        control.add(new JLabel("寄件人名稱"), new GridBagConstraints(1, 3, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtSednerName = new JTextField("MES系統訊息", 10), new GridBagConstraints(2, 3, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));
        control.add(new JLabel("寄件人mail"), new GridBagConstraints(3, 3, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtSenderMail = new JTextField("gp_report@ccic.com.tw", 10), new GridBagConstraints(4, 3, 1, 1, 0.3, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));

        control.add(new JLabel("收件人"), new GridBagConstraints(1, 4, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtReceiverMail = new JTextField("", 10), new GridBagConstraints(2, 4, 3, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));

        control.add(new JLabel("html格式"), new GridBagConstraints(1, 5, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(cbIsHtml = new JCheckBox(), new GridBagConstraints(2, 5, 3, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));

        control.add(new JLabel("主旨"), new GridBagConstraints(1, 6, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        control.add(txtSubject = new JTextField("", 10), new GridBagConstraints(2, 6, 3, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 1, 1));
        control.add(new JScrollPane(txtBody = new JTextArea()), new GridBagConstraints(1, 7, 4, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 1, 1));

        add(control, new GridBagConstraints(1, 1, 1, 2, 0, 1, GridBagConstraints.EAST, GridBagConstraints.VERTICAL, new Insets(3, 3, 3, 3), 1, 1));

        add(new JLabel("LOG"), new GridBagConstraints(2, 1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        add(btnSubmit = new JButton("發送"), new GridBagConstraints(3, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 1, 1));
        add(new JScrollPane(txtConsole = new JTextArea()), new GridBagConstraints(2, 2, 2, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 1, 1));

        btnSubmit.addActionListener(btnSubmit_Click);

        // redirect console
        System.setOut(new PrintStream(new OutputStream() {

            StringBuffer buffer = new StringBuffer();

            @Override
            public void write(int b) throws IOException {
                switch (b) {
                case '\n':
                    txtConsole.append(buffer.toString() + System.getProperty("line.separator"));
                    buffer.delete(0, buffer.length() - 1);
                    break;
                default:
                    buffer.append((char) b);
                    break;
                }
            }
        }));

        setSize(600, 400);
        SwingWrench.setLocationCenter(this);
    }

    private ActionListener btnSubmit_Click = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {

            try {
                System.out.printf("==========Try sending mail at %s==========%n", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));

                PostCenter<PostCenter> pc = new PostCenter<PostCenter>();

                pc.init(txtIP.getText().trim(), Integer.parseInt(txtPort.getText().trim()), true, txtAccount.getText().trim(), txtPassword.getText().trim());
                pc.setDebug(true);
                pc.setDebugOut(System.out);
                pc.setEncoding("UTF-8");

                if (txtSednerName.getText().trim().length() == 0)
                    pc.setSender(txtSenderMail.getText().trim());
                else
                    pc.setSender(txtSenderMail.getText().trim(), txtSednerName.getText().trim());

                String[] receivers = txtReceiverMail.getText().replaceAll("\\s", "").replaceAll(",", ";").split(";");

                for (String s : receivers) {
                    pc.addReceiver(s);
                }

                pc.send(txtSubject.getText(), txtBody.getText(), cbIsHtml.isSelected());
            } catch (Exception ex) {
                ex.printStackTrace(System.out);
            }

            System.out.println();
            System.out.println();
            System.out.println();
        }
    };

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new PostMan().setVisible(true);
    }

}
A good url validate regular expression
^(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?$
GridView paging style design
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
    ...... >
    <Columns>
        <asp:BoundField DataField="Name" HeaderText="姓名" SortExpression="Name" />
        <asp:BoundField DataField="OrgID" HeaderText="單位編號" SortExpression="OrgID" />
        .............
    </Columns>
    <PagerTemplate>
        <div style="text-align:center;">
            <asp:LinkButton ID="btnFirstPage" runat="server" CommandArgument="First" CommandName="Page" Text="First"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex > 0 %>' />
            <asp:LinkButton ID="btnPrevPage" runat="server" CommandArgument="Prev" CommandName="Page" Text="Pre"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex > 0 %>' />
                
            <asp:LinkButton ID="btnP4" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex-3 > 0 %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex-3 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex-3 %>' />
            <asp:LinkButton ID="btnP3" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex-2 > 0 %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex-2 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex-2 %>' />
            <asp:LinkButton ID="btnP2" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex-1 > 0 %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex-1 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex-1 %>' />
            <asp:LinkButton ID="btnP1" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex > 0 %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex %>' />
                
            <asp:LinkButton ID="btnCurrent" runat="server"
                Enabled="false"
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex+1 %>' />
                
            <asp:LinkButton ID="btnN1" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+1 < (Container.NamingContainer as GridView).PageCount %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex+2 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex+2 %>' />
            <asp:LinkButton ID="btnN2" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+2 < (Container.NamingContainer as GridView).PageCount %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex+3 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex+3 %>' />
            <asp:LinkButton ID="btnN3" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+3 < (Container.NamingContainer as GridView).PageCount %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex+4 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex+4 %>' />
            <asp:LinkButton ID="btnN4" runat="server"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+4 < (Container.NamingContainer as GridView).PageCount %>'
                CommandArgument='<%# (Container.NamingContainer as GridView).PageIndex+5 %>'
                CommandName="Page" Text='<%# (Container.NamingContainer as GridView).PageIndex+5 %>' />
                
            <asp:LinkButton ID="btnNextPage" runat="server" CommandArgument="Next" CommandName="Page" Text="Next"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+1 < (Container.NamingContainer as GridView).PageCount %>' />
            <asp:LinkButton ID="btnLastPage" runat="server" CommandArgument="Last" CommandName="Page" Text="Last"
                Visible='<%# (Container.NamingContainer as GridView).PageIndex+1 < (Container.NamingContainer as GridView).PageCount %>' />
                
            ,共<%# (Container.NamingContainer as GridView).PageCount %>頁,
            到第<asp:TextBox ID="tbPageIndex" runat="server" Text='<%# (Container.NamingContainer as GridView).PageIndex+1 %>' Columns="3" />
            <asp:LinkButton ID="btnGotoPage" runat="server" Text="Go" OnClick="GotoPage_Click"
                OnClientClick="__doPostBack($(this).attr('id').split('_').join('$'),$(this).parent().find('input:text').val());return false;" />
        </div>
    </PagerTemplate>
</asp:GridView>
protected void GotoPage_Click(object sender, EventArgs e)
{
    GridView gv = (sender as LinkButton).NamingContainer.NamingContainer as GridView;

    try
    {
        // __doPostBack 參數
        int p = int.Parse(Request.Form["__EVENTARGUMENT"]);

        if (p < 1 || p > gv.PageCount)
        {
            ClientScript.RegisterClientScriptBlock(
                GetType(),
                "f",
                "alert('錯誤頁碼!');",
                true
            );
        }
        else
        {
            gv.PageIndex = p - 1;
            gv.DataBind();
        }
    }
    catch
    {
        ClientScript.RegisterClientScriptBlock(
            GetType(),
            "f",
            "alert('錯誤頁碼!');",
            true
        );
    }
}
IDES 4.7 Installation
  1. 電腦名稱不能使用特殊名稱(bin/etc/var ...)
  2. 網路卡-> File and Printer Sharing for Microsoft Networks ->網路應用程式的資料輸送量最大化
  3. 安裝jdk1.4 (不升級)
  4. 設置JAVA_HOME
  5. 調高虛擬記憶體
  6. 安裝oracle
  7. 清空暫存資料夾 (%USERPROFILE%\Local Settings\Temp, %SystemRoot%\TEMP)
  8. 時間修改為2029年避免過期, 過晚的時間會發生無法安裝
  9. 載入export data時, 會檢查exportXX的data資料夾, 將exportXX以網路磁碟機的方式顯示在根目錄
Clipboard Usage
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class ClipboardUsage implements ClipboardOwner {

    public void setClipboardContents(String aString) {
        StringSelection stringSelection = new StringSelection(aString);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, this);
    }

    public String getClipboardContents() {
        String result = "";
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        // odd: the Object param of getContents is not currently used
        Transferable contents = clipboard.getContents(null);
        boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
        if (hasTransferableText) {
            try {
                result = (String) contents.getTransferData(DataFlavor.stringFlavor);
            } catch (UnsupportedFlavorException ex) {
                // highly unlikely since we are using a standard DataFlavor
                System.out.println(ex);
                ex.printStackTrace();
            } catch (IOException ex) {
                System.out.println(ex);
                ex.printStackTrace();
            }
        }
        return result;
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        ClipboardUsage cu = new ClipboardUsage();
        System.out.printf("Clipboard : %s%n", cu.getClipboardContents());
        cu.setClipboardContents("clipboard test.");
        System.out.printf("Clipboard : %s%n", cu.getClipboardContents());
    }

}
Fill zero in front of number
SQL Server:
select replicate('0', (10-len('123')))+'123'
Oracle:
SELECT LPad('123',10,'0') FROM dual
DB2:
values char(repeat('0',10-length('123'))||'123',10)
DataList paging
//利用PageDataSource來做分頁功能
PagedDataSource pds = new PagedDataSource();
//將PageDataSource綁定SqlDataSource
pds.DataSource = SqlDataSource1.Select(DataSourceSelectArguments.Empty);
pds.AllowPaging = true;
// 分頁大小
pds.PageSize = 6;

int PageIndex;
//分頁參數
if (!string.IsNullOrEmpty(Request.QueryString["Page"]) && int.TryParse(Request.QueryString["Page"], out PageIndex))
{
    PageIndex = Convert.ToInt32(Request.QueryString["Page"]);
}
else
{
    PageIndex = 1;
}

pds.CurrentPageIndex = PageIndex - 1;

// 最後一頁
if (!pds.IsLastPage)
{
    hlNext.NavigateUrl = Request.CurrentExecutionFilePath + "?Page=" + Convert.ToString(PageIndex + 1);
    if (Request.QueryString["type"] != null) hlNext.NavigateUrl += "&type=" + Request.QueryString["type"];
}
else
{
    hlNext.Visible = false;
}


//將DataList綁定PageDataSource
this.DataList1.DataSource = pds;
this.DataList1.DataBind();
JTable : multi line cell
table.getColumnModel().getColumn(i).setCellRenderer(new DefaultTableCellRenderer() {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        String v = (String) value;
        String[] vs = v.split("\n");

        JPanel p = new JPanel(new GridLayout(vs.length, 1)) {
            @Override
            public void setForeground(Color fg) {
                for (int i = 0; i < getComponentCount(); i++) {
                    getComponent(i).setForeground(fg);
                }
                super.setForeground(fg);
            }

            @Override
            public void setBackground(Color bg) {
                for (int i = 0; i < getComponentCount(); i++) {
                    getComponent(i).setBackground(bg);
                }
                super.setBackground(bg);
            }
        };

        // 內容
        for (String s : vs) {
            JLabel l = new JLabel(s, JLabel.LEFT);
            l.setOpaque(true);
            p.add(l);
        }
        // 列高
        table.setRowHeight(row, table.getRowHeight() * vs.length);

        // 顏色設定
        p.setOpaque(true);
        p.setBackground(Color.white);

        // 變更背景及字體 顏色同, 同時變更內部元件的顏色
        if (isSelected) {
            p.setBackground(UIManager.getColor("Table.selectionBackground"));
            p.setForeground(UIManager.getColor("Table.selectionForeground"));
        }

        if (hasFocus) {
            p.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));

            if (table.isCellEditable(row, column)) {
                p.setForeground(UIManager.getColor("Table.focusCellForeground"));
                p.setBackground(UIManager.getColor("Table.focusCellBackground"));
            }
        } else {
            p.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        }

        return p;
    }
});
focus on validating
function focusOnInvalidControl() {
    for (var i = 0; i < Page_Validators.length; i++) {
        if (!Page_Validators[i].isvalid) {
            document.getElementById(Page_Validators[i].controltovalidate).focus();
            return;
        }
    }
}
Programmingly end cell edit mode of jtable
// The following code saves the current value in the cell being edited
// and stops the editing process:
if (table.getCellEditor() != null) {
    table.getCellEditor().stopCellEditing();
}
// The following code discards any changes made by the user and stops
// the editing process:
if (table.getCellEditor() != null) {
    table.getCellEditor().cancelCellEditing();
}
Test polymorphism in reflection method invoke
package y11.m04;

import java.lang.reflect.Method;

public class d28t01 {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // Test polymorphism in reflection
        Object invoker = new Invoker();
        Class clazz = invoker.getClass();

        Dialer p1 = new Phone("12345");
        Phone p2 = new Phone("234567");
        CellPhone p3 = new CellPhone("345678");

        // cause java.lang.NosuchMethodException
        try {
            Method m1 = clazz.getDeclaredMethod("use", p1.getClass());
            m1.invoke(invoker, p1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Method m2 = clazz.getDeclaredMethod("use", p2.getClass());
            m2.invoke(invoker, p1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Method m3 = clazz.getDeclaredMethod("use", p3.getClass());
            m3.invoke(invoker, p1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Method[] ms = clazz.getDeclaredMethods();
        for (Method m : ms) {
            if (m.getName().equals("use")) {
                Class[] paramTypes = m.getParameterTypes();
                if (paramTypes.length == 1 && paramTypes[0].isAssignableFrom(p1.getClass())) {
                    m.invoke(invoker, p1);
                }
            }

            if (m.getName().equals("use")) {
                Class[] paramTypes = m.getParameterTypes();
                if (paramTypes.length == 1 && paramTypes[0].isAssignableFrom(p2.getClass())) {
                    m.invoke(invoker, p2);
                }
            }

            if (m.getName().equals("use")) {
                Class[] paramTypes = m.getParameterTypes();
                if (paramTypes.length == 1 && paramTypes[0].isAssignableFrom(p3.getClass())) {
                    m.invoke(invoker, p3);
                }
            }
        }
    }
}

class Invoker {
    public void use(Dialer dialer) {
        if (dialer != null)
            dialer.call();
    }
}

interface Dialer {
    void call();
}

class Phone implements Dialer {
    public String number;

    public Phone(String number) {
        this.number = number;
    }

    public void call() {
        System.out.printf("Call %s%n", number);
    }
}

class CellPhone extends Phone {

    public CellPhone(String number) {
        super(number);
    }

    @Override
    public void call() {
        System.out.printf("Dial %s%n", number);
    }
}