AppQ
What is AppQ?
AppQ는 Kurogo Mobile Framework 의 하나의 component 입니다. 이것은 모바일 웹 모듈을 iOS 와 Android native application으로 빠르게 porting 해 주는 기능을 하죠. AppQ는 hybrid 앱 시스템입니다. 네이티브 엡 안에 웹뷰로 embedded 된 Kurogo Mobile Web Module들이 있게 되는 것이죠.
AppQ Features
AppQ modules can co-exist with native Kurogo-iOS and Kurogo Android modules
- native와 AppQ 모듈들을 쉽게 mixing 하고 matching 하도록 함으로서 여러분들은 기능적인 면에 좀 더 집중할 수 있게 됩니다. 쿠로고 모듈들이 native 에 fully implementation 되도록 AppQ 가 도와드립니다.
AppQ modules use templates customized for each native platform
- AppQ leverages the Kurogo Mobile Web’s template inheritance system to allow you to customize your UI elements for each native platform.
- Stock Kurogo Mobile Web templates are already customized for the native platforms.
AppQ modules store CSS, Javascript and images inside the native app
(AppQ 모듈은 native 앱 안에 CSS, Javascript, 이미지등을 저장합니다.)
- 이렇게 함으로서 페이지 로딩 시간과 네트워크 bandwidth use를 절감시킬 수 있습니다.
- 여러분의 native app 에 이런 파일들을 포함시킴으로서 이 앱을 시작할 때 일반적인 모바일 웹 보다 좀 더 빠르게 로딩할 수 있도록 해 줍니다.
- 여러분의 모바일 웹 UI를 업데이트 할 때 native 앱들은 모듈 파일들의 new version들을 다운로드 할 겁니다.
AppQ 1.0 Technical Capabilities and Limitations
어떤 Kurogo Mobile Web module 이라도 AppQ 모듈이 될 수 있습니다. 여러분이 웹 모듈로 만들 수 있다면 AppQ 모듈로도 만들 수 있습니다. 웹 모듈과 마찬가지로 AppQ 모듈들은 Kurogo Mobile Web server 로부터 live content 를 display 합니다. AppQ 는 아직까지 여러분의 native 앱이 offline viewing 을 위한 저장이나 cache 작업을 충분히 지원하지는 못합니다.
1.0 버전에서는 아래와 같은 기능과 제한이 있습니다.
What AppQ 1.0 can do:
- Anything a Kurogo Mobile Web module can do, including:
- Module development with HTML, CSS and Javascript technologies
- Kurogo Mobile Web theming support
- Ability to update module look and feel without releasing new versions of the native apps
- Use custom “native look and feel” assets for common UI elements and built-in Kurogo mobile web templates
- Access to native UI elements:
- Navigation bar: can set title, back button title and add a refresh content button
- Alert dialogs
- Action dialogs (cancel, optional destructive button, and up to 10 other optional buttons)
- Share dialog (automatically via Smarty share.tpl template)
- Native mail composition dialog when user taps on a mailto: link
- Basic GPS location as provided by HTML5 web engine (navigator.geolocation)
What AppQ 1.0 can’t do:
- Offline storage
- Providing AppQ offline storage similar to what is available on fully native apps is a difficult technical and architectural problem
- HTML5 offline storage is too small for many use cases
- Access to native storage mechanisms is a difficult technical and architectural problem on Android
- On Android the APIs necessary for this (web view cache) were introduced in Ice Cream Sandwich (ICS)
- Currently most devices are on Gingerbread so we cannot require ICS
- All supported iOS versions can provide this functionality via NSURLCache and CoreData
- On Android the APIs necessary for this (web view cache) were introduced in Ice Cream Sandwich (ICS)
- Camera access
- NFC access
- Other direct sensor access
Preparing a Web Module for AppQ
대부분의 모듈들은 약간의 작업만 하면 AppQ를 적용할 수 있습니다. 약간의 modification은 필요하죠. 특히 많은 javascript 나 conditional UI display 가 있는 complex 모듈의 경우는 좀 더 작업이 필요할 겁니다.
Telling AppQ about your module pages
AppQ 가 알아야할 여러분의 모듈에 대한 것들 중 하나는 어떤 페이지들이 지원될 것이냐는 겁니다. AppQ는 이 정보를 모듈의 pages.ini configuration 파일에서 가져 옵니다. AppQ가 제대로 작동할 수 있도록 여러분 모듈의 각 페이지들이 pages.ini 에 리스트 되야 합니다.
pages.ini
[index] [detail] pageTitle = "Detail" [search] pageTitle = "Search Results" breadcrumbTitle = "Search"
Locating images and other static assets
AppQ는 웹 모듈에서 사용되는 자바스크립트, css , 이미지 등의 asset을 zip 파일로 빌드합니다. 이런 파일들이 검색되면 모든 템플릿 variable들과 함께 이 파일들은 template에 로드되게 됩니다. 만약 여러분 웹 모듈이 템플릿 variable이 set 됐을 떄 특정 UI element들만 보여준다면 AppQ는 그러한 element들을 찾지 못할 겁니다. 이것을 하기 위해 각 모듈을 initializeForPage() 의 custom version 을 정의할 수 있는데요. 이것은 AppQ에 의해 사용되는 initializeForNativeTemplatePage() 라고 불립니다. 이 기능을 정의할 때 탬플릿 variable들을 세팅하셔야 합니다. 그러면 이미지나 CSS, 자바스크립트 파일까지 포함한 모든 UI element 들이 visible 하게 됩니다.
예를 들어 여기 index와 search 페이지에 에 ellipsizer javascript module을 사용하는 모듈이 있습니다. 그리고 detail page에 share button 을 가지고 있구요.
MyWebModule.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php protected function initializeForNativeTemplatePage() { // Native template support // specify anything that goes into the header or footer here // and force the appearance of assets so they get loaded into the template switch ($this->page) { case 'index': // force appearance of section select button $this->assign('sections', array(1, 2)); case 'search': $this->addInternalJavascript('/common/javascript/lib/ellipsizer.js'); break; case 'story': $this->assign('shareTitle', $this->getLocalizedString('SHARE_THIS_STORY')); $this->assign('shareEmailURL', 'dummy'); $this->assign('shareRemark', 'dummy'); $this->assign('storyURL', 'dummy'); } } |
두번째 옵션은 array 에 있는 파일들을 정해주기 위한 겁니다. 이 옵션은 어떤 asset을 display 하기 위해 많은 code 가 요구 될 때 간단하게 작업할 수 있는 옵션입니다.
MyWebModule.php
1 2 3 4 5 6 7 8 9 10 | <?php protected function nativeWebTemplateAssets() { return array( '/min/g=file:/common/javascript/lib/ellipsizer.js', '/common/images/share.png', '/common/images/button-email.png', '/common/images/button-facebook.png', '/common/images/button-twitter.png' ); } |
세번째 옵션은 module.ini 파일에 필요한 내용들 입니다. 이 옵션은 여러분의 custom module theme 에 이미지를 add 하고 subclass에서는 add 하고 싶지 않을 때 아주 유용하죠.
module.ini
[module] title = "AppQ Test" disabled = 0 protected = 0 search = 1 secure = 0 MAX_RESULTS = 10 SHARING_ENABLED = 1 [native_template] additional_assets[] = "/min/g=file:/common/javascript/lib/ellipsizer.js" additional_assets[] = "/common/images/share.png" additional_assets[] = "/common/images/button-email.png" additional_assets[] = "/common/images/button-facebook.png" additional_assets[] = "/common/images/button-twitter.png" [strings] help[] = "The news home screen features most recent news across all categories. Click on an individual news item to read the full story. Note that clicking a link within the story will launch your browser. You can share each article using email, Facebook, or Twitter by clicking on the gray arrow button top right."
Javascript global variables
가끔 웹 모듈들은 글로벌 namespace로 variable들을 세팅합니다. 그러면 로딩된 자바스크립트 파일들에서 계속 참조되겠죠.
AppQ-incompatible global variable use
아래 예제를 보시죠. 이 site 는 custom header.tpl을 정의했습니다. 이 탬플릿에는 글로벌 자바스크립트 변수인 myGlobals 가 템플릿 변수의 배열로 정의돼 있구요.
header.tpl
{extends file="findExtends:common/templates/header.tpl"} {block name="javascript"} <script type="text/javascript"> var myGlobals = {json_encode($globalsArray)}; </script> {$smarty.block.parent} {/block}
그리고 이 site의 common.js 에서 myGlobals 변수가 참조 됩니다. (파일의 top level 에서)
common.js
var firstGlobal = myGlobals[0];
이런 테크닉은 AppQ 와 같이 사용할 수 없습니다. 왜냐하면 <head> tag 는 비어있고 자바스크립트 파일은 전에 generate 되고 페이지당 content 는 AJAX를 통해서 로드되기 때문이죠. 위와 같은 경우에는 myGlobals 값이 항상 null 일겁니다. 왜냐하면 globalsArray 가 html wrapper 가 generate 될 때 세팅되지 않을 것이기 때문입니다.
AppQ-compatible global variable use
AppQ 는 글로벌 변수의 사용을 모두 막지는 않습니다. key 는 built-in 모듈 함수인 WebModule::addInlineJavascript() 와 WebModule::addInlineJavascriptFooter()를사용해 페이지마다 글로벌 자바스크립트 변수들을 정의하고 WebModule::addOnLoad()
를 사용해서 common.js 안의 function 을 trigger 해서 그것들을 reference 하도록 하는 겁니다. AppQ는 AJAX call 이 이루어진 이후에 이 자바스크립트 블럭을 있어야 할 위치에 자동으로 옮겨 놓습니다. 그리고 글로벌 namespace 에 선언하게 되죠.
예를 들어 위의 myGlobals
variable 를 implementing 하는 AppQ-safe 방법은 header.tpl 를 오버라이딩하는 대신입니다. 우리는 extra 자바스크립트를 모듈의 php 파일에 옮깁니다.
MyWebModule.php
<?php protected function initializeForPage() { parent::initializeForPage(); $this->addInlineJavascript('var myGlobals = '.json_encode($this->globalsArray).';'); $this->addOnLoad('myOnLoad();'); }
그리고나서 common.js 의 load 함수 내에 firstGlobal 을 initialize 하죠.
common.js
var firstGlobal = null; function myOnLoad() { firstGlobal = myGlobals[0]; }
Using Native Callbacks
AppQ 는 간단한 작업으로 native 기능을 가능하도록 합니다.
Page Load
페이지 로드시 AppQ는 page title을 set 하고 그 페이지의 navigation stack 에 보여지게 될 back button 의 title을 세팅하게 됩니다. 디폴트로 AppQ는 모바일 웹에서 사용하는 page title과 breadcrumb title을 사용합니다. AppQ에서 다른 이름을 사용하고 싶으면 모듈의 pages.ini 의 nativePageTitle 와 nativeBreadcrumbTitle 를 수정하시면 됩니다.
추가로 AppQ는 navigation bar에 reload button을 추가할 수 있도록 해 줍니다. 이 reload 버튼은 페이지의 content를 reload 할 수 있도록 해 주죠. 이것도 pages.ini 의 nativePageRefresh or programmatically 를 수정해 주시면 됩니다. 그리고 WebModule::setWebBridgePageRefresh() 함수도 사용하시구요.
Dialogs
hybrid 앱에서 유저에게 메세지를 안내하는 방법중이 하나가 dialogs 입니다. 이 dialog 는 top 에 URL을 가지고 있는 자바스크립트 팝업이던지 floating div 이고 native dialog 처럼 보이는 것이 될 겁니다. AppQ 모듈을 좀 더 native 처럼 만들도록 하기 위해 AppQ는 native dialog를 만들수 있는 자바스크립트 함수를 제공합니다.
Alert Dialogs
Alert dialog는 유저에게 기대하지 않은 상황이 초래 됐을 때 무엇인가를 알리기 위해 사용됩니다. 그리고 유저에게 cancel 이라던지 어떤 action을 할것인지를 물어보는 기능이 있을 겁니다.
kgoBridge.alertDialog(title, message, cancelButtonTitle, mainButtonTitle, alternateButtonTitle, statusCallback, buttonCallback)
- title - (required) A short human readable title (shown in bold on the dialog)
- message - (optional) A human-readable message (show in regular text below the title)
- cancelButtonTitle - (required) Title of the button which dismisses the alert and cancels any actions the alert refers to
- mainButtonTitle - (optional) Title of the primary button
- alternateButtonTitle - (optional) Title of an alternate button
- statusCallback - (optional) A callback function which will
return an error if the dialog fails to display. The callback should
have the following signature:
- function statusCallback(error, params)
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- code - a numeric code indicating what error occurred
- title - a short string categorizing the error
- message - a string describing the error
- params - (ignored) always null
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- function statusCallback(error, params)
- buttonCallback - (optional) A callback function which is
called when one of the buttons is clicked. The callback should have the
following signature:
- function buttonCallback(error, params)
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- code - a numeric code indicating what error occurred
- title - a short string categorizing the error
- message - a string describing the error
- params - If there is no error, the params object will contain the following property:
- button - with a string value indicating which button was tapped. This string may be one of:
- cancel
- main
- alternate
- button - with a string value indicating which button was tapped. This string may be one of:
- function buttonCallback(error, params)
일반적인 상황들을 간략화 하기 위해 아래 두가지 함수를 사용하실 수 있습니다.
kgoBridge.alert(message, responseCallback)
- message - (required) A human-readable message
- responseCallback - (optional) A callback function which
will be called when the dialog is dismissed. The callback should have
the following signature:
- function responseCallback()
kgoBridge.confirm(question, responseCallback)
- question - (required) A human-readable message
- responseCallback - (optional) A callback function which
will be called when the dialog is dismissed. The callback should have
the following signature:
- function responseCallback(confirmed)
- confirmed - true if the user clicked “OK” and false if they clicked “Cancel”.
- function responseCallback(confirmed)
Action Dialogs
kgoBridge.actionDialog(title, cancelButtonTitle, destructiveButtonTitle, alternateButtonTitles, statusCallback, buttonCallback)
- title - (required) A short human readable title
- cancelButtonTitle - (required) Title of the button which dismisses the dialog and cancels the action the alert refers to
- destructiveButtonTitle - (optional) Title of a destructive action if there is one (e.g. delete data). Button is emphasized or shown in red to warn user.
- alternateButtonTitles - (required) An array of titles of additional buttons to display. Each button should correspond to a possible non-destructive action the user can take.
- statusCallback - (optional) A callback function which will
return an error if the dialog fails to display. The callback should
have the following signature:
- function statusCallback(error, params)
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- code - a numeric code indicating what error occurred
- title - a short string categorizing the error
- message - a string describing the error
- params - (ignored) always null
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- function statusCallback(error, params)
- buttonCallback - (optional) A callback function which is
called when one of the buttons is clicked. The callback should have the
following signature:
- function buttonClickedCallback(error, params)
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- code - a numeric code indicating what error occurred
- title - a short string categorizing the error
- message - a string describing the error
- params - If there is no error, the params object will contain the following property:
- button - with a string value indicating which button was tapped. This string may be one of:
- cancel
- destructive
- alternateN - where N is a number between 0 and the number of alternate buttons minus 1
- button - with a string value indicating which button was tapped. This string may be one of:
- error - If there is no error, this will be null. If there is an error, the error object will contain the following properties:
- function buttonClickedCallback(error, params)
일반적인 상황들을 간략화 하기 위해 아래 두가지 함수를 사용하실 수 있습니다.
kgoBridge.shareDialog(buttonConfig)
- buttonConfig - (required) An object with the following properties
- mail - (optional) a string containing a URL to share something via email (mailto:user@example.com)
- facebook - (optional) a string containing a URL to share something on Facebook
- twitter - (optional) a string containing a URL to share something on Twitter
일반적으로 kgobridge.shareDialog() function를 call 할 필요는 없습니다. 그냥 share.tpl 템플릿을 include 하시면 이 함수가 자동으로 call 할 겁니다.
Debug Logging
iOS 에서는 UIWebView 밖의 곳에서 logging message를 표시하는 console을 사용하기 어렵습니다. 이것을 하기 위해 AppQ는 logging function을 제공합니다. 이 함수는 native 앱이 디버그 모드에서 run 할 경우 NSLog()를 통해 Xcode console 로 메세지를 보낼 겁니다. 이 함수는 안드로이드에서도 사용할 수 있습니다.
kgoBridge.log(message)
- message - (required) A human-readable message to log to the native console
Theming a Module for AppQ
Kurogo Mobile 웹은 stock 템플릿을 위해 native app images 와 styles를 활용합니다. 만약 여러분이 custom UI를 사용한다면 아마 AppQ 에 맞는 어떤 UI theme 을 사용하기를 우ㅝㄴ할 겁니다. 여러분은 모든 native platform에 적용하거나 아니면 특정 platform 에만 적용되는 AppQ 용 theme을 사용하실 수 있습니다. 이것은 모바일 웹에서 phone 브라우저의 서로 다른 type들을 구분하기 위해 사용한 pagetype/platform
mechanism을 이용해서 구현할 수 있습니다.
Targeting AppQ devices
특별히 target native app을 하도록 도와주기 위해 AppQ는 세번째 classification type은 "browser" 를 제공합니다. 이것을 이용하면 각 pagetype과 platform 별로 그에 해당하는 브라우저도 구분할 수 있습니다.
예를 들어 아래 여러 CSS 가 있고 그 영향을 받을 device 들이 있습니다.
pagetype | - | platform | - | browser | Devices Impacted | |
---|---|---|---|---|---|---|
common | .css | all devices | ||||
compliant | .css | all phones | ||||
tablet | .css | all phones | ||||
common | - | android | .css | all Android Devices | ||
compliant | - | android | .css | all Android phones | ||
compliant | - | iphone | .css | all iPhones | ||
common | - | common | - | native | .css | AppQ on all devices |
compliant | - | common | - | native | .css | AppQ on all phones |
tablet | - | common | - | native | .css | AppQ on all tablets |
common | - | android | - | native | .css | AppQ on Android devices |
common | - | iphone | - | native | .css | AppQ on iOS devices |
compliant | - | android | - | native | .css | AppQ on Android phones |
compliant | - | iphone | - | native | .css | AppQ on iOS phones |
tablet | - | android | - | native | .css | AppQ on Android tablets |
tablet | - | iphone | - | native | .css | AppQ on iPad |
자바스크립트 파일과 템플릿 그리고 이미지 directory들도 비슷한 naming scheme을 따릅니다.
Debugging AppQ theme problems
AppQ theming에서의 디버깅 문제는 full featured DOM inspector의 제한 때문에 device 에서 하기엔 어려운 점이 있습니다. 다행히도 AppQ 모듈을 디버깅하기 위해 Kurogo Mobile Web server 의 device debugging feature 를 사용할 수 있습니다.
우선 site.ini 파일에서 DEVICE_DEBUG=1이 되어 있어야 합니다. 그 다음 http://localhost/device/compliant-iphone-native/mymodule/로 가셔서 여러분 모듈의 AppQ iPhone module version을 보세요. 그리고 http://localhost/device/tablet-android-native/mymodule/은 모듈의 AppQ 안드로이드 태블릿 버전을 보여줄 겁니다. 이 때 native 앱의 브라우저와 유사한 웹 브라우저를 사용하셔야 될 겁니다. 예를 들어 iOS 와 안드로이드는 Webkit 브라우저를 사용하니까 Safari 나 Chrome 을 사용해서 디버깅 하셔야 됩니다.
AppQ는 native navigation stack 을 제공하기 때문에 AppQ device
debugging mode 는 breadcrumb bar를 display 하지 않을 겁니다. 대신에 뒤로 가기 위해 browser navigation arrow를 사용하셔야 됩니다.
The AppQ Native Asset Zip File
일단 여러분의 모듈이 AppQ를 지원하도록 modify 되면 여러분의 첫번째 asset zip 파일을 빌드하실 수 있습니다. 이 archive 에는 모든 이미지와 CSS 그리고 자바스크립트가 포함 됩니다. 이것들은 퍼포먼스를 개선할 수 있도록 native 내에서 locally cache 되게 됩니다.
Building the Asset Zip File
asset zip 파일을 빌드하려면 Admin panel로 가셔서 왼쪽 메뉴의 Module Configuration을 선택하세요. 그러면 오른쪽에 모듈 이름 다음에 3개의 탭을 보실 수 있을 겁니다. 여기서 AppQ 탭을 선택하세요. iPhone 과 Android 템플릿으로 빌드하기 위한 버튼들을 보실 수 있을 겁니다. 빌드하고 싶은 것을 골라서 클릭하세요. AppQ asset zip 파일이 generate 될 겁니다. 파일 크기에 따라 시간이 좀 걸릴 수 있습니다.
asset zip files이 모드 빌드 되면 각 버튼 밑에 이미지를 다운 로드 할 수 있는 링크를 보시게 될 겁니다. 이 링크는 다음과 같을 겁니다. http://www.example.com/media/web_bridge/iphone/mymodule.zip. 만약 이 사이트에 tablet theme을 enable 하도록 했다면 AppQ는 같은 asset zip file에 tablet version 도 같이 빌드 할 겁니다. http://www.example.com/media/web_bridge/iphone/mymodule-tablet.zip.
asset zip 파일들을 새롭게 빌드 할 때마다 Kurogo Mobile Web server는 새로운 파일을 다운로드 받으라고 알려 줄 겁니다. 아마 production server에 올릴 수 있도록 용량을 줄이기 위해 여러번 빌드 할 수 있을 겁니다. 그 때 마다 새로운 파일을 다운로드 받으셔야 합니다.
Preloading the Asset Zip File
AppQ asset zip 파일은 여러분의 site의 media 폴더 내의 Kurogo Mobile Web server 에 있습니다. Kurogo Mobile Web server는 native 앱에게 어떤 모듈이 AppQ를 지원하는지 얘기해 줍니다. 그리고 그 앱은 media 폴더에서 그 asset 파일들을 다운로드 받을 겁니다. 이 작업은 매번 asset zip file들이 change 될 때마다 반복될 겁니다. 이 asset zip 파일에 현재 버전을 넣는 다면 유저가 처음 앱을 시작할 때 훨씬 빨리 보여줄 수 있겠죠.
Admin panel은 이 asset zip file들의 copy를 얻을 수 있도록 다운로드 할 수 있는 link 를 제공합니다. 만약 여러분이 tablet 버전을 가지고 있다면 거기에 대한 링크도 있을 겁니다.
iOS (iPhone and iPad)
AppQ asset file은 iOS 에는 프로젝트의 resource 폴더에 있습니다. 아래에 iOS app “MyApp” 과 AppQ 모듈인 “mymodule” 에 대한 asset zip file path example 이 있습니다.
- Kurogo-iOS/Projects/MyApp/Resources/modules/mymodule/mymodule.zip
- Kurogo-iOS/Projects/MyApp/Resources/modules/mymodule/mymodule-tablet.zip
이 파일들은 Xcode 폴더 references를 통해서 여러분 프로젝트에 자동적으로 추가 될 겁니다.
Android
아래에 안드로이드 앱 “MyApp” 과
AppQ module “mymodule” 가 있는 경로 예제가 있습니다.
- Kurogo-Android/site/MyApp/config/modules/mymodule/assets/web_bridge.zip
- Kurogo-Android/site/MyApp/config/modules/mymodule/assets/web_bridge-tablet.zip
이 위치에 asset zip 파일들이 copy 되면 여러분 프로젝트를 clean 하시고 rebuild 하세요. 그러면 asset들이 여러분 앱에 built 될 겁니다.
Updating an AppQ Module
여러분의 모듈을 업데이트하고 그것을 Kurogo Mobile
Web server 에 deploy 할 때마다 여러분은 이 새로운 asset zip file을 빌드할 필요가 있습니다. 그래야 그 zip 파일이 모바일 웹 버전과 일치할 수 있습니다. 현재 존재하는 native app은 new zip file을 다운로드 할 겁니다. 그러니까 여러분은 이미 이전 버전을 사용하고 있는 유저에 대해서는 걱정하실 필요가 없습니다. 일단 Kurogo Mobile Web
server를 deploy 하고 난 후에 여러분은 새로운 zip 파일과 함께 여러분의 native 앱의 새 버전을 release 하고 싶어질 겁니다. 그래야 "first launch" experience 에서 새로운 버전의 asset zip file을 다운로드 받는 일이 없을 테니까요. 여러분의 모듈에 이미지가 아주 많이 있지 않다면 zip 파일은 그리 크지 않을 겁니다. 하지만 네트워크 속도가 느리다면 다운로드 시간이 noticeable 하게 될 겁니다.
'WEB_APP > Kurogo' 카테고리의 다른 글
Kurogo Tutorial 24 - People Module - (0) | 2012.10.10 |
---|---|
Kurogo Tutorial 23 - Links Module - (0) | 2012.10.10 |
Kurogo Tutorial 22 - Content Module - (0) | 2012.10.10 |
Database Authentication (0) | 2012.09.12 |
Authentication (0) | 2012.09.06 |
Flat File Authentication (0) | 2012.09.06 |
Access Control and Authorization (0) | 2012.09.06 |
Kurogo Tutorial 21 - Emergency Module - (0) | 2012.07.12 |
Kurogo Tutorial 20 - Module Interaction - (0) | 2012.06.13 |
Kurogo Tutorial 19 - The Kurogo Object - (0) | 2012.06.12 |