2014年10月31日 星期五

Collections SORT 自小而大

自小而大
             

 List<ServiceCategoryVo> list = serviceCategoryResponseVo.getServiceCategory();
   
                Collections.sort(list, new Comparator<ServiceCategoryVo>() {

                    @Override
                    public int compare(ServiceCategoryVo a, ServiceCategoryVo b) {
                        if(a.getNo()>b.getNo()){
                            return 1;   
                        }else{
                            return 0;   
                        }
                       
                    }
                   
                });
                for(ServiceCategoryVo s:list){
                    Log.d("TAG","NO:"+s.getNo()+"getServiceName:"+s.getServiceName());
                   
                }

MonkeyTest

    Please help to test MonkeyTest by following command:
        adb shell monkey -p com.ewallet.citygo.dev -v 1500


http://android-test-tw.blogspot.tw/2012/10/android-monkey-automation-test.html
http://www.slideshare.net/ContusQA/monkey-talk-automation

2014年10月29日 星期三

facebook sdk


 copy -patse    fbExampleMyApplication.zip下載
http://1drv.ms/1LpzJjB
0.build.gradle
    compile 'com.android.support:appcompat-v7:19.1.+'
    compile 'com.facebook.android:facebook-android-sdk:3.23.0'

1.AndroidManifest.xml   
uses-permission and com.facebook.LoginActivity and  meta-data
2.strings.xml      app_id
3.mainfragment.xml   com.facebook.widget.LoginButton
4.MainFragment LoginButton
5.dashboard  
use pkname and activityname to get app_id and
Single Sign On
https://developers.facebook.com/apps/935943056446383/settings/basic/
reading

https://developers.facebook.com/docs/android/login-with-facebook/v2.2?locale=zh_TW


printKeyHash method provide hashkey you need


ps
1."C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -exportcert -alias androiddebugkey -keystore C:\Users\linkulife\.android\debug.keystore | C:\openssl\bin\openssl.exe sha1 -binary | C:\openssl\bin\openssl.exe base64

2.http://javatechig.com/android/how-to-get-key-hashes-for-android-facebook-app


如果要取得個人資訊請看
https://developers.facebook.com/docs/android/graph/?locale=zh_TW
https://developers.facebook.com/docs/graph-api/using-graph-api/v2.2?locale=zh_TW#fieldexpansion

2014年10月27日 星期一

androidannotation 獲得view的方法

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        v = inflater.inflate(R.layout.visacard, container, false);
        return null;
    }

VolleyErrorController

package com.ewallet.citygo.controller;

import android.content.Context;

import com.android.volley.*;
import com.android.volley.VolleyError;
import com.ewallet.citygo.utils.Utils;

public class VolleyErrorController {
    VolleyError volleyError;
    Context context;
    public VolleyErrorController(Context context,VolleyError volleyError) {
        this.volleyError = volleyError;
        this.context=context;
    }

    TimeoutError timeoutError = new TimeoutError();
    //AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。
    //NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。
    //NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。
    //ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。
    //SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xx HTTP状态代码。
    //TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。
    public void showMsg() {
        if (volleyError instanceof NoConnectionError) {
            Utils.alertWithOneButton(context, "連不上伺服器,請開啟網路");
        } else if (volleyError instanceof TimeoutError) {
            Utils.alertWithOneButton(context, "網路逾時請洽客服");
        } else if (volleyError instanceof AuthFailureError) {
            Utils.alertWithOneButton(context, "伺服器認證失敗請洽客服");
        } else if (volleyError instanceof ServerError) {
            Utils.alertWithOneButton(context, "伺服器連線失敗請洽客服");
        } else if (volleyError instanceof NetworkError) {
            Utils.alertWithOneButton(context, "伺服器網域找不到 請稍後在試");
        } else if (volleyError instanceof ParseError) {
            Utils.alertWithOneButton(context, "收到不預期的結果請更新版本");
        }
    }
}

2014年10月26日 星期日

關閉小鍵盤

        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
                Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mainView.getWindowToken(), 0);

2014年10月24日 星期五

INTENT中傳遞物件/fragment傳遞物件

  傳送的LoginFragment

 Bundle bundle = new Bundle();
  bundle.putSerializable(BundleIndex.LoginFragment.toString(), user);


        MoveStockFragment moveStockFragment = new MoveStockFragment();
      
        TransactionHandler.getInstance().transition(getActivity(), bundle, this, moveStockFragment, R.id.mainFrameLayout);

收到的  MoveStockFragment中

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.movestockfragment, container, false);
        Bundle bundle = getArguments();
        if(bundle==null){
            Utils.instance.log("MoveStockFragment:bundle==null");
        }
        user = (User) bundle.getSerializable(BundleIndex.LoginFragment.toString());
        bundle.remove(BundleIndex.LoginFragment.toString());
//要記得刪掉避免再次取得

        ButterKnife.inject(this, v);
        return v;
    }



 ---------------------------------------------------------

送的ACTIVITY
 Intent intent = new Intent();
                        Bundle bundle = new Bundle();

                        bundle.putSerializable("FavoriteStoreWrapper", favoriteStoreAryList.get(position));
                        intent.putExtras(bundle);
                        intent.setClass(getActivity(), NearByDetailActivity.class);
                        startActivity(intent);

 收的ACTIVITY
 Bundle bundle = this.getIntent().getExtras();
favoriteStoreWrapper =
 (FavoriteStoreWrapper) getIntent().getSerializableExtra("FavoriteStoreWrapper");

Genymotion 如何安裝 Google Play 商店?

http://portable.easylife.tw/3966
http://wiki.rootzwiki.com/Google_Apps#Universal_Packages_2

2014年10月23日 星期四

獲得螢幕的寬高.

    /**
     * 獲得螢幕的寬高.
     *
     * @return the sreen width height
     */
    public void getSreenWidthHeight() {
/*
        DisplayMetrics dm = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);

        m_density = dm.density;
        mWidth = dm.widthPixels;
        mHeight = dm.heightPixels;
        m_dpi = dm.densityDpi;
        */

    }

日期格式轉換

    public static String strtimestampToStr(String strtimestamp){
        Timestamp stamp = new Timestamp(Long.parseLong(strtimestamp));
          Date date = new Date(stamp.getTime());
        return Utils.dateToStr(date);
    }
    public static String dateToStr(Date date) {
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String date1 = sdf.format(date);
        return date1;
        // 把日期字串轉為想要的格式

    }


把原本是字串的轉乘字串

                        DateFormat formatter = new SimpleDateFormat("yyyy-MM-DD");
                                Date mydate = null;
                                try {
                                    mydate = formatter.parse(date);
                                } catch (ParseException e) {
                                    e.printStackTrace();
                                }
                               
                                info2.m_strDate = Utils.dateToStr(mydate);

2014年10月22日 星期三

JsonUtils

/*
 *
 */
package com.ewallet.citygo.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.json.JSONObject;

import com.ewallet.citygo.config.AppConfig;

// TODO: Auto-generated Javadoc

/**
 * The Class JsonUtils.
 */
public class JsonUtils {

    /**
     * The Constant URL.
     */
    public static final String URL = AppConfig.PHOTOSERVERIP;
    public static final String RETRIEVE_MESSAGE_DETAIL = JsonUtils.URL + "SmartCatchCityGoWsWeb/ws/message/RETRIEVE_MESSAGE_DETAIL";
    //public static final String URL = "http://125.227.157.216:9168/";//JsonUtils周邊商家圖庫 2014/08/20 廢棄
    public static final String QUERY_NEARBY_BRANCH_BY_CONDITION = "SmartCatchCityGoWsWeb/ws/user/QUERY_NEARBY_BRANCHS_BY_CONDITIONS_AND_PAGING";
    //    public static final String QUERY_DISTRICT_BRANCHES = "user/QUERY_DISTRICT_BRANCHES_BY_CONDITIONS_AUTO_SORT_AND_PAGING";
    public static final String QUERY_MESSAGES_BY_TYPE_PAGING = "SmartCatchCityGoWsWeb/ws/message/QUERY_MESSAGES_BY_TYPE_PAGING";
    //    public static final String QUERY_SERVICE_NAME_BY_CATEGORY = "SmartCatchCityGoWsWeb/ws/service_category/get_category";
    public static final String QUERY_SERVICE_NAME_BY_CATEGORY = "SmartCatchCityGoWsWeb/ws/category/get_category";
    public static final String SUCCESS_MESSAGE = "SUCCESS";
    public static final String NOT_FOUND = "NOT_FOUND";
    /**
     * The Constant QUERY_NEARBY_BRANCH.
     */
    public static final String QUERY_NEARBY_BRANCH = "user/QUERY_NEARBY_BRANCHS_BY_CONDITIONS_AND_PAGING";
//    public static final String QUERY_DISTRICT_BRANCHES = "user/QUERY_DISTRICT_BRANCHES_BY_CONDITIONS_AUTO_SORT_AND_PAGING";
    /** The Constant QUERY_MESSAGES_BY_TYPE_PAGING. */

    /**
     * String convert to json object.
     *
     * @param value the value
     * @return the JSON object
     */
    public static JSONObject stringConvertToJsonObject(String value) {
        JSONObject object = null;
        try {
            object = new JSONObject(value);
        } catch (Exception e) {
            // TODO: handle exception
        }

        return object;

    }


    /**
     * Post.
     *
     * @param url  the url
     * @param json the json
     * @return the string
     */
    public static String POST(String url, String json) {
        InputStream inputStream = null;
        String result = "";
        try {

            // 1. create HttpClient
            HttpClient httpclient = new DefaultHttpClient();
            // 2. make POST request to the given URL
            HttpPost httpPost = new HttpPost(url);

            //Log.d("JsonUtils POST json.toString()", json.toString());
            // ** Alternative way to convert Person object to JSON string usin
            // Jackson Lib
            // ObjectMapper mapper = new ObjectMapper();
            // json = mapper.writeValueAsString(person);

            // 5. set json to StringEntity

            StringEntity se = new StringEntity(json.toString(), HTTP.UTF_8);

            // 6. set httpPost Entity
            httpPost.setEntity(se);

            // 7. Set some headers to inform server about the type of the
            // content
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-type", "application/json");
            // httpPost.setHeader("user-agent", "Java/1.7.0_17");
            // httpPost.setHeader("connection", "keep-alive");

            // 8. Execute POST request to the given URL
            HttpResponse httpResponse = httpclient.execute(httpPost);

            // 9. receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // 10. convert inputstream to string
            if (inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 11. return result
        Utils.myLog(result);


        return result;
    }

    /**
     * Convert input stream to string.
     *
     * @param inputStream the input stream
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private static String convertInputStreamToString(InputStream inputStream)
            throws IOException {
        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while ((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;

    }
}

2014年10月21日 星期二

PopupMenu

PopupMenu popup = new PopupMenu(getActivity(), radioMember);
                popup.getMenuInflater().inflate(R.menu.onmemberclick, popup.getMenu());
                popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.EditProfile: {
                                EditProfile editProfile = new EditProfile_();
                                editProfile.setMemberFragmentChildFragmentManager(getChildFragmentManager());
                                FragmentTransaction ft = getChildFragmentManager().beginTransaction();
                                ft.replace(R.id.memberFramelayout, editProfile, "editProfile").addToBackStack(null);
                                ft.commit();
                               
                            }
                            case R.id.ChangePw: {
                               
                                ChangePw changePw = new ChangePw_();
                                changePw.setMemberFragmentChildFragmentManager(getChildFragmentManager());
                                FragmentTransaction ft =  getChildFragmentManager().beginTransaction();
                                ft.replace(R.id.memberFramelayout, changePw, "changePw").addToBackStack(null);
                                ft.commit();
                            }
                            case R.id.ChangeTransactionPw: {
                               
                                ChangeTransactionPw changeTransactionPw = new ChangeTransactionPw_();
                                changeTransactionPw.setMemberFragmentChildFragmentManager(getChildFragmentManager());
                                FragmentTransaction ft =  getChildFragmentManager().beginTransaction();
                                ft.replace(R.id.memberFramelayout, changeTransactionPw, "changeTransactionPw").addToBackStack(null);
                                ft.commit();
                            }
                        }
                        return true;
                    }
                });
                popup.show();
           

Effective Java

Effective Java

2014年10月17日 星期五

取得有效位數

String strdist = new DecimalFormat("0.00").format(productStoreVo.getDist());

spinner 某的tItem 的string

(String) parent.getItemAtPosition(position)

ksop2

/*
 *
 */
package com.ewallet.citygo.utils;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.util.Log;

import com.ewallet.citygo.bean.TransactionCreateBean;
import com.ewallet.citygo.bean.TransactionStatusBean;
import com.ewallet.citygo.config.AppConfig;
import com.ewallet.citygo.manager.AccountManager;

// TODO: Auto-generated Javadoc
/**
 * The Class Transaction.
 */
public class Transaction {
   
    /**
     * Creates the.
     *
     * @param bean the bean
     * @param source_id the source_id
     * @param source_count the source_count
     * @param tpaytype the tpaytype
     * @param price the price
     * @return true, if successful
     */
    public boolean create(TransactionCreateBean bean, int source_id, int source_count, String tpaytype, int price) {
       
        boolean result = false;
        SoapObject request = new SoapObject(AppConfig.NAMESPACE, "create");
        request.addProperty("source_id", source_id);
        request.addProperty("source_count", source_count);
        request.addProperty("tpaytype", tpaytype);
        request.addProperty("price", price);
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_SITE);
        try {
            androidHttpTransport.call(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_ACTION, envelope);
            SoapObject response = (SoapObject) envelope.getResponse();
            bean.status = getInt(response, "status");
            bean.message = getString(response, "message");
            bean.txId = getInt(response, "txId");
            AccountManager.getAccountManager().myAccount.setTransactionId(String.valueOf(bean.txId));
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
       
    }
   
    /**
     * Listen status.
     *
     * @param bean the bean
     * @param tx_id the tx_id
     * @return true, if successful
     */
    public boolean listenStatus(TransactionStatusBean bean, int tx_id) {
        boolean result = false;
        SoapObject request = new SoapObject(AppConfig.NAMESPACE, "listenStatus");
        request.addProperty("tx_id", tx_id);
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_SITE);
        try {
            androidHttpTransport.call(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_ACTION, envelope);
            SoapObject response = (SoapObject) envelope.getResponse();
            bean.status = getInt(response, "tstatus");
            Log.v("ListenStatus", String.valueOf(bean.status));
            if (bean.status == 1)
                result = true;
           
        } catch (Exception e) {
        }
        return result;
    }
   
    /**
     * Scan update info.
     *
     * @param source_id the source_id
     * @param source_count the source_count
     * @param price the price
     * @param dest_id the dest_id
     * @param dest_count the dest_count
     * @param tx_id the tx_id
     * @param issuer the issuer
     * @param serial_no the serial_no
     * @param card_id the card_id
     * @param card_no the card_no
     * @return true, if successful
     */
    public boolean scanUpdateInfo(int source_id, int source_count, int price,
            int dest_id, int dest_count, int tx_id,
            String issuer, String serial_no, int card_id, String card_no) {
        TransactionStatusBean bean = new TransactionStatusBean();
        boolean result = false;
        SoapObject request = new SoapObject(AppConfig.NAMESPACE, "scanUpdateInfo");
        request.addProperty("source_id", source_id);
        request.addProperty("source_count", source_count);
        request.addProperty("tpaytype", "1");
        request.addProperty("price", price);
        request.addProperty("dest_id", dest_id);
        request.addProperty("dest_count", dest_count);
        request.addProperty("tx_id", tx_id);
        request.addProperty("issuer", issuer);
        request.addProperty("serial_no", serial_no);
        request.addProperty("card_id", card_id);
        request.addProperty("card_no", card_no);
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_SITE);
        try {
            androidHttpTransport.call(AppConfig.SERVER_SITE + AppConfig.JAVA_TRANSACTION_ACTION, envelope);
            SoapObject response = (SoapObject) envelope.getResponse();
            bean.status = getInt(response, "status");
            bean.message = getString(response, "message");
            if (getInt(response, "tstatus") == 1)
                result = true;
        } catch (Exception e) {
        }
        return result;
       
    }


    /**
     * Gets the int.
     *
     * @param response the response
     * @param name the name
     * @return the int
     */
    private int getInt(SoapObject response, String name) {
        return Integer.parseInt(response.getProperty(name).toString());
    }
   
    /**
     * Gets the string.
     *
     * @param response the response
     * @param name the name
     * @return the string
     */
    private String getString(SoapObject response, String name) {
        return response.getProperty(name).toString();
    }
   
}

2014年10月16日 星期四

gson

    public static String toJson(Object obj) {
        ObjectMapper om = new ObjectMapper();
        om.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, Boolean.FALSE);
        // 忽略新增未知 回傳參數

        om.setSerializationInclusion(Inclusion.NON_NULL);
        try {
            return om.writeValueAsString(obj);
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T fromJson(String src, Class<T> t) {
        ObjectMapper om = new ObjectMapper();
        om.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, Boolean.FALSE);
        // 忽略新增未知 回傳參數
        try {
            return ((T) om.readValue(src, t));
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
        return null;
    }

2014年10月12日 星期日

struts2 ServletConfig

http://www.codejava.net/frameworks/struts/reading-parameters-from-webxml-in-struts2-action-class

  <context-param>
    <param-name>host</param-name>
    <param-value>192.168.123.233</param-value>
</context-param>




        String conf = ServletActionContext.getServletContext().getInitParameter("host");
      
        System.out.println("Login,conf: "+conf);

匯出資料庫 注意事項

匯出資料庫 注意事項
取消勾選 顯示說明
勾選 加入 CREATE DATABASE / USE 指令

2014年10月9日 星期四

Android. Layout background stretches

 如果用 ScrollView在最外層 會導致背景拉長 解決辦法
http://stackoverflow.com/questions/11448416/android-layout-background-stretches

<?xml version="1.0" encoding="utf-8"?>



    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@drawable/m_bg"


   android:gravity="center" />


//don't use this if you want scrollView`
//        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        se

2014年10月6日 星期一

join

select transaction.* ,member.*, memberowner.*  ,store.* from  transaction

right join member      on transaction.`memberId`=member.`memberId`
right join memberowner on transaction.`mo_sn` =memberowner.`mo_sn`
right join store       on transaction.`storeId`=store.storeId

2014年10月5日 星期日

小鍵盤往上頂


小鍵盤往上頂
1.activity設定
        <activity
            android:name=".MainActivity"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="stateUnspecified|adjustResize">

2.layout上ScrollView作為根 並且設定粗體

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_above="@+id/butto_register"
    android:windowSoftInputMode="adjustPan">


     //don't use this if you want scrollView`
//        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        


install git on server

https://www.digitalocean.com/community/tutorials/how-to-install-git-on-a-centos-6-4-vps
http://git-scm.com/book/en/Getting-Started-First-Time-Git-Setup

git bash

 git bash指令
切換資料夾
cd "D:/keith/android/JrSysDev"
git init
 git remote add  sci_ewallet https://adsl99801@bitbucket.org/sciewallet/sci-ewallet.git

如果不能push 要先
 fetch 再merge 再pull 就可以push了
aAav1432.cc18tv.com/


http://git-scm.com/book/zh-tw/Git-%E5%9F%BA%E7%A4%8E-%E6%AA%A2%E8%A6%96%E6%8F%90%E4%BA%A4%E7%9A%84%E6%AD%B7%E5%8F%B2%E8%A8%98%E9%8C%84


如果要用local的蓋過遠端的
git  push --force ori



查詢歷史某個字串
git rev-list --all | xargs git grep expression