Source Code Cross Referenced for LaborYearEndBalanceForwardServiceImpl.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » module » labor » service » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » Kuali Financial System » org.kuali.module.labor.service.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2007 The Kuali Foundation.
003:         * 
004:         * Licensed under the Educational Community License, Version 1.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         * 
008:         * http://www.opensource.org/licenses/ecl1.php
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:        package org.kuali.module.labor.service.impl;
017:
018:        import static org.kuali.module.gl.bo.OriginEntrySource.LABOR_YEAR_END_BALANCE_FORWARD;
019:        import static org.kuali.module.labor.LaborConstants.DestinationNames.LEDGER_BALANCE;
020:        import static org.kuali.module.labor.LaborConstants.DestinationNames.ORIGN_ENTRY;
021:
022:        import java.math.BigDecimal;
023:        import java.sql.Date;
024:        import java.util.ArrayList;
025:        import java.util.HashMap;
026:        import java.util.Iterator;
027:        import java.util.List;
028:        import java.util.Map;
029:
030:        import org.kuali.core.service.BusinessObjectService;
031:        import org.kuali.core.service.DateTimeService;
032:        import org.kuali.core.service.KualiConfigurationService;
033:        import org.kuali.core.util.KualiDecimal;
034:        import org.kuali.kfs.KFSConstants;
035:        import org.kuali.kfs.KFSPropertyConstants;
036:        import org.kuali.kfs.bo.Options;
037:        import org.kuali.kfs.context.SpringContext;
038:        import org.kuali.kfs.service.OptionsService;
039:        import org.kuali.kfs.service.ParameterService;
040:        import org.kuali.kfs.service.impl.ParameterConstants;
041:        import org.kuali.module.gl.GLConstants;
042:        import org.kuali.module.gl.bo.OriginEntryGroup;
043:        import org.kuali.module.gl.bo.Transaction;
044:        import org.kuali.module.gl.service.OriginEntryGroupService;
045:        import org.kuali.module.gl.util.Message;
046:        import org.kuali.module.gl.util.Summary;
047:        import org.kuali.module.labor.LaborConstants;
048:        import org.kuali.module.labor.LaborKeyConstants;
049:        import org.kuali.module.labor.LaborConstants.YearEnd;
050:        import org.kuali.module.labor.batch.LaborYearEndBalanceForwardStep;
051:        import org.kuali.module.labor.bo.LaborOriginEntry;
052:        import org.kuali.module.labor.bo.LedgerBalance;
053:        import org.kuali.module.labor.bo.LedgerBalanceForYearEndBalanceForward;
054:        import org.kuali.module.labor.service.LaborLedgerBalanceService;
055:        import org.kuali.module.labor.service.LaborOriginEntryService;
056:        import org.kuali.module.labor.service.LaborReportService;
057:        import org.kuali.module.labor.service.LaborYearEndBalanceForwardService;
058:        import org.kuali.module.labor.util.DebitCreditUtil;
059:        import org.kuali.module.labor.util.ObjectUtil;
060:        import org.kuali.module.labor.util.ReportRegistry;
061:        import org.springframework.transaction.annotation.Transactional;
062:
063:        /**
064:         * Labor Ledger Year End – Inception to Date Beginning Balance process moves the Year-to-Date Total plus the Contracts and Grants
065:         * Beginning Balances to the Contracts and Grants Beginning Balances of the new fiscal year for a designated group of accounts (to
066:         * be identified by fund group and sub fund group).
067:         */
068:        @Transactional
069:        public class LaborYearEndBalanceForwardServiceImpl implements 
070:                LaborYearEndBalanceForwardService {
071:            private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
072:                    .getLogger(LaborYearEndBalanceForwardServiceImpl.class);
073:
074:            private LaborLedgerBalanceService laborLedgerBalanceService;
075:            private OriginEntryGroupService originEntryGroupService;
076:            private LaborOriginEntryService laborOriginEntryService;
077:
078:            private OptionsService optionsService;
079:
080:            private BusinessObjectService businessObjectService;
081:            private LaborReportService laborReportService;
082:            private DateTimeService dateTimeService;
083:            private ParameterService parameterService;
084:
085:            private final static int LINE_INTERVAL = 2;
086:
087:            /**
088:             * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance()
089:             */
090:            public void forwardBalance() {
091:                Integer fiscalYear = Integer.valueOf(parameterService
092:                        .getParameterValue(
093:                                LaborYearEndBalanceForwardStep.class,
094:                                YearEnd.OLD_FISCAL_YEAR));
095:                this .forwardBalance(fiscalYear);
096:            }
097:
098:            /**
099:             * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance(java.lang.Integer)
100:             */
101:            public void forwardBalance(Integer fiscalYear) {
102:                forwardBalance(fiscalYear, fiscalYear + 1);
103:            }
104:
105:            /**
106:             * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance(java.lang.Integer, java.lang.Integer)
107:             */
108:            public void forwardBalance(Integer fiscalYear, Integer newFiscalYear) {
109:                String reportsDirectory = ReportRegistry.getReportsDirectory();
110:                Date runDate = dateTimeService.getCurrentSqlDate();
111:
112:                List<Summary> reportSummary = new ArrayList<Summary>();
113:                Map<Transaction, List<Message>> errorMap = new HashMap<Transaction, List<Message>>();
114:                OriginEntryGroup validGroup = originEntryGroupService
115:                        .createGroup(runDate, LABOR_YEAR_END_BALANCE_FORWARD,
116:                                true, true, true);
117:
118:                Map<String, String> fieldValues = new HashMap<String, String>();
119:                fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR,
120:                        fiscalYear.toString());
121:
122:                int numberOfBalance = businessObjectService.countMatching(
123:                        LedgerBalance.class, fieldValues);
124:                int numberOfSelectedBalance = this .processLedgerBalances(
125:                        fiscalYear, newFiscalYear, validGroup, errorMap,
126:                        runDate);
127:
128:                Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
129:                        KFSConstants.OperationType.READ, numberOfBalance, 0);
130:                Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
131:                        KFSConstants.OperationType.SELECT,
132:                        numberOfSelectedBalance, 0);
133:                Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
134:                        KFSConstants.OperationType.REPORT_ERROR, errorMap
135:                                .size(), 0);
136:                reportSummary.add(new Summary(reportSummary.size()
137:                        + LINE_INTERVAL, "", 0));
138:                Summary.updateReportSummary(reportSummary, ORIGN_ENTRY,
139:                        KFSConstants.OperationType.INSERT,
140:                        numberOfSelectedBalance, 0);
141:
142:                laborReportService.generateStatisticsReport(reportSummary,
143:                        errorMap, ReportRegistry.LABOR_YEAR_END_STATISTICS,
144:                        reportsDirectory, runDate);
145:                laborReportService.generateOutputSummaryReport(validGroup,
146:                        ReportRegistry.LABOR_YEAR_END_OUTPUT, reportsDirectory,
147:                        runDate);
148:            }
149:
150:            /**
151:             * post the qualified balances into origin entry table for the further labor ledger processing
152:             * 
153:             * @param balanceIterator the given ledger balances that will be carried forward
154:             * @param newFiscalYear the new fiscal year
155:             * @param validGroup the group that the posted transaction belongs to
156:             * @param errorMap the map that records the error messages
157:             * @param runDate the date the transaction is posted
158:             * @return the number of qualified balances
159:             */
160:            private int processLedgerBalances(Integer fiscalYear,
161:                    Integer newFiscalYear, OriginEntryGroup validGroup,
162:                    Map<Transaction, List<Message>> errorMap, Date runDate) {
163:                Options options = optionsService.getOptions(fiscalYear);
164:
165:                List<String> processableBalanceTypeCodes = this 
166:                        .getProcessableBalanceTypeCode(options);
167:                List<String> processableObjectTypeCodes = this 
168:                        .getProcessableObjectTypeCodes(options);
169:                List<String> subFundGroupCodes = this 
170:                        .getSubFundGroupProcessed();
171:                List<String> fundGroupCodes = this .getFundGroupProcessed();
172:
173:                // process the selected balances by balance type and object type
174:                Map<String, String> fieldValues = new HashMap<String, String>();
175:                int numberOfSelectedBalance = 0;
176:                for (String balanceTypeCode : processableBalanceTypeCodes) {
177:                    fieldValues.put(
178:                            KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE,
179:                            balanceTypeCode);
180:
181:                    for (String objectTypeCode : processableObjectTypeCodes) {
182:                        fieldValues
183:                                .put(
184:                                        KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE,
185:                                        objectTypeCode);
186:
187:                        fieldValues.remove(LaborConstants.ACCOUNT_FIELDS[0]);
188:                        fieldValues.remove(LaborConstants.ACCOUNT_FIELDS[1]);
189:                        List<List<String>> accounts = laborLedgerBalanceService
190:                                .findAccountsInFundGroups(fiscalYear,
191:                                        fieldValues, subFundGroupCodes,
192:                                        fundGroupCodes);
193:
194:                        for (List<String> account : accounts) {
195:                            fieldValues.put(LaborConstants.ACCOUNT_FIELDS[0],
196:                                    account.get(0));
197:                            fieldValues.put(LaborConstants.ACCOUNT_FIELDS[1],
198:                                    account.get(1));
199:
200:                            Iterator<LedgerBalanceForYearEndBalanceForward> balanceIterator = laborLedgerBalanceService
201:                                    .findBalancesForFiscalYear(fiscalYear,
202:                                            fieldValues, subFundGroupCodes,
203:                                            fundGroupCodes);
204:                            numberOfSelectedBalance += postSelectedBalancesAsOriginEntries(
205:                                    balanceIterator, newFiscalYear, validGroup,
206:                                    errorMap, runDate);
207:                        }
208:                    }
209:                }
210:                return numberOfSelectedBalance;
211:            }
212:
213:            /**
214:             * post the qualified balances into origin entry table for the further labor ledger processing
215:             * 
216:             * @param balanceIterator the given ledger balances that will be carried forward
217:             * @param newFiscalYear the new fiscal year
218:             * @param validGroup the group that the posted transaction belongs to
219:             * @param errorMap the map that records the error messages
220:             * @param runDate the date the transaction is posted
221:             * @return the number of qualified balances
222:             */
223:            private int postSelectedBalancesAsOriginEntries(
224:                    Iterator<LedgerBalanceForYearEndBalanceForward> balanceIterator,
225:                    Integer newFiscalYear, OriginEntryGroup validGroup,
226:                    Map<Transaction, List<Message>> errorMap, Date runDate) {
227:                int numberOfSelectedBalance = 0;
228:                String description = this .getDescription();
229:                String originationCode = this .getOriginationCode();
230:                String documentTypeCode = this .getDocumentTypeCode();
231:
232:                while (balanceIterator != null && balanceIterator.hasNext()) {
233:                    LedgerBalanceForYearEndBalanceForward balance = balanceIterator
234:                            .next();
235:                    List<Message> errors = null;
236:
237:                    boolean isValidBalance = validateBalance(balance, errors);
238:                    LaborOriginEntry laborOriginEntry = new LaborOriginEntry();
239:                    if (isValidBalance) {
240:                        laborOriginEntry.setEntryGroupId(validGroup.getId());
241:                        laborOriginEntry.setUniversityFiscalYear(newFiscalYear);
242:                        laborOriginEntry
243:                                .setFinancialDocumentTypeCode(documentTypeCode);
244:                        laborOriginEntry
245:                                .setFinancialSystemOriginationCode(originationCode);
246:                        laborOriginEntry
247:                                .setTransactionLedgerEntryDescription(description);
248:
249:                        this .postAsOriginEntry(balance, laborOriginEntry,
250:                                runDate);
251:                        numberOfSelectedBalance++;
252:                    } else if (errors != null && !errors.isEmpty()) {
253:                        ObjectUtil.buildObject(laborOriginEntry, balance);
254:                        errorMap.put(laborOriginEntry, errors);
255:                    }
256:                    laborOriginEntry = null;
257:                    balance = null;
258:                }
259:                return numberOfSelectedBalance;
260:            }
261:
262:            /**
263:             * determine if the given balance is qualified to be carried forward to new fiscal year
264:             * 
265:             * @param balance the given ledger balance that could be carried forward
266:             * @param errors the error list that is updated if the given balacne is not qualified for carry forward
267:             * @return true if the balance is qualified; otherwise, false
268:             */
269:            private boolean validateBalance(
270:                    LedgerBalanceForYearEndBalanceForward balance,
271:                    List<Message> errors) {
272:                /** This is the placeholder for addtional business rule validation. The former rules were moved down to data access layer. * */
273:                return true;
274:            }
275:
276:            /**
277:             * post the qualified balance into origin entry table for the further labor ledger processing
278:             * 
279:             * @param balance the given ledger balance that will be carried forward
280:             * @param newFiscalYear the new fiscal year
281:             * @param validGroup the group that the posted transaction belongs to
282:             * @param postingDate the date the transaction is posted
283:             */
284:            private void postAsOriginEntry(
285:                    LedgerBalanceForYearEndBalanceForward balance,
286:                    LaborOriginEntry originEntry, Date postingDate) {
287:                try {
288:                    originEntry.setAccountNumber(balance.getAccountNumber());
289:                    originEntry.setChartOfAccountsCode(balance
290:                            .getChartOfAccountsCode());
291:                    originEntry.setSubAccountNumber(balance
292:                            .getSubAccountNumber());
293:                    originEntry.setFinancialObjectCode(balance
294:                            .getFinancialObjectCode());
295:                    originEntry.setFinancialSubObjectCode(balance
296:                            .getFinancialSubObjectCode());
297:                    originEntry.setFinancialBalanceTypeCode(balance
298:                            .getFinancialBalanceTypeCode());
299:                    originEntry.setFinancialObjectTypeCode(balance
300:                            .getFinancialObjectTypeCode());
301:
302:                    originEntry.setPositionNumber(balance.getPositionNumber());
303:                    originEntry.setEmplid(balance.getEmplid());
304:                    originEntry.setDocumentNumber(balance
305:                            .getFinancialBalanceTypeCode()
306:                            + balance.getAccountNumber());
307:
308:                    originEntry.setProjectCode(KFSConstants
309:                            .getDashProjectCode());
310:                    originEntry
311:                            .setUniversityFiscalPeriodCode(KFSConstants.PERIOD_CODE_CG_BEGINNING_BALANCE);
312:
313:                    KualiDecimal transactionAmount = balance
314:                            .getAccountLineAnnualBalanceAmount();
315:                    transactionAmount = transactionAmount.add(balance
316:                            .getContractsGrantsBeginningBalanceAmount());
317:
318:                    originEntry
319:                            .setTransactionLedgerEntryAmount(transactionAmount
320:                                    .abs());
321:                    originEntry.setTransactionDebitCreditCode(DebitCreditUtil
322:                            .getDebitCreditCode(transactionAmount, false));
323:
324:                    originEntry.setTransactionLedgerEntrySequenceNumber(null);
325:                    originEntry.setTransactionTotalHours(BigDecimal.ZERO);
326:                    originEntry.setTransactionDate(postingDate);
327:
328:                    laborOriginEntryService.save(originEntry);
329:                } catch (Exception e) {
330:                    LOG.error(e);
331:                }
332:            }
333:
334:            /**
335:             * get the fund group codes that are acceptable by year-end process
336:             * 
337:             * @return the fund group codes that are acceptable by year-end process
338:             */
339:            private List<String> getFundGroupProcessed() {
340:                return parameterService.getParameterValues(
341:                        LaborYearEndBalanceForwardStep.class,
342:                        YearEnd.FUND_GROUP_PROCESSED);
343:            }
344:
345:            /**
346:             * get the fund group codes that are acceptable by year-end process
347:             * 
348:             * @return the fund group codes that are acceptable by year-end process
349:             */
350:            private List<String> getSubFundGroupProcessed() {
351:                return parameterService.getParameterValues(
352:                        LaborYearEndBalanceForwardStep.class,
353:                        YearEnd.SUB_FUND_GROUP_PROCESSED);
354:            }
355:
356:            /**
357:             * get the balance type codes that are acceptable by year-end process
358:             * 
359:             * @return the balance type codes that are acceptable by year-end process
360:             */
361:            private List<String> getProcessableBalanceTypeCode(Options options) {
362:                List<String> processableBalanceTypeCodes = new ArrayList<String>();
363:                processableBalanceTypeCodes.add(options
364:                        .getActualFinancialBalanceTypeCd());
365:                return processableBalanceTypeCodes;
366:            }
367:
368:            /**
369:             * get the object type codes that are acceptable by year-end process
370:             * 
371:             * @param options the given system options
372:             * @return the object type codes that are acceptable by year-end process
373:             */
374:            private List<String> getProcessableObjectTypeCodes(Options options) {
375:                List<String> processableObjectTypeCodes = new ArrayList<String>();
376:
377:                processableObjectTypeCodes.add(options
378:                        .getFinObjTypeExpenditureexpCd());
379:                processableObjectTypeCodes.add(options
380:                        .getFinObjTypeExpNotExpendCode());
381:
382:                return processableObjectTypeCodes;
383:            }
384:
385:            /**
386:             * get the document type code of the transaction posted by year-end process
387:             * 
388:             * @return the document type code of the transaction posted by year-end process
389:             */
390:            private String getDocumentTypeCode() {
391:                return parameterService.getParameterValue(
392:                        ParameterConstants.GENERAL_LEDGER_BATCH.class,
393:                        GLConstants.ANNUAL_CLOSING_DOCUMENT_TYPE);
394:            }
395:
396:            /**
397:             * get the origination code of the transaction posted by year-end process
398:             * 
399:             * @return the origination code of the transaction posted by year-end process
400:             */
401:            private String getOriginationCode() {
402:                return parameterService.getParameterValue(
403:                        LaborYearEndBalanceForwardStep.class,
404:                        YearEnd.ORIGINATION_CODE);
405:            }
406:
407:            /**
408:             * get the description of the transaction posted by year-end process
409:             * 
410:             * @return the description of the transaction posted by year-end process
411:             */
412:            private String getDescription() {
413:                return SpringContext
414:                        .getBean(KualiConfigurationService.class)
415:                        .getPropertyString(
416:                                LaborKeyConstants.MESSAGE_YEAR_END_TRANSACTION_DESCRIPTON);
417:            }
418:
419:            /**
420:             * Sets the businessObjectService attribute value.
421:             * 
422:             * @param businessObjectService The businessObjectService to set.
423:             */
424:            public void setBusinessObjectService(
425:                    BusinessObjectService businessObjectService) {
426:                this .businessObjectService = businessObjectService;
427:            }
428:
429:            /**
430:             * Sets the dateTimeService attribute value.
431:             * 
432:             * @param dateTimeService The dateTimeService to set.
433:             */
434:            public void setDateTimeService(DateTimeService dateTimeService) {
435:                this .dateTimeService = dateTimeService;
436:            }
437:
438:            public void setParameterService(ParameterService parameterService) {
439:                this .parameterService = parameterService;
440:            }
441:
442:            /**
443:             * Sets the laborLedgerBalanceService attribute value.
444:             * 
445:             * @param laborLedgerBalanceService The laborLedgerBalanceService to set.
446:             */
447:            public void setLaborLedgerBalanceService(
448:                    LaborLedgerBalanceService laborLedgerBalanceService) {
449:                this .laborLedgerBalanceService = laborLedgerBalanceService;
450:            }
451:
452:            /**
453:             * Sets the optionsService attribute value.
454:             * 
455:             * @param optionsService The optionsService to set.
456:             */
457:            public void setOptionsService(OptionsService optionsService) {
458:                this .optionsService = optionsService;
459:            }
460:
461:            /**
462:             * Sets the originEntryGroupService attribute value.
463:             * 
464:             * @param originEntryGroupService The originEntryGroupService to set.
465:             */
466:            public void setOriginEntryGroupService(
467:                    OriginEntryGroupService originEntryGroupService) {
468:                this .originEntryGroupService = originEntryGroupService;
469:            }
470:
471:            /**
472:             * Sets the laborReportService attribute value.
473:             * 
474:             * @param laborReportService The laborReportService to set.
475:             */
476:            public void setLaborReportService(
477:                    LaborReportService laborReportService) {
478:                this .laborReportService = laborReportService;
479:            }
480:
481:            /**
482:             * Sets the laborOriginEntryService attribute value.
483:             * 
484:             * @param laborOriginEntryService The laborOriginEntryService to set.
485:             */
486:            public void setLaborOriginEntryService(
487:                    LaborOriginEntryService laborOriginEntryService) {
488:                this.laborOriginEntryService = laborOriginEntryService;
489:            }
490:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.