Repository: Urinx/SublimeCode
Branch: master
Commit: 9d07c01d69e1
Files: 763
Total size: 87.4 MB
Directory structure:
gitextract_fjit1hwf/
├── .gitignore
├── LICENSE
├── README.md
├── Sublime/
│ ├── Cycript.framework/
│ │ ├── Cycript
│ │ └── Headers/
│ │ └── Cycript.h
│ ├── Podfile
│ ├── Pods/
│ │ ├── AASquaresLoading/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Source/
│ │ │ └── AASquaresLoading.swift
│ │ ├── Alamofire/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Source/
│ │ │ ├── Alamofire.swift
│ │ │ ├── Download.swift
│ │ │ ├── Error.swift
│ │ │ ├── Manager.swift
│ │ │ ├── MultipartFormData.swift
│ │ │ ├── NetworkReachabilityManager.swift
│ │ │ ├── Notifications.swift
│ │ │ ├── ParameterEncoding.swift
│ │ │ ├── Request.swift
│ │ │ ├── Response.swift
│ │ │ ├── ResponseSerialization.swift
│ │ │ ├── Result.swift
│ │ │ ├── ServerTrustPolicy.swift
│ │ │ ├── Stream.swift
│ │ │ ├── Timeline.swift
│ │ │ ├── Upload.swift
│ │ │ └── Validation.swift
│ │ ├── AlamofireRSSParser/
│ │ │ ├── LICENSE
│ │ │ ├── Pod/
│ │ │ │ └── Classes/
│ │ │ │ ├── AlamofireRSSParser.h
│ │ │ │ ├── AlamofireRSSParser.swift
│ │ │ │ ├── RSSFeed.swift
│ │ │ │ └── RSSItem.swift
│ │ │ └── README.md
│ │ ├── CYRTextView/
│ │ │ ├── CYRTextView/
│ │ │ │ ├── CYRLayoutManager.h
│ │ │ │ ├── CYRLayoutManager.m
│ │ │ │ ├── CYRTextStorage.h
│ │ │ │ ├── CYRTextStorage.m
│ │ │ │ ├── CYRTextView.h
│ │ │ │ ├── CYRTextView.m
│ │ │ │ ├── CYRToken.h
│ │ │ │ └── CYRToken.m
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ ├── Charts/
│ │ │ ├── Charts/
│ │ │ │ └── Classes/
│ │ │ │ ├── Animation/
│ │ │ │ │ ├── ChartAnimationEasing.swift
│ │ │ │ │ └── ChartAnimator.swift
│ │ │ │ ├── Charts/
│ │ │ │ │ ├── BarChartView.swift
│ │ │ │ │ ├── BarLineChartViewBase.swift
│ │ │ │ │ ├── BubbleChartView.swift
│ │ │ │ │ ├── CandleStickChartView.swift
│ │ │ │ │ ├── ChartViewBase.swift
│ │ │ │ │ ├── CombinedChartView.swift
│ │ │ │ │ ├── HorizontalBarChartView.swift
│ │ │ │ │ ├── LineChartView.swift
│ │ │ │ │ ├── PieChartView.swift
│ │ │ │ │ ├── PieRadarChartViewBase.swift
│ │ │ │ │ ├── RadarChartView.swift
│ │ │ │ │ └── ScatterChartView.swift
│ │ │ │ ├── Components/
│ │ │ │ │ ├── ChartAxisBase.swift
│ │ │ │ │ ├── ChartComponentBase.swift
│ │ │ │ │ ├── ChartLegend.swift
│ │ │ │ │ ├── ChartLimitLine.swift
│ │ │ │ │ ├── ChartMarker.swift
│ │ │ │ │ ├── ChartXAxis.swift
│ │ │ │ │ └── ChartYAxis.swift
│ │ │ │ ├── Data/
│ │ │ │ │ ├── Implementations/
│ │ │ │ │ │ ├── ChartBaseDataSet.swift
│ │ │ │ │ │ └── Standard/
│ │ │ │ │ │ ├── BarChartData.swift
│ │ │ │ │ │ ├── BarChartDataEntry.swift
│ │ │ │ │ │ ├── BarChartDataSet.swift
│ │ │ │ │ │ ├── BarLineScatterCandleBubbleChartData.swift
│ │ │ │ │ │ ├── BarLineScatterCandleBubbleChartDataSet.swift
│ │ │ │ │ │ ├── BubbleChartData.swift
│ │ │ │ │ │ ├── BubbleChartDataEntry.swift
│ │ │ │ │ │ ├── BubbleChartDataSet.swift
│ │ │ │ │ │ ├── CandleChartData.swift
│ │ │ │ │ │ ├── CandleChartDataEntry.swift
│ │ │ │ │ │ ├── CandleChartDataSet.swift
│ │ │ │ │ │ ├── ChartData.swift
│ │ │ │ │ │ ├── ChartDataEntry.swift
│ │ │ │ │ │ ├── ChartDataSet.swift
│ │ │ │ │ │ ├── CombinedChartData.swift
│ │ │ │ │ │ ├── LineChartData.swift
│ │ │ │ │ │ ├── LineChartDataSet.swift
│ │ │ │ │ │ ├── LineRadarChartDataSet.swift
│ │ │ │ │ │ ├── LineScatterCandleRadarChartDataSet.swift
│ │ │ │ │ │ ├── PieChartData.swift
│ │ │ │ │ │ ├── PieChartDataSet.swift
│ │ │ │ │ │ ├── RadarChartData.swift
│ │ │ │ │ │ ├── RadarChartDataSet.swift
│ │ │ │ │ │ ├── ScatterChartData.swift
│ │ │ │ │ │ └── ScatterChartDataSet.swift
│ │ │ │ │ └── Interfaces/
│ │ │ │ │ ├── IBarChartDataSet.swift
│ │ │ │ │ ├── IBarLineScatterCandleBubbleChartDataSet.swift
│ │ │ │ │ ├── IBubbleChartDataSet.swift
│ │ │ │ │ ├── ICandleChartDataSet.swift
│ │ │ │ │ ├── IChartDataSet.swift
│ │ │ │ │ ├── ILineChartDataSet.swift
│ │ │ │ │ ├── ILineRadarChartDataSet.swift
│ │ │ │ │ ├── ILineScatterCandleRadarChartDataSet.swift
│ │ │ │ │ ├── IPieChartDataSet.swift
│ │ │ │ │ ├── IRadarChartDataSet.swift
│ │ │ │ │ └── IScatterChartDataSet.swift
│ │ │ │ ├── Filters/
│ │ │ │ │ ├── ChartDataApproximatorFilter.swift
│ │ │ │ │ └── ChartDataBaseFilter.swift
│ │ │ │ ├── Formatters/
│ │ │ │ │ ├── ChartDefaultFillFormatter.swift
│ │ │ │ │ ├── ChartDefaultXAxisValueFormatter.swift
│ │ │ │ │ ├── ChartFillFormatter.swift
│ │ │ │ │ └── ChartXAxisValueFormatter.swift
│ │ │ │ ├── Highlight/
│ │ │ │ │ ├── BarChartHighlighter.swift
│ │ │ │ │ ├── ChartHighlight.swift
│ │ │ │ │ ├── ChartHighlighter.swift
│ │ │ │ │ ├── ChartRange.swift
│ │ │ │ │ ├── CombinedHighlighter.swift
│ │ │ │ │ └── HorizontalBarChartHighlighter.swift
│ │ │ │ ├── Interfaces/
│ │ │ │ │ ├── BarChartDataProvider.swift
│ │ │ │ │ ├── BarLineScatterCandleBubbleChartDataProvider.swift
│ │ │ │ │ ├── BubbleChartDataProvider.swift
│ │ │ │ │ ├── CandleChartDataProvider.swift
│ │ │ │ │ ├── ChartDataProvider.swift
│ │ │ │ │ ├── LineChartDataProvider.swift
│ │ │ │ │ └── ScatterChartDataProvider.swift
│ │ │ │ ├── Jobs/
│ │ │ │ │ ├── AnimatedMoveViewJob.swift
│ │ │ │ │ ├── AnimatedViewPortJob.swift
│ │ │ │ │ ├── AnimatedZoomViewJob.swift
│ │ │ │ │ ├── ChartViewPortJob.swift
│ │ │ │ │ ├── MoveChartViewJob.swift
│ │ │ │ │ └── ZoomChartViewJob.swift
│ │ │ │ ├── Renderers/
│ │ │ │ │ ├── BarChartRenderer.swift
│ │ │ │ │ ├── BubbleChartRenderer.swift
│ │ │ │ │ ├── CandleStickChartRenderer.swift
│ │ │ │ │ ├── ChartAxisRendererBase.swift
│ │ │ │ │ ├── ChartDataRendererBase.swift
│ │ │ │ │ ├── ChartLegendRenderer.swift
│ │ │ │ │ ├── ChartRendererBase.swift
│ │ │ │ │ ├── ChartXAxisRenderer.swift
│ │ │ │ │ ├── ChartXAxisRendererBarChart.swift
│ │ │ │ │ ├── ChartXAxisRendererHorizontalBarChart.swift
│ │ │ │ │ ├── ChartXAxisRendererRadarChart.swift
│ │ │ │ │ ├── ChartYAxisRenderer.swift
│ │ │ │ │ ├── ChartYAxisRendererHorizontalBarChart.swift
│ │ │ │ │ ├── ChartYAxisRendererRadarChart.swift
│ │ │ │ │ ├── CombinedChartRenderer.swift
│ │ │ │ │ ├── HorizontalBarChartRenderer.swift
│ │ │ │ │ ├── LineChartRenderer.swift
│ │ │ │ │ ├── LineRadarChartRenderer.swift
│ │ │ │ │ ├── LineScatterCandleRadarChartRenderer.swift
│ │ │ │ │ ├── PieChartRenderer.swift
│ │ │ │ │ ├── RadarChartRenderer.swift
│ │ │ │ │ └── ScatterChartRenderer.swift
│ │ │ │ └── Utils/
│ │ │ │ ├── ChartColorTemplates.swift
│ │ │ │ ├── ChartFill.swift
│ │ │ │ ├── ChartPlatform.swift
│ │ │ │ ├── ChartSelectionDetail.swift
│ │ │ │ ├── ChartTransformer.swift
│ │ │ │ ├── ChartTransformerHorizontalBarChart.swift
│ │ │ │ ├── ChartUtils.swift
│ │ │ │ └── ChartViewPortHandler.swift
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ ├── DGElasticPullToRefresh/
│ │ │ ├── DGElasticPullToRefresh/
│ │ │ │ ├── DGElasticPullToRefreshConstants.swift
│ │ │ │ ├── DGElasticPullToRefreshExtensions.swift
│ │ │ │ ├── DGElasticPullToRefreshLoadingView.swift
│ │ │ │ ├── DGElasticPullToRefreshLoadingViewCircle.swift
│ │ │ │ └── DGElasticPullToRefreshView.swift
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ ├── EZAudio/
│ │ │ ├── EZAudio/
│ │ │ │ ├── AEFloatConverter.h
│ │ │ │ ├── AEFloatConverter.m
│ │ │ │ ├── EZAudio.h
│ │ │ │ ├── EZAudio.m
│ │ │ │ ├── EZAudioFile.h
│ │ │ │ ├── EZAudioFile.m
│ │ │ │ ├── EZAudioPlayer.h
│ │ │ │ ├── EZAudioPlayer.m
│ │ │ │ ├── EZAudioPlot.h
│ │ │ │ ├── EZAudioPlot.m
│ │ │ │ ├── EZAudioPlotGL.h
│ │ │ │ ├── EZAudioPlotGL.m
│ │ │ │ ├── EZAudioPlotGLKViewController.h
│ │ │ │ ├── EZAudioPlotGLKViewController.m
│ │ │ │ ├── EZMicrophone.h
│ │ │ │ ├── EZMicrophone.m
│ │ │ │ ├── EZOutput.h
│ │ │ │ ├── EZOutput.m
│ │ │ │ ├── EZPlot.h
│ │ │ │ ├── EZPlot.m
│ │ │ │ ├── EZRecorder.h
│ │ │ │ ├── EZRecorder.m
│ │ │ │ ├── TPCircularBuffer.c
│ │ │ │ └── TPCircularBuffer.h
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ ├── Gifu/
│ │ │ ├── Carthage/
│ │ │ │ └── Checkouts/
│ │ │ │ └── Runes/
│ │ │ │ └── Source/
│ │ │ │ └── Runes.swift
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Source/
│ │ │ ├── AnimatableImageView.swift
│ │ │ ├── AnimatedFrame.swift
│ │ │ ├── Animator.swift
│ │ │ ├── ArrayExtension.swift
│ │ │ ├── CGSizeExtension.swift
│ │ │ ├── FunctionalHelpers.swift
│ │ │ ├── Gifu.h
│ │ │ ├── ImageSourceHelpers.swift
│ │ │ └── UIImageExtension.swift
│ │ ├── NMSSH/
│ │ │ ├── LICENSE
│ │ │ ├── NMSSH/
│ │ │ │ ├── Config/
│ │ │ │ │ ├── NMSSH+Protected.h
│ │ │ │ │ ├── NMSSHLogger.h
│ │ │ │ │ ├── NMSSHLogger.m
│ │ │ │ │ ├── socket_helper.h
│ │ │ │ │ └── socket_helper.m
│ │ │ │ ├── NMSFTP.h
│ │ │ │ ├── NMSFTP.m
│ │ │ │ ├── NMSFTPFile.h
│ │ │ │ ├── NMSFTPFile.m
│ │ │ │ ├── NMSSH.h
│ │ │ │ ├── NMSSHChannel.h
│ │ │ │ ├── NMSSHChannel.m
│ │ │ │ ├── NMSSHConfig.h
│ │ │ │ ├── NMSSHConfig.m
│ │ │ │ ├── NMSSHHostConfig.h
│ │ │ │ ├── NMSSHHostConfig.m
│ │ │ │ ├── NMSSHSession.h
│ │ │ │ ├── NMSSHSession.m
│ │ │ │ └── Protocols/
│ │ │ │ ├── NMSSHChannelDelegate.h
│ │ │ │ └── NMSSHSessionDelegate.h
│ │ │ ├── NMSSH-iOS/
│ │ │ │ ├── Libraries/
│ │ │ │ │ ├── include/
│ │ │ │ │ │ └── libssh2/
│ │ │ │ │ │ ├── libssh2.h
│ │ │ │ │ │ ├── libssh2_publickey.h
│ │ │ │ │ │ └── libssh2_sftp.h
│ │ │ │ │ └── lib/
│ │ │ │ │ ├── libcrypto.a
│ │ │ │ │ ├── libssh2.a
│ │ │ │ │ └── libssl.a
│ │ │ │ └── NMSSH.h
│ │ │ └── README.md
│ │ ├── Pods.xcodeproj/
│ │ │ └── project.pbxproj
│ │ ├── RongCloudIMKit/
│ │ │ └── Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/
│ │ │ ├── Emoji.plist
│ │ │ ├── RongCloud.bundle/
│ │ │ │ ├── sms-received.caf
│ │ │ │ └── unicode_to_hanyu_pinyin.txt
│ │ │ ├── RongIMKit.framework/
│ │ │ │ ├── Headers/
│ │ │ │ │ ├── RCAttributedLabel.h
│ │ │ │ │ ├── RCBaseViewController.h
│ │ │ │ │ ├── RCChatSessionInputBarControl.h
│ │ │ │ │ ├── RCContentView.h
│ │ │ │ │ ├── RCConversationBaseCell.h
│ │ │ │ │ ├── RCConversationCell.h
│ │ │ │ │ ├── RCConversationListViewController.h
│ │ │ │ │ ├── RCConversationModel.h
│ │ │ │ │ ├── RCConversationSettingTableViewController.h
│ │ │ │ │ ├── RCConversationSettingTableViewHeader.h
│ │ │ │ │ ├── RCConversationViewController.h
│ │ │ │ │ ├── RCEmojiBoardView.h
│ │ │ │ │ ├── RCIM.h
│ │ │ │ │ ├── RCImageMessageCell.h
│ │ │ │ │ ├── RCImageMessageProgressView.h
│ │ │ │ │ ├── RCImagePreviewController.h
│ │ │ │ │ ├── RCKitUtility.h
│ │ │ │ │ ├── RCLocationMessageCell.h
│ │ │ │ │ ├── RCLocationPickerViewController.h
│ │ │ │ │ ├── RCLocationViewController.h
│ │ │ │ │ ├── RCMessageBaseCell.h
│ │ │ │ │ ├── RCMessageBubbleTipView.h
│ │ │ │ │ ├── RCMessageCell.h
│ │ │ │ │ ├── RCMessageCellDelegate.h
│ │ │ │ │ ├── RCMessageCellNotificationModel.h
│ │ │ │ │ ├── RCMessageModel.h
│ │ │ │ │ ├── RCPluginBoardView.h
│ │ │ │ │ ├── RCPublicServiceChatViewController.h
│ │ │ │ │ ├── RCPublicServiceListViewController.h
│ │ │ │ │ ├── RCPublicServiceProfileViewController.h
│ │ │ │ │ ├── RCPublicServiceSearchViewController.h
│ │ │ │ │ ├── RCRichContentMessageCell.h
│ │ │ │ │ ├── RCSettingViewController.h
│ │ │ │ │ ├── RCTextMessageCell.h
│ │ │ │ │ ├── RCTextView.h
│ │ │ │ │ ├── RCThemeDefine.h
│ │ │ │ │ ├── RCTipLabel.h
│ │ │ │ │ ├── RCTipMessageCell.h
│ │ │ │ │ ├── RCUnknownMessageCell.h
│ │ │ │ │ ├── RCVoiceMessageCell.h
│ │ │ │ │ └── RongIMKit.h
│ │ │ │ ├── Info.plist
│ │ │ │ └── RongIMKit
│ │ │ ├── RongIMLib.framework/
│ │ │ │ ├── Headers/
│ │ │ │ │ ├── RCAMRDataConverter.h
│ │ │ │ │ ├── RCChatRoomInfo.h
│ │ │ │ │ ├── RCChatRoomMemberInfo.h
│ │ │ │ │ ├── RCCommandMessage.h
│ │ │ │ │ ├── RCCommandNotificationMessage.h
│ │ │ │ │ ├── RCContactNotificationMessage.h
│ │ │ │ │ ├── RCConversation.h
│ │ │ │ │ ├── RCDiscussion.h
│ │ │ │ │ ├── RCDiscussionNotificationMessage.h
│ │ │ │ │ ├── RCGroup.h
│ │ │ │ │ ├── RCGroupNotificationMessage.h
│ │ │ │ │ ├── RCHandShakeMessage.h
│ │ │ │ │ ├── RCIMClient.h
│ │ │ │ │ ├── RCImageMessage.h
│ │ │ │ │ ├── RCInformationNotificationMessage.h
│ │ │ │ │ ├── RCLocationMessage.h
│ │ │ │ │ ├── RCMessage.h
│ │ │ │ │ ├── RCMessageContent.h
│ │ │ │ │ ├── RCMessageContentView.h
│ │ │ │ │ ├── RCProfileNotificationMessage.h
│ │ │ │ │ ├── RCPublicServiceCommandMessage.h
│ │ │ │ │ ├── RCPublicServiceMenu.h
│ │ │ │ │ ├── RCPublicServiceMenuItem.h
│ │ │ │ │ ├── RCPublicServiceMultiRichContentMessage.h
│ │ │ │ │ ├── RCPublicServiceProfile.h
│ │ │ │ │ ├── RCPublicServiceRichContentMessage.h
│ │ │ │ │ ├── RCRealTimeLocationEndMessage.h
│ │ │ │ │ ├── RCRealTimeLocationManager.h
│ │ │ │ │ ├── RCRealTimeLocationStartMessage.h
│ │ │ │ │ ├── RCRichContentItem.h
│ │ │ │ │ ├── RCRichContentMessage.h
│ │ │ │ │ ├── RCStatusDefine.h
│ │ │ │ │ ├── RCStatusMessage.h
│ │ │ │ │ ├── RCSuspendMessage.h
│ │ │ │ │ ├── RCTextMessage.h
│ │ │ │ │ ├── RCUnknownMessage.h
│ │ │ │ │ ├── RCUploadImageStatusListener.h
│ │ │ │ │ ├── RCUserInfo.h
│ │ │ │ │ ├── RCUserTypingStatus.h
│ │ │ │ │ ├── RCUtilities.h
│ │ │ │ │ ├── RCVoiceMessage.h
│ │ │ │ │ ├── RCWatchKitStatusDelegate.h
│ │ │ │ │ ├── RongIMLib.h
│ │ │ │ │ ├── interf_dec.h
│ │ │ │ │ └── interf_enc.h
│ │ │ │ ├── Info.plist
│ │ │ │ ├── RCConfig.plist
│ │ │ │ └── RongIMLib
│ │ │ ├── en.lproj/
│ │ │ │ └── RongCloudKit.strings
│ │ │ ├── libopencore-amrnb.a
│ │ │ └── zh-Hans.lproj/
│ │ │ └── RongCloudKit.strings
│ │ ├── SJCSimplePDFView/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── SJCSimplePDFView/
│ │ │ ├── SJCSimplePDFView.h
│ │ │ └── SJCSimplePDFView.m
│ │ ├── SSZipArchive/
│ │ │ ├── LICENSE.txt
│ │ │ ├── README.md
│ │ │ └── SSZipArchive/
│ │ │ ├── Common.h
│ │ │ ├── SSZipArchive.h
│ │ │ ├── SSZipArchive.m
│ │ │ ├── ZipArchive.h
│ │ │ ├── aes/
│ │ │ │ ├── aes.h
│ │ │ │ ├── aes_via_ace.h
│ │ │ │ ├── aescrypt.c
│ │ │ │ ├── aeskey.c
│ │ │ │ ├── aesopt.h
│ │ │ │ ├── aestab.c
│ │ │ │ ├── aestab.h
│ │ │ │ ├── brg_endian.h
│ │ │ │ ├── brg_types.h
│ │ │ │ ├── entropy.c
│ │ │ │ ├── entropy.h
│ │ │ │ ├── fileenc.c
│ │ │ │ ├── fileenc.h
│ │ │ │ ├── hmac.c
│ │ │ │ ├── hmac.h
│ │ │ │ ├── prng.c
│ │ │ │ ├── prng.h
│ │ │ │ ├── pwd2key.c
│ │ │ │ ├── pwd2key.h
│ │ │ │ ├── sha1.c
│ │ │ │ └── sha1.h
│ │ │ └── minizip/
│ │ │ ├── crypt.h
│ │ │ ├── ioapi.c
│ │ │ ├── ioapi.h
│ │ │ ├── mztools.c
│ │ │ ├── mztools.h
│ │ │ ├── unzip.c
│ │ │ ├── unzip.h
│ │ │ ├── zip.c
│ │ │ └── zip.h
│ │ ├── Swifter/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Sources/
│ │ │ ├── DemoServer.swift
│ │ │ ├── File.swift
│ │ │ ├── HttpHandlers+Files.swift
│ │ │ ├── HttpHandlers+WebSockets.swift
│ │ │ ├── HttpHandlers.swift
│ │ │ ├── HttpParser.swift
│ │ │ ├── HttpRequest.swift
│ │ │ ├── HttpResponse.swift
│ │ │ ├── HttpRouter.swift
│ │ │ ├── HttpServer.swift
│ │ │ ├── HttpServerIO.swift
│ │ │ ├── Socket.swift
│ │ │ ├── String+BASE64.swift
│ │ │ ├── String+Misc.swift
│ │ │ └── String+SHA1.swift
│ │ ├── SwiftyJSON/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Source/
│ │ │ └── SwiftyJSON.swift
│ │ ├── Target Support Files/
│ │ │ ├── AASquaresLoading/
│ │ │ │ ├── AASquaresLoading-dummy.m
│ │ │ │ ├── AASquaresLoading-prefix.pch
│ │ │ │ ├── AASquaresLoading-umbrella.h
│ │ │ │ ├── AASquaresLoading.modulemap
│ │ │ │ ├── AASquaresLoading.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── Alamofire/
│ │ │ │ ├── Alamofire-dummy.m
│ │ │ │ ├── Alamofire-prefix.pch
│ │ │ │ ├── Alamofire-umbrella.h
│ │ │ │ ├── Alamofire.modulemap
│ │ │ │ ├── Alamofire.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── AlamofireRSSParser/
│ │ │ │ ├── AlamofireRSSParser-dummy.m
│ │ │ │ ├── AlamofireRSSParser-prefix.pch
│ │ │ │ ├── AlamofireRSSParser-umbrella.h
│ │ │ │ ├── AlamofireRSSParser.modulemap
│ │ │ │ ├── AlamofireRSSParser.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── CYRTextView/
│ │ │ │ ├── CYRTextView-dummy.m
│ │ │ │ ├── CYRTextView-prefix.pch
│ │ │ │ ├── CYRTextView-umbrella.h
│ │ │ │ ├── CYRTextView.modulemap
│ │ │ │ ├── CYRTextView.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── Charts/
│ │ │ │ ├── Charts-dummy.m
│ │ │ │ ├── Charts-prefix.pch
│ │ │ │ ├── Charts-umbrella.h
│ │ │ │ ├── Charts.modulemap
│ │ │ │ ├── Charts.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── DGElasticPullToRefresh/
│ │ │ │ ├── DGElasticPullToRefresh-dummy.m
│ │ │ │ ├── DGElasticPullToRefresh-prefix.pch
│ │ │ │ ├── DGElasticPullToRefresh-umbrella.h
│ │ │ │ ├── DGElasticPullToRefresh.modulemap
│ │ │ │ ├── DGElasticPullToRefresh.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── EZAudio/
│ │ │ │ ├── EZAudio-dummy.m
│ │ │ │ ├── EZAudio-prefix.pch
│ │ │ │ ├── EZAudio-umbrella.h
│ │ │ │ ├── EZAudio.modulemap
│ │ │ │ ├── EZAudio.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── Gifu/
│ │ │ │ ├── Gifu-dummy.m
│ │ │ │ ├── Gifu-prefix.pch
│ │ │ │ ├── Gifu-umbrella.h
│ │ │ │ ├── Gifu.modulemap
│ │ │ │ ├── Gifu.xcconfig
│ │ │ │ └── Info.plist
│ │ │ ├── NMSSH/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── NMSSH-dummy.m
│ │ │ │ ├── NMSSH-prefix.pch
│ │ │ │ ├── NMSSH-umbrella.h
│ │ │ │ ├── NMSSH.modulemap
│ │ │ │ └── NMSSH.xcconfig
│ │ │ ├── Pods/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── Pods-acknowledgements.markdown
│ │ │ │ ├── Pods-acknowledgements.plist
│ │ │ │ ├── Pods-dummy.m
│ │ │ │ ├── Pods-frameworks.sh
│ │ │ │ ├── Pods-resources.sh
│ │ │ │ ├── Pods-umbrella.h
│ │ │ │ ├── Pods.debug.xcconfig
│ │ │ │ ├── Pods.modulemap
│ │ │ │ └── Pods.release.xcconfig
│ │ │ ├── SJCSimplePDFView/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── SJCSimplePDFView-dummy.m
│ │ │ │ ├── SJCSimplePDFView-prefix.pch
│ │ │ │ ├── SJCSimplePDFView-umbrella.h
│ │ │ │ ├── SJCSimplePDFView.modulemap
│ │ │ │ └── SJCSimplePDFView.xcconfig
│ │ │ ├── SSZipArchive/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── SSZipArchive-dummy.m
│ │ │ │ ├── SSZipArchive-prefix.pch
│ │ │ │ ├── SSZipArchive-umbrella.h
│ │ │ │ ├── SSZipArchive.modulemap
│ │ │ │ └── SSZipArchive.xcconfig
│ │ │ ├── Swifter/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── Swifter-dummy.m
│ │ │ │ ├── Swifter-prefix.pch
│ │ │ │ ├── Swifter-umbrella.h
│ │ │ │ ├── Swifter.modulemap
│ │ │ │ └── Swifter.xcconfig
│ │ │ ├── SwiftyJSON/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── SwiftyJSON-dummy.m
│ │ │ │ ├── SwiftyJSON-prefix.pch
│ │ │ │ ├── SwiftyJSON-umbrella.h
│ │ │ │ ├── SwiftyJSON.modulemap
│ │ │ │ └── SwiftyJSON.xcconfig
│ │ │ ├── ZLMusicFlowWaveView/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── ZLMusicFlowWaveView-dummy.m
│ │ │ │ ├── ZLMusicFlowWaveView-prefix.pch
│ │ │ │ ├── ZLMusicFlowWaveView-umbrella.h
│ │ │ │ ├── ZLMusicFlowWaveView.modulemap
│ │ │ │ └── ZLMusicFlowWaveView.xcconfig
│ │ │ └── ZLSinusWaveView/
│ │ │ ├── Info.plist
│ │ │ ├── ZLSinusWaveView-dummy.m
│ │ │ ├── ZLSinusWaveView-prefix.pch
│ │ │ ├── ZLSinusWaveView-umbrella.h
│ │ │ ├── ZLSinusWaveView.modulemap
│ │ │ └── ZLSinusWaveView.xcconfig
│ │ ├── ZLMusicFlowWaveView/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── ZLMusicFlowWaveView/
│ │ │ ├── ZLMusicFlowDecorativeView.h
│ │ │ ├── ZLMusicFlowDecorativeView.m
│ │ │ ├── ZLMusicFlowWaveView.h
│ │ │ └── ZLMusicFlowWaveView.m
│ │ └── ZLSinusWaveView/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── ZLSinusWaveView/
│ │ ├── ZLSinusWaveView.h
│ │ └── ZLSinusWaveView.m
│ ├── Sublime/
│ │ ├── AppDelegate.swift
│ │ ├── AppInfoViewController.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Repositories.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_douban_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_facebook_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_instagram.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_line_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_more_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_pinterest_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_qq_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_qzone_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_sina_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_twitter_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_wechat_session_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Share_wechat_timeline_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Stars.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── add_friend_icon_addfriend.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── add_friend_icon_group.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── add_friend_icon_offical.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── app_small_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── code_share_btn.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── comment.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── config_cycript.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── config_full_screen_code_reading.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── config_show_hidden_file.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate1.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate3.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate4.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate5.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── donate_weixin.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── explore_codezZ.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_3fr.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_7z.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_aac.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_ai.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_asc.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_asp.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_avi.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_bas.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_cls.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_code_share.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_cpp.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_cr2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_cs.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_css.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_csv.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_dll.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_dmg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_dng.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_eps.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_exe.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_fff.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_flv.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_gif.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_gis.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_gpx.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_html.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_j2k.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_jp2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_jpg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_js.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_jsp.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_kml.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_kmz.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_mov.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_mp3.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_mp4.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_mpg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_nef.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_nmea.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_ogg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_osm.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_otf.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_pdf.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_png.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_ppt.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_pptx.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_ps.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_psd.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_py.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_rar.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_raw.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_svg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_tar.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_tif.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_ttf.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_txt.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_unknown.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_vb.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_vbs.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_wav.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_wma.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_woff.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_word.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_wsh.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_xaml.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_xls.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_xml.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── file_zip.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── folder.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── function_rss.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── function_scan.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── gist_bg.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_avatar.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_folder.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_fork.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_login.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_star.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── github_watcher.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── open_safari.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── pdf_continuous.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── pdf_horizontal.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── pdf_vertical.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── repo_download.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── right_arrow.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_cache.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_configure.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_donate.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_feedback.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_github.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_license.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_reading.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_server.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_ssh.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_storage.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_sublime.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── setting_themes.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_done.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_keyboard.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_password.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_port.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_server.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── ssh_user.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── tab_icon_explore.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── tab_icon_files.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── tab_icon_setting.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── user_author.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── user_info.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── user_robot.imageset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── BoardModel.swift
│ │ ├── BoardView.swift
│ │ ├── Code.swift
│ │ ├── CodeEngine.swift
│ │ ├── CodeViewController.swift
│ │ ├── ConfigTableViewController.swift
│ │ ├── Configure.swift
│ │ ├── Constant.swift
│ │ ├── ContactInfoViewController.swift
│ │ ├── ContactTableViewController.swift
│ │ ├── CustomServer.swift
│ │ ├── DonateViewController.swift
│ │ ├── ExploreTableViewController.swift
│ │ ├── FolderTableViewController.swift
│ │ ├── Gist.swift
│ │ ├── GistTable.swift
│ │ ├── GithubAccountTableViewController.swift
│ │ ├── GithubTableViewController.swift
│ │ ├── Global.swift
│ │ ├── GomokuAI.swift
│ │ ├── GomokuViewController.swift
│ │ ├── HTTPServerTableViewController.swift
│ │ ├── ImageFileViewController.swift
│ │ ├── ImagePageViewController.swift
│ │ ├── Info.plist
│ │ ├── LICENSE/
│ │ │ ├── AASquaresLoading.LICENSE
│ │ │ ├── Alamofire.LICENSE
│ │ │ ├── AlamofireRSSParser.LICENSE
│ │ │ ├── CYRTextView.LICENSE
│ │ │ ├── Charts.LICENSE
│ │ │ ├── DGElasticPullToRefresh.LICENSE
│ │ │ ├── EZAudio.LICENSE
│ │ │ ├── Gifu.LICENSE
│ │ │ ├── MobileVLCKit.LICENSE
│ │ │ ├── NMSSH.LICENSE
│ │ │ ├── RongCloudIMKit.LICENSE
│ │ │ ├── SJCSimplePDFView.LICENSE
│ │ │ ├── SSZipArchive.LICENSE
│ │ │ ├── Swifter.LICENSE
│ │ │ ├── SwiftyJSON.LICENSE
│ │ │ ├── ZLMusicFlowWaveView.LICENSE
│ │ │ └── ZLSinusWaveView.LICENSE
│ │ ├── LicenseTableViewController.swift
│ │ ├── LogoView.xib
│ │ ├── MainTableViewController.swift
│ │ ├── MessageListViewController.swift
│ │ ├── MusicViewController.swift
│ │ ├── NewFileViewController.swift
│ │ ├── PDFViewController.swift
│ │ ├── RCChatViewController.swift
│ │ ├── RSSItemListTableViewController.swift
│ │ ├── RSSListTableViewController.swift
│ │ ├── ReadingViewController.swift
│ │ ├── Repo.swift
│ │ ├── ReposTableViewController.swift
│ │ ├── SDK/
│ │ │ └── Weixin/
│ │ │ ├── WXApi.h
│ │ │ ├── WXApiObject.h
│ │ │ ├── WechatAuthSDK.h
│ │ │ └── libWeChatSDK.a
│ │ ├── SSHAddNewServerViewController.swift
│ │ ├── SSHServerListTableViewController.swift
│ │ ├── SSHTerminalViewController.swift
│ │ ├── SettingTableViewController.swift
│ │ ├── StorageViewController.swift
│ │ ├── Sublime-Bridging-Header.h
│ │ ├── SublimeSafari.swift
│ │ ├── SublimeServer.swift
│ │ ├── Utils/
│ │ │ ├── ActionSheet.swift
│ │ │ ├── Device.swift
│ │ │ ├── Extension/
│ │ │ │ ├── Array.swift
│ │ │ │ ├── Date.swift
│ │ │ │ ├── Number.swift
│ │ │ │ ├── Operation.swift
│ │ │ │ ├── Other.swift
│ │ │ │ ├── String.swift
│ │ │ │ ├── UIApplication.swift
│ │ │ │ ├── UIColor.swift
│ │ │ │ ├── UIImage.swift
│ │ │ │ ├── UIImageView.swift
│ │ │ │ ├── UITableView.swift
│ │ │ │ ├── UITextView.swift
│ │ │ │ ├── UIView.swift
│ │ │ │ └── UIViewController.swift
│ │ │ ├── File.swift
│ │ │ ├── Function.swift
│ │ │ ├── Github.swift
│ │ │ ├── Log.swift
│ │ │ ├── Network.swift
│ │ │ ├── NumberedTextView.swift
│ │ │ ├── Obj-C/
│ │ │ │ ├── MusicWave.h
│ │ │ │ ├── MusicWave.m
│ │ │ │ ├── ObjC.h
│ │ │ │ └── ObjC.m
│ │ │ ├── Plist.swift
│ │ │ ├── PopupMenu.swift
│ │ │ ├── QRCode.swift
│ │ │ ├── QRCodeReader.swift
│ │ │ ├── RCIM.swift
│ │ │ ├── RearrangeTable.swift
│ │ │ ├── ShareToWeixin.swift
│ │ │ ├── SublimeTable.swift
│ │ │ ├── UnitTest.swift
│ │ │ └── VideoPlayerTimeView.swift
│ │ ├── VideoViewController.swift
│ │ ├── Web/
│ │ │ ├── 404.html
│ │ │ ├── README.txt
│ │ │ ├── index.html
│ │ │ ├── js/
│ │ │ │ └── index.js
│ │ │ └── license.txt
│ │ ├── WebServerLog.swift
│ │ ├── en.lproj/
│ │ │ └── Localizable.strings
│ │ ├── zh-Hans.lproj/
│ │ │ └── Localizable.strings
│ │ └── 山外小楼夜听雨.m4a
│ ├── Sublime.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace/
│ │ └── contents.xcworkspacedata
│ └── Sublime.xcworkspace/
│ └── contents.xcworkspacedata
└── Sublime_icons.sketch
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
fastlane/report.xml
fastlane/screenshots
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: README.md
================================================
# SublimeCode [](http://github.com/Urinx/SublimeCode) [](http://github.com/Urinx/SublimeCode/fork) [](https://github.com/Urinx/SublimeCode/blob/master/LICENSE)  [](https://github.com/Urinx/SublimeCode/releases)
一个代码阅读应用 - iOS
### 屏幕截图

## 功能说明
### 代码阅读
支持多种编程语言的语法高亮,全屏阅读模式,以及支持生成图片的形式分享代码到朋友圈等。

### 多种文件支持
支持查看多种格式的文件类型,包括图片,视频,音频,PDF等。

### Github支持
现在你可以在本应用里浏览Github里自己的项目和Star的项目了,也能够下载到本地离线阅读代码哟!是不是很方便呢。

### 本地HTTP服务器
还可以是一个本地HTTP服务器哦,支持Log纪录,在手机上方便的与朋友分享自己的网页。

### Cycript支持
Cycript是混合了objective-c与javascript语法的一个工具,让开发者在命令行下和应用交互,在运行时查看和修改应用。而我们的应用也集成了Cycript,是不是很酷炫呢!小伙伴们赶快来体验吧。

### 乱七八糟的功能
是的,你还可以像朋友圈一样的浏览Gist,还能SSH到自己的服务器,以及RSS订阅,与Github好友聊天,二维码扫描等等。没有做不到,只有想不到。

### 以及更多
其实里面还有超级多的功能等待着你去探索和发现,在关于页面里摇一摇还有彩蛋哟!如果你有好的想法和建议也可以告诉我们,说不定下次就加进去了呢。
### 如何安装
鉴于该应用没有上架App Store,同时也没有用企业证书签名,所以目前你只能通过以下两种方式安装,注意的是两者均需要在Mac环境下,以及安装了Xcode。推荐采取方案一的方式。
> 方案一:
>
> 1. 下载已经build好的[ipa文件](https://github.com/Urinx/SublimeCode/releases)。
> 2. 使用Xcode新建一个项目,bundle id可以为`com.xxx.Sublime`,生成相应的证书。
> 3. 使用[iOS App Signer](https://github.com/DanTheMan827/ios-app-signer)重签名本应用,注意选择上一步生成的对应的证书。
> 4. 然后就可以使用iTunes,Xcode等各种软件将重签名后的ipa文件安装到设备上。
> 方案二:
>
> 1. 下载本项目[源码](https://github.com/Urinx/SublimeCode/archive/v1.0.zip)。
> 2. 注意修改bundle id,再编译到设备上。
================================================
FILE: Sublime/Cycript.framework/Headers/Cycript.h
================================================
/* Cycript - Optimizing JavaScript Compiler/Runtime
* Copyright (C) 2009-2013 Jay Freeman (saurik)
*/
/* GNU General Public License, Version 3 {{{ */
/*
* Cycript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Cycript is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cycript. If not, see .
**/
/* }}} */
#ifndef CYCRIPT_CYCRIPT_H
#define CYCRIPT_CYCRIPT_H
#ifdef __cplusplus
extern "C" {
#endif
void CYListenServer(short port);
#ifdef __cplusplus
}
#endif
#endif/*CYCRIPT_CYCRIPT_H*/
================================================
FILE: Sublime/Podfile
================================================
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'Alamofire', '~> 3.0'
pod 'CYRTextView'
pod 'ZLMusicFlowWaveView'
pod 'SJCSimplePDFView'
pod 'Swifter'
pod 'SwiftyJSON'
pod 'AASquaresLoading'
pod 'DGElasticPullToRefresh'
pod 'SSZipArchive'
pod 'Gifu'
pod 'RongCloudIMKit'
pod 'NMSSH'
pod 'AlamofireRSSParser'
pod 'Charts'
================================================
FILE: Sublime/Pods/AASquaresLoading/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 Anas AIT ALI
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Sublime/Pods/AASquaresLoading/README.md
================================================
# AASquaresLoading
Simple loading animation using squares

## Example
```swift
let loadingSquare = AASquaresLoading(target: self.view, size: 40)
// Customize background
loadingSquare.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.4)
// Customize color
loadingSquare.color = UIColor.whiteColor()
// Start loading
loadingSquare.start()
....
// Stop loading
loadingSquare.stop()
```
More examples in the demo project.
## Installation
### CocoaPods
1. Add to your podfile : `pod 'AASquaresLoading'`
2. In your terminal : `pod install`
### Manual
1. Add `AASquaresLoading.swift` to your project
2. That's all you can use it!
## Usage
### Basic
1. As a UIView method
```swift
self.view.squareLoading.start(0.0)
...
self.view.squareLoading.stop(0.0)
```
2. As a standalone class
```swift
let loadingSquare = AASquaresLoading(target: self.view, size: 40)
loadingSquare.start()
....
loadingSquare.stop()
```
3. As a custom class interface builder by setting AASquareLoading as a custom class for a UIView
### Customization
##### Change background color
```swift
self.view.squareLoading.backgroundColor = UIColor.redColor()
```
##### Change squares color
```swift
self.view.squareLoading.color = UIColor.whiteColor()
```
##### Change the square size
```swift
self.view.squareLoading.setSquareSize(120)
```
## License
The MIT License (MIT)
Copyright (c) 2015 Anas AIT-ALI
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Sublime/Pods/AASquaresLoading/Source/AASquaresLoading.swift
================================================
//
// AASquaresLoading.swift
// Etix Mobile
//
// Created by Anas Ait Ali on 18/02/15.
// Copyright (c) 2015 Etix. All rights reserved.
//
import UIKit
//MARK: AASquareLoadingInterface
/**
Interface for the AASquareLoading class
*/
public protocol AASquareLoadingInterface: class {
var color : UIColor { get set }
var backgroundColor : UIColor? { get set }
func start(delay : NSTimeInterval)
func stop(delay : NSTimeInterval)
func setSquareSize(size: Float)
}
private var AASLAssociationKey: UInt8 = 0
//MARK: UIView extension
public extension UIView {
/**
Variable to allow access to the class AASquareLoading
*/
public var squareLoading: AASquareLoadingInterface {
get {
if let value = objc_getAssociatedObject(self, &AASLAssociationKey) as? AASquareLoadingInterface {
return value
} else {
let squareLoading = AASquaresLoading(target: self)
objc_setAssociatedObject(self, &AASLAssociationKey, squareLoading,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
return squareLoading
}
}
set {
objc_setAssociatedObject(self, &AASLAssociationKey, newValue,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}
//MARK: AASquareLoading class
/**
Main class AASquareLoading
*/
public class AASquaresLoading : UIView, AASquareLoadingInterface {
public var view : UIView = UIView()
private(set) public var size : Float = 0
public var color : UIColor = UIColor(red: 0, green: 0.48, blue: 1, alpha: 1) {
didSet {
for layer in squares {
layer.backgroundColor = color.CGColor
}
}
}
public var parentView : UIView?
private var squareSize: Float?
private var gapSize: Float?
private var moveTime: Float?
private var squareStartX: Float?
private var squareStartY: Float?
private var squareStartOpacity: Float?
private var squareEndX: Float?
private var squareEndY: Float?
private var squareEndOpacity: Float?
private var squareOffsetX: [Float] = [Float](count: 9, repeatedValue: 0)
private var squareOffsetY: [Float] = [Float](count: 9, repeatedValue: 0)
private var squareOpacity: [Float] = [Float](count: 9, repeatedValue: 0)
private var squares : [CALayer] = [CALayer]()
private var frameHeightOffset: CGFloat = 0
public init(target: UIView) {
super.init(frame: target.frame)
parentView = target
setup(self.size)
}
public init(target: UIView, size: Float) {
super.init(frame: target.frame)
parentView = target
setup(size)
}
public init(target: UIView, size: Float, hasNavigation: Bool, hasTabbar: Bool) {
super.init(frame: target.frame)
if hasNavigation {
self.frameHeightOffset += 64
}
if hasTabbar {
self.frameHeightOffset += 49
}
parentView = target
setup(size)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup(0)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup(0)
}
public override func layoutSubviews() {
updateFrame()
super.layoutSubviews()
}
private func setup(size: Float) {
self.size = size
updateFrame()
self.initialize()
}
private func updateFrame() {
if parentView != nil {
self.frame = CGRectMake(0, 0, CGRectGetWidth(parentView!.frame), CGRectGetHeight(parentView!.frame) - self.frameHeightOffset)
}
if size == 0 {
let width = frame.size.width
let height = frame.size.height
size = width > height ? Float(height/8) : Float(width/8)
}
self.view.frame = CGRectMake(frame.width / 2 - CGFloat(size) / 2,
frame.height / 2 - CGFloat(size) / 2, CGFloat(size), CGFloat(size))
}
/**
Function to start the loading animation
- Parameter delay : The delay before the loading start
*/
public func start(delay : NSTimeInterval = 0.0) {
if (parentView != nil) {
self.layer.opacity = 0
self.parentView!.addSubview(self)
UIView.animateWithDuration(0.6, delay: delay, options: UIViewAnimationOptions.CurveEaseInOut,
animations: { () -> Void in
self.layer.opacity = 1
}, completion: nil)
}
}
/**
Function to start the loading animation
- Parameter delay : The delay before the loading start
*/
public func stop(delay : NSTimeInterval = 0.0) {
if (parentView != nil) {
self.layer.opacity = 1
UIView.animateWithDuration(0.6, delay: delay, options: UIViewAnimationOptions.CurveEaseInOut,
animations: { () -> Void in
self.layer.opacity = 0
}, completion: { (success: Bool) -> Void in
self.removeFromSuperview()
})
}
}
public func setSquareSize(size: Float) {
self.view.layer.sublayers = nil
setup(size)
}
private func initialize() {
let gap : Float = 0.04
gapSize = size * gap
squareSize = size * (1.0 - 2 * gap) / 3
moveTime = 0.15
squares = [CALayer]()
self.addSubview(view)
if (self.backgroundColor == nil) {
self.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.9)
}
for var i : Int = 0; i < 3; i++ {
for var j : Int = 0; j < 3; j++ {
var offsetX, offsetY : Float
let idx : Int = 3 * i + j
if i == 1 {
offsetX = squareSize! * (2 - Float(j)) + gapSize! * (2 - Float(j))
offsetY = squareSize! * Float(i) + gapSize! * Float(i)
} else {
offsetX = squareSize! * Float(j) + gapSize! * Float(j)
offsetY = squareSize! * Float(i) + gapSize! * Float(i)
}
squareOffsetX[idx] = offsetX
squareOffsetY[idx] = offsetY
squareOpacity[idx] = 0.1 * (Float(idx) + 1)
}
}
squareStartX = squareOffsetX[0]
squareStartY = squareOffsetY[0] - 2 * squareSize! - 2 * gapSize!
squareStartOpacity = 0.0
squareEndX = squareOffsetX[8]
squareEndY = squareOffsetY[8] + 2 * squareSize! + 2 * gapSize!
squareEndOpacity = 0.0
for var i = -1; i < 9; i++ {
self.addSquareAnimation(i)
}
}
private func addSquareAnimation(position: Int) {
let square : CALayer = CALayer()
if position == -1 {
square.frame = CGRectMake(CGFloat(squareStartX!), CGFloat(squareStartY!),
CGFloat(squareSize!), CGFloat(squareSize!))
square.opacity = squareStartOpacity!
} else {
square.frame = CGRectMake(CGFloat(squareOffsetX[position]),
CGFloat(squareOffsetY[position]), CGFloat(squareSize!), CGFloat(squareSize!))
square.opacity = squareOpacity[position]
}
square.backgroundColor = self.color.CGColor
squares.append(square)
self.view.layer.addSublayer(square)
var keyTimes = [Float]()
var alphas = [Float]()
keyTimes.append(0.0)
if position == -1 {
alphas.append(0.0)
} else {
alphas.append(squareOpacity[position])
}
if position == 0 {
square.opacity = 0.0
}
let sp : CGPoint = square.position
let path : CGMutablePathRef = CGPathCreateMutable()
CGPathMoveToPoint(path, nil, sp.x, sp.y)
var x, y, a : Float
if position == -1 {
x = squareOffsetX[0] - squareStartX!
y = squareOffsetY[0] - squareStartY!
a = squareOpacity[0]
} else if position == 8 {
x = squareEndX! - squareOffsetX[position]
y = squareEndY! - squareOffsetY[position]
a = squareEndOpacity!
} else {
x = squareOffsetX[position + 1] - squareOffsetX[position]
y = squareOffsetY[position + 1] - squareOffsetY[position]
a = squareOpacity[position + 1]
}
CGPathAddLineToPoint(path, nil, sp.x + CGFloat(x), sp.y + CGFloat(y))
keyTimes.append(1.0 / 8.0)
alphas.append(a)
CGPathAddLineToPoint(path, nil, sp.x + CGFloat(x), sp.y + CGFloat(y))
keyTimes.append(1.0)
alphas.append(a)
let posAnim : CAKeyframeAnimation = CAKeyframeAnimation(keyPath: "position")
posAnim.removedOnCompletion = false
posAnim.duration = Double(moveTime! * 8)
posAnim.path = path
posAnim.keyTimes = keyTimes
let alphaAnim : CAKeyframeAnimation = CAKeyframeAnimation(keyPath: "opacity")
alphaAnim.removedOnCompletion = false
alphaAnim.duration = Double(moveTime! * 8)
alphaAnim.values = alphas
alphaAnim.keyTimes = keyTimes
let blankAnim : CAKeyframeAnimation = CAKeyframeAnimation(keyPath: "opacity")
blankAnim.removedOnCompletion = false
blankAnim.beginTime = Double(moveTime! * 8)
blankAnim.duration = Double(moveTime!)
blankAnim.values = [0.0, 0.0]
blankAnim.keyTimes = [0.0, 1.0]
var beginTime : Float
if position == -1 {
beginTime = 0
} else {
beginTime = moveTime! * Float(8 - position)
}
let group : CAAnimationGroup = CAAnimationGroup()
group.animations = [posAnim, alphaAnim, blankAnim]
group.beginTime = CACurrentMediaTime() + Double(beginTime)
group.repeatCount = HUGE
group.removedOnCompletion = false
group.delegate = self
group.duration = Double(9 * moveTime!)
square.addAnimation(group, forKey: "square-\(position)")
}
}
================================================
FILE: Sublime/Pods/Alamofire/LICENSE
================================================
Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: Sublime/Pods/Alamofire/README.md
================================================

[](https://travis-ci.org/Alamofire/Alamofire)
[](https://img.shields.io/cocoapods/v/Alamofire.svg)
[](https://github.com/Carthage/Carthage)
[](http://cocoadocs.org/docsets/Alamofire)
[](http://twitter.com/AlamofireSF)
Alamofire is an HTTP networking library written in Swift.
## Features
- [x] Chainable Request / Response methods
- [x] URL / JSON / plist Parameter Encoding
- [x] Upload File / Data / Stream / MultipartFormData
- [x] Download using Request or Resume data
- [x] Authentication with NSURLCredential
- [x] HTTP Response Validation
- [x] TLS Certificate and Public Key Pinning
- [x] Progress Closure & NSProgress
- [x] cURL Debug Output
- [x] Comprehensive Unit Test Coverage
- [x] [Complete Documentation](http://cocoadocs.org/docsets/Alamofire)
## Requirements
- iOS 8.0+ / Mac OS X 10.9+ / tvOS 9.0+ / watchOS 2.0+
- Xcode 7.2+
## Migration Guides
- [Alamofire 3.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md)
- [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md)
## Communication
- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/alamofire). (Tag 'alamofire')
- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/alamofire).
- If you **found a bug**, open an issue.
- If you **have a feature request**, open an issue.
- If you **want to contribute**, submit a pull request.
## Installation
> **Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9).**
>
> Alamofire is no longer supported on iOS 7 due to the lack of support for frameworks. Without frameworks, running Travis-CI against iOS 7 would require a second duplicated test target. The separate test suite would need to import all the Swift files and the tests would need to be duplicated and re-written. This split would be too difficult to maintain to ensure the highest possible quality of the Alamofire ecosystem.
### CocoaPods
[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
```bash
$ gem install cocoapods
```
> CocoaPods 0.39.0+ is required to build Alamofire 3.0.0+.
To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`:
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'Alamofire', '~> 3.0'
```
Then, run the following command:
```bash
$ pod install
```
### Carthage
[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
```bash
$ brew update
$ brew install carthage
```
To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`:
```ogdl
github "Alamofire/Alamofire" ~> 3.0
```
Run `carthage update` to build the framework and drag the built `Alamofire.framework` into your Xcode project.
### Manually
If you prefer not to use either of the aforementioned dependency managers, you can integrate Alamofire into your project manually.
#### Embedded Framework
- Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository:
```bash
$ git init
```
- Add Alamofire as a git [submodule](http://git-scm.com/docs/git-submodule) by running the following command:
```bash
$ git submodule add https://github.com/Alamofire/Alamofire.git
```
- Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project.
> It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter.
- Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target.
- Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar.
- In the tab bar at the top of that window, open the "General" panel.
- Click on the `+` button under the "Embedded Binaries" section.
- You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder.
> It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`.
- Select the top `Alamofire.framework` for iOS and the bottom one for OS X.
> You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as either `Alamofire iOS` or `Alamofire OSX`.
- And that's it!
> The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.
---
## Usage
### Making a Request
```swift
import Alamofire
Alamofire.request(.GET, "https://httpbin.org/get")
```
### Response Handling
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
```
> Networking in Alamofire is done _asynchronously_. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are [very good reasons](https://developer.apple.com/library/ios/qa/qa1693/_index.html) for doing it this way.
> Rather than blocking execution to wait for a response from the server, a [callback](http://en.wikipedia.org/wiki/Callback_%28computer_programming%29) is specified to handle the response once it's received. The result of a request is only available inside the scope of a response handler. Any execution contingent on the response or data received from the server must be done within a handler.
### Response Serialization
**Built-in Response Methods**
- `response()`
- `responseData()`
- `responseString(encoding: NSStringEncoding)`
- `responseJSON(options: NSJSONReadingOptions)`
- `responsePropertyList(options: NSPropertyListReadOptions)`
#### Response Handler
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.response { request, response, data, error in
print(request)
print(response)
print(data)
print(error)
}
```
> The `response` serializer does NOT evaluate any of the response data. It merely forwards on all the information directly from the URL session delegate. We strongly encourage you to leverage the other response serializers taking advantage of `Response` and `Result` types.
#### Response Data Handler
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseData { response in
print(response.request)
print(response.response)
print(response.result)
}
```
#### Response String Handler
```swift
Alamofire.request(.GET, "https://httpbin.org/get")
.responseString { response in
print("Success: \(response.result.isSuccess)")
print("Response String: \(response.result.value)")
}
```
#### Response JSON Handler
```swift
Alamofire.request(.GET, "https://httpbin.org/get")
.responseJSON { response in
debugPrint(response)
}
```
#### Chained Response Handlers
Response handlers can even be chained:
```swift
Alamofire.request(.GET, "https://httpbin.org/get")
.responseString { response in
print("Response String: \(response.result.value)")
}
.responseJSON { response in
print("Response JSON: \(response.result.value)")
}
```
### HTTP Methods
`Alamofire.Method` lists the HTTP methods defined in [RFC 7231 §4.3](http://tools.ietf.org/html/rfc7231#section-4.3):
```swift
public enum Method: String {
case OPTIONS, GET, HEAD, POST, PUT, PATCH, DELETE, TRACE, CONNECT
}
```
These values can be passed as the first argument of the `Alamofire.request` method:
```swift
Alamofire.request(.POST, "https://httpbin.org/post")
Alamofire.request(.PUT, "https://httpbin.org/put")
Alamofire.request(.DELETE, "https://httpbin.org/delete")
```
### Parameters
#### GET Request With URL-Encoded Parameters
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
// https://httpbin.org/get?foo=bar
```
#### POST Request With URL-Encoded Parameters
```swift
let parameters = [
"foo": "bar",
"baz": ["a", 1],
"qux": [
"x": 1,
"y": 2,
"z": 3
]
]
Alamofire.request(.POST, "https://httpbin.org/post", parameters: parameters)
// HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
```
### Parameter Encoding
Parameters can also be encoded as JSON, Property List, or any custom format, using the `ParameterEncoding` enum:
```swift
enum ParameterEncoding {
case URL
case URLEncodedInURL
case JSON
case PropertyList(format: NSPropertyListFormat, options: NSPropertyListWriteOptions)
case Custom((URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?))
func encode(request: NSURLRequest, parameters: [String: AnyObject]?) -> (NSURLRequest, NSError?)
{ ... }
}
```
- `URL`: A query string to be set as or appended to any existing URL query for `GET`, `HEAD`, and `DELETE` requests, or set as the body for requests with any other HTTP method. The `Content-Type` HTTP header field of an encoded request with HTTP body is set to `application/x-www-form-urlencoded`. _Since there is no published specification for how to encode collection types, Alamofire follows the convention of appending `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for nested dictionary values (`foo[bar]=baz`)._
- `URLEncodedInURL`: Creates query string to be set as or appended to any existing URL query. Uses the same implementation as the `.URL` case, but always applies the encoded result to the URL.
- `JSON`: Uses `NSJSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`.
- `PropertyList`: Uses `NSPropertyListSerialization` to create a plist representation of the parameters object, according to the associated format and write options values, which is set as the body of the request. The `Content-Type` HTTP header field of an encoded request is set to `application/x-plist`.
- `Custom`: Uses the associated closure value to construct a new request given an existing request and parameters.
#### Manual Parameter Encoding of an NSURLRequest
```swift
let URL = NSURL(string: "https://httpbin.org/get")!
var request = NSMutableURLRequest(URL: URL)
let parameters = ["foo": "bar"]
let encoding = Alamofire.ParameterEncoding.URL
(request, _) = encoding.encode(request, parameters: parameters)
```
#### POST Request with JSON-encoded Parameters
```swift
let parameters = [
"foo": [1,2,3],
"bar": [
"baz": "qux"
]
]
Alamofire.request(.POST, "https://httpbin.org/post", parameters: parameters, encoding: .JSON)
// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
```
### HTTP Headers
Adding a custom HTTP header to a `Request` is supported directly in the global `request` method. This makes it easy to attach HTTP headers to a `Request` that can be constantly changing.
> For HTTP headers that do not change, it is recommended to set them on the `NSURLSessionConfiguration` so they are automatically applied to any `NSURLSessionTask` created by the underlying `NSURLSession`.
```swift
let headers = [
"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Content-Type": "application/x-www-form-urlencoded"
]
Alamofire.request(.GET, "https://httpbin.org/get", headers: headers)
.responseJSON { response in
debugPrint(response)
}
```
### Caching
Caching is handled on the system framework level by [`NSURLCache`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/occ/cl/NSURLCache).
### Uploading
**Supported Upload Types**
- File
- Data
- Stream
- MultipartFormData
#### Uploading a File
```swift
let fileURL = NSBundle.mainBundle().URLForResource("Default", withExtension: "png")
Alamofire.upload(.POST, "https://httpbin.org/post", file: fileURL)
```
#### Uploading with Progress
```swift
Alamofire.upload(.POST, "https://httpbin.org/post", file: fileURL)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
print(totalBytesWritten)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes written on main queue: \(totalBytesWritten)")
}
}
.responseJSON { response in
debugPrint(response)
}
```
#### Uploading MultipartFormData
```swift
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
```
### Downloading
**Supported Download Types**
- Request
- Resume Data
#### Downloading a File
```swift
Alamofire.download(.GET, "https://httpbin.org/stream/100") { temporaryURL, response in
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
return directoryURL.URLByAppendingPathComponent(pathComponent!)
}
```
#### Using the Default Download Destination
```swift
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
Alamofire.download(.GET, "https://httpbin.org/stream/100", destination: destination)
```
#### Downloading a File w/Progress
```swift
Alamofire.download(.GET, "https://httpbin.org/stream/100", destination: destination)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
print(totalBytesRead)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes read on main queue: \(totalBytesRead)")
}
}
.response { _, _, _, error in
if let error = error {
print("Failed with error: \(error)")
} else {
print("Downloaded file successfully")
}
}
```
#### Accessing Resume Data for Failed Downloads
```swift
Alamofire.download(.GET, "https://httpbin.org/stream/100", destination: destination)
.response { _, _, data, _ in
if let
data = data,
resumeDataString = NSString(data: data, encoding: NSUTF8StringEncoding)
{
print("Resume Data: \(resumeDataString)")
} else {
print("Resume Data was empty")
}
}
```
> The `data` parameter is automatically populated with the `resumeData` if available.
```swift
let download = Alamofire.download(.GET, "https://httpbin.org/stream/100", destination: destination)
download.response { _, _, _, _ in
if let
resumeData = download.resumeData,
resumeDataString = NSString(data: resumeData, encoding: NSUTF8StringEncoding)
{
print("Resume Data: \(resumeDataString)")
} else {
print("Resume Data was empty")
}
}
```
### Authentication
Authentication is handled on the system framework level by [`NSURLCredential` and `NSURLAuthenticationChallenge`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLAuthenticationChallenge_Class/Reference/Reference.html).
**Supported Authentication Schemes**
- [HTTP Basic](http://en.wikipedia.org/wiki/Basic_access_authentication)
- [HTTP Digest](http://en.wikipedia.org/wiki/Digest_access_authentication)
- [Kerberos](http://en.wikipedia.org/wiki/Kerberos_%28protocol%29)
- [NTLM](http://en.wikipedia.org/wiki/NT_LAN_Manager)
#### HTTP Basic Authentication
The `authenticate` method on a `Request` will automatically provide an `NSURLCredential` to an `NSURLAuthenticationChallenge` when appropriate:
```swift
let user = "user"
let password = "password"
Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(user: user, password: password)
.responseJSON { response in
debugPrint(response)
}
```
Depending upon your server implementation, an `Authorization` header may also be appropriate:
```swift
let user = "user"
let password = "password"
let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentialData.base64EncodedStringWithOptions([])
let headers = ["Authorization": "Basic \(base64Credentials)"]
Alamofire.request(.GET, "https://httpbin.org/basic-auth/user/password", headers: headers)
.responseJSON { response in
debugPrint(response)
}
```
#### Authentication with NSURLCredential
```swift
let user = "user"
let password = "password"
let credential = NSURLCredential(user: user, password: password, persistence: .ForSession)
Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(usingCredential: credential)
.responseJSON { response in
debugPrint(response)
}
```
### Validation
By default, Alamofire treats any completed request to be successful, regardless of the content of the response. Calling `validate` before a response handler causes an error to be generated if the response had an unacceptable status code or MIME type.
#### Manual Validation
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.response { response in
print(response)
}
```
#### Automatic Validation
Automatically validates status code within `200...299` range, and that the `Content-Type` header of the response matches the `Accept` header of the request, if one is provided.
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
print("Validation Successful")
case .Failure(let error):
print(error)
}
}
```
### Timeline
Alamofire collects timings throughout the lifecycle of a `Request` and creates a `Timeline` object exposed as a property on a `Response`.
```swift
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
print(response.timeline)
}
```
The above reports the following `Timeline` info:
- `Latency`: 0.428 seconds
- `Request Duration`: 0.428 seconds
- `Serialization Duration`: 0.001 seconds
- `Total Duration`: 0.429 seconds
### Printable
```swift
let request = Alamofire.request(.GET, "https://httpbin.org/ip")
print(request)
// GET https://httpbin.org/ip (200)
```
### DebugPrintable
```swift
let request = Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
debugPrint(request)
```
#### Output (cURL)
```bash
$ curl -i \
-H "User-Agent: Alamofire" \
-H "Accept-Encoding: Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
-H "Accept-Language: en;q=1.0,fr;q=0.9,de;q=0.8,zh-Hans;q=0.7,zh-Hant;q=0.6,ja;q=0.5" \
"https://httpbin.org/get?foo=bar"
```
---
## Advanced Usage
> Alamofire is built on `NSURLSession` and the Foundation URL Loading System. To make the most of
this framework, it is recommended that you be familiar with the concepts and capabilities of the underlying networking stack.
**Recommended Reading**
- [URL Loading System Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html)
- [NSURLSession Class Reference](https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/Introduction/Introduction.html#//apple_ref/occ/cl/NSURLSession)
- [NSURLCache Class Reference](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/occ/cl/NSURLCache)
- [NSURLAuthenticationChallenge Class Reference](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLAuthenticationChallenge_Class/Reference/Reference.html)
### Manager
Top-level convenience methods like `Alamofire.request` use a shared instance of `Alamofire.Manager`, which is configured with the default `NSURLSessionConfiguration`.
As such, the following two statements are equivalent:
```swift
Alamofire.request(.GET, "https://httpbin.org/get")
```
```swift
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "https://httpbin.org/get")!))
```
Applications can create managers for background and ephemeral sessions, as well as new managers that customize the default session configuration, such as for default headers (`HTTPAdditionalHeaders`) or timeout interval (`timeoutIntervalForRequest`).
#### Creating a Manager with Default Configuration
```swift
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let manager = Alamofire.Manager(configuration: configuration)
```
#### Creating a Manager with Background Configuration
```swift
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.example.app.background")
let manager = Alamofire.Manager(configuration: configuration)
```
#### Creating a Manager with Ephemeral Configuration
```swift
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let manager = Alamofire.Manager(configuration: configuration)
```
#### Modifying Session Configuration
```swift
var defaultHeaders = Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders ?? [:]
defaultHeaders["DNT"] = "1 (Do Not Track Enabled)"
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = defaultHeaders
let manager = Alamofire.Manager(configuration: configuration)
```
> This is **not** recommended for `Authorization` or `Content-Type` headers. Instead, use `URLRequestConvertible` and `ParameterEncoding`, respectively.
### Request
The result of a `request`, `upload`, or `download` method is an instance of `Alamofire.Request`. A request is always created using a constructor method from an owning manager, and never initialized directly.
Methods like `authenticate`, `validate` and `responseData` return the caller in order to facilitate chaining.
Requests can be suspended, resumed, and cancelled:
- `suspend()`: Suspends the underlying task and dispatch queue
- `resume()`: Resumes the underlying task and dispatch queue. If the owning manager does not have `startRequestsImmediately` set to `true`, the request must call `resume()` in order to start.
- `cancel()`: Cancels the underlying task, producing an error that is passed to any registered response handlers.
### Response Serialization
#### Creating a Custom Response Serializer
Alamofire provides built-in response serialization for strings, JSON, and property lists, but others can be added in extensions on `Alamofire.Request`.
For example, here's how a response handler using [Ono](https://github.com/mattt/Ono) might be implemented:
```swift
extension Request {
public static func XMLResponseSerializer() -> ResponseSerializer {
return ResponseSerializer { request, response, data, error in
guard error == nil else { return .Failure(error!) }
guard let validData = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
do {
let XML = try ONOXMLDocument(data: validData)
return .Success(XML)
} catch {
return .Failure(error as NSError)
}
}
}
public func responseXMLDocument(completionHandler: Response -> Void) -> Self {
return response(responseSerializer: Request.XMLResponseSerializer(), completionHandler: completionHandler)
}
}
```
#### Generic Response Object Serialization
Generics can be used to provide automatic, type-safe response object serialization.
```swift
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject(completionHandler: Response -> Void) -> Self {
let responseSerializer = ResponseSerializer { request, response, data, error in
guard error == nil else { return .Failure(error!) }
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):
if let
response = response,
responseObject = T(response: response, representation: value)
{
return .Success(responseObject)
} else {
let failureReason = "JSON could not be serialized into response object: \(value)"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
case .Failure(let error):
return .Failure(error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
```
```swift
final class User: ResponseObjectSerializable {
let username: String
let name: String
init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.username = response.URL!.lastPathComponent!
self.name = representation.valueForKeyPath("name") as! String
}
}
```
```swift
Alamofire.request(.GET, "https://example.com/users/mattt")
.responseObject { (response: Response) in
debugPrint(response)
}
```
The same approach can also be used to handle endpoints that return a representation of a collection of objects:
```swift
public protocol ResponseCollectionSerializable {
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self]
}
extension Alamofire.Request {
public func responseCollection(completionHandler: Response<[T], NSError> -> Void) -> Self {
let responseSerializer = ResponseSerializer<[T], NSError> { request, response, data, error in
guard error == nil else { return .Failure(error!) }
let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):
if let response = response {
return .Success(T.collection(response: response, representation: value))
} else {
let failureReason = "Response collection could not be serialized due to nil response"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
case .Failure(let error):
return .Failure(error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
```
```swift
final class User: ResponseObjectSerializable, ResponseCollectionSerializable {
let username: String
let name: String
init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.username = response.URL!.lastPathComponent!
self.name = representation.valueForKeyPath("name") as! String
}
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [User] {
var users: [User] = []
if let representation = representation as? [[String: AnyObject]] {
for userRepresentation in representation {
if let user = User(response: response, representation: userRepresentation) {
users.append(user)
}
}
}
return users
}
}
```
```swift
Alamofire.request(.GET, "http://example.com/users")
.responseCollection { (response: Response<[User], NSError>) in
debugPrint(response)
}
```
### URLStringConvertible
Types adopting the `URLStringConvertible` protocol can be used to construct URL strings, which are then used to construct URL requests. `NSString`, `NSURL`, `NSURLComponents`, and `NSURLRequest` conform to `URLStringConvertible` by default, allowing any of them to be passed as `URLString` parameters to the `request`, `upload`, and `download` methods:
```swift
let string = NSString(string: "https://httpbin.org/post")
Alamofire.request(.POST, string)
let URL = NSURL(string: string)!
Alamofire.request(.POST, URL)
let URLRequest = NSURLRequest(URL: URL)
Alamofire.request(.POST, URLRequest) // overrides `HTTPMethod` of `URLRequest`
let URLComponents = NSURLComponents(URL: URL, resolvingAgainstBaseURL: true)
Alamofire.request(.POST, URLComponents)
```
Applications interacting with web applications in a significant manner are encouraged to have custom types conform to `URLStringConvertible` as a convenient way to map domain-specific models to server resources.
#### Type-Safe Routing
```swift
extension User: URLStringConvertible {
static let baseURLString = "http://example.com"
var URLString: String {
return User.baseURLString + "/users/\(username)/"
}
}
```
```swift
let user = User(username: "mattt")
Alamofire.request(.GET, user) // http://example.com/users/mattt
```
### URLRequestConvertible
Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests. `NSURLRequest` conforms to `URLRequestConvertible` by default, allowing it to be passed into `request`, `upload`, and `download` methods directly (this is the recommended way to specify custom HTTP body for individual requests):
```swift
let URL = NSURL(string: "https://httpbin.org/post")!
let mutableURLRequest = NSMutableURLRequest(URL: URL)
mutableURLRequest.HTTPMethod = "POST"
let parameters = ["foo": "bar"]
do {
mutableURLRequest.HTTPBody = try NSJSONSerialization.dataWithJSONObject(parameters, options: NSJSONWritingOptions())
} catch {
// No-op
}
mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
Alamofire.request(mutableURLRequest)
```
Applications interacting with web applications in a significant manner are encouraged to have custom types conform to `URLRequestConvertible` as a way to ensure consistency of requested endpoints. Such an approach can be used to abstract away server-side inconsistencies and provide type-safe routing, as well as manage authentication credentials and other state.
#### API Parameter Abstraction
```swift
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static let perPage = 50
case Search(query: String, page: Int)
// MARK: URLRequestConvertible
var URLRequest: NSMutableURLRequest {
let result: (path: String, parameters: [String: AnyObject]) = {
switch self {
case .Search(let query, let page) where page > 1:
return ("/search", ["q": query, "offset": Router.perPage * page])
case .Search(let query, _):
return ("/search", ["q": query])
}
}()
let URL = NSURL(string: Router.baseURLString)!
let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(result.path))
let encoding = Alamofire.ParameterEncoding.URL
return encoding.encode(URLRequest, parameters: result.parameters).0
}
}
```
```swift
Alamofire.request(Router.Search(query: "foo bar", page: 1)) // ?q=foo%20bar&offset=50
```
#### CRUD & Authorization
```swift
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
case CreateUser([String: AnyObject])
case ReadUser(String)
case UpdateUser(String, [String: AnyObject])
case DestroyUser(String)
var method: Alamofire.Method {
switch self {
case .CreateUser:
return .POST
case .ReadUser:
return .GET
case .UpdateUser:
return .PUT
case .DestroyUser:
return .DELETE
}
}
var path: String {
switch self {
case .CreateUser:
return "/users"
case .ReadUser(let username):
return "/users/\(username)"
case .UpdateUser(let username, _):
return "/users/\(username)"
case .DestroyUser(let username):
return "/users/\(username)"
}
}
// MARK: URLRequestConvertible
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: Router.baseURLString)!
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.rawValue
if let token = Router.OAuthToken {
mutableURLRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
switch self {
case .CreateUser(let parameters):
return Alamofire.ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0
case .UpdateUser(_, let parameters):
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
default:
return mutableURLRequest
}
}
}
```
```swift
Alamofire.request(Router.ReadUser("mattt")) // GET /users/mattt
```
### Security
Using a secure HTTPS connection when communicating with servers and web services is an important step in securing sensitive data. By default, Alamofire will evaluate the certificate chain provided by the server using Apple's built in validation provided by the Security framework. While this guarantees the certificate chain is valid, it does not prevent man-in-the-middle (MITM) attacks or other potential vulnerabilities. In order to mitigate MITM attacks, applications dealing with sensitive customer data or financial information should use certificate or public key pinning provided by the `ServerTrustPolicy`.
#### ServerTrustPolicy
The `ServerTrustPolicy` enumeration evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when connecting to a server over a secure HTTPS connection.
```swift
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
```
There are many different cases of server trust evaluation giving you complete control over the validation process:
* `PerformDefaultEvaluation`: Uses the default server trust evaluation while allowing you to control whether to validate the host provided by the challenge.
* `PinCertificates`: Uses the pinned certificates to validate the server trust. The server trust is considered valid if one of the pinned certificates match one of the server certificates.
* `PinPublicKeys`: Uses the pinned public keys to validate the server trust. The server trust is considered valid if one of the pinned public keys match one of the server certificate public keys.
* `DisableEvaluation`: Disables all evaluation which in turn will always consider any server trust as valid.
* `CustomEvaluation`: Uses the associated closure to evaluate the validity of the server trust thus giving you complete control over the validation process. Use with caution.
#### Server Trust Policy Manager
The `ServerTrustPolicyManager` is responsible for storing an internal mapping of server trust policies to a particular host. This allows Alamofire to evaluate each host against a different server trust policy.
```swift
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .DisableEvaluation
]
let manager = Manager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
```
> Make sure to keep a reference to the new `Manager` instance, otherwise your requests will all get cancelled when your `manager` is deallocated.
These server trust policies will result in the following behavior:
* `test.example.com` will always use certificate pinning with certificate chain and host validation enabled thus requiring the following criteria to be met to allow the TLS handshake to succeed:
* Certificate chain MUST be valid.
* Certificate chain MUST include one of the pinned certificates.
* Challenge host MUST match the host in the certificate chain's leaf certificate.
* `insecure.expired-apis.com` will never evaluate the certificate chain and will always allow the TLS handshake to succeed.
* All other hosts will use the default evaluation provided by Apple.
##### Subclassing Server Trust Policy Manager
If you find yourself needing more flexible server trust policy matching behavior (i.e. wildcarded domains), then subclass the `ServerTrustPolicyManager` and override the `serverTrustPolicyForHost` method with your own custom implementation.
```swift
class CustomServerTrustPolicyManager: ServerTrustPolicyManager {
override func serverTrustPolicyForHost(host: String) -> ServerTrustPolicy? {
var policy: ServerTrustPolicy?
// Implement your custom domain matching behavior...
return policy
}
}
```
#### Validating the Host
The `.PerformDefaultEvaluation`, `.PinCertificates` and `.PinPublicKeys` server trust policies all take a `validateHost` parameter. Setting the value to `true` will cause the server trust evaluation to verify that hostname in the certificate matches the hostname of the challenge. If they do not match, evaluation will fail. A `validateHost` value of `false` will still evaluate the full certificate chain, but will not validate the hostname of the leaf certificate.
> It is recommended that `validateHost` always be set to `true` in production environments.
#### Validating the Certificate Chain
Pinning certificates and public keys both have the option of validating the certificate chain using the `validateCertificateChain` parameter. By setting this value to `true`, the full certificate chain will be evaluated in addition to performing a byte equality check against the pinned certficates or public keys. A value of `false` will skip the certificate chain validation, but will still perform the byte equality check.
There are several cases where it may make sense to disable certificate chain validation. The most common use cases for disabling validation are self-signed and expired certificates. The evaluation would always fail in both of these cases, but the byte equality check will still ensure you are receiving the certificate you expect from the server.
> It is recommended that `validateCertificateChain` always be set to `true` in production environments.
#### App Transport Security
With the addition of App Transport Security (ATS) in iOS 9, it is possible that using a custom `ServerTrustPolicyManager` with several `ServerTrustPolicy` objects will have no effect. If you continuously see `CFNetwork SSLHandshake failed (-9806)` errors, you have probably run into this problem. Apple's ATS system overrides the entire challenge system unless you configure the ATS settings in your app's plist to disable enough of it to allow your app to evaluate the server trust.
If you run into this problem (high probability with self-signed certificates), you can work around this issue by adding the following to your `Info.plist`.
```xml
NSAppTransportSecurity
NSExceptionDomains
example.com
NSExceptionAllowsInsecureHTTPLoads
NSExceptionRequiresForwardSecrecy
NSIncludesSubdomains
NSTemporaryExceptionMinimumTLSVersion
TLSv1.2
```
Whether you need to set the `NSExceptionRequiresForwardSecrecy` to `NO` depends on whether your TLS connection is using an allowed cipher suite. In certain cases, it will need to be set to `NO`. The `NSExceptionAllowsInsecureHTTPLoads` MUST be set to `YES` in order to allow the `SessionDelegate` to receive challenge callbacks. Once the challenge callbacks are being called, the `ServerTrustPolicyManager` will take over the server trust evaluation. You may also need to specify the `NSTemporaryExceptionMinimumTLSVersion` if you're trying to connect to a host that only supports TLS versions less than `1.2`.
> It is recommended to always use valid certificates in production environments.
### Network Reachability
The `NetworkReachabilityManager` listens for reachability changes of hosts and addresses for both WWAN and WiFi network interfaces.
```swift
let manager = NetworkReachabilityManager(host: "www.apple.com")
manager?.listener = { status in
print("Network Status Changed: \(status)")
}
manager?.startListening()
```
> Make sure to remember to retain the `manager` in the above example, or no status changes will be reported.
There are some important things to remember when using network reachability to determine what to do next.
* **Do NOT** use Reachability to determine if a network request should be sent.
* You should **ALWAYS** send it.
* When Reachability is restored, use the event to retry failed network requests.
* Even though the network requests may still fail, this is a good moment to retry them.
* The network reachability status can be useful for determining why a network request may have failed.
* If a network request fails, it is more useful to tell the user that the network request failed due to being offline rather than a more technical errror, such as "request timed out."
> It is recommended to check out [WWDC 2012 Session 706, "Networking Best Practices"](https://developer.apple.com/videos/play/wwdc2012-706/) for more info.
---
## Component Libraries
In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem.
* [AlamofireImage](https://github.com/Alamofire/AlamofireImage) - An image library including image response serializers, `UIImage` and `UIImageView` extensions, custom image filters, an auto-purging in-memory cache and a priority-based image downloading system.
## Open Rdars
The following rdars have some affect on the current implementation of Alamofire.
* [rdar://21349340](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in test case
## FAQ
### What's the origin of the name Alamofire?
Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), a hybrid variant of the Bluebonnet, the official state flower of Texas.
---
## Credits
Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases.
### Security Disclosure
If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to security@alamofire.org. Please do not post it to a public issue tracker.
## License
Alamofire is released under the MIT license. See LICENSE for details.
================================================
FILE: Sublime/Pods/Alamofire/Source/Alamofire.swift
================================================
// Alamofire.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// MARK: - URLStringConvertible
/**
Types adopting the `URLStringConvertible` protocol can be used to construct URL strings, which are then used to
construct URL requests.
*/
public protocol URLStringConvertible {
/**
A URL that conforms to RFC 2396.
Methods accepting a `URLStringConvertible` type parameter parse it according to RFCs 1738 and 1808.
See https://tools.ietf.org/html/rfc2396
See https://tools.ietf.org/html/rfc1738
See https://tools.ietf.org/html/rfc1808
*/
var URLString: String { get }
}
extension String: URLStringConvertible {
public var URLString: String {
return self
}
}
extension NSURL: URLStringConvertible {
public var URLString: String {
return absoluteString
}
}
extension NSURLComponents: URLStringConvertible {
public var URLString: String {
return URL!.URLString
}
}
extension NSURLRequest: URLStringConvertible {
public var URLString: String {
return URL!.URLString
}
}
// MARK: - URLRequestConvertible
/**
Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests.
*/
public protocol URLRequestConvertible {
/// The URL request.
var URLRequest: NSMutableURLRequest { get }
}
extension NSURLRequest: URLRequestConvertible {
public var URLRequest: NSMutableURLRequest {
return self.mutableCopy() as! NSMutableURLRequest
}
}
// MARK: - Convenience
func URLRequest(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil)
-> NSMutableURLRequest
{
let mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: URLString.URLString)!)
mutableURLRequest.HTTPMethod = method.rawValue
if let headers = headers {
for (headerField, headerValue) in headers {
mutableURLRequest.setValue(headerValue, forHTTPHeaderField: headerField)
}
}
return mutableURLRequest
}
// MARK: - Request Methods
/**
Creates a request using the shared manager instance for the specified method, URL string, parameters, and
parameter encoding.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter parameters: The parameters. `nil` by default.
- parameter encoding: The parameter encoding. `.URL` by default.
- parameter headers: The HTTP headers. `nil` by default.
- returns: The created request.
*/
public func request(
method: Method,
_ URLString: URLStringConvertible,
parameters: [String: AnyObject]? = nil,
encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil)
-> Request
{
return Manager.sharedInstance.request(
method,
URLString,
parameters: parameters,
encoding: encoding,
headers: headers
)
}
/**
Creates a request using the shared manager instance for the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request
- returns: The created request.
*/
public func request(URLRequest: URLRequestConvertible) -> Request {
return Manager.sharedInstance.request(URLRequest.URLRequest)
}
// MARK: - Upload Methods
// MARK: File
/**
Creates an upload request using the shared manager instance for the specified method, URL string, and file.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter file: The file to upload.
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
file: NSURL)
-> Request
{
return Manager.sharedInstance.upload(method, URLString, headers: headers, file: file)
}
/**
Creates an upload request using the shared manager instance for the specified URL request and file.
- parameter URLRequest: The URL request.
- parameter file: The file to upload.
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, file: NSURL) -> Request {
return Manager.sharedInstance.upload(URLRequest, file: file)
}
// MARK: Data
/**
Creates an upload request using the shared manager instance for the specified method, URL string, and data.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter data: The data to upload.
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
data: NSData)
-> Request
{
return Manager.sharedInstance.upload(method, URLString, headers: headers, data: data)
}
/**
Creates an upload request using the shared manager instance for the specified URL request and data.
- parameter URLRequest: The URL request.
- parameter data: The data to upload.
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, data: NSData) -> Request {
return Manager.sharedInstance.upload(URLRequest, data: data)
}
// MARK: Stream
/**
Creates an upload request using the shared manager instance for the specified method, URL string, and stream.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter stream: The stream to upload.
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
stream: NSInputStream)
-> Request
{
return Manager.sharedInstance.upload(method, URLString, headers: headers, stream: stream)
}
/**
Creates an upload request using the shared manager instance for the specified URL request and stream.
- parameter URLRequest: The URL request.
- parameter stream: The stream to upload.
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, stream: NSInputStream) -> Request {
return Manager.sharedInstance.upload(URLRequest, stream: stream)
}
// MARK: MultipartFormData
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
`MultipartFormDataEncodingMemoryThreshold` by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
method,
URLString,
headers: headers,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter URLRequest: The URL request.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
`MultipartFormDataEncodingMemoryThreshold` by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
URLRequest: URLRequestConvertible,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
URLRequest,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
// MARK: - Download Methods
// MARK: URL Request
/**
Creates a download request using the shared manager instance for the specified method and URL string.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter parameters: The parameters. `nil` by default.
- parameter encoding: The parameter encoding. `.URL` by default.
- parameter headers: The HTTP headers. `nil` by default.
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(
method: Method,
_ URLString: URLStringConvertible,
parameters: [String: AnyObject]? = nil,
encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil,
destination: Request.DownloadFileDestination)
-> Request
{
return Manager.sharedInstance.download(
method,
URLString,
parameters: parameters,
encoding: encoding,
headers: headers,
destination: destination
)
}
/**
Creates a download request using the shared manager instance for the specified URL request.
- parameter URLRequest: The URL request.
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(URLRequest: URLRequestConvertible, destination: Request.DownloadFileDestination) -> Request {
return Manager.sharedInstance.download(URLRequest, destination: destination)
}
// MARK: Resume Data
/**
Creates a request using the shared manager instance for downloading from the resume data produced from a
previous request cancellation.
- parameter resumeData: The resume data. This is an opaque data blob produced by `NSURLSessionDownloadTask`
when a task is cancelled. See `NSURLSession -downloadTaskWithResumeData:` for additional
information.
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(resumeData data: NSData, destination: Request.DownloadFileDestination) -> Request {
return Manager.sharedInstance.download(data, destination: destination)
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Download.swift
================================================
// Download.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
extension Manager {
private enum Downloadable {
case Request(NSURLRequest)
case ResumeData(NSData)
}
private func download(downloadable: Downloadable, destination: Request.DownloadFileDestination) -> Request {
var downloadTask: NSURLSessionDownloadTask!
switch downloadable {
case .Request(let request):
dispatch_sync(queue) {
downloadTask = self.session.downloadTaskWithRequest(request)
}
case .ResumeData(let resumeData):
dispatch_sync(queue) {
downloadTask = self.session.downloadTaskWithResumeData(resumeData)
}
}
let request = Request(session: session, task: downloadTask)
if let downloadDelegate = request.delegate as? Request.DownloadTaskDelegate {
downloadDelegate.downloadTaskDidFinishDownloadingToURL = { session, downloadTask, URL in
return destination(URL, downloadTask.response as! NSHTTPURLResponse)
}
}
delegate[request.delegate.task] = request.delegate
if startRequestsImmediately {
request.resume()
}
return request
}
// MARK: Request
/**
Creates a download request for the specified method, URL string, parameters, parameter encoding, headers
and destination.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter parameters: The parameters. `nil` by default.
- parameter encoding: The parameter encoding. `.URL` by default.
- parameter headers: The HTTP headers. `nil` by default.
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(
method: Method,
_ URLString: URLStringConvertible,
parameters: [String: AnyObject]? = nil,
encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil,
destination: Request.DownloadFileDestination)
-> Request
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
let encodedURLRequest = encoding.encode(mutableURLRequest, parameters: parameters).0
return download(encodedURLRequest, destination: destination)
}
/**
Creates a request for downloading from the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(URLRequest: URLRequestConvertible, destination: Request.DownloadFileDestination) -> Request {
return download(.Request(URLRequest.URLRequest), destination: destination)
}
// MARK: Resume Data
/**
Creates a request for downloading from the resume data produced from a previous request cancellation.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter resumeData: The resume data. This is an opaque data blob produced by `NSURLSessionDownloadTask`
when a task is cancelled. See `NSURLSession -downloadTaskWithResumeData:` for
additional information.
- parameter destination: The closure used to determine the destination of the downloaded file.
- returns: The created download request.
*/
public func download(resumeData: NSData, destination: Request.DownloadFileDestination) -> Request {
return download(.ResumeData(resumeData), destination: destination)
}
}
// MARK: -
extension Request {
/**
A closure executed once a request has successfully completed in order to determine where to move the temporary
file written to during the download process. The closure takes two arguments: the temporary file URL and the URL
response, and returns a single argument: the file URL where the temporary file should be moved.
*/
public typealias DownloadFileDestination = (NSURL, NSHTTPURLResponse) -> NSURL
/**
Creates a download file destination closure which uses the default file manager to move the temporary file to a
file URL in the first available directory with the specified search path directory and search path domain mask.
- parameter directory: The search path directory. `.DocumentDirectory` by default.
- parameter domain: The search path domain mask. `.UserDomainMask` by default.
- returns: A download file destination closure.
*/
public class func suggestedDownloadDestination(
directory directory: NSSearchPathDirectory = .DocumentDirectory,
domain: NSSearchPathDomainMask = .UserDomainMask)
-> DownloadFileDestination
{
return { temporaryURL, response -> NSURL in
let directoryURLs = NSFileManager.defaultManager().URLsForDirectory(directory, inDomains: domain)
if !directoryURLs.isEmpty {
return directoryURLs[0].URLByAppendingPathComponent(response.suggestedFilename!)
}
return temporaryURL
}
}
/// The resume data of the underlying download task if available after a failure.
public var resumeData: NSData? {
var data: NSData?
if let delegate = delegate as? DownloadTaskDelegate {
data = delegate.resumeData
}
return data
}
// MARK: - DownloadTaskDelegate
class DownloadTaskDelegate: TaskDelegate, NSURLSessionDownloadDelegate {
var downloadTask: NSURLSessionDownloadTask? { return task as? NSURLSessionDownloadTask }
var downloadProgress: ((Int64, Int64, Int64) -> Void)?
var resumeData: NSData?
override var data: NSData? { return resumeData }
// MARK: - NSURLSessionDownloadDelegate
// MARK: Override Closures
var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> NSURL)?
var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)?
var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)?
// MARK: Delegate Methods
func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didFinishDownloadingToURL location: NSURL)
{
if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
do {
let destination = downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
try NSFileManager.defaultManager().moveItemAtURL(location, toURL: destination)
} catch {
self.error = error as NSError
}
}
}
func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64)
{
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
if let downloadTaskDidWriteData = downloadTaskDidWriteData {
downloadTaskDidWriteData(
session,
downloadTask,
bytesWritten,
totalBytesWritten,
totalBytesExpectedToWrite
)
} else {
progress.totalUnitCount = totalBytesExpectedToWrite
progress.completedUnitCount = totalBytesWritten
downloadProgress?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
}
}
func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didResumeAtOffset fileOffset: Int64,
expectedTotalBytes: Int64)
{
if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
} else {
progress.totalUnitCount = expectedTotalBytes
progress.completedUnitCount = fileOffset
}
}
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Error.swift
================================================
// Error.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/// The `Error` struct provides a convenience for creating custom Alamofire NSErrors.
public struct Error {
/// The domain used for creating all Alamofire errors.
public static let Domain = "com.alamofire.error"
/// The custom error codes generated by Alamofire.
public enum Code: Int {
case InputStreamReadFailed = -6000
case OutputStreamWriteFailed = -6001
case ContentTypeValidationFailed = -6002
case StatusCodeValidationFailed = -6003
case DataSerializationFailed = -6004
case StringSerializationFailed = -6005
case JSONSerializationFailed = -6006
case PropertyListSerializationFailed = -6007
}
/**
Creates an `NSError` with the given error code and failure reason.
- parameter code: The error code.
- parameter failureReason: The failure reason.
- returns: An `NSError` with the given error code and failure reason.
*/
public static func errorWithCode(code: Code, failureReason: String) -> NSError {
return errorWithCode(code.rawValue, failureReason: failureReason)
}
/**
Creates an `NSError` with the given error code and failure reason.
- parameter code: The error code.
- parameter failureReason: The failure reason.
- returns: An `NSError` with the given error code and failure reason.
*/
public static func errorWithCode(code: Int, failureReason: String) -> NSError {
let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
return NSError(domain: Domain, code: code, userInfo: userInfo)
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Manager.swift
================================================
// Manager.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
Responsible for creating and managing `Request` objects, as well as their underlying `NSURLSession`.
*/
public class Manager {
// MARK: - Properties
/**
A shared instance of `Manager`, used by top-level Alamofire request methods, and suitable for use directly
for any ad hoc requests.
*/
public static let sharedInstance: Manager = {
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders
return Manager(configuration: configuration)
}()
/**
Creates default values for the "Accept-Encoding", "Accept-Language" and "User-Agent" headers.
*/
public static let defaultHTTPHeaders: [String: String] = {
// Accept-Encoding HTTP Header; see https://tools.ietf.org/html/rfc7230#section-4.2.3
let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5"
// Accept-Language HTTP Header; see https://tools.ietf.org/html/rfc7231#section-5.3.5
let acceptLanguage = NSLocale.preferredLanguages().prefix(6).enumerate().map { index, languageCode in
let quality = 1.0 - (Double(index) * 0.1)
return "\(languageCode);q=\(quality)"
}.joinWithSeparator(", ")
// User-Agent Header; see https://tools.ietf.org/html/rfc7231#section-5.5.3
let userAgent: String = {
if let info = NSBundle.mainBundle().infoDictionary {
let executable: AnyObject = info[kCFBundleExecutableKey as String] ?? "Unknown"
let bundle: AnyObject = info[kCFBundleIdentifierKey as String] ?? "Unknown"
let version: AnyObject = info[kCFBundleVersionKey as String] ?? "Unknown"
let os: AnyObject = NSProcessInfo.processInfo().operatingSystemVersionString ?? "Unknown"
var mutableUserAgent = NSMutableString(string: "\(executable)/\(bundle) (\(version); OS \(os))") as CFMutableString
let transform = NSString(string: "Any-Latin; Latin-ASCII; [:^ASCII:] Remove") as CFString
if CFStringTransform(mutableUserAgent, UnsafeMutablePointer(nil), transform, false) {
return mutableUserAgent as String
}
}
return "Alamofire"
}()
return [
"Accept-Encoding": acceptEncoding,
"Accept-Language": acceptLanguage,
"User-Agent": userAgent
]
}()
let queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)
/// The underlying session.
public let session: NSURLSession
/// The session delegate handling all the task and session delegate callbacks.
public let delegate: SessionDelegate
/// Whether to start requests immediately after being constructed. `true` by default.
public var startRequestsImmediately: Bool = true
/**
The background completion handler closure provided by the UIApplicationDelegate
`application:handleEventsForBackgroundURLSession:completionHandler:` method. By setting the background
completion handler, the SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` closure implementation
will automatically call the handler.
If you need to handle your own events before the handler is called, then you need to override the
SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` and manually call the handler when finished.
`nil` by default.
*/
public var backgroundCompletionHandler: (() -> Void)?
// MARK: - Lifecycle
/**
Initializes the `Manager` instance with the specified configuration, delegate and server trust policy.
- parameter configuration: The configuration used to construct the managed session.
`NSURLSessionConfiguration.defaultSessionConfiguration()` by default.
- parameter delegate: The delegate used when initializing the session. `SessionDelegate()` by
default.
- parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
challenges. `nil` by default.
- returns: The new `Manager` instance.
*/
public init(
configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: SessionDelegate = SessionDelegate(),
serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
self.delegate = delegate
self.session = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
/**
Initializes the `Manager` instance with the specified session, delegate and server trust policy.
- parameter session: The URL session.
- parameter delegate: The delegate of the URL session. Must equal the URL session's delegate.
- parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
challenges. `nil` by default.
- returns: The new `Manager` instance if the URL session's delegate matches the delegate parameter.
*/
public init?(
session: NSURLSession,
delegate: SessionDelegate,
serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
self.delegate = delegate
self.session = session
guard delegate === session.delegate else { return nil }
commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
private func commonInit(serverTrustPolicyManager serverTrustPolicyManager: ServerTrustPolicyManager?) {
session.serverTrustPolicyManager = serverTrustPolicyManager
delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
dispatch_async(dispatch_get_main_queue()) { strongSelf.backgroundCompletionHandler?() }
}
}
deinit {
session.invalidateAndCancel()
}
// MARK: - Request
/**
Creates a request for the specified method, URL string, parameters, parameter encoding and headers.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter parameters: The parameters. `nil` by default.
- parameter encoding: The parameter encoding. `.URL` by default.
- parameter headers: The HTTP headers. `nil` by default.
- returns: The created request.
*/
public func request(
method: Method,
_ URLString: URLStringConvertible,
parameters: [String: AnyObject]? = nil,
encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil)
-> Request
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
let encodedURLRequest = encoding.encode(mutableURLRequest, parameters: parameters).0
return request(encodedURLRequest)
}
/**
Creates a request for the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request
- returns: The created request.
*/
public func request(URLRequest: URLRequestConvertible) -> Request {
var dataTask: NSURLSessionDataTask!
dispatch_sync(queue) { dataTask = self.session.dataTaskWithRequest(URLRequest.URLRequest) }
let request = Request(session: session, task: dataTask)
delegate[request.delegate.task] = request.delegate
if startRequestsImmediately {
request.resume()
}
return request
}
// MARK: - SessionDelegate
/**
Responsible for handling all delegate callbacks for the underlying session.
*/
public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
private var subdelegates: [Int: Request.TaskDelegate] = [:]
private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)
subscript(task: NSURLSessionTask) -> Request.TaskDelegate? {
get {
var subdelegate: Request.TaskDelegate?
dispatch_sync(subdelegateQueue) { subdelegate = self.subdelegates[task.taskIdentifier] }
return subdelegate
}
set {
dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue }
}
}
/**
Initializes the `SessionDelegate` instance.
- returns: The new `SessionDelegate` instance.
*/
public override init() {
super.init()
}
// MARK: - NSURLSessionDelegate
// MARK: Override Closures
/// Overrides default behavior for NSURLSessionDelegate method `URLSession:didBecomeInvalidWithError:`.
public var sessionDidBecomeInvalidWithError: ((NSURLSession, NSError?) -> Void)?
/// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`.
public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
/// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`.
public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)?
// MARK: Delegate Methods
/**
Tells the delegate that the session has been invalidated.
- parameter session: The session object that was invalidated.
- parameter error: The error that caused invalidation, or nil if the invalidation was explicit.
*/
public func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
sessionDidBecomeInvalidWithError?(session, error)
}
/**
Requests credentials from the delegate in response to a session-level authentication request from the remote server.
- parameter session: The session containing the task that requested authentication.
- parameter challenge: An object that contains the request for authentication.
- parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
*/
public func URLSession(
session: NSURLSession,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
{
var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
var credential: NSURLCredential?
if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
(disposition, credential) = sessionDidReceiveChallenge(session, challenge)
} else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let host = challenge.protectionSpace.host
if let
serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
serverTrust = challenge.protectionSpace.serverTrust
{
if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
disposition = .UseCredential
credential = NSURLCredential(forTrust: serverTrust)
} else {
disposition = .CancelAuthenticationChallenge
}
}
}
completionHandler(disposition, credential)
}
/**
Tells the delegate that all messages enqueued for a session have been delivered.
- parameter session: The session that no longer has any outstanding requests.
*/
public func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
sessionDidFinishEventsForBackgroundURLSession?(session)
}
// MARK: - NSURLSessionTaskDelegate
// MARK: Override Closures
/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`.
public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?
/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didReceiveChallenge:completionHandler:`.
public var taskDidReceiveChallenge: ((NSURLSession, NSURLSessionTask, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:session:task:needNewBodyStream:`.
public var taskNeedNewBodyStream: ((NSURLSession, NSURLSessionTask) -> NSInputStream!)?
/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
public var taskDidSendBodyData: ((NSURLSession, NSURLSessionTask, Int64, Int64, Int64) -> Void)?
/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didCompleteWithError:`.
public var taskDidComplete: ((NSURLSession, NSURLSessionTask, NSError?) -> Void)?
// MARK: Delegate Methods
/**
Tells the delegate that the remote server requested an HTTP redirect.
- parameter session: The session containing the task whose request resulted in a redirect.
- parameter task: The task whose request resulted in a redirect.
- parameter response: An object containing the server’s response to the original request.
- parameter request: A URL request object filled out with the new location.
- parameter completionHandler: A closure that your handler should call with either the value of the request
parameter, a modified URL request object, or NULL to refuse the redirect and
return the body of the redirect response.
*/
public func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
willPerformHTTPRedirection response: NSHTTPURLResponse,
newRequest request: NSURLRequest,
completionHandler: ((NSURLRequest?) -> Void))
{
var redirectRequest: NSURLRequest? = request
if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
}
completionHandler(redirectRequest)
}
/**
Requests credentials from the delegate in response to an authentication request from the remote server.
- parameter session: The session containing the task whose request requires authentication.
- parameter task: The task whose request requires authentication.
- parameter challenge: An object that contains the request for authentication.
- parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
*/
public func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
{
if let taskDidReceiveChallenge = taskDidReceiveChallenge {
completionHandler(taskDidReceiveChallenge(session, task, challenge))
} else if let delegate = self[task] {
delegate.URLSession(
session,
task: task,
didReceiveChallenge: challenge,
completionHandler: completionHandler
)
} else {
URLSession(session, didReceiveChallenge: challenge, completionHandler: completionHandler)
}
}
/**
Tells the delegate when a task requires a new request body stream to send to the remote server.
- parameter session: The session containing the task that needs a new body stream.
- parameter task: The task that needs a new body stream.
- parameter completionHandler: A completion handler that your delegate method should call with the new body stream.
*/
public func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
needNewBodyStream completionHandler: ((NSInputStream?) -> Void))
{
if let taskNeedNewBodyStream = taskNeedNewBodyStream {
completionHandler(taskNeedNewBodyStream(session, task))
} else if let delegate = self[task] {
delegate.URLSession(session, task: task, needNewBodyStream: completionHandler)
}
}
/**
Periodically informs the delegate of the progress of sending body content to the server.
- parameter session: The session containing the data task.
- parameter task: The data task.
- parameter bytesSent: The number of bytes sent since the last time this delegate method was called.
- parameter totalBytesSent: The total number of bytes sent so far.
- parameter totalBytesExpectedToSend: The expected length of the body data.
*/
public func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
didSendBodyData bytesSent: Int64,
totalBytesSent: Int64,
totalBytesExpectedToSend: Int64)
{
if let taskDidSendBodyData = taskDidSendBodyData {
taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
} else if let delegate = self[task] as? Request.UploadTaskDelegate {
delegate.URLSession(
session,
task: task,
didSendBodyData: bytesSent,
totalBytesSent: totalBytesSent,
totalBytesExpectedToSend: totalBytesExpectedToSend
)
}
}
/**
Tells the delegate that the task finished transferring data.
- parameter session: The session containing the task whose request finished transferring data.
- parameter task: The task whose request finished transferring data.
- parameter error: If an error occurred, an error object indicating how the transfer failed, otherwise nil.
*/
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if let taskDidComplete = taskDidComplete {
taskDidComplete(session, task, error)
} else if let delegate = self[task] {
delegate.URLSession(session, task: task, didCompleteWithError: error)
}
NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidComplete, object: task)
self[task] = nil
}
// MARK: - NSURLSessionDataDelegate
// MARK: Override Closures
/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveResponse:completionHandler:`.
public var dataTaskDidReceiveResponse: ((NSURLSession, NSURLSessionDataTask, NSURLResponse) -> NSURLSessionResponseDisposition)?
/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didBecomeDownloadTask:`.
public var dataTaskDidBecomeDownloadTask: ((NSURLSession, NSURLSessionDataTask, NSURLSessionDownloadTask) -> Void)?
/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveData:`.
public var dataTaskDidReceiveData: ((NSURLSession, NSURLSessionDataTask, NSData) -> Void)?
/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`.
public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse!)?
// MARK: Delegate Methods
/**
Tells the delegate that the data task received the initial reply (headers) from the server.
- parameter session: The session containing the data task that received an initial reply.
- parameter dataTask: The data task that received an initial reply.
- parameter response: A URL response object populated with headers.
- parameter completionHandler: A completion handler that your code calls to continue the transfer, passing a
constant to indicate whether the transfer should continue as a data task or
should become a download task.
*/
public func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
didReceiveResponse response: NSURLResponse,
completionHandler: ((NSURLSessionResponseDisposition) -> Void))
{
var disposition: NSURLSessionResponseDisposition = .Allow
if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
disposition = dataTaskDidReceiveResponse(session, dataTask, response)
}
completionHandler(disposition)
}
/**
Tells the delegate that the data task was changed to a download task.
- parameter session: The session containing the task that was replaced by a download task.
- parameter dataTask: The data task that was replaced by a download task.
- parameter downloadTask: The new download task that replaced the data task.
*/
public func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask)
{
if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask {
dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask)
} else {
let downloadDelegate = Request.DownloadTaskDelegate(task: downloadTask)
self[downloadTask] = downloadDelegate
}
}
/**
Tells the delegate that the data task has received some of the expected data.
- parameter session: The session containing the data task that provided data.
- parameter dataTask: The data task that provided data.
- parameter data: A data object containing the transferred data.
*/
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
}
}
/**
Asks the delegate whether the data (or upload) task should store the response in the cache.
- parameter session: The session containing the data (or upload) task.
- parameter dataTask: The data (or upload) task.
- parameter proposedResponse: The default caching behavior. This behavior is determined based on the current
caching policy and the values of certain received headers, such as the Pragma
and Cache-Control headers.
- parameter completionHandler: A block that your handler must call, providing either the original proposed
response, a modified version of that response, or NULL to prevent caching the
response. If your delegate implements this method, it must call this completion
handler; otherwise, your app leaks memory.
*/
public func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
willCacheResponse proposedResponse: NSCachedURLResponse,
completionHandler: ((NSCachedURLResponse?) -> Void))
{
if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))
} else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
delegate.URLSession(
session,
dataTask: dataTask,
willCacheResponse: proposedResponse,
completionHandler: completionHandler
)
} else {
completionHandler(proposedResponse)
}
}
// MARK: - NSURLSessionDownloadDelegate
// MARK: Override Closures
/// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didFinishDownloadingToURL:`.
public var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> Void)?
/// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:`.
public var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)?
/// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`.
public var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)?
// MARK: Delegate Methods
/**
Tells the delegate that a download task has finished downloading.
- parameter session: The session containing the download task that finished.
- parameter downloadTask: The download task that finished.
- parameter location: A file URL for the temporary file. Because the file is temporary, you must either
open the file for reading or move it to a permanent location in your app’s sandbox
container directory before returning from this delegate method.
*/
public func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didFinishDownloadingToURL location: NSURL)
{
if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
} else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
delegate.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
}
}
/**
Periodically informs the delegate about the download’s progress.
- parameter session: The session containing the download task.
- parameter downloadTask: The download task.
- parameter bytesWritten: The number of bytes transferred since the last time this delegate
method was called.
- parameter totalBytesWritten: The total number of bytes transferred so far.
- parameter totalBytesExpectedToWrite: The expected length of the file, as provided by the Content-Length
header. If this header was not provided, the value is
`NSURLSessionTransferSizeUnknown`.
*/
public func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64)
{
if let downloadTaskDidWriteData = downloadTaskDidWriteData {
downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
} else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
delegate.URLSession(
session,
downloadTask: downloadTask,
didWriteData: bytesWritten,
totalBytesWritten: totalBytesWritten,
totalBytesExpectedToWrite: totalBytesExpectedToWrite
)
}
}
/**
Tells the delegate that the download task has resumed downloading.
- parameter session: The session containing the download task that finished.
- parameter downloadTask: The download task that resumed. See explanation in the discussion.
- parameter fileOffset: If the file's cache policy or last modified date prevents reuse of the
existing content, then this value is zero. Otherwise, this value is an
integer representing the number of bytes on disk that do not need to be
retrieved again.
- parameter expectedTotalBytes: The expected length of the file, as provided by the Content-Length header.
If this header was not provided, the value is NSURLSessionTransferSizeUnknown.
*/
public func URLSession(
session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didResumeAtOffset fileOffset: Int64,
expectedTotalBytes: Int64)
{
if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
} else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
delegate.URLSession(
session,
downloadTask: downloadTask,
didResumeAtOffset: fileOffset,
expectedTotalBytes: expectedTotalBytes
)
}
}
// MARK: - NSURLSessionStreamDelegate
var _streamTaskReadClosed: Any?
var _streamTaskWriteClosed: Any?
var _streamTaskBetterRouteDiscovered: Any?
var _streamTaskDidBecomeInputStream: Any?
// MARK: - NSObject
public override func respondsToSelector(selector: Selector) -> Bool {
switch selector {
case "URLSession:didBecomeInvalidWithError:":
return sessionDidBecomeInvalidWithError != nil
case "URLSession:didReceiveChallenge:completionHandler:":
return sessionDidReceiveChallenge != nil
case "URLSessionDidFinishEventsForBackgroundURLSession:":
return sessionDidFinishEventsForBackgroundURLSession != nil
case "URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:":
return taskWillPerformHTTPRedirection != nil
case "URLSession:dataTask:didReceiveResponse:completionHandler:":
return dataTaskDidReceiveResponse != nil
default:
return self.dynamicType.instancesRespondToSelector(selector)
}
}
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/MultipartFormData.swift
================================================
// MultipartFormData.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
#if os(iOS) || os(watchOS) || os(tvOS)
import MobileCoreServices
#elseif os(OSX)
import CoreServices
#endif
/**
Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body. There are currently two ways to encode
multipart form data. The first way is to encode the data directly in memory. This is very efficient, but can lead
to memory issues if the dataset is too large. The second way is designed for larger datasets and will write all the
data to a single file on disk with all the proper boundary segmentation. The second approach MUST be used for
larger datasets such as video content, otherwise your app may run out of memory when trying to encode the dataset.
For more information on `multipart/form-data` in general, please refer to the RFC-2388 and RFC-2045 specs as well
and the w3 form documentation.
- https://www.ietf.org/rfc/rfc2388.txt
- https://www.ietf.org/rfc/rfc2045.txt
- https://www.w3.org/TR/html401/interact/forms.html#h-17.13
*/
public class MultipartFormData {
// MARK: - Helper Types
struct EncodingCharacters {
static let CRLF = "\r\n"
}
struct BoundaryGenerator {
enum BoundaryType {
case Initial, Encapsulated, Final
}
static func randomBoundary() -> String {
return String(format: "alamofire.boundary.%08x%08x", arc4random(), arc4random())
}
static func boundaryData(boundaryType boundaryType: BoundaryType, boundary: String) -> NSData {
let boundaryText: String
switch boundaryType {
case .Initial:
boundaryText = "--\(boundary)\(EncodingCharacters.CRLF)"
case .Encapsulated:
boundaryText = "\(EncodingCharacters.CRLF)--\(boundary)\(EncodingCharacters.CRLF)"
case .Final:
boundaryText = "\(EncodingCharacters.CRLF)--\(boundary)--\(EncodingCharacters.CRLF)"
}
return boundaryText.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
}
class BodyPart {
let headers: [String: String]
let bodyStream: NSInputStream
let bodyContentLength: UInt64
var hasInitialBoundary = false
var hasFinalBoundary = false
init(headers: [String: String], bodyStream: NSInputStream, bodyContentLength: UInt64) {
self.headers = headers
self.bodyStream = bodyStream
self.bodyContentLength = bodyContentLength
}
}
// MARK: - Properties
/// The `Content-Type` header value containing the boundary used to generate the `multipart/form-data`.
public var contentType: String { return "multipart/form-data; boundary=\(boundary)" }
/// The content length of all body parts used to generate the `multipart/form-data` not including the boundaries.
public var contentLength: UInt64 { return bodyParts.reduce(0) { $0 + $1.bodyContentLength } }
/// The boundary used to separate the body parts in the encoded form data.
public let boundary: String
private var bodyParts: [BodyPart]
private var bodyPartError: NSError?
private let streamBufferSize: Int
// MARK: - Lifecycle
/**
Creates a multipart form data object.
- returns: The multipart form data object.
*/
public init() {
self.boundary = BoundaryGenerator.randomBoundary()
self.bodyParts = []
/**
* The optimal read/write buffer size in bytes for input and output streams is 1024 (1KB). For more
* information, please refer to the following article:
* - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html
*/
self.streamBufferSize = 1024
}
// MARK: - Body Parts
/**
Creates a body part from the data and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- `Content-Disposition: form-data; name=#{name}` (HTTP Header)
- Encoded data
- Multipart form boundary
- parameter data: The data to encode into the multipart form data.
- parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
*/
public func appendBodyPart(data data: NSData, name: String) {
let headers = contentHeaders(name: name)
let stream = NSInputStream(data: data)
let length = UInt64(data.length)
appendBodyPart(stream: stream, length: length, headers: headers)
}
/**
Creates a body part from the data and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- `Content-Disposition: form-data; name=#{name}` (HTTP Header)
- `Content-Type: #{generated mimeType}` (HTTP Header)
- Encoded data
- Multipart form boundary
- parameter data: The data to encode into the multipart form data.
- parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
- parameter mimeType: The MIME type to associate with the data content type in the `Content-Type` HTTP header.
*/
public func appendBodyPart(data data: NSData, name: String, mimeType: String) {
let headers = contentHeaders(name: name, mimeType: mimeType)
let stream = NSInputStream(data: data)
let length = UInt64(data.length)
appendBodyPart(stream: stream, length: length, headers: headers)
}
/**
Creates a body part from the data and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)
- `Content-Type: #{mimeType}` (HTTP Header)
- Encoded file data
- Multipart form boundary
- parameter data: The data to encode into the multipart form data.
- parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
- parameter fileName: The filename to associate with the data in the `Content-Disposition` HTTP header.
- parameter mimeType: The MIME type to associate with the data in the `Content-Type` HTTP header.
*/
public func appendBodyPart(data data: NSData, name: String, fileName: String, mimeType: String) {
let headers = contentHeaders(name: name, fileName: fileName, mimeType: mimeType)
let stream = NSInputStream(data: data)
let length = UInt64(data.length)
appendBodyPart(stream: stream, length: length, headers: headers)
}
/**
Creates a body part from the file and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- `Content-Disposition: form-data; name=#{name}; filename=#{generated filename}` (HTTP Header)
- `Content-Type: #{generated mimeType}` (HTTP Header)
- Encoded file data
- Multipart form boundary
The filename in the `Content-Disposition` HTTP header is generated from the last path component of the
`fileURL`. The `Content-Type` HTTP header MIME type is generated by mapping the `fileURL` extension to the
system associated MIME type.
- parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.
- parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header.
*/
public func appendBodyPart(fileURL fileURL: NSURL, name: String) {
if let
fileName = fileURL.lastPathComponent,
pathExtension = fileURL.pathExtension
{
let mimeType = mimeTypeForPathExtension(pathExtension)
appendBodyPart(fileURL: fileURL, name: name, fileName: fileName, mimeType: mimeType)
} else {
let failureReason = "Failed to extract the fileName of the provided URL: \(fileURL)"
setBodyPartError(Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason))
}
}
/**
Creates a body part from the file and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- Content-Disposition: form-data; name=#{name}; filename=#{filename} (HTTP Header)
- Content-Type: #{mimeType} (HTTP Header)
- Encoded file data
- Multipart form boundary
- parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.
- parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header.
- parameter fileName: The filename to associate with the file content in the `Content-Disposition` HTTP header.
- parameter mimeType: The MIME type to associate with the file content in the `Content-Type` HTTP header.
*/
public func appendBodyPart(fileURL fileURL: NSURL, name: String, fileName: String, mimeType: String) {
let headers = contentHeaders(name: name, fileName: fileName, mimeType: mimeType)
//============================================================
// Check 1 - is file URL?
//============================================================
guard fileURL.fileURL else {
let failureReason = "The file URL does not point to a file URL: \(fileURL)"
let error = Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason)
setBodyPartError(error)
return
}
//============================================================
// Check 2 - is file URL reachable?
//============================================================
var isReachable = true
if #available(OSX 10.10, *) {
isReachable = fileURL.checkPromisedItemIsReachableAndReturnError(nil)
}
guard isReachable else {
let error = Error.errorWithCode(NSURLErrorBadURL, failureReason: "The file URL is not reachable: \(fileURL)")
setBodyPartError(error)
return
}
//============================================================
// Check 3 - is file URL a directory?
//============================================================
var isDirectory: ObjCBool = false
guard let
path = fileURL.path
where NSFileManager.defaultManager().fileExistsAtPath(path, isDirectory: &isDirectory) && !isDirectory else
{
let failureReason = "The file URL is a directory, not a file: \(fileURL)"
let error = Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason)
setBodyPartError(error)
return
}
//============================================================
// Check 4 - can the file size be extracted?
//============================================================
var bodyContentLength: UInt64?
do {
if let
path = fileURL.path,
fileSize = try NSFileManager.defaultManager().attributesOfItemAtPath(path)[NSFileSize] as? NSNumber
{
bodyContentLength = fileSize.unsignedLongLongValue
}
} catch {
// No-op
}
guard let length = bodyContentLength else {
let failureReason = "Could not fetch attributes from the file URL: \(fileURL)"
let error = Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason)
setBodyPartError(error)
return
}
//============================================================
// Check 5 - can a stream be created from file URL?
//============================================================
guard let stream = NSInputStream(URL: fileURL) else {
let failureReason = "Failed to create an input stream from the file URL: \(fileURL)"
let error = Error.errorWithCode(NSURLErrorCannotOpenFile, failureReason: failureReason)
setBodyPartError(error)
return
}
appendBodyPart(stream: stream, length: length, headers: headers)
}
/**
Creates a body part from the stream and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)
- `Content-Type: #{mimeType}` (HTTP Header)
- Encoded stream data
- Multipart form boundary
- parameter stream: The input stream to encode in the multipart form data.
- parameter length: The content length of the stream.
- parameter name: The name to associate with the stream content in the `Content-Disposition` HTTP header.
- parameter fileName: The filename to associate with the stream content in the `Content-Disposition` HTTP header.
- parameter mimeType: The MIME type to associate with the stream content in the `Content-Type` HTTP header.
*/
public func appendBodyPart(
stream stream: NSInputStream,
length: UInt64,
name: String,
fileName: String,
mimeType: String)
{
let headers = contentHeaders(name: name, fileName: fileName, mimeType: mimeType)
appendBodyPart(stream: stream, length: length, headers: headers)
}
/**
Creates a body part with the headers, stream and length and appends it to the multipart form data object.
The body part data will be encoded using the following format:
- HTTP headers
- Encoded stream data
- Multipart form boundary
- parameter stream: The input stream to encode in the multipart form data.
- parameter length: The content length of the stream.
- parameter headers: The HTTP headers for the body part.
*/
public func appendBodyPart(stream stream: NSInputStream, length: UInt64, headers: [String: String]) {
let bodyPart = BodyPart(headers: headers, bodyStream: stream, bodyContentLength: length)
bodyParts.append(bodyPart)
}
// MARK: - Data Encoding
/**
Encodes all the appended body parts into a single `NSData` object.
It is important to note that this method will load all the appended body parts into memory all at the same
time. This method should only be used when the encoded data will have a small memory footprint. For large data
cases, please use the `writeEncodedDataToDisk(fileURL:completionHandler:)` method.
- throws: An `NSError` if encoding encounters an error.
- returns: The encoded `NSData` if encoding is successful.
*/
public func encode() throws -> NSData {
if let bodyPartError = bodyPartError {
throw bodyPartError
}
let encoded = NSMutableData()
bodyParts.first?.hasInitialBoundary = true
bodyParts.last?.hasFinalBoundary = true
for bodyPart in bodyParts {
let encodedData = try encodeBodyPart(bodyPart)
encoded.appendData(encodedData)
}
return encoded
}
/**
Writes the appended body parts into the given file URL.
This process is facilitated by reading and writing with input and output streams, respectively. Thus,
this approach is very memory efficient and should be used for large body part data.
- parameter fileURL: The file URL to write the multipart form data into.
- throws: An `NSError` if encoding encounters an error.
*/
public func writeEncodedDataToDisk(fileURL: NSURL) throws {
if let bodyPartError = bodyPartError {
throw bodyPartError
}
if let path = fileURL.path where NSFileManager.defaultManager().fileExistsAtPath(path) {
let failureReason = "A file already exists at the given file URL: \(fileURL)"
throw Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason)
} else if !fileURL.fileURL {
let failureReason = "The URL does not point to a valid file: \(fileURL)"
throw Error.errorWithCode(NSURLErrorBadURL, failureReason: failureReason)
}
let outputStream: NSOutputStream
if let possibleOutputStream = NSOutputStream(URL: fileURL, append: false) {
outputStream = possibleOutputStream
} else {
let failureReason = "Failed to create an output stream with the given URL: \(fileURL)"
throw Error.errorWithCode(NSURLErrorCannotOpenFile, failureReason: failureReason)
}
outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream.open()
self.bodyParts.first?.hasInitialBoundary = true
self.bodyParts.last?.hasFinalBoundary = true
for bodyPart in self.bodyParts {
try writeBodyPart(bodyPart, toOutputStream: outputStream)
}
outputStream.close()
outputStream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
}
// MARK: - Private - Body Part Encoding
private func encodeBodyPart(bodyPart: BodyPart) throws -> NSData {
let encoded = NSMutableData()
let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()
encoded.appendData(initialData)
let headerData = encodeHeaderDataForBodyPart(bodyPart)
encoded.appendData(headerData)
let bodyStreamData = try encodeBodyStreamDataForBodyPart(bodyPart)
encoded.appendData(bodyStreamData)
if bodyPart.hasFinalBoundary {
encoded.appendData(finalBoundaryData())
}
return encoded
}
private func encodeHeaderDataForBodyPart(bodyPart: BodyPart) -> NSData {
var headerText = ""
for (key, value) in bodyPart.headers {
headerText += "\(key): \(value)\(EncodingCharacters.CRLF)"
}
headerText += EncodingCharacters.CRLF
return headerText.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
private func encodeBodyStreamDataForBodyPart(bodyPart: BodyPart) throws -> NSData {
let inputStream = bodyPart.bodyStream
inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream.open()
var error: NSError?
let encoded = NSMutableData()
while inputStream.hasBytesAvailable {
var buffer = [UInt8](count: streamBufferSize, repeatedValue: 0)
let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
if inputStream.streamError != nil {
error = inputStream.streamError
break
}
if bytesRead > 0 {
encoded.appendBytes(buffer, length: bytesRead)
} else if bytesRead < 0 {
let failureReason = "Failed to read from input stream: \(inputStream)"
error = Error.errorWithCode(.InputStreamReadFailed, failureReason: failureReason)
break
} else {
break
}
}
inputStream.close()
inputStream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
if let error = error {
throw error
}
return encoded
}
// MARK: - Private - Writing Body Part to Output Stream
private func writeBodyPart(bodyPart: BodyPart, toOutputStream outputStream: NSOutputStream) throws {
try writeInitialBoundaryDataForBodyPart(bodyPart, toOutputStream: outputStream)
try writeHeaderDataForBodyPart(bodyPart, toOutputStream: outputStream)
try writeBodyStreamForBodyPart(bodyPart, toOutputStream: outputStream)
try writeFinalBoundaryDataForBodyPart(bodyPart, toOutputStream: outputStream)
}
private func writeInitialBoundaryDataForBodyPart(
bodyPart: BodyPart,
toOutputStream outputStream: NSOutputStream)
throws
{
let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()
return try writeData(initialData, toOutputStream: outputStream)
}
private func writeHeaderDataForBodyPart(bodyPart: BodyPart, toOutputStream outputStream: NSOutputStream) throws {
let headerData = encodeHeaderDataForBodyPart(bodyPart)
return try writeData(headerData, toOutputStream: outputStream)
}
private func writeBodyStreamForBodyPart(bodyPart: BodyPart, toOutputStream outputStream: NSOutputStream) throws {
let inputStream = bodyPart.bodyStream
inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream.open()
while inputStream.hasBytesAvailable {
var buffer = [UInt8](count: streamBufferSize, repeatedValue: 0)
let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
if let streamError = inputStream.streamError {
throw streamError
}
if bytesRead > 0 {
if buffer.count != bytesRead {
buffer = Array(buffer[0.. 0 {
if outputStream.hasSpaceAvailable {
let bytesWritten = outputStream.write(buffer, maxLength: bytesToWrite)
if let streamError = outputStream.streamError {
throw streamError
}
if bytesWritten < 0 {
let failureReason = "Failed to write to output stream: \(outputStream)"
throw Error.errorWithCode(.OutputStreamWriteFailed, failureReason: failureReason)
}
bytesToWrite -= bytesWritten
if bytesToWrite > 0 {
buffer = Array(buffer[bytesWritten.. String {
if let
id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, nil)?.takeRetainedValue(),
contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue()
{
return contentType as String
}
return "application/octet-stream"
}
// MARK: - Private - Content Headers
private func contentHeaders(name name: String) -> [String: String] {
return ["Content-Disposition": "form-data; name=\"\(name)\""]
}
private func contentHeaders(name name: String, mimeType: String) -> [String: String] {
return [
"Content-Disposition": "form-data; name=\"\(name)\"",
"Content-Type": "\(mimeType)"
]
}
private func contentHeaders(name name: String, fileName: String, mimeType: String) -> [String: String] {
return [
"Content-Disposition": "form-data; name=\"\(name)\"; filename=\"\(fileName)\"",
"Content-Type": "\(mimeType)"
]
}
// MARK: - Private - Boundary Encoding
private func initialBoundaryData() -> NSData {
return BoundaryGenerator.boundaryData(boundaryType: .Initial, boundary: boundary)
}
private func encapsulatedBoundaryData() -> NSData {
return BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundary: boundary)
}
private func finalBoundaryData() -> NSData {
return BoundaryGenerator.boundaryData(boundaryType: .Final, boundary: boundary)
}
// MARK: - Private - Errors
private func setBodyPartError(error: NSError) {
if bodyPartError == nil {
bodyPartError = error
}
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/NetworkReachabilityManager.swift
================================================
// NetworkReachabilityManager.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if !os(watchOS)
import Foundation
import SystemConfiguration
/**
The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and
WiFi network interfaces.
Reachability can be used to determine background information about why a network operation failed, or to retry
network requests when a connection is established. It should not be used to prevent a user from initiating a network
request, as it's possible that an initial request may be required to establish reachability.
*/
public class NetworkReachabilityManager {
/**
Defines the various states of network reachability.
- Unknown: It is unknown whether the network is reachable.
- NotReachable: The network is not reachable.
- ReachableOnWWAN: The network is reachable over the WWAN connection.
- ReachableOnWiFi: The network is reachable over the WiFi connection.
*/
public enum NetworkReachabilityStatus {
case Unknown
case NotReachable
case Reachable(ConnectionType)
}
/**
Defines the various connection types detected by reachability flags.
- EthernetOrWiFi: The connection type is either over Ethernet or WiFi.
- WWAN: The connection type is a WWAN connection.
*/
public enum ConnectionType {
case EthernetOrWiFi
case WWAN
}
/// A closure executed when the network reachability status changes. The closure takes a single argument: the
/// network reachability status.
public typealias Listener = NetworkReachabilityStatus -> Void
// MARK: - Properties
/// Whether the network is currently reachable.
public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi }
/// Whether the network is currently reachable over the WWAN interface.
public var isReachableOnWWAN: Bool { return networkReachabilityStatus == .Reachable(.WWAN) }
/// Whether the network is currently reachable over Ethernet or WiFi interface.
public var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) }
/// The current network reachability status.
public var networkReachabilityStatus: NetworkReachabilityStatus {
guard let flags = self.flags else { return .Unknown }
return networkReachabilityStatusForFlags(flags)
}
/// The dispatch queue to execute the `listener` closure on.
public var listenerQueue: dispatch_queue_t = dispatch_get_main_queue()
/// A closure executed when the network reachability status changes.
public var listener: Listener?
private var flags: SCNetworkReachabilityFlags? {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachability, &flags) {
return flags
}
return nil
}
private let reachability: SCNetworkReachability
private var previousFlags: SCNetworkReachabilityFlags
// MARK: - Initialization
/**
Creates a `NetworkReachabilityManager` instance with the specified host.
- parameter host: The host used to evaluate network reachability.
- returns: The new `NetworkReachabilityManager` instance.
*/
public convenience init?(host: String) {
guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil }
self.init(reachability: reachability)
}
/**
Creates a `NetworkReachabilityManager` instance with the default socket address (`sockaddr_in6`).
- returns: The new `NetworkReachabilityManager` instance.
*/
public convenience init?() {
var address = sockaddr_in6()
address.sin6_len = UInt8(sizeofValue(address))
address.sin6_family = sa_family_t(AF_INET6)
guard let reachability = withUnsafePointer(&address, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else { return nil }
self.init(reachability: reachability)
}
private init(reachability: SCNetworkReachability) {
self.reachability = reachability
self.previousFlags = SCNetworkReachabilityFlags()
}
deinit {
stopListening()
}
// MARK: - Listening
/**
Starts listening for changes in network reachability status.
- returns: `true` if listening was started successfully, `false` otherwise.
*/
public func startListening() -> Bool {
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())
let callbackEnabled = SCNetworkReachabilitySetCallback(
reachability,
{ (_, flags, info) in
let reachability = Unmanaged.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
reachability.notifyListener(flags)
},
&context
)
let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue)
dispatch_async(listenerQueue) {
self.previousFlags = SCNetworkReachabilityFlags()
self.notifyListener(self.flags ?? SCNetworkReachabilityFlags())
}
return callbackEnabled && queueEnabled
}
/**
Stops listening for changes in network reachability status.
*/
public func stopListening() {
SCNetworkReachabilitySetCallback(reachability, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachability, nil)
}
// MARK: - Internal - Listener Notification
func notifyListener(flags: SCNetworkReachabilityFlags) {
guard previousFlags != flags else { return }
previousFlags = flags
listener?(networkReachabilityStatusForFlags(flags))
}
// MARK: - Internal - Network Reachability Status
func networkReachabilityStatusForFlags(flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus {
guard flags.contains(.Reachable) else { return .NotReachable }
var networkStatus: NetworkReachabilityStatus = .NotReachable
if !flags.contains(.ConnectionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
if flags.contains(.ConnectionOnDemand) || flags.contains(.ConnectionOnTraffic) {
if !flags.contains(.InterventionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
}
#if os(iOS)
if flags.contains(.IsWWAN) { networkStatus = .Reachable(.WWAN) }
#endif
return networkStatus
}
}
// MARK: -
extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {}
/**
Returns whether the two network reachability status values are equal.
- parameter lhs: The left-hand side value to compare.
- parameter rhs: The right-hand side value to compare.
- returns: `true` if the two values are equal, `false` otherwise.
*/
public func ==(
lhs: NetworkReachabilityManager.NetworkReachabilityStatus,
rhs: NetworkReachabilityManager.NetworkReachabilityStatus)
-> Bool
{
switch (lhs, rhs) {
case (.Unknown, .Unknown):
return true
case (.NotReachable, .NotReachable):
return true
case let (.Reachable(lhsConnectionType), .Reachable(rhsConnectionType)):
return lhsConnectionType == rhsConnectionType
default:
return false
}
}
#endif
================================================
FILE: Sublime/Pods/Alamofire/Source/Notifications.swift
================================================
// Notifications.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/// Contains all the `NSNotification` names posted by Alamofire with descriptions of each notification's payload.
public struct Notifications {
/// Used as a namespace for all `NSURLSessionTask` related notifications.
public struct Task {
/// Notification posted when an `NSURLSessionTask` is resumed. The notification `object` contains the resumed
/// `NSURLSessionTask`.
public static let DidResume = "com.alamofire.notifications.task.didResume"
/// Notification posted when an `NSURLSessionTask` is suspended. The notification `object` contains the
/// suspended `NSURLSessionTask`.
public static let DidSuspend = "com.alamofire.notifications.task.didSuspend"
/// Notification posted when an `NSURLSessionTask` is cancelled. The notification `object` contains the
/// cancelled `NSURLSessionTask`.
public static let DidCancel = "com.alamofire.notifications.task.didCancel"
/// Notification posted when an `NSURLSessionTask` is completed. The notification `object` contains the
/// completed `NSURLSessionTask`.
public static let DidComplete = "com.alamofire.notifications.task.didComplete"
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/ParameterEncoding.swift
================================================
// ParameterEncoding.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
HTTP method definitions.
See https://tools.ietf.org/html/rfc7231#section-4.3
*/
public enum Method: String {
case OPTIONS, GET, HEAD, POST, PUT, PATCH, DELETE, TRACE, CONNECT
}
// MARK: ParameterEncoding
/**
Used to specify the way in which a set of parameters are applied to a URL request.
- `URL`: Creates a query string to be set as or appended to any existing URL query for `GET`, `HEAD`,
and `DELETE` requests, or set as the body for requests with any other HTTP method. The
`Content-Type` HTTP header field of an encoded request with HTTP body is set to
`application/x-www-form-urlencoded; charset=utf-8`. Since there is no published specification
for how to encode collection types, the convention of appending `[]` to the key for array
values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for nested
dictionary values (`foo[bar]=baz`).
- `URLEncodedInURL`: Creates query string to be set as or appended to any existing URL query. Uses the same
implementation as the `.URL` case, but always applies the encoded result to the URL.
- `JSON`: Uses `NSJSONSerialization` to create a JSON representation of the parameters object, which is
set as the body of the request. The `Content-Type` HTTP header field of an encoded request is
set to `application/json`.
- `PropertyList`: Uses `NSPropertyListSerialization` to create a plist representation of the parameters object,
according to the associated format and write options values, which is set as the body of the
request. The `Content-Type` HTTP header field of an encoded request is set to
`application/x-plist`.
- `Custom`: Uses the associated closure value to construct a new request given an existing request and
parameters.
*/
public enum ParameterEncoding {
case URL
case URLEncodedInURL
case JSON
case PropertyList(NSPropertyListFormat, NSPropertyListWriteOptions)
case Custom((URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?))
/**
Creates a URL request by encoding parameters and applying them onto an existing request.
- parameter URLRequest: The request to have parameters applied
- parameter parameters: The parameters to apply
- returns: A tuple containing the constructed request and the error that occurred during parameter encoding,
if any.
*/
public func encode(
URLRequest: URLRequestConvertible,
parameters: [String: AnyObject]?)
-> (NSMutableURLRequest, NSError?)
{
var mutableURLRequest = URLRequest.URLRequest
guard let parameters = parameters else { return (mutableURLRequest, nil) }
var encodingError: NSError? = nil
switch self {
case .URL, .URLEncodedInURL:
func query(parameters: [String: AnyObject]) -> String {
var components: [(String, String)] = []
for key in parameters.keys.sort(<) {
let value = parameters[key]!
components += queryComponents(key, value)
}
return (components.map { "\($0)=\($1)" } as [String]).joinWithSeparator("&")
}
func encodesParametersInURL(method: Method) -> Bool {
switch self {
case .URLEncodedInURL:
return true
default:
break
}
switch method {
case .GET, .HEAD, .DELETE:
return true
default:
return false
}
}
if let method = Method(rawValue: mutableURLRequest.HTTPMethod) where encodesParametersInURL(method) {
if let
URLComponents = NSURLComponents(URL: mutableURLRequest.URL!, resolvingAgainstBaseURL: false)
where !parameters.isEmpty
{
let percentEncodedQuery = (URLComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
URLComponents.percentEncodedQuery = percentEncodedQuery
mutableURLRequest.URL = URLComponents.URL
}
} else {
if mutableURLRequest.valueForHTTPHeaderField("Content-Type") == nil {
mutableURLRequest.setValue(
"application/x-www-form-urlencoded; charset=utf-8",
forHTTPHeaderField: "Content-Type"
)
}
mutableURLRequest.HTTPBody = query(parameters).dataUsingEncoding(
NSUTF8StringEncoding,
allowLossyConversion: false
)
}
case .JSON:
do {
let options = NSJSONWritingOptions()
let data = try NSJSONSerialization.dataWithJSONObject(parameters, options: options)
mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
mutableURLRequest.HTTPBody = data
} catch {
encodingError = error as NSError
}
case .PropertyList(let format, let options):
do {
let data = try NSPropertyListSerialization.dataWithPropertyList(
parameters,
format: format,
options: options
)
mutableURLRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type")
mutableURLRequest.HTTPBody = data
} catch {
encodingError = error as NSError
}
case .Custom(let closure):
(mutableURLRequest, encodingError) = closure(mutableURLRequest, parameters)
}
return (mutableURLRequest, encodingError)
}
/**
Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion.
- parameter key: The key of the query component.
- parameter value: The value of the query component.
- returns: The percent-escaped, URL encoded query string components.
*/
public func queryComponents(key: String, _ value: AnyObject) -> [(String, String)] {
var components: [(String, String)] = []
if let dictionary = value as? [String: AnyObject] {
for (nestedKey, value) in dictionary {
components += queryComponents("\(key)[\(nestedKey)]", value)
}
} else if let array = value as? [AnyObject] {
for value in array {
components += queryComponents("\(key)[]", value)
}
} else {
components.append((escape(key), escape("\(value)")))
}
return components
}
/**
Returns a percent-escaped string following RFC 3986 for a query string key or value.
RFC 3986 states that the following characters are "reserved" characters.
- General Delimiters: ":", "#", "[", "]", "@", "?", "/"
- Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
should be percent-escaped in the query string.
- parameter string: The string to be percent-escaped.
- returns: The percent-escaped string.
*/
public func escape(string: String) -> String {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
let allowedCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy() as! NSMutableCharacterSet
allowedCharacterSet.removeCharactersInString(generalDelimitersToEncode + subDelimitersToEncode)
var escaped = ""
//==========================================================================================================
//
// Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
// hundred Chinense characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
// longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
// info, please refer to:
//
// - https://github.com/Alamofire/Alamofire/issues/206
//
//==========================================================================================================
if #available(iOS 8.3, OSX 10.10, *) {
escaped = string.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet) ?? string
} else {
let batchSize = 50
var index = string.startIndex
while index != string.endIndex {
let startIndex = index
let endIndex = index.advancedBy(batchSize, limit: string.endIndex)
let range = Range(start: startIndex, end: endIndex)
let substring = string.substringWithRange(range)
escaped += substring.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet) ?? substring
index = endIndex
}
}
return escaped
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Request.swift
================================================
// Request.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
Responsible for sending a request and receiving the response and associated data from the server, as well as
managing its underlying `NSURLSessionTask`.
*/
public class Request {
// MARK: - Properties
/// The delegate for the underlying task.
public let delegate: TaskDelegate
/// The underlying task.
public var task: NSURLSessionTask { return delegate.task }
/// The session belonging to the underlying task.
public let session: NSURLSession
/// The request sent or to be sent to the server.
public var request: NSURLRequest? { return task.originalRequest }
/// The response received from the server, if any.
public var response: NSHTTPURLResponse? { return task.response as? NSHTTPURLResponse }
/// The progress of the request lifecycle.
public var progress: NSProgress { return delegate.progress }
var startTime: CFAbsoluteTime?
var endTime: CFAbsoluteTime?
// MARK: - Lifecycle
init(session: NSURLSession, task: NSURLSessionTask) {
self.session = session
switch task {
case is NSURLSessionUploadTask:
delegate = UploadTaskDelegate(task: task)
case is NSURLSessionDataTask:
delegate = DataTaskDelegate(task: task)
case is NSURLSessionDownloadTask:
delegate = DownloadTaskDelegate(task: task)
default:
delegate = TaskDelegate(task: task)
}
delegate.queue.addOperationWithBlock { self.endTime = CFAbsoluteTimeGetCurrent() }
}
// MARK: - Authentication
/**
Associates an HTTP Basic credential with the request.
- parameter user: The user.
- parameter password: The password.
- parameter persistence: The URL credential persistence. `.ForSession` by default.
- returns: The request.
*/
public func authenticate(
user user: String,
password: String,
persistence: NSURLCredentialPersistence = .ForSession)
-> Self
{
let credential = NSURLCredential(user: user, password: password, persistence: persistence)
return authenticate(usingCredential: credential)
}
/**
Associates a specified credential with the request.
- parameter credential: The credential.
- returns: The request.
*/
public func authenticate(usingCredential credential: NSURLCredential) -> Self {
delegate.credential = credential
return self
}
// MARK: - Progress
/**
Sets a closure to be called periodically during the lifecycle of the request as data is written to or read
from the server.
- For uploads, the progress closure returns the bytes written, total bytes written, and total bytes expected
to write.
- For downloads and data tasks, the progress closure returns the bytes read, total bytes read, and total bytes
expected to read.
- parameter closure: The code to be executed periodically during the lifecycle of the request.
- returns: The request.
*/
public func progress(closure: ((Int64, Int64, Int64) -> Void)? = nil) -> Self {
if let uploadDelegate = delegate as? UploadTaskDelegate {
uploadDelegate.uploadProgress = closure
} else if let dataDelegate = delegate as? DataTaskDelegate {
dataDelegate.dataProgress = closure
} else if let downloadDelegate = delegate as? DownloadTaskDelegate {
downloadDelegate.downloadProgress = closure
}
return self
}
/**
Sets a closure to be called periodically during the lifecycle of the request as data is read from the server.
This closure returns the bytes most recently received from the server, not including data from previous calls.
If this closure is set, data will only be available within this closure, and will not be saved elsewhere. It is
also important to note that the `response` closure will be called with nil `responseData`.
- parameter closure: The code to be executed periodically during the lifecycle of the request.
- returns: The request.
*/
public func stream(closure: (NSData -> Void)? = nil) -> Self {
if let dataDelegate = delegate as? DataTaskDelegate {
dataDelegate.dataStream = closure
}
return self
}
// MARK: - State
/**
Resumes the request.
*/
public func resume() {
if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }
task.resume()
NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidResume, object: task)
}
/**
Suspends the request.
*/
public func suspend() {
task.suspend()
NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidSuspend, object: task)
}
/**
Cancels the request.
*/
public func cancel() {
if let
downloadDelegate = delegate as? DownloadTaskDelegate,
downloadTask = downloadDelegate.downloadTask
{
downloadTask.cancelByProducingResumeData { data in
downloadDelegate.resumeData = data
}
} else {
task.cancel()
}
NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidCancel, object: task)
}
// MARK: - TaskDelegate
/**
The task delegate is responsible for handling all delegate callbacks for the underlying task as well as
executing all operations attached to the serial operation queue upon task completion.
*/
public class TaskDelegate: NSObject {
/// The serial operation queue used to execute all operations after the task completes.
public let queue: NSOperationQueue
let task: NSURLSessionTask
let progress: NSProgress
var data: NSData? { return nil }
var error: NSError?
var initialResponseTime: CFAbsoluteTime?
var credential: NSURLCredential?
init(task: NSURLSessionTask) {
self.task = task
self.progress = NSProgress(totalUnitCount: 0)
self.queue = {
let operationQueue = NSOperationQueue()
operationQueue.maxConcurrentOperationCount = 1
operationQueue.suspended = true
if #available(OSX 10.10, *) {
operationQueue.qualityOfService = NSQualityOfService.Utility
}
return operationQueue
}()
}
deinit {
queue.cancelAllOperations()
queue.suspended = false
}
// MARK: - NSURLSessionTaskDelegate
// MARK: Override Closures
var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?
var taskDidReceiveChallenge: ((NSURLSession, NSURLSessionTask, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
var taskNeedNewBodyStream: ((NSURLSession, NSURLSessionTask) -> NSInputStream?)?
var taskDidCompleteWithError: ((NSURLSession, NSURLSessionTask, NSError?) -> Void)?
// MARK: Delegate Methods
func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
willPerformHTTPRedirection response: NSHTTPURLResponse,
newRequest request: NSURLRequest,
completionHandler: ((NSURLRequest?) -> Void))
{
var redirectRequest: NSURLRequest? = request
if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
}
completionHandler(redirectRequest)
}
func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
{
var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
var credential: NSURLCredential?
if let taskDidReceiveChallenge = taskDidReceiveChallenge {
(disposition, credential) = taskDidReceiveChallenge(session, task, challenge)
} else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let host = challenge.protectionSpace.host
if let
serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
serverTrust = challenge.protectionSpace.serverTrust
{
if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
disposition = .UseCredential
credential = NSURLCredential(forTrust: serverTrust)
} else {
disposition = .CancelAuthenticationChallenge
}
}
} else {
if challenge.previousFailureCount > 0 {
disposition = .CancelAuthenticationChallenge
} else {
credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
if credential != nil {
disposition = .UseCredential
}
}
}
completionHandler(disposition, credential)
}
func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
needNewBodyStream completionHandler: ((NSInputStream?) -> Void))
{
var bodyStream: NSInputStream?
if let taskNeedNewBodyStream = taskNeedNewBodyStream {
bodyStream = taskNeedNewBodyStream(session, task)
}
completionHandler(bodyStream)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if let taskDidCompleteWithError = taskDidCompleteWithError {
taskDidCompleteWithError(session, task, error)
} else {
if let error = error {
self.error = error
if let
downloadDelegate = self as? DownloadTaskDelegate,
userInfo = error.userInfo as? [String: AnyObject],
resumeData = userInfo[NSURLSessionDownloadTaskResumeData] as? NSData
{
downloadDelegate.resumeData = resumeData
}
}
queue.suspended = false
}
}
}
// MARK: - DataTaskDelegate
class DataTaskDelegate: TaskDelegate, NSURLSessionDataDelegate {
var dataTask: NSURLSessionDataTask? { return task as? NSURLSessionDataTask }
private var totalBytesReceived: Int64 = 0
private var mutableData: NSMutableData
override var data: NSData? {
if dataStream != nil {
return nil
} else {
return mutableData
}
}
private var expectedContentLength: Int64?
private var dataProgress: ((bytesReceived: Int64, totalBytesReceived: Int64, totalBytesExpectedToReceive: Int64) -> Void)?
private var dataStream: ((data: NSData) -> Void)?
override init(task: NSURLSessionTask) {
mutableData = NSMutableData()
super.init(task: task)
}
// MARK: - NSURLSessionDataDelegate
// MARK: Override Closures
var dataTaskDidReceiveResponse: ((NSURLSession, NSURLSessionDataTask, NSURLResponse) -> NSURLSessionResponseDisposition)?
var dataTaskDidBecomeDownloadTask: ((NSURLSession, NSURLSessionDataTask, NSURLSessionDownloadTask) -> Void)?
var dataTaskDidReceiveData: ((NSURLSession, NSURLSessionDataTask, NSData) -> Void)?
var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse?)?
// MARK: Delegate Methods
func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
didReceiveResponse response: NSURLResponse,
completionHandler: (NSURLSessionResponseDisposition -> Void))
{
var disposition: NSURLSessionResponseDisposition = .Allow
expectedContentLength = response.expectedContentLength
if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
disposition = dataTaskDidReceiveResponse(session, dataTask, response)
}
completionHandler(disposition)
}
func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask)
{
dataTaskDidBecomeDownloadTask?(session, dataTask, downloadTask)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else {
if let dataStream = dataStream {
dataStream(data: data)
} else {
mutableData.appendData(data)
}
totalBytesReceived += data.length
let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
progress.totalUnitCount = totalBytesExpected
progress.completedUnitCount = totalBytesReceived
dataProgress?(
bytesReceived: Int64(data.length),
totalBytesReceived: totalBytesReceived,
totalBytesExpectedToReceive: totalBytesExpected
)
}
}
func URLSession(
session: NSURLSession,
dataTask: NSURLSessionDataTask,
willCacheResponse proposedResponse: NSCachedURLResponse,
completionHandler: ((NSCachedURLResponse?) -> Void))
{
var cachedResponse: NSCachedURLResponse? = proposedResponse
if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
cachedResponse = dataTaskWillCacheResponse(session, dataTask, proposedResponse)
}
completionHandler(cachedResponse)
}
}
}
// MARK: - CustomStringConvertible
extension Request: CustomStringConvertible {
/**
The textual representation used when written to an output stream, which includes the HTTP method and URL, as
well as the response status code if a response has been received.
*/
public var description: String {
var components: [String] = []
if let HTTPMethod = request?.HTTPMethod {
components.append(HTTPMethod)
}
if let URLString = request?.URL?.absoluteString {
components.append(URLString)
}
if let response = response {
components.append("(\(response.statusCode))")
}
return components.joinWithSeparator(" ")
}
}
// MARK: - CustomDebugStringConvertible
extension Request: CustomDebugStringConvertible {
func cURLRepresentation() -> String {
var components = ["$ curl -i"]
guard let
request = self.request,
URL = request.URL,
host = URL.host
else {
return "$ curl command could not be created"
}
if let HTTPMethod = request.HTTPMethod where HTTPMethod != "GET" {
components.append("-X \(HTTPMethod)")
}
if let credentialStorage = self.session.configuration.URLCredentialStorage {
let protectionSpace = NSURLProtectionSpace(
host: host,
port: URL.port?.integerValue ?? 0,
`protocol`: URL.scheme,
realm: host,
authenticationMethod: NSURLAuthenticationMethodHTTPBasic
)
if let credentials = credentialStorage.credentialsForProtectionSpace(protectionSpace)?.values {
for credential in credentials {
components.append("-u \(credential.user!):\(credential.password!)")
}
} else {
if let credential = delegate.credential {
components.append("-u \(credential.user!):\(credential.password!)")
}
}
}
if session.configuration.HTTPShouldSetCookies {
if let
cookieStorage = session.configuration.HTTPCookieStorage,
cookies = cookieStorage.cookiesForURL(URL) where !cookies.isEmpty
{
let string = cookies.reduce("") { $0 + "\($1.name)=\($1.value ?? String());" }
components.append("-b \"\(string.substringToIndex(string.endIndex.predecessor()))\"")
}
}
if let headerFields = request.allHTTPHeaderFields {
for (field, value) in headerFields {
switch field {
case "Cookie":
continue
default:
components.append("-H \"\(field): \(value)\"")
}
}
}
if let additionalHeaders = session.configuration.HTTPAdditionalHeaders {
for (field, value) in additionalHeaders {
switch field {
case "Cookie":
continue
default:
components.append("-H \"\(field): \(value)\"")
}
}
}
if let
HTTPBodyData = request.HTTPBody,
HTTPBody = String(data: HTTPBodyData, encoding: NSUTF8StringEncoding)
{
let escapedBody = HTTPBody.stringByReplacingOccurrencesOfString("\"", withString: "\\\"")
components.append("-d \"\(escapedBody)\"")
}
components.append("\"\(URL.absoluteString)\"")
return components.joinWithSeparator(" \\\n\t")
}
/// The textual representation used when written to an output stream, in the form of a cURL command.
public var debugDescription: String {
return cURLRepresentation()
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Response.swift
================================================
// Response.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/// Used to store all response data returned from a completed `Request`.
public struct Response {
/// The URL request sent to the server.
public let request: NSURLRequest?
/// The server's response to the URL request.
public let response: NSHTTPURLResponse?
/// The data returned by the server.
public let data: NSData?
/// The result of response serialization.
public let result: Result
/// The timeline of the complete lifecycle of the `Request`.
public let timeline: Timeline
/**
Initializes the `Response` instance with the specified URL request, URL response, server data and response
serialization result.
- parameter request: The URL request sent to the server.
- parameter response: The server's response to the URL request.
- parameter data: The data returned by the server.
- parameter result: The result of response serialization.
- parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
- returns: the new `Response` instance.
*/
public init(
request: NSURLRequest?,
response: NSHTTPURLResponse?,
data: NSData?,
result: Result,
timeline: Timeline = Timeline())
{
self.request = request
self.response = response
self.data = data
self.result = result
self.timeline = timeline
}
}
// MARK: - CustomStringConvertible
extension Response: CustomStringConvertible {
/// The textual representation used when written to an output stream, which includes whether the result was a
/// success or failure.
public var description: String {
return result.debugDescription
}
}
// MARK: - CustomDebugStringConvertible
extension Response: CustomDebugStringConvertible {
/// The debug textual representation used when written to an output stream, which includes the URL request, the URL
/// response, the server data and the response serialization result.
public var debugDescription: String {
var output: [String] = []
output.append(request != nil ? "[Request]: \(request!)" : "[Request]: nil")
output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
output.append("[Data]: \(data?.length ?? 0) bytes")
output.append("[Result]: \(result.debugDescription)")
output.append("[Timeline]: \(timeline.debugDescription)")
return output.joinWithSeparator("\n")
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/ResponseSerialization.swift
================================================
// ResponseSerialization.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// MARK: ResponseSerializer
/**
The type in which all response serializers must conform to in order to serialize a response.
*/
public protocol ResponseSerializerType {
/// The type of serialized object to be created by this `ResponseSerializerType`.
typealias SerializedObject
/// The type of error to be created by this `ResponseSerializer` if serialization fails.
typealias ErrorObject: ErrorType
/**
A closure used by response handlers that takes a request, response, data and error and returns a result.
*/
var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result { get }
}
// MARK: -
/**
A generic `ResponseSerializerType` used to serialize a request, response, and data into a serialized object.
*/
public struct ResponseSerializer: ResponseSerializerType {
/// The type of serialized object to be created by this `ResponseSerializer`.
public typealias SerializedObject = Value
/// The type of error to be created by this `ResponseSerializer` if serialization fails.
public typealias ErrorObject = Error
/**
A closure used by response handlers that takes a request, response, data and error and returns a result.
*/
public var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result
/**
Initializes the `ResponseSerializer` instance with the given serialize response closure.
- parameter serializeResponse: The closure used to serialize the response.
- returns: The new generic response serializer instance.
*/
public init(serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result) {
self.serializeResponse = serializeResponse
}
}
// MARK: - Default
extension Request {
/**
Adds a handler to be called once the request has finished.
- parameter queue: The queue on which the completion handler is dispatched.
- parameter completionHandler: The code to be executed once the request has finished.
- returns: The request.
*/
public func response(
queue queue: dispatch_queue_t? = nil,
completionHandler: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Void)
-> Self
{
delegate.queue.addOperationWithBlock {
dispatch_async(queue ?? dispatch_get_main_queue()) {
completionHandler(self.request, self.response, self.delegate.data, self.delegate.error)
}
}
return self
}
/**
Adds a handler to be called once the request has finished.
- parameter queue: The queue on which the completion handler is dispatched.
- parameter responseSerializer: The response serializer responsible for serializing the request, response,
and data.
- parameter completionHandler: The code to be executed once the request has finished.
- returns: The request.
*/
public func response(
queue queue: dispatch_queue_t? = nil,
responseSerializer: T,
completionHandler: Response -> Void)
-> Self
{
delegate.queue.addOperationWithBlock {
let result = responseSerializer.serializeResponse(
self.request,
self.response,
self.delegate.data,
self.delegate.error
)
let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
let timeline = Timeline(
requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
initialResponseTime: initialResponseTime,
requestCompletedTime: requestCompletedTime,
serializationCompletedTime: CFAbsoluteTimeGetCurrent()
)
let response = Response(
request: self.request,
response: self.response,
data: self.delegate.data,
result: result,
timeline: timeline
)
dispatch_async(queue ?? dispatch_get_main_queue()) { completionHandler(response) }
}
return self
}
}
// MARK: - Data
extension Request {
/**
Creates a response serializer that returns the associated data as-is.
- returns: A data response serializer.
*/
public static func dataResponseSerializer() -> ResponseSerializer {
return ResponseSerializer { _, response, data, error in
guard error == nil else { return .Failure(error!) }
if let response = response where response.statusCode == 204 { return .Success(NSData()) }
guard let validData = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
return .Success(validData)
}
}
/**
Adds a handler to be called once the request has finished.
- parameter completionHandler: The code to be executed once the request has finished.
- returns: The request.
*/
public func responseData(completionHandler: Response -> Void) -> Self {
return response(responseSerializer: Request.dataResponseSerializer(), completionHandler: completionHandler)
}
}
// MARK: - String
extension Request {
/**
Creates a response serializer that returns a string initialized from the response data with the specified
string encoding.
- parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
response, falling back to the default HTTP default character set, ISO-8859-1.
- returns: A string response serializer.
*/
public static func stringResponseSerializer(
var encoding encoding: NSStringEncoding? = nil)
-> ResponseSerializer
{
return ResponseSerializer { _, response, data, error in
guard error == nil else { return .Failure(error!) }
if let response = response where response.statusCode == 204 { return .Success("") }
guard let validData = data else {
let failureReason = "String could not be serialized. Input data was nil."
let error = Error.errorWithCode(.StringSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
if let encodingName = response?.textEncodingName where encoding == nil {
encoding = CFStringConvertEncodingToNSStringEncoding(
CFStringConvertIANACharSetNameToEncoding(encodingName)
)
}
let actualEncoding = encoding ?? NSISOLatin1StringEncoding
if let string = String(data: validData, encoding: actualEncoding) {
return .Success(string)
} else {
let failureReason = "String could not be serialized with encoding: \(actualEncoding)"
let error = Error.errorWithCode(.StringSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
}
}
/**
Adds a handler to be called once the request has finished.
- parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
server response, falling back to the default HTTP default character set,
ISO-8859-1.
- parameter completionHandler: A closure to be executed once the request has finished.
- returns: The request.
*/
public func responseString(
encoding encoding: NSStringEncoding? = nil,
completionHandler: Response -> Void)
-> Self
{
return response(
responseSerializer: Request.stringResponseSerializer(encoding: encoding),
completionHandler: completionHandler
)
}
}
// MARK: - JSON
extension Request {
/**
Creates a response serializer that returns a JSON object constructed from the response data using
`NSJSONSerialization` with the specified reading options.
- parameter options: The JSON serialization reading options. `.AllowFragments` by default.
- returns: A JSON object response serializer.
*/
public static func JSONResponseSerializer(
options options: NSJSONReadingOptions = .AllowFragments)
-> ResponseSerializer
{
return ResponseSerializer { _, response, data, error in
guard error == nil else { return .Failure(error!) }
if let response = response where response.statusCode == 204 { return .Success(NSNull()) }
guard let validData = data where validData.length > 0 else {
let failureReason = "JSON could not be serialized. Input data was nil or zero length."
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
do {
let JSON = try NSJSONSerialization.JSONObjectWithData(validData, options: options)
return .Success(JSON)
} catch {
return .Failure(error as NSError)
}
}
}
/**
Adds a handler to be called once the request has finished.
- parameter options: The JSON serialization reading options. `.AllowFragments` by default.
- parameter completionHandler: A closure to be executed once the request has finished.
- returns: The request.
*/
public func responseJSON(
options options: NSJSONReadingOptions = .AllowFragments,
completionHandler: Response -> Void)
-> Self
{
return response(
responseSerializer: Request.JSONResponseSerializer(options: options),
completionHandler: completionHandler
)
}
}
// MARK: - Property List
extension Request {
/**
Creates a response serializer that returns an object constructed from the response data using
`NSPropertyListSerialization` with the specified reading options.
- parameter options: The property list reading options. `NSPropertyListReadOptions()` by default.
- returns: A property list object response serializer.
*/
public static func propertyListResponseSerializer(
options options: NSPropertyListReadOptions = NSPropertyListReadOptions())
-> ResponseSerializer
{
return ResponseSerializer { _, response, data, error in
guard error == nil else { return .Failure(error!) }
if let response = response where response.statusCode == 204 { return .Success(NSNull()) }
guard let validData = data where validData.length > 0 else {
let failureReason = "Property list could not be serialized. Input data was nil or zero length."
let error = Error.errorWithCode(.PropertyListSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
do {
let plist = try NSPropertyListSerialization.propertyListWithData(validData, options: options, format: nil)
return .Success(plist)
} catch {
return .Failure(error as NSError)
}
}
}
/**
Adds a handler to be called once the request has finished.
- parameter options: The property list reading options. `0` by default.
- parameter completionHandler: A closure to be executed once the request has finished. The closure takes 3
arguments: the URL request, the URL response, the server data and the result
produced while creating the property list.
- returns: The request.
*/
public func responsePropertyList(
options options: NSPropertyListReadOptions = NSPropertyListReadOptions(),
completionHandler: Response -> Void)
-> Self
{
return response(
responseSerializer: Request.propertyListResponseSerializer(options: options),
completionHandler: completionHandler
)
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Result.swift
================================================
// Result.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
Used to represent whether a request was successful or encountered an error.
- Success: The request and all post processing operations were successful resulting in the serialization of the
provided associated value.
- Failure: The request encountered an error resulting in a failure. The associated values are the original data
provided by the server as well as the error that caused the failure.
*/
public enum Result {
case Success(Value)
case Failure(Error)
/// Returns `true` if the result is a success, `false` otherwise.
public var isSuccess: Bool {
switch self {
case .Success:
return true
case .Failure:
return false
}
}
/// Returns `true` if the result is a failure, `false` otherwise.
public var isFailure: Bool {
return !isSuccess
}
/// Returns the associated value if the result is a success, `nil` otherwise.
public var value: Value? {
switch self {
case .Success(let value):
return value
case .Failure:
return nil
}
}
/// Returns the associated error value if the result is a failure, `nil` otherwise.
public var error: Error? {
switch self {
case .Success:
return nil
case .Failure(let error):
return error
}
}
}
// MARK: - CustomStringConvertible
extension Result: CustomStringConvertible {
/// The textual representation used when written to an output stream, which includes whether the result was a
/// success or failure.
public var description: String {
switch self {
case .Success:
return "SUCCESS"
case .Failure:
return "FAILURE"
}
}
}
// MARK: - CustomDebugStringConvertible
extension Result: CustomDebugStringConvertible {
/// The debug textual representation used when written to an output stream, which includes whether the result was a
/// success or failure in addition to the value or error.
public var debugDescription: String {
switch self {
case .Success(let value):
return "SUCCESS: \(value)"
case .Failure(let error):
return "FAILURE: \(error)"
}
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/ServerTrustPolicy.swift
================================================
// ServerTrustPolicy.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/// Responsible for managing the mapping of `ServerTrustPolicy` objects to a given host.
public class ServerTrustPolicyManager {
/// The dictionary of policies mapped to a particular host.
public let policies: [String: ServerTrustPolicy]
/**
Initializes the `ServerTrustPolicyManager` instance with the given policies.
Since different servers and web services can have different leaf certificates, intermediate and even root
certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This
allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key
pinning for host3 and disabling evaluation for host4.
- parameter policies: A dictionary of all policies mapped to a particular host.
- returns: The new `ServerTrustPolicyManager` instance.
*/
public init(policies: [String: ServerTrustPolicy]) {
self.policies = policies
}
/**
Returns the `ServerTrustPolicy` for the given host if applicable.
By default, this method will return the policy that perfectly matches the given host. Subclasses could override
this method and implement more complex mapping implementations such as wildcards.
- parameter host: The host to use when searching for a matching policy.
- returns: The server trust policy for the given host if found.
*/
public func serverTrustPolicyForHost(host: String) -> ServerTrustPolicy? {
return policies[host]
}
}
// MARK: -
extension NSURLSession {
private struct AssociatedKeys {
static var ManagerKey = "NSURLSession.ServerTrustPolicyManager"
}
var serverTrustPolicyManager: ServerTrustPolicyManager? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager
}
set (manager) {
objc_setAssociatedObject(self, &AssociatedKeys.ManagerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
// MARK: - ServerTrustPolicy
/**
The `ServerTrustPolicy` evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when
connecting to a server over a secure HTTPS connection. The policy configuration then evaluates the server trust
with a given set of criteria to determine whether the server trust is valid and the connection should be made.
Using pinned certificates or public keys for evaluation helps prevent man-in-the-middle (MITM) attacks and other
vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged
to route all communication over an HTTPS connection with pinning enabled.
- PerformDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to
validate the host provided by the challenge. Applications are encouraged to always
validate the host in production environments to guarantee the validity of the server's
certificate chain.
- PinCertificates: Uses the pinned certificates to validate the server trust. The server trust is
considered valid if one of the pinned certificates match one of the server certificates.
By validating both the certificate chain and host, certificate pinning provides a very
secure form of server trust validation mitigating most, if not all, MITM attacks.
Applications are encouraged to always validate the host and require a valid certificate
chain in production environments.
- PinPublicKeys: Uses the pinned public keys to validate the server trust. The server trust is considered
valid if one of the pinned public keys match one of the server certificate public keys.
By validating both the certificate chain and host, public key pinning provides a very
secure form of server trust validation mitigating most, if not all, MITM attacks.
Applications are encouraged to always validate the host and require a valid certificate
chain in production environments.
- DisableEvaluation: Disables all evaluation which in turn will always consider any server trust as valid.
- CustomEvaluation: Uses the associated closure to evaluate the validity of the server trust.
*/
public enum ServerTrustPolicy {
case PerformDefaultEvaluation(validateHost: Bool)
case PinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
case PinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
case DisableEvaluation
case CustomEvaluation((serverTrust: SecTrust, host: String) -> Bool)
// MARK: - Bundle Location
/**
Returns all certificates within the given bundle with a `.cer` file extension.
- parameter bundle: The bundle to search for all `.cer` files.
- returns: All certificates within the given bundle.
*/
public static func certificatesInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecCertificate] {
var certificates: [SecCertificate] = []
let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
bundle.pathsForResourcesOfType(fileExtension, inDirectory: nil)
}.flatten())
for path in paths {
if let
certificateData = NSData(contentsOfFile: path),
certificate = SecCertificateCreateWithData(nil, certificateData)
{
certificates.append(certificate)
}
}
return certificates
}
/**
Returns all public keys within the given bundle with a `.cer` file extension.
- parameter bundle: The bundle to search for all `*.cer` files.
- returns: All public keys within the given bundle.
*/
public static func publicKeysInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecKey] {
var publicKeys: [SecKey] = []
for certificate in certificatesInBundle(bundle) {
if let publicKey = publicKeyForCertificate(certificate) {
publicKeys.append(publicKey)
}
}
return publicKeys
}
// MARK: - Evaluation
/**
Evaluates whether the server trust is valid for the given host.
- parameter serverTrust: The server trust to evaluate.
- parameter host: The host of the challenge protection space.
- returns: Whether the server trust is valid.
*/
public func evaluateServerTrust(serverTrust: SecTrust, isValidForHost host: String) -> Bool {
var serverTrustIsValid = false
switch self {
case let .PerformDefaultEvaluation(validateHost):
let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
SecTrustSetPolicies(serverTrust, [policy])
serverTrustIsValid = trustIsValid(serverTrust)
case let .PinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
if validateCertificateChain {
let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
SecTrustSetPolicies(serverTrust, [policy])
SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates)
SecTrustSetAnchorCertificatesOnly(serverTrust, true)
serverTrustIsValid = trustIsValid(serverTrust)
} else {
let serverCertificatesDataArray = certificateDataForTrust(serverTrust)
let pinnedCertificatesDataArray = certificateDataForCertificates(pinnedCertificates)
outerLoop: for serverCertificateData in serverCertificatesDataArray {
for pinnedCertificateData in pinnedCertificatesDataArray {
if serverCertificateData.isEqualToData(pinnedCertificateData) {
serverTrustIsValid = true
break outerLoop
}
}
}
}
case let .PinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost):
var certificateChainEvaluationPassed = true
if validateCertificateChain {
let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
SecTrustSetPolicies(serverTrust, [policy])
certificateChainEvaluationPassed = trustIsValid(serverTrust)
}
if certificateChainEvaluationPassed {
outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeysForTrust(serverTrust) as [AnyObject] {
for pinnedPublicKey in pinnedPublicKeys as [AnyObject] {
if serverPublicKey.isEqual(pinnedPublicKey) {
serverTrustIsValid = true
break outerLoop
}
}
}
}
case .DisableEvaluation:
serverTrustIsValid = true
case let .CustomEvaluation(closure):
serverTrustIsValid = closure(serverTrust: serverTrust, host: host)
}
return serverTrustIsValid
}
// MARK: - Private - Trust Validation
private func trustIsValid(trust: SecTrust) -> Bool {
var isValid = false
var result = SecTrustResultType(kSecTrustResultInvalid)
let status = SecTrustEvaluate(trust, &result)
if status == errSecSuccess {
let unspecified = SecTrustResultType(kSecTrustResultUnspecified)
let proceed = SecTrustResultType(kSecTrustResultProceed)
isValid = result == unspecified || result == proceed
}
return isValid
}
// MARK: - Private - Certificate Data
private func certificateDataForTrust(trust: SecTrust) -> [NSData] {
var certificates: [SecCertificate] = []
for index in 0.. [NSData] {
return certificates.map { SecCertificateCopyData($0) as NSData }
}
// MARK: - Private - Public Key Extraction
private static func publicKeysForTrust(trust: SecTrust) -> [SecKey] {
var publicKeys: [SecKey] = []
for index in 0.. SecKey? {
var publicKey: SecKey?
let policy = SecPolicyCreateBasicX509()
var trust: SecTrust?
let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust)
if let trust = trust where trustCreationStatus == errSecSuccess {
publicKey = SecTrustCopyPublicKey(trust)
}
return publicKey
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Stream.swift
================================================
// Stream.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
#if !os(watchOS)
@available(iOS 9.0, OSX 10.11, tvOS 9.0, *)
extension Manager {
private enum Streamable {
case Stream(String, Int)
case NetService(NSNetService)
}
private func stream(streamable: Streamable) -> Request {
var streamTask: NSURLSessionStreamTask!
switch streamable {
case .Stream(let hostName, let port):
dispatch_sync(queue) {
streamTask = self.session.streamTaskWithHostName(hostName, port: port)
}
case .NetService(let netService):
dispatch_sync(queue) {
streamTask = self.session.streamTaskWithNetService(netService)
}
}
let request = Request(session: session, task: streamTask)
delegate[request.delegate.task] = request.delegate
if startRequestsImmediately {
request.resume()
}
return request
}
/**
Creates a request for bidirectional streaming with the given hostname and port.
- parameter hostName: The hostname of the server to connect to.
- parameter port: The port of the server to connect to.
:returns: The created stream request.
*/
public func stream(hostName hostName: String, port: Int) -> Request {
return stream(.Stream(hostName, port))
}
/**
Creates a request for bidirectional streaming with the given `NSNetService`.
- parameter netService: The net service used to identify the endpoint.
- returns: The created stream request.
*/
public func stream(netService netService: NSNetService) -> Request {
return stream(.NetService(netService))
}
}
// MARK: -
@available(iOS 9.0, OSX 10.11, tvOS 9.0, *)
extension Manager.SessionDelegate: NSURLSessionStreamDelegate {
// MARK: Override Closures
/// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:readClosedForStreamTask:`.
public var streamTaskReadClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
get {
return _streamTaskReadClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void
}
set {
_streamTaskReadClosed = newValue
}
}
/// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:writeClosedForStreamTask:`.
public var streamTaskWriteClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
get {
return _streamTaskWriteClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void
}
set {
_streamTaskWriteClosed = newValue
}
}
/// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:betterRouteDiscoveredForStreamTask:`.
public var streamTaskBetterRouteDiscovered: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
get {
return _streamTaskBetterRouteDiscovered as? (NSURLSession, NSURLSessionStreamTask) -> Void
}
set {
_streamTaskBetterRouteDiscovered = newValue
}
}
/// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:streamTask:didBecomeInputStream:outputStream:`.
public var streamTaskDidBecomeInputStream: ((NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void)? {
get {
return _streamTaskDidBecomeInputStream as? (NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void
}
set {
_streamTaskDidBecomeInputStream = newValue
}
}
// MARK: Delegate Methods
/**
Tells the delegate that the read side of the connection has been closed.
- parameter session: The session.
- parameter streamTask: The stream task.
*/
public func URLSession(session: NSURLSession, readClosedForStreamTask streamTask: NSURLSessionStreamTask) {
streamTaskReadClosed?(session, streamTask)
}
/**
Tells the delegate that the write side of the connection has been closed.
- parameter session: The session.
- parameter streamTask: The stream task.
*/
public func URLSession(session: NSURLSession, writeClosedForStreamTask streamTask: NSURLSessionStreamTask) {
streamTaskWriteClosed?(session, streamTask)
}
/**
Tells the delegate that the system has determined that a better route to the host is available.
- parameter session: The session.
- parameter streamTask: The stream task.
*/
public func URLSession(session: NSURLSession, betterRouteDiscoveredForStreamTask streamTask: NSURLSessionStreamTask) {
streamTaskBetterRouteDiscovered?(session, streamTask)
}
/**
Tells the delegate that the stream task has been completed and provides the unopened stream objects.
- parameter session: The session.
- parameter streamTask: The stream task.
- parameter inputStream: The new input stream.
- parameter outputStream: The new output stream.
*/
public func URLSession(
session: NSURLSession,
streamTask: NSURLSessionStreamTask,
didBecomeInputStream inputStream: NSInputStream,
outputStream: NSOutputStream)
{
streamTaskDidBecomeInputStream?(session, streamTask, inputStream, outputStream)
}
}
#endif
================================================
FILE: Sublime/Pods/Alamofire/Source/Timeline.swift
================================================
// Timeline.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/// Responsible for computing the timing metrics for the complete lifecycle of a `Request`.
public struct Timeline {
/// The time the request was initialized.
public let requestStartTime: CFAbsoluteTime
/// The time the first bytes were received from or sent to the server.
public let initialResponseTime: CFAbsoluteTime
/// The time when the request was completed.
public let requestCompletedTime: CFAbsoluteTime
/// The time when the response serialization was completed.
public let serializationCompletedTime: CFAbsoluteTime
/// The time interval in seconds from the time the request started to the initial response from the server.
public let latency: NSTimeInterval
/// The time interval in seconds from the time the request started to the time the request completed.
public let requestDuration: NSTimeInterval
/// The time interval in seconds from the time the request completed to the time response serialization completed.
public let serializationDuration: NSTimeInterval
/// The time interval in seconds from the time the request started to the time response serialization completed.
public let totalDuration: NSTimeInterval
/**
Creates a new `Timeline` instance with the specified request times.
- parameter requestStartTime: The time the request was initialized. Defaults to `0.0`.
- parameter initialResponseTime: The time the first bytes were received from or sent to the server.
Defaults to `0.0`.
- parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`.
- parameter serializationCompletedTime: The time when the response serialization was completed. Defaults
to `0.0`.
- returns: The new `Timeline` instance.
*/
public init(
requestStartTime: CFAbsoluteTime = 0.0,
initialResponseTime: CFAbsoluteTime = 0.0,
requestCompletedTime: CFAbsoluteTime = 0.0,
serializationCompletedTime: CFAbsoluteTime = 0.0)
{
self.requestStartTime = requestStartTime
self.initialResponseTime = initialResponseTime
self.requestCompletedTime = requestCompletedTime
self.serializationCompletedTime = serializationCompletedTime
self.latency = initialResponseTime - requestStartTime
self.requestDuration = requestCompletedTime - requestStartTime
self.serializationDuration = serializationCompletedTime - requestCompletedTime
self.totalDuration = serializationCompletedTime - requestStartTime
}
}
// MARK: - CustomStringConvertible
extension Timeline: CustomStringConvertible {
/// The textual representation used when written to an output stream, which includes the latency, the request
/// duration and the total duration.
public var description: String {
let latency = String(format: "%.3f", self.latency)
let requestDuration = String(format: "%.3f", self.requestDuration)
let serializationDuration = String(format: "%.3f", self.serializationDuration)
let totalDuration = String(format: "%.3f", self.totalDuration)
let timings = [
"\"Latency\": \(latency) secs",
"\"Request Duration\": \(requestDuration) secs",
"\"Serialization Duration\": \(serializationDuration) secs",
"\"Total Duration\": \(totalDuration) secs"
]
return "Timeline: { \(timings.joinWithSeparator(", ")) }"
}
}
// MARK: - CustomDebugStringConvertible
extension Timeline: CustomDebugStringConvertible {
/// The textual representation used when written to an output stream, which includes the request start time, the
/// initial response time, the request completed time, the serialization completed time, the latency, the request
/// duration and the total duration.
public var debugDescription: String {
let timings = [
"\"Request Start Time\": \(requestStartTime)",
"\"Initial Response Time\": \(initialResponseTime)",
"\"Request Completed Time\": \(requestCompletedTime)",
"\"Serialization Completed Time\": \(serializationCompletedTime)",
"\"Latency\": \(latency) secs",
"\"Request Duration\": \(requestDuration) secs",
"\"Serialization Duration\": \(serializationDuration) secs",
"\"Total Duration\": \(totalDuration) secs"
]
return "Timeline: { \(timings.joinWithSeparator(", ")) }"
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Upload.swift
================================================
// Upload.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
extension Manager {
private enum Uploadable {
case Data(NSURLRequest, NSData)
case File(NSURLRequest, NSURL)
case Stream(NSURLRequest, NSInputStream)
}
private func upload(uploadable: Uploadable) -> Request {
var uploadTask: NSURLSessionUploadTask!
var HTTPBodyStream: NSInputStream?
switch uploadable {
case .Data(let request, let data):
dispatch_sync(queue) {
uploadTask = self.session.uploadTaskWithRequest(request, fromData: data)
}
case .File(let request, let fileURL):
dispatch_sync(queue) {
uploadTask = self.session.uploadTaskWithRequest(request, fromFile: fileURL)
}
case .Stream(let request, let stream):
dispatch_sync(queue) {
uploadTask = self.session.uploadTaskWithStreamedRequest(request)
}
HTTPBodyStream = stream
}
let request = Request(session: session, task: uploadTask)
if HTTPBodyStream != nil {
request.delegate.taskNeedNewBodyStream = { _, _ in
return HTTPBodyStream
}
}
delegate[request.delegate.task] = request.delegate
if startRequestsImmediately {
request.resume()
}
return request
}
// MARK: File
/**
Creates a request for uploading a file to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request
- parameter file: The file to upload
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, file: NSURL) -> Request {
return upload(.File(URLRequest.URLRequest, file))
}
/**
Creates a request for uploading a file to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter file: The file to upload
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
file: NSURL)
-> Request
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
return upload(mutableURLRequest, file: file)
}
// MARK: Data
/**
Creates a request for uploading data to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request.
- parameter data: The data to upload.
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, data: NSData) -> Request {
return upload(.Data(URLRequest.URLRequest, data))
}
/**
Creates a request for uploading data to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter data: The data to upload
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
data: NSData)
-> Request
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
return upload(mutableURLRequest, data: data)
}
// MARK: Stream
/**
Creates a request for uploading a stream to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request.
- parameter stream: The stream to upload.
- returns: The created upload request.
*/
public func upload(URLRequest: URLRequestConvertible, stream: NSInputStream) -> Request {
return upload(.Stream(URLRequest.URLRequest, stream))
}
/**
Creates a request for uploading a stream to the specified URL request.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter stream: The stream to upload.
- returns: The created upload request.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
stream: NSInputStream)
-> Request
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
return upload(mutableURLRequest, stream: stream)
}
// MARK: MultipartFormData
/// Default memory threshold used when encoding `MultipartFormData`.
public static let MultipartFormDataEncodingMemoryThreshold: UInt64 = 10 * 1024 * 1024
/**
Defines whether the `MultipartFormData` encoding was successful and contains result of the encoding as
associated values.
- Success: Represents a successful `MultipartFormData` encoding and contains the new `Request` along with
streaming information.
- Failure: Used to represent a failure in the `MultipartFormData` encoding and also contains the encoding
error.
*/
public enum MultipartFormDataEncodingResult {
case Success(request: Request, streamingFromDisk: Bool, streamFileURL: NSURL?)
case Failure(ErrorType)
}
/**
Encodes the `MultipartFormData` and creates a request to upload the result to the specified URL request.
It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
used for larger payloads such as video content.
The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
technique was used.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
`MultipartFormDataEncodingMemoryThreshold` by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
method: Method,
_ URLString: URLStringConvertible,
headers: [String: String]? = nil,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (MultipartFormDataEncodingResult -> Void)?)
{
let mutableURLRequest = URLRequest(method, URLString, headers: headers)
return upload(
mutableURLRequest,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
/**
Encodes the `MultipartFormData` and creates a request to upload the result to the specified URL request.
It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
used for larger payloads such as video content.
The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
technique was used.
If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
- parameter URLRequest: The URL request.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
`MultipartFormDataEncodingMemoryThreshold` by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
URLRequest: URLRequestConvertible,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (MultipartFormDataEncodingResult -> Void)?)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let formData = MultipartFormData()
multipartFormData(formData)
let URLRequestWithContentType = URLRequest.URLRequest
URLRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: "Content-Type")
let isBackgroundSession = self.session.configuration.identifier != nil
if formData.contentLength < encodingMemoryThreshold && !isBackgroundSession {
do {
let data = try formData.encode()
let encodingResult = MultipartFormDataEncodingResult.Success(
request: self.upload(URLRequestWithContentType, data: data),
streamingFromDisk: false,
streamFileURL: nil
)
dispatch_async(dispatch_get_main_queue()) {
encodingCompletion?(encodingResult)
}
} catch {
dispatch_async(dispatch_get_main_queue()) {
encodingCompletion?(.Failure(error as NSError))
}
}
} else {
let fileManager = NSFileManager.defaultManager()
let tempDirectoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
let directoryURL = tempDirectoryURL.URLByAppendingPathComponent("com.alamofire.manager/multipart.form.data")
let fileName = NSUUID().UUIDString
let fileURL = directoryURL.URLByAppendingPathComponent(fileName)
do {
try fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
try formData.writeEncodedDataToDisk(fileURL)
dispatch_async(dispatch_get_main_queue()) {
let encodingResult = MultipartFormDataEncodingResult.Success(
request: self.upload(URLRequestWithContentType, file: fileURL),
streamingFromDisk: true,
streamFileURL: fileURL
)
encodingCompletion?(encodingResult)
}
} catch {
dispatch_async(dispatch_get_main_queue()) {
encodingCompletion?(.Failure(error as NSError))
}
}
}
}
}
}
// MARK: -
extension Request {
// MARK: - UploadTaskDelegate
class UploadTaskDelegate: DataTaskDelegate {
var uploadTask: NSURLSessionUploadTask? { return task as? NSURLSessionUploadTask }
var uploadProgress: ((Int64, Int64, Int64) -> Void)!
// MARK: - NSURLSessionTaskDelegate
// MARK: Override Closures
var taskDidSendBodyData: ((NSURLSession, NSURLSessionTask, Int64, Int64, Int64) -> Void)?
// MARK: Delegate Methods
func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
didSendBodyData bytesSent: Int64,
totalBytesSent: Int64,
totalBytesExpectedToSend: Int64)
{
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
if let taskDidSendBodyData = taskDidSendBodyData {
taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
} else {
progress.totalUnitCount = totalBytesExpectedToSend
progress.completedUnitCount = totalBytesSent
uploadProgress?(bytesSent, totalBytesSent, totalBytesExpectedToSend)
}
}
}
}
================================================
FILE: Sublime/Pods/Alamofire/Source/Validation.swift
================================================
// Validation.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
extension Request {
/**
Used to represent whether validation was successful or encountered an error resulting in a failure.
- Success: The validation was successful.
- Failure: The validation failed encountering the provided error.
*/
public enum ValidationResult {
case Success
case Failure(NSError)
}
/**
A closure used to validate a request that takes a URL request and URL response, and returns whether the
request was valid.
*/
public typealias Validation = (NSURLRequest?, NSHTTPURLResponse) -> ValidationResult
/**
Validates the request, using the specified closure.
If validation fails, subsequent calls to response handlers will have an associated error.
- parameter validation: A closure to validate the request.
- returns: The request.
*/
public func validate(validation: Validation) -> Self {
delegate.queue.addOperationWithBlock {
if let
response = self.response where self.delegate.error == nil,
case let .Failure(error) = validation(self.request, response)
{
self.delegate.error = error
}
}
return self
}
// MARK: - Status Code
/**
Validates that the response has a status code in the specified range.
If validation fails, subsequent calls to response handlers will have an associated error.
- parameter range: The range of acceptable status codes.
- returns: The request.
*/
public func validate(statusCode acceptableStatusCode: S) -> Self {
return validate { _, response in
if acceptableStatusCode.contains(response.statusCode) {
return .Success
} else {
let failureReason = "Response status code was unacceptable: \(response.statusCode)"
return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason))
}
}
}
// MARK: - Content-Type
private struct MIMEType {
let type: String
let subtype: String
init?(_ string: String) {
let components: [String] = {
let stripped = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
let split = stripped.substringToIndex(stripped.rangeOfString(";")?.startIndex ?? stripped.endIndex)
return split.componentsSeparatedByString("/")
}()
if let
type = components.first,
subtype = components.last
{
self.type = type
self.subtype = subtype
} else {
return nil
}
}
func matches(MIME: MIMEType) -> Bool {
switch (type, subtype) {
case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"):
return true
default:
return false
}
}
}
/**
Validates that the response has a content type in the specified array.
If validation fails, subsequent calls to response handlers will have an associated error.
- parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes.
- returns: The request.
*/
public func validate(contentType acceptableContentTypes: S) -> Self {
return validate { _, response in
guard let validData = self.delegate.data where validData.length > 0 else { return .Success }
if let
responseContentType = response.MIMEType,
responseMIMEType = MIMEType(responseContentType)
{
for contentType in acceptableContentTypes {
if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) {
return .Success
}
}
} else {
for contentType in acceptableContentTypes {
if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" {
return .Success
}
}
}
let failureReason: String
if let responseContentType = response.MIMEType {
failureReason = (
"Response content type \"\(responseContentType)\" does not match any acceptable " +
"content types: \(acceptableContentTypes)"
)
} else {
failureReason = "Response content type was missing and acceptable content type does not match \"*/*\""
}
return .Failure(Error.errorWithCode(.ContentTypeValidationFailed, failureReason: failureReason))
}
}
// MARK: - Automatic
/**
Validates that the response has a status code in the default acceptable range of 200...299, and that the content
type matches any specified in the Accept HTTP header field.
If validation fails, subsequent calls to response handlers will have an associated error.
- returns: The request.
*/
public func validate() -> Self {
let acceptableStatusCodes: Range = 200..<300
let acceptableContentTypes: [String] = {
if let accept = request?.valueForHTTPHeaderField("Accept") {
return accept.componentsSeparatedByString(",")
}
return ["*/*"]
}()
return validate(statusCode: acceptableStatusCodes).validate(contentType: acceptableContentTypes)
}
}
================================================
FILE: Sublime/Pods/AlamofireRSSParser/LICENSE
================================================
Copyright (c) 2016 Don Angelillo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: Sublime/Pods/AlamofireRSSParser/Pod/Classes/AlamofireRSSParser.h
================================================
//
// AlamofireRSSParser.h
// AlamofireRSSParser
//
// Created by Donald Angelillo on 3/1/16.
// Copyright © 2016 Donald Angelillo. All rights reserved.
//
#import
//! Project version number for AlamofireRSSParser.
FOUNDATION_EXPORT double AlamofireRSSParserVersionNumber;
//! Project version string for AlamofireRSSParser.
FOUNDATION_EXPORT const unsigned char AlamofireRSSParserVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import
================================================
FILE: Sublime/Pods/AlamofireRSSParser/Pod/Classes/AlamofireRSSParser.swift
================================================
//
// AlamofireRSSParser.swift
// Pods
//
// Created by Donald Angelillo on 3/2/16.
//
//
import Foundation
import Alamofire
extension Request {
/**
Creates a response serializer that returns an `RSSFeed` object initialized from the response data.
- Returns: An RSS response serializer.
*/
public static func RSSResponseSerializer() -> ResponseSerializer {
return ResponseSerializer { request, response, data, error in
guard error == nil else {
return .Failure(error!)
}
guard let validData = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
let parser = AlamofireRSSParser(data: validData)
let parsedResults: (feed: RSSFeed?, error: NSError?) = parser.parse()
if let feed = parsedResults.feed {
return .Success(feed)
} else {
return .Failure(parsedResults.error!)
}
}
}
/**
Adds a handler to be called once the request has finished.
- Parameter completionHandler: A closure to be executed once the request has finished.
- Returns: The request.
*/
public func responseRSS(completionHandler: Response -> Void) -> Self {
return response(responseSerializer: Request.RSSResponseSerializer(), completionHandler: completionHandler)
}
//public func responseRSS(parser parser: AlamofireRSSParser?, completionHandler: Response -> Void) -> Self {
// return response(responseSerializer: Request.RSSResponseSerializer(parser), completionHandler: completionHandler)
//}
}
/**
This class does the bulk of the work. Implements the `NSXMLParserDelegate` protocol.
Unfortunately due to this it's also required to implement the `NSObject` protocol.
And unfortunately due to that there doesn't seem to be any way to make this class have a valid public initializer,
despite it being marked public. I would love to have it be publicly accessible because I would like to able to pass
a custom-created instance of this class with configuration properties set into `responseRSS` (see the commented out overload above)
*/
public class AlamofireRSSParser: NSObject, NSXMLParserDelegate {
var parser: NSXMLParser? = nil
var feed: RSSFeed? = nil
var parsingItems: Bool = false
var currentItem: RSSItem? = nil
var currentString: String!
var currentAttributes: [String: String]? = nil
var parseError: NSError? = nil
public var data: NSData? = nil {
didSet {
if let data = data {
self.parser = NSXMLParser(data: data)
self.parser?.delegate = self
}
}
}
override init() {
self.parser = NSXMLParser();
super.init()
}
init(data: NSData) {
self.parser = NSXMLParser(data: data)
super.init()
self.parser?.delegate = self
}
/**
Kicks off the RSS parsing.
- Returns: A tuple containing an `RSSFeed` object if parsing was successful (`nil` otherwise) and
an `NSError` object if an error occurred (`nil` otherwise).
*/
func parse() -> (feed: RSSFeed?, error: NSError?) {
self.feed = RSSFeed()
self.currentItem = nil
self.currentAttributes = nil
self.currentString = String()
self.parser?.parse()
return (feed: self.feed, error: self.parseError)
}
//MARK: - NSXMLParserDelegate
public func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
self.currentString = String()
self.currentAttributes = attributeDict
if ((elementName == "item") || (elementName == "entry")) {
self.currentItem = RSSItem()
}
}
public func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
//if we're at the item level
if let currentItem = self.currentItem {
if ((elementName == "item") || (elementName == "entry")) {
self.feed?.items.append(currentItem)
return
}
if (elementName == "title") {
currentItem.title = self.currentString
}
if (elementName == "description") {
currentItem.itemDescription = self.currentString
}
if (elementName == "link") {
currentItem.link = self.currentString
}
if (elementName == "guid") {
currentItem.guid = self.currentString
}
if (elementName == "author") {
currentItem.author = self.currentString
}
if (elementName == "comments") {
currentItem.comments = self.currentString
}
if (elementName == "source") {
currentItem.source = self.currentString
}
if (elementName == "pubDate") {
if let date = RSSDateFormatter.rfc822DateFormatter().dateFromString(self.currentString) {
currentItem.pubDate = date
} else if let date = RSSDateFormatter.rfc822DateFormatter2().dateFromString(self.currentString) {
currentItem.pubDate = date
}
}
if (elementName == "published") {
if let date = RSSDateFormatter.publishedDateFormatter().dateFromString(self.currentString) {
currentItem.pubDate = date
} else if let date = RSSDateFormatter.publishedDateFormatter2().dateFromString(self.currentString) {
currentItem.pubDate = date
}
}
if (elementName == "media:thumbnail") {
if let attributes = self.currentAttributes {
if let url = attributes["url"] {
currentItem.mediaThumbnail = url
}
}
}
if (elementName == "media:content") {
if let attributes = self.currentAttributes {
if let url = attributes["url"] {
currentItem.mediaContent = url
}
}
}
//if we're at the top level
} else {
if (elementName == "title") {
self.feed?.title = self.currentString
}
if (elementName == "description") {
self.feed?.feedDescription = self.currentString
}
if (elementName == "link") {
self.feed?.link = self.currentString
}
if (elementName == "language") {
self.feed?.language = self.currentString
}
if (elementName == "copyright") {
self.feed?.copyright = self.currentString
}
if (elementName == "managingEditor") {
self.feed?.managingEditor = self.currentString
}
if (elementName == "webMaster") {
self.feed?.webMaster = self.currentString
}
if (elementName == "generator") {
self.feed?.generator = self.currentString
}
if (elementName == "docs") {
self.feed?.docs = self.currentString
}
if (elementName == "ttl") {
self.feed?.ttl = Int(self.currentString)
}
if (elementName == "pubDate") {
if let date = RSSDateFormatter.rfc822DateFormatter().dateFromString(self.currentString) {
self.feed?.pubDate = date
} else if let date = RSSDateFormatter.rfc822DateFormatter2().dateFromString(self.currentString) {
self.feed?.pubDate = date
}
}
if (elementName == "published") {
if let date = RSSDateFormatter.publishedDateFormatter().dateFromString(self.currentString) {
self.feed?.pubDate = date
} else if let date = RSSDateFormatter.publishedDateFormatter2().dateFromString(self.currentString) {
self.feed?.pubDate = date
}
}
if (elementName == "lastBuildDate") {
if let date = RSSDateFormatter.rfc822DateFormatter().dateFromString(self.currentString) {
self.feed?.lastBuildDate = date
} else if let date = RSSDateFormatter.rfc822DateFormatter2().dateFromString(self.currentString) {
self.feed?.lastBuildDate = date
}
}
}
}
public func parser(parser: NSXMLParser, foundCharacters string: String) {
self.currentString.appendContentsOf(string)
}
public func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
self.parseError = parseError
self.parser?.abortParsing()
}
}
/**
Struct containing various `NSDateFormatter` s
*/
struct RSSDateFormatter {
static func rfc822DateFormatter() -> NSDateFormatter {
let dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss Z"
return dateFormatter
}
static func rfc822DateFormatter2() -> NSDateFormatter {
let dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z"
return dateFormatter
}
static func publishedDateFormatter() -> NSDateFormatter {
let dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
return dateFormatter
}
static func publishedDateFormatter2() -> NSDateFormatter {
let dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssz"
return dateFormatter
}
}
================================================
FILE: Sublime/Pods/AlamofireRSSParser/Pod/Classes/RSSFeed.swift
================================================
//
// RSSFeed.swift
// AlamofireRSSParser
//
// Created by Donald Angelillo on 3/1/16.
// Copyright © 2016 Donald Angelillo. All rights reserved.
//
import Foundation
/**
RSS gets deserialized into an instance of `RSSFeed`. Top-level RSS elements are housed here.
Item-level elements are deserialized into `RSSItem` objects and stored in the `items` property.
*/
public class RSSFeed: CustomStringConvertible {
public var title: String? = nil
public var link: String? = nil
public var feedDescription: String? = nil
public var pubDate: NSDate? = nil
public var lastBuildDate: NSDate? = nil
public var language: String? = nil
public var copyright: String? = nil
public var managingEditor: String? = nil
public var webMaster: String? = nil
public var generator: String? = nil
public var docs: String? = nil
public var ttl: NSNumber? = nil
public var items: [RSSItem] = Array()
public var description: String {
return "title: \(self.title)\nfeedDescription: \(self.feedDescription)\nlink: \(self.link)\npubDate: \(self.pubDate)\nlastBuildDate: \(self.lastBuildDate)\nlanguage: \(self.language)\ncopyright: \(self.copyright)\nmanagingEditor: \(self.managingEditor)\nwebMaster: \(self.webMaster)\ngenerator: \(self.generator)\ndocs: \(self.docs)\nttl: \(self.ttl)\nitems: \n\(self.items)"
}
}
================================================
FILE: Sublime/Pods/AlamofireRSSParser/Pod/Classes/RSSItem.swift
================================================
//
// RSSItem.swift
// AlamofireRSSParser
//
// Created by Donald Angelillo on 3/1/16.
// Copyright © 2016 Donald Angelillo. All rights reserved.
//
import Foundation
/**
Item-level elements are deserialized into `RSSItem` objects and stored in the `items` array of an `RSSFeed` instance
*/
public class RSSItem: CustomStringConvertible {
public var title: String? = nil
public var link: String? = nil
/**
Upon setting this property the `itemDescription` will be scanned for HTML and all image urls will be extracted and stored in `imagesFromDescription`
*/
public var itemDescription: String? = nil {
didSet {
if let itemDescription = self.itemDescription {
self.imagesFromDescription = self.imagesFromHTMLString(itemDescription)
}
}
}
public var guid: String? = nil
public var author: String? = nil
public var comments: String? = nil
public var source: String? = nil
public var pubDate: NSDate? = nil
public var mediaThumbnail: String? = nil;
public var mediaContent: String? = nil;
public var imagesFromDescription: [String]? = nil;
public var description: String {
return "\ttitle: \(self.title)\n\tlink: \(self.link)\n\titemDescription: \(self.itemDescription)\n\tguid: \(self.guid)\n\tauthor: \(self.author)\n\tcomments: \(self.comments)\n\tsource: \(self.source)\n\tpubDate: \(self.pubDate)\nmediaThumbnail: \(self.mediaThumbnail)\nmediaContent: \(self.mediaContent)\nimagesFromDescription: \(self.imagesFromDescription)\n\n"
}
/**
Retrieves all the images (\
tags) from a given String contaning HTML using a regex.
- Parameter htmlString: A String containing HTML
- Returns: an array of image url Strings ([String])
*/
private func imagesFromHTMLString(htmlString: String) -> [String] {
let htmlNSString = htmlString as NSString;
var images: [String] = Array();
do {
let regex = try NSRegularExpression(pattern: "(https?)\\S*(png|jpg|jpeg|gif)", options: [NSRegularExpressionOptions.CaseInsensitive])
regex.enumerateMatchesInString(htmlString, options: [NSMatchingOptions.ReportProgress], range: NSMakeRange(0, htmlString.characters.count)) { (result, flags, stop) -> Void in
if let range = result?.range {
images.append(htmlNSString.substringWithRange(range)) //because Swift ranges are still completely ridiculous
}
}
}
catch {
}
return images;
}
}
================================================
FILE: Sublime/Pods/AlamofireRSSParser/README.md
================================================
# AlamofireRSSParser
[](https://travis-ci.org/AdeptusAstartes/AlamofireRSSParser)
[](http://cocoapods.org/pods/AlamofireRSSParser)
[](http://cocoapods.org/pods/AlamofireRSSParser)
[](http://cocoapods.org/pods/AlamofireRSSParser)
## Requirements
- Xcode 7.2+
- Alamofire 3.0.0 or higher
**Note:** Version 1.0.1 currently locks the Alamofire dependency at ~> 3.2.1 because for some misguided reason the Alamofire Foundation decided to force us to use Xcode 7.3 in order to use Alamofire 3.3.0.
## Installation
### Cocoapods
AlamofireRSSParser is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod "AlamofireRSSParser"
```
Then
```swift
import AlamofireRSSParser
```
wherever you're using it.
### Manually
Alternately you can add the contents of AlamofireRSSParser/Pod/Classes/ to your project and import the classes as appropriate.
## Usage
_Note: To run the example project, clone the repo, and run `pod install` from the Example directory first._
You use AlamofireRSSParser just like any other response handler in Alamofire:
```swift
let url = "http://rss.cnn.com/rss/cnn_topstories.rss"
Alamofire.request(.GET, url).responseRSS() { (response) -> Void in
if let feed: RSSFeed = response.result.value {
//do something with your new RSSFeed object!
for item in feed.items {
print(item)
}
}
}
```
AlamofireRSSParser returns an RSSFeed object that contains an array of RSSItem objects.
##What It Does and Doesn't Do
I think we can all admit that RSS implementations are a bit all over the place. This project is meant to parse all of the common, high level bits of the [RSS 2.0 spec](http://cyber.law.harvard.edu/rss/rss.html) that people actually use/care about. It is not meant to comprehensively parse **all** RSS.
RSS 2.0 spec elements that it currently parses:
- title
- link
- itemDescription
- guid
- author
- comments
- source
- pubDate
In addition, since this is a Swift port of what was originally the backbone of [Heavy Headlines](https://itunes.apple.com/us/app/heavy-headlines-metal-news/id623879550?mt=8) it also parses portions of the [Media RSS Specification 1.5.1](http://www.rssboard.org/media-rss).
Current elements:
- media:content
- media: thumbnail
It also yanks all of the images that may be linked in the `itemDescription` (if it's HTML) and creates a nice array named `imagesFromDescription` that you can use for more image content.
If you need more elements parsed please file an issue or even better, **please contribute**! That's why this is on GitHub.
## Author
Don Angelillo, dangelillo@gmail.com
Inspired by Thibaut LE LEVIER's awesome orginal [Block RSSParser](https://github.com/tibo/BlockRSSParser) AFNetworking Plugin.
## License
AlamofireRSSParser is available under the MIT license. See the LICENSE file for more info.
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRLayoutManager.h
================================================
//
// CYRLayoutManager.h
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
// Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
@interface CYRLayoutManager : NSLayoutManager
@property (nonatomic, strong) UIFont *lineNumberFont;
@property (nonatomic, strong) UIColor *lineNumberColor;
@property (nonatomic, strong) UIColor *selectedLineNumberColor;
@property (nonatomic, readonly) CGFloat gutterWidth;
@property (nonatomic, assign) NSRange selectedRange;
- (CGRect)paragraphRectForRange:(NSRange)range;
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRLayoutManager.m
================================================
//
// CYRLayoutManager.h
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
// Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "CYRLayoutManager.h"
static CGFloat kMinimumGutterWidth = 30.f;
@interface CYRLayoutManager ()
@property (nonatomic, assign) CGFloat gutterWidth;
@property (nonatomic, assign) UIEdgeInsets lineAreaInset;
@property (nonatomic) NSUInteger lastParaLocation;
@property (nonatomic) NSUInteger lastParaNumber;
@end
@implementation CYRLayoutManager
#pragma mark - Initialization & Setup
- (instancetype)init
{
self = [super init];
if (self)
{
[self _commonSetup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self _commonSetup];
}
return self;
}
- (void)_commonSetup
{
self.gutterWidth = kMinimumGutterWidth;
self.selectedRange = NSMakeRange(0, 0);
self.lineAreaInset = UIEdgeInsetsMake(0, 10, 0, 4);
self.lineNumberColor = [UIColor grayColor];
self.lineNumberFont = [UIFont systemFontOfSize:10.0f];
self.selectedLineNumberColor = [UIColor colorWithWhite:0.9 alpha:0];
}
#pragma mark - Convenience
- (CGRect)paragraphRectForRange:(NSRange)range
{
range = [self.textStorage.string paragraphRangeForRange:range];
range = [self glyphRangeForCharacterRange:range actualCharacterRange:NULL];
CGRect startRect = [self lineFragmentRectForGlyphAtIndex:range.location effectiveRange:NULL];
CGRect endRect = [self lineFragmentRectForGlyphAtIndex:range.location + range.length - 1 effectiveRange:NULL];
CGRect paragraphRectForRange = CGRectUnion(startRect, endRect);
paragraphRectForRange = CGRectOffset(paragraphRectForRange, _gutterWidth, 8);
return paragraphRectForRange;
}
- (NSUInteger) _paraNumberForRange:(NSRange) charRange
{
// NSString does not provide a means of efficiently determining the paragraph number of a range of text. This code
// attempts to optimize what would normally be a series linear searches by keeping track of the last paragraph number
// found and uses that as the starting point for next paragraph number search. This works (mostly) because we
// are generally asked for continguous increasing sequences of paragraph numbers. Also, this code is called in the
// course of drawing a pagefull of text, and so even when moving back, the number of paragraphs to search for is
// relativly low, even in really long bodies of text.
//
// This all falls down when the user edits the text, and can potentially invalidate the cached paragraph number which
// causes a (potentially lengthy) search from the beginning of the string.
if (charRange.location == self.lastParaLocation)
return self.lastParaNumber;
else if (charRange.location < self.lastParaLocation)
{
// We need to look backwards from the last known paragraph for the new paragraph range. This generally happens
// when the text in the UITextView scrolls downward, revaling paragraphs before/above the ones previously drawn.
NSString* s = self.textStorage.string;
__block NSUInteger paraNumber = self.lastParaNumber;
[s enumerateSubstringsInRange:NSMakeRange(charRange.location, self.lastParaLocation - charRange.location)
options:NSStringEnumerationByParagraphs |
NSStringEnumerationSubstringNotRequired |
NSStringEnumerationReverse
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
if (enclosingRange.location <= charRange.location) {
*stop = YES;
}
--paraNumber;
}];
self.lastParaLocation = charRange.location;
self.lastParaNumber = paraNumber;
return paraNumber;
}
else
{
// We need to look forward from the last known paragraph for the new paragraph range. This generally happens
// when the text in the UITextView scrolls upwards, revealing paragraphs that follow the ones previously drawn.
NSString* s = self.textStorage.string;
__block NSUInteger paraNumber = self.lastParaNumber;
[s enumerateSubstringsInRange:NSMakeRange(self.lastParaLocation, charRange.location - self.lastParaLocation)
options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
if (enclosingRange.location >= charRange.location) {
*stop = YES;
}
++paraNumber;
}];
self.lastParaLocation = charRange.location;
self.lastParaNumber = paraNumber;
return paraNumber;
}
}
#pragma mark - Layouting
- (void)processEditingForTextStorage:(NSTextStorage *)textStorage edited:(NSTextStorageEditActions)editMask range:(NSRange)newCharRange changeInLength:(NSInteger)delta invalidatedRange:(NSRange)invalidatedCharRange
{
[super processEditingForTextStorage:textStorage edited:editMask range:newCharRange changeInLength:delta invalidatedRange:invalidatedCharRange];
if (invalidatedCharRange.location < self.lastParaLocation)
{
// When the backing store is edited ahead the cached paragraph location, invalidate the cache and force a complete
// recalculation. We cannot be much smarter than this because we don't know how many paragraphs have been deleted
// since the text has already been removed from the backing store.
self.lastParaLocation = 0;
self.lastParaNumber = 0;
}
}
#pragma mark - Drawing
- (void) drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin
{
[super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin];
// Draw line numbers. Note that the background for line number gutter is drawn by the LineNumberTextView class.
NSDictionary* atts = @{NSFontAttributeName : _lineNumberFont ,
NSForegroundColorAttributeName : _lineNumberColor};
[self enumerateLineFragmentsForGlyphRange:glyphsToShow
usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) {
NSRange charRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:nil];
NSRange paraRange = [self.textStorage.string paragraphRangeForRange:charRange];
BOOL showCursorRect = NSLocationInRange(_selectedRange.location, paraRange);
if (showCursorRect)
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect cursorRect = CGRectMake(0, usedRect.origin.y + 8, _gutterWidth, usedRect.size.height);
CGContextSetFillColorWithColor(context, _selectedLineNumberColor.CGColor);
CGContextFillRect(context, cursorRect);
}
// Only draw line numbers for the paragraph's first line fragment. Subsequent fragments are wrapped portions of the paragraph and don't get the line number.
if (charRange.location == paraRange.location) {
CGRect gutterRect = CGRectOffset(CGRectMake(0, rect.origin.y, _gutterWidth, rect.size.height), origin.x, origin.y);
NSUInteger paraNumber = [self _paraNumberForRange:charRange];
NSString* ln = [NSString stringWithFormat:@"%ld", (unsigned long) paraNumber + 1];
CGSize size = [ln sizeWithAttributes:atts];
[ln drawInRect:CGRectOffset(gutterRect, CGRectGetWidth(gutterRect) - _lineAreaInset.right - size.width - _gutterWidth, (CGRectGetHeight(gutterRect) - size.height) / 2.0)
withAttributes:atts];
}
}];
}
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRTextStorage.h
================================================
//
// CYRTextStorage.h
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
@interface CYRTextStorage : NSTextStorage
@property (nonatomic, strong) NSArray *tokens;
@property (nonatomic, strong) UIFont *defaultFont;
@property (nonatomic, strong) UIColor *defaultTextColor;
- (void)update;
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRTextStorage.m
================================================
//
// CYRTextStorage.m
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "CYRTextStorage.h"
#import "CYRToken.h"
@interface CYRTextStorage ()
@property (nonatomic, strong) NSMutableAttributedString *attributedString;
@property (nonatomic, strong) NSMutableDictionary *regularExpressionCache;
@end
@implementation CYRTextStorage
#pragma mark - Initialization & Setup
- (id)init
{
if (self = [super init])
{
_defaultFont = [UIFont systemFontOfSize:12.0f];
_defaultTextColor = [UIColor blackColor];
_attributedString = [NSMutableAttributedString new];
_tokens = @[];
_regularExpressionCache = @{}.mutableCopy;
}
return self;
}
#pragma mark - Overrides
- (void)setTokens:(NSMutableArray *)tokens
{
_tokens = tokens;
// Clear the regular expression cache
[self.regularExpressionCache removeAllObjects];
// Redraw all text
[self update];
}
- (NSString *)string
{
return [_attributedString string];
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
{
return [_attributedString attributesAtIndex:location effectiveRange:range];
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)str
{
[self beginEditing];
[_attributedString replaceCharactersInRange:range withString:str];
[self edited:NSTextStorageEditedCharacters | NSTextStorageEditedAttributes range:range changeInLength:str.length - range.length];
[self endEditing];
}
- (void)setAttributes:(NSDictionary*)attrs range:(NSRange)range
{
[self beginEditing];
[_attributedString setAttributes:attrs range:range];
[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
[self endEditing];
}
-(void)processEditing
{
[self performReplacementsForRange:[self editedRange]];
[super processEditing];
}
- (void)performReplacementsForRange:(NSRange)changedRange
{
NSRange extendedRange = NSUnionRange(changedRange, [[_attributedString string] lineRangeForRange:NSMakeRange(NSMaxRange(changedRange), 0)]);
[self applyStylesToRange:extendedRange];
}
-(void)update
{
NSRange range = NSMakeRange(0, self.length);
NSDictionary *attributes =
@{
NSFontAttributeName : self.defaultFont,
NSForegroundColorAttributeName : self.defaultTextColor
};
[self addAttributes:attributes range:range];
[self applyStylesToRange:range];
}
- (void)applyStylesToRange:(NSRange)searchRange
{
if (self.editedRange.location == NSNotFound)
{
return;
}
NSRange paragaphRange = [self.string paragraphRangeForRange: self.editedRange];
// Reset the text attributes
NSDictionary *attributes =
@{
NSFontAttributeName : self.defaultFont,
NSForegroundColorAttributeName : self.defaultTextColor
};
[self setAttributes:attributes range:paragaphRange];
for (CYRToken *attribute in self.tokens)
{
NSRegularExpression *regex = [self expressionForDefinition:attribute.name];
[regex enumerateMatchesInString:self.string options:0 range:paragaphRange
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
[attribute.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, id attributeValue, BOOL *stop) {
[self addAttribute:attributeName value:attributeValue range:result.range];
}];
}];
}
}
- (NSRegularExpression *)expressionForDefinition:(NSString *)definition
{
__block CYRToken *attribute = nil;
[self.tokens enumerateObjectsUsingBlock:^(CYRToken *enumeratedAttribute, NSUInteger idx, BOOL *stop) {
if ([enumeratedAttribute.name isEqualToString:definition])
{
attribute = enumeratedAttribute;
*stop = YES;
}
}];
NSRegularExpression *expression = self.regularExpressionCache[attribute.expression];
if (!expression)
{
expression = [NSRegularExpression regularExpressionWithPattern:attribute.expression
options:NSRegularExpressionCaseInsensitive error:nil];
[self.regularExpressionCache setObject:expression forKey:definition];
}
return expression;
}
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRTextView.h
================================================
//
// CYRTextView.h
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
// Copyright (c) 2013 Dominik Hauser
// Copyright (c) 2013 Sam Rijs
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
// Gestures sourced from: https://github.com/srijs/NLTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
#import "CYRToken.h"
@interface CYRTextView : UITextView
@property (nonatomic, strong) NSArray *tokens;
@property (nonatomic, strong) UIPanGestureRecognizer *singleFingerPanRecognizer;
@property (nonatomic, strong) UIPanGestureRecognizer *doubleFingerPanRecognizer;
@property UIColor *gutterBackgroundColor;
@property UIColor *gutterLineColor;
@property (nonatomic, assign) BOOL lineCursorEnabled;
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRTextView.m
================================================
//
// CYRTextView.m
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
// Copyright (c) 2013 Dominik Hauser
// Copyright (c) 2013 Sam Rijs
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "CYRTextView.h"
#import "CYRLayoutManager.h"
#import "CYRTextStorage.h"
#define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f]
static void *CYRTextViewContext = &CYRTextViewContext;
static const float kCursorVelocity = 1.0f/8.0f;
@interface CYRTextView ()
@property (nonatomic, strong) CYRLayoutManager *lineNumberLayoutManager;
@property (nonatomic, strong) CYRTextStorage *syntaxTextStorage;
@end
@implementation CYRTextView
{
NSRange startRange;
}
#pragma mark - Initialization & Setup
- (id)initWithFrame:(CGRect)frame
{
CYRTextStorage *textStorage = [CYRTextStorage new];
CYRLayoutManager *layoutManager = [CYRLayoutManager new];
self.lineNumberLayoutManager = layoutManager;
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
// Wrap text to the text view's frame
textContainer.widthTracksTextView = YES;
[layoutManager addTextContainer:textContainer];
[textStorage removeLayoutManager:textStorage.layoutManagers.firstObject];
[textStorage addLayoutManager:layoutManager];
self.syntaxTextStorage = textStorage;
if ((self = [super initWithFrame:frame textContainer:textContainer]))
{
self.contentMode = UIViewContentModeRedraw; // causes drawRect: to be called on frame resizing and device rotation
[self _commonSetup];
}
return self;
}
- (void)_commonSetup
{
// Setup observers
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(font)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(textColor)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextViewDidChangeNotification:) name:UITextViewTextDidChangeNotification object:self];
// Setup defaults
self.font = [UIFont systemFontOfSize:16.0f];
self.textColor = [UIColor blackColor];
self.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.autocorrectionType = UITextAutocorrectionTypeNo;
self.lineCursorEnabled = YES;
self.gutterBackgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
self.gutterLineColor = [UIColor lightGrayColor];
// Inset the content to make room for line numbers
self.textContainerInset = UIEdgeInsetsMake(8, self.lineNumberLayoutManager.gutterWidth, 8, 0);
// Setup the gesture recognizers
_singleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(singleFingerPanHappend:)];
_singleFingerPanRecognizer.maximumNumberOfTouches = 1;
[self addGestureRecognizer:_singleFingerPanRecognizer];
_doubleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doubleFingerPanHappend:)];
_doubleFingerPanRecognizer.minimumNumberOfTouches = 2;
[self addGestureRecognizer:_doubleFingerPanRecognizer];
}
#pragma mark - Cleanup
- (void)dealloc
{
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(font))];
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(textColor))];
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange))];
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange))];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:NSStringFromSelector(@selector(font))] && context == CYRTextViewContext)
{
// Whenever the UITextView font is changed we want to keep a reference in the stickyFont ivar. We do this to counteract a bug where the underlying font can be changed without notice and cause undesired behaviour.
self.syntaxTextStorage.defaultFont = self.font;
}
else if ([keyPath isEqualToString:NSStringFromSelector(@selector(textColor))] && context == CYRTextViewContext)
{
self.syntaxTextStorage.defaultTextColor = self.textColor;
}
else if (([keyPath isEqualToString:NSStringFromSelector(@selector(selectedTextRange))] ||
[keyPath isEqualToString:NSStringFromSelector(@selector(selectedRange))]) && context == CYRTextViewContext)
{
[self setNeedsDisplay];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Notifications
- (void)handleTextViewDidChangeNotification:(NSNotification *)notification
{
if (notification.object == self)
{
CGRect line = [self caretRectForPosition: self.selectedTextRange.start];
CGFloat overflow = line.origin.y + line.size.height - ( self.contentOffset.y + self.bounds.size.height - self.contentInset.bottom - self.contentInset.top );
if ( overflow > 0 )
{
// We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
// Scroll caret to visible area
CGPoint offset = self.contentOffset;
offset.y += overflow + 7; // leave 7 pixels margin
// Cannot animate with setContentOffset:animated: or caret will not appear
// [UIView animateWithDuration:.2 animations:^{
// [self setContentOffset:offset];
// }];
}
}
}
#pragma mark - Overrides
- (void)setTokens:(NSMutableArray *)tokens
{
[self.syntaxTextStorage setTokens:tokens];
}
- (NSArray *)tokens
{
CYRTextStorage *syntaxTextStorage = (CYRTextStorage *)self.textStorage;
return syntaxTextStorage.tokens;
}
- (void)setText:(NSString *)text
{
UITextRange *textRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
[self replaceRange:textRange withText:text];
}
#pragma mark - Line Drawing
// Original implementation sourced from: https://github.com/alldritt/TextKit_LineNumbers
- (void)drawRect:(CGRect)rect
{
// Drag the line number gutter background. The line numbers them selves are drawn by LineNumberLayoutManager.
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = self.bounds;
CGFloat height = MAX(CGRectGetHeight(bounds), self.contentSize.height) + 200;
// Set the regular fill
CGContextSetFillColorWithColor(context, self.gutterBackgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(bounds.origin.x, bounds.origin.y, self.lineNumberLayoutManager.gutterWidth, height));
// Draw line
CGContextSetFillColorWithColor(context, self.gutterLineColor.CGColor);
CGContextFillRect(context, CGRectMake(self.lineNumberLayoutManager.gutterWidth, bounds.origin.y, 0.5, height));
if (_lineCursorEnabled)
{
self.lineNumberLayoutManager.selectedRange = self.selectedRange;
NSRange glyphRange = [self.lineNumberLayoutManager.textStorage.string paragraphRangeForRange:self.selectedRange];
glyphRange = [self.lineNumberLayoutManager glyphRangeForCharacterRange:glyphRange actualCharacterRange:NULL];
self.lineNumberLayoutManager.selectedRange = glyphRange;
[self.lineNumberLayoutManager invalidateDisplayForGlyphRange:glyphRange];
}
[super drawRect:rect];
}
#pragma mark - Gestures
// Sourced from: https://github.com/srijs/NLTextView
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
// Only accept horizontal pans for the code navigation to preserve correct scrolling behaviour.
if (gestureRecognizer == _singleFingerPanRecognizer || gestureRecognizer == _doubleFingerPanRecognizer)
{
CGPoint translation = [gestureRecognizer translationInView:self];
return fabs(translation.x) > fabs(translation.y);
}
return YES;
}
// Sourced from: https://github.com/srijs/NLTextView
- (void)singleFingerPanHappend:(UIPanGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan)
{
startRange = self.selectedRange;
}
CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0);
self.selectedRange = NSMakeRange(cursorLocation, 0);
}
// Sourced from: https://github.com/srijs/NLTextView
- (void)doubleFingerPanHappend:(UIPanGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan)
{
startRange = self.selectedRange;
}
CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0);
if (cursorLocation > startRange.location)
{
self.selectedRange = NSMakeRange(startRange.location, fabs(startRange.location - cursorLocation));
}
else
{
self.selectedRange = NSMakeRange(cursorLocation, fabs(startRange.location - cursorLocation));
}
}
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRToken.h
================================================
//
// CYRTextAttribute.h
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
@interface CYRToken : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *expression;
@property (nonatomic, strong) NSDictionary *attributes;
+ (instancetype)tokenWithName:(NSString *)name expression:(NSString *)expression attributes:(NSDictionary *)attributes;
@end
================================================
FILE: Sublime/Pods/CYRTextView/CYRTextView/CYRToken.m
================================================
//
// CYRTextAttribute.m
//
// Version 0.4.0
//
// Created by Illya Busigin on 01/05/2014.
// Copyright (c) 2014 Cyrillian, Inc.
//
// Distributed under MIT license.
// Get the latest version from here:
//
// https://github.com/illyabusigin/CYRTextView
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Cyrillian, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "CYRToken.h"
@implementation CYRToken
+ (instancetype)tokenWithName:(NSString *)name expression:(NSString *)expression attributes:(NSDictionary *)attributes
{
CYRToken *textAttribute = [CYRToken new];
textAttribute.name = name;
textAttribute.expression = expression;
textAttribute.attributes = attributes;
return textAttribute;
}
@end
================================================
FILE: Sublime/Pods/CYRTextView/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Cyrillian, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Sublime/Pods/CYRTextView/README.md
================================================
# CYRTextView
by **Illya Busigin**
- Visit my blog at [http://illyabusigin.com/](http://illyabusigin.com/)
- Follow [@illyabusigin on Twitter](http://twitter.com/illyabusigin)
Purpose
--------------
CYRTextView is a UITextView subclass that implements a variety of features that are relevant to a syntax or code text view. There are many subclasses of UITextView out there with the release of TextKit but none that are specifically tailored towards a code/syntax view. CYRTextView aims to change this. Features include:
- Regular expression based text highlighting with support for multiple text attributes for each expression
- Line numbers
- Gesture based navigation
Long term, I would like to turn CYRTextView into a full fledged code editor component with code folding, markers, annotation, and more.
Screenshot
--------------
Requirements
-----------------------------
iOS 7.0 or later (**with ARC**) for iPhone, iPad and iPod touch
Installation
---------------
To use CYRTextView, just drag the class files into your project and add the CoreText framework. You can create CYRTextView instances programatically, or create them in Interface Builder by dragging an ordinary UITextView into your view and setting its class to CYRTextView.
If you are using Interface Builder, to set the custom properties of CYRTextView (ones that are not supported by regular UIViews) either create an IBOutlet for your view and set the properties in code, or use the User Defined Runtime Attributes feature in Interface Builder (introduced in Xcode 4.2 for iOS 5+).
**NOTE**: The current version (0.4.0) is alpha quality at best. Use at your own risk!
Example
---------------
CYRTextView includes an example project that demonstrates how to subclass CYRTextView to provide highlighting behavior for multiple attributes with a default set of normal, bold, and italic fonts.
Bugs & Feature Requests
---------------
There is **no support** offered with this component. If you would like a feature or find a bug, please submit a feature request through the [GitHub issue tracker](http://github.com/illyabusigin/CYRTextView/issues).
Pull-requests for bug-fixes and features are welcome!
Attribution
--------------
CYRTextView uses portions of code from the following sources.
| Component | Description | License |
| ------------- |:-------------:| -----:|
| [NLTextView](https://github.com/srijs/NLTextView) | A UITextView with Syntax Highlighting and Pan-Gesture Navigation / Selection | [MIT](https://github.com/srijs/NLTextView/blob/master/NLTextView/NLTextView.h) |
| [TextKit_LineNumbers](https://github.com/alldritt/TextKit_LineNumbers) | iOS7 Text Kit - Text View with Line Numbers | [MIT](https://github.com/alldritt/TextKit_LineNumbers) |
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Animation/ChartAnimationEasing.swift
================================================
//
// ChartAnimationUtils.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public enum ChartEasingOption: Int
{
case Linear
case EaseInQuad
case EaseOutQuad
case EaseInOutQuad
case EaseInCubic
case EaseOutCubic
case EaseInOutCubic
case EaseInQuart
case EaseOutQuart
case EaseInOutQuart
case EaseInQuint
case EaseOutQuint
case EaseInOutQuint
case EaseInSine
case EaseOutSine
case EaseInOutSine
case EaseInExpo
case EaseOutExpo
case EaseInOutExpo
case EaseInCirc
case EaseOutCirc
case EaseInOutCirc
case EaseInElastic
case EaseOutElastic
case EaseInOutElastic
case EaseInBack
case EaseOutBack
case EaseInOutBack
case EaseInBounce
case EaseOutBounce
case EaseInOutBounce
}
public typealias ChartEasingFunctionBlock = ((elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat)
internal func easingFunctionFromOption(easing: ChartEasingOption) -> ChartEasingFunctionBlock
{
switch easing
{
case .Linear:
return EasingFunctions.Linear
case .EaseInQuad:
return EasingFunctions.EaseInQuad
case .EaseOutQuad:
return EasingFunctions.EaseOutQuad
case .EaseInOutQuad:
return EasingFunctions.EaseInOutQuad
case .EaseInCubic:
return EasingFunctions.EaseInCubic
case .EaseOutCubic:
return EasingFunctions.EaseOutCubic
case .EaseInOutCubic:
return EasingFunctions.EaseInOutCubic
case .EaseInQuart:
return EasingFunctions.EaseInQuart
case .EaseOutQuart:
return EasingFunctions.EaseOutQuart
case .EaseInOutQuart:
return EasingFunctions.EaseInOutQuart
case .EaseInQuint:
return EasingFunctions.EaseInQuint
case .EaseOutQuint:
return EasingFunctions.EaseOutQuint
case .EaseInOutQuint:
return EasingFunctions.EaseInOutQuint
case .EaseInSine:
return EasingFunctions.EaseInSine
case .EaseOutSine:
return EasingFunctions.EaseOutSine
case .EaseInOutSine:
return EasingFunctions.EaseInOutSine
case .EaseInExpo:
return EasingFunctions.EaseInExpo
case .EaseOutExpo:
return EasingFunctions.EaseOutExpo
case .EaseInOutExpo:
return EasingFunctions.EaseInOutExpo
case .EaseInCirc:
return EasingFunctions.EaseInCirc
case .EaseOutCirc:
return EasingFunctions.EaseOutCirc
case .EaseInOutCirc:
return EasingFunctions.EaseInOutCirc
case .EaseInElastic:
return EasingFunctions.EaseInElastic
case .EaseOutElastic:
return EasingFunctions.EaseOutElastic
case .EaseInOutElastic:
return EasingFunctions.EaseInOutElastic
case .EaseInBack:
return EasingFunctions.EaseInBack
case .EaseOutBack:
return EasingFunctions.EaseOutBack
case .EaseInOutBack:
return EasingFunctions.EaseInOutBack
case .EaseInBounce:
return EasingFunctions.EaseInBounce
case .EaseOutBounce:
return EasingFunctions.EaseOutBounce
case .EaseInOutBounce:
return EasingFunctions.EaseInOutBounce
}
}
internal struct EasingFunctions
{
internal static let Linear = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in return CGFloat(elapsed / duration); }
internal static let EaseInQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return position * position
}
internal static let EaseOutQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return -position * (position - 2.0)
}
internal static let EaseInOutQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / (duration / 2.0))
if (position < 1.0)
{
return 0.5 * position * position
}
return -0.5 * ((--position) * (position - 2.0) - 1.0)
}
internal static let EaseInCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return position * position * position
}
internal static let EaseOutCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
position--
return (position * position * position + 1.0)
}
internal static let EaseInOutCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / (duration / 2.0))
if (position < 1.0)
{
return 0.5 * position * position * position
}
position -= 2.0
return 0.5 * (position * position * position + 2.0)
}
internal static let EaseInQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return position * position * position * position
}
internal static let EaseOutQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
position--
return -(position * position * position * position - 1.0)
}
internal static let EaseInOutQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / (duration / 2.0))
if (position < 1.0)
{
return 0.5 * position * position * position * position
}
position -= 2.0
return -0.5 * (position * position * position * position - 2.0)
}
internal static let EaseInQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return position * position * position * position * position
}
internal static let EaseOutQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
position--
return (position * position * position * position * position + 1.0)
}
internal static let EaseInOutQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / (duration / 2.0))
if (position < 1.0)
{
return 0.5 * position * position * position * position * position
}
else
{
position -= 2.0
return 0.5 * (position * position * position * position * position + 2.0)
}
}
internal static let EaseInSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position: NSTimeInterval = elapsed / duration
return CGFloat( -cos(position * M_PI_2) + 1.0 )
}
internal static let EaseOutSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position: NSTimeInterval = elapsed / duration
return CGFloat( sin(position * M_PI_2) )
}
internal static let EaseInOutSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position: NSTimeInterval = elapsed / duration
return CGFloat( -0.5 * (cos(M_PI * position) - 1.0) )
}
internal static let EaseInExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
return (elapsed == 0) ? 0.0 : CGFloat(pow(2.0, 10.0 * (elapsed / duration - 1.0)))
}
internal static let EaseOutExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
return (elapsed == duration) ? 1.0 : (-CGFloat(pow(2.0, -10.0 * elapsed / duration)) + 1.0)
}
internal static let EaseInOutExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
if (elapsed == 0)
{
return 0.0
}
if (elapsed == duration)
{
return 1.0
}
var position: NSTimeInterval = elapsed / (duration / 2.0)
if (position < 1.0)
{
return CGFloat( 0.5 * pow(2.0, 10.0 * (position - 1.0)) )
}
position = position - 1.0
return CGFloat( 0.5 * (-pow(2.0, -10.0 * position) + 2.0) )
}
internal static let EaseInCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
return -(CGFloat(sqrt(1.0 - position * position)) - 1.0)
}
internal static let EaseOutCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position = CGFloat(elapsed / duration)
position--
return CGFloat( sqrt(1 - position * position) )
}
internal static let EaseInOutCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position: NSTimeInterval = elapsed / (duration / 2.0)
if (position < 1.0)
{
return CGFloat( -0.5 * (sqrt(1.0 - position * position) - 1.0) )
}
position -= 2.0
return CGFloat( 0.5 * (sqrt(1.0 - position * position) + 1.0) )
}
internal static let EaseInElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
if (elapsed == 0.0)
{
return 0.0
}
var position: NSTimeInterval = elapsed / duration
if (position == 1.0)
{
return 1.0
}
var p = duration * 0.3
var s = p / (2.0 * M_PI) * asin(1.0)
position -= 1.0
return CGFloat( -(pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p)) )
}
internal static let EaseOutElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
if (elapsed == 0.0)
{
return 0.0
}
var position: NSTimeInterval = elapsed / duration
if (position == 1.0)
{
return 1.0
}
var p = duration * 0.3
var s = p / (2.0 * M_PI) * asin(1.0)
return CGFloat( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p) + 1.0 )
}
internal static let EaseInOutElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
if (elapsed == 0.0)
{
return 0.0
}
var position: NSTimeInterval = elapsed / (duration / 2.0)
if (position == 2.0)
{
return 1.0
}
var p = duration * (0.3 * 1.5)
var s = p / (2.0 * M_PI) * asin(1.0)
if (position < 1.0)
{
position -= 1.0
return CGFloat( -0.5 * (pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p)) )
}
position -= 1.0
return CGFloat( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p) * 0.5 + 1.0 )
}
internal static let EaseInBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
let s: NSTimeInterval = 1.70158
var position: NSTimeInterval = elapsed / duration
return CGFloat( position * position * ((s + 1.0) * position - s) )
}
internal static let EaseOutBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
let s: NSTimeInterval = 1.70158
var position: NSTimeInterval = elapsed / duration
position -= 1.0
return CGFloat( position * position * ((s + 1.0) * position + s) + 1.0 )
}
internal static let EaseInOutBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var s: NSTimeInterval = 1.70158
var position: NSTimeInterval = elapsed / (duration / 2.0)
if (position < 1.0)
{
s *= 1.525
return CGFloat( 0.5 * (position * position * ((s + 1.0) * position - s)) )
}
s *= 1.525
position -= 2.0
return CGFloat( 0.5 * (position * position * ((s + 1.0) * position + s) + 2.0) )
}
internal static let EaseInBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
return 1.0 - EaseOutBounce(duration - elapsed, duration)
}
internal static let EaseOutBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
var position: NSTimeInterval = elapsed / duration
if (position < (1.0 / 2.75))
{
return CGFloat( 7.5625 * position * position )
}
else if (position < (2.0 / 2.75))
{
position -= (1.5 / 2.75)
return CGFloat( 7.5625 * position * position + 0.75 )
}
else if (position < (2.5 / 2.75))
{
position -= (2.25 / 2.75)
return CGFloat( 7.5625 * position * position + 0.9375 )
}
else
{
position -= (2.625 / 2.75)
return CGFloat( 7.5625 * position * position + 0.984375 )
}
}
internal static let EaseInOutBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
if (elapsed < (duration / 2.0))
{
return EaseInBounce(elapsed * 2.0, duration) * 0.5
}
return EaseOutBounce(elapsed * 2.0 - duration, duration) * 0.5 + 0.5
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Animation/ChartAnimator.swift
================================================
//
// ChartAnimator.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
@objc
public protocol ChartAnimatorDelegate
{
/// Called when the Animator has stepped.
func chartAnimatorUpdated(chartAnimator: ChartAnimator)
/// Called when the Animator has stopped.
func chartAnimatorStopped(chartAnimator: ChartAnimator)
}
public class ChartAnimator: NSObject
{
public weak var delegate: ChartAnimatorDelegate?
public var updateBlock: (() -> Void)?
public var stopBlock: (() -> Void)?
/// the phase that is animated and influences the drawn values on the x-axis
public var phaseX: CGFloat = 1.0
/// the phase that is animated and influences the drawn values on the y-axis
public var phaseY: CGFloat = 1.0
private var _startTimeX: NSTimeInterval = 0.0
private var _startTimeY: NSTimeInterval = 0.0
private var _displayLink: NSUIDisplayLink!
private var _durationX: NSTimeInterval = 0.0
private var _durationY: NSTimeInterval = 0.0
private var _endTimeX: NSTimeInterval = 0.0
private var _endTimeY: NSTimeInterval = 0.0
private var _endTime: NSTimeInterval = 0.0
private var _enabledX: Bool = false
private var _enabledY: Bool = false
private var _easingX: ChartEasingFunctionBlock?
private var _easingY: ChartEasingFunctionBlock?
public override init()
{
super.init()
}
deinit
{
stop()
}
public func stop()
{
if (_displayLink != nil)
{
_displayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
_displayLink = nil
_enabledX = false
_enabledY = false
// If we stopped an animation in the middle, we do not want to leave it like this
if phaseX != 1.0 || phaseY != 1.0
{
phaseX = 1.0
phaseY = 1.0
if (delegate != nil)
{
delegate!.chartAnimatorUpdated(self)
}
if (updateBlock != nil)
{
updateBlock!()
}
}
if (delegate != nil)
{
delegate!.chartAnimatorStopped(self)
}
if (stopBlock != nil)
{
stopBlock?()
}
}
}
private func updateAnimationPhases(currentTime: NSTimeInterval)
{
if (_enabledX)
{
let elapsedTime: NSTimeInterval = currentTime - _startTimeX
let duration: NSTimeInterval = _durationX
var elapsed: NSTimeInterval = elapsedTime
if (elapsed > duration)
{
elapsed = duration
}
if (_easingX != nil)
{
phaseX = _easingX!(elapsed: elapsed, duration: duration)
}
else
{
phaseX = CGFloat(elapsed / duration)
}
}
if (_enabledY)
{
let elapsedTime: NSTimeInterval = currentTime - _startTimeY
let duration: NSTimeInterval = _durationY
var elapsed: NSTimeInterval = elapsedTime
if (elapsed > duration)
{
elapsed = duration
}
if (_easingY != nil)
{
phaseY = _easingY!(elapsed: elapsed, duration: duration)
}
else
{
phaseY = CGFloat(elapsed / duration)
}
}
}
@objc private func animationLoop()
{
let currentTime: NSTimeInterval = CACurrentMediaTime()
updateAnimationPhases(currentTime)
if (delegate != nil)
{
delegate!.chartAnimatorUpdated(self)
}
if (updateBlock != nil)
{
updateBlock!()
}
if (currentTime >= _endTime)
{
stop()
}
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingX: an easing function for the animation on the x axis
/// - parameter easingY: an easing function for the animation on the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
{
stop()
_startTimeX = CACurrentMediaTime()
_startTimeY = _startTimeX
_durationX = xAxisDuration
_durationY = yAxisDuration
_endTimeX = _startTimeX + xAxisDuration
_endTimeY = _startTimeY + yAxisDuration
_endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
_enabledX = xAxisDuration > 0.0
_enabledY = yAxisDuration > 0.0
_easingX = easingX
_easingY = easingY
// Take care of the first frame if rendering is already scheduled...
updateAnimationPhases(_startTimeX)
if (_enabledX || _enabledY)
{
_displayLink = NSUIDisplayLink(target: self, selector: #selector(ChartAnimator.animationLoop))
_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOptionX: the easing function for the animation on the x axis
/// - parameter easingOptionY: the easing function for the animation on the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
{
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingFunctionFromOption(easingOptionX), easingY: easingFunctionFromOption(easingOptionY))
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easing: an easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easing, easingY: easing)
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOption: the easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval)
{
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: .EaseInOutSine)
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter easing: an easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
_startTimeX = CACurrentMediaTime()
_durationX = xAxisDuration
_endTimeX = _startTimeX + xAxisDuration
_endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
_enabledX = xAxisDuration > 0.0
_easingX = easing
// Take care of the first frame if rendering is already scheduled...
updateAnimationPhases(_startTimeX)
if (_enabledX || _enabledY)
{
if _displayLink === nil
{
_displayLink = NSUIDisplayLink(target: self, selector: #selector(ChartAnimator.animationLoop))
_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter easingOption: the easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
animate(xAxisDuration: xAxisDuration, easing: easingFunctionFromOption(easingOption))
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval)
{
animate(xAxisDuration: xAxisDuration, easingOption: .EaseInOutSine)
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easing: an easing function for the animation
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
_startTimeY = CACurrentMediaTime()
_durationY = yAxisDuration
_endTimeY = _startTimeY + yAxisDuration
_endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
_enabledY = yAxisDuration > 0.0
_easingY = easing
// Take care of the first frame if rendering is already scheduled...
updateAnimationPhases(_startTimeY)
if (_enabledX || _enabledY)
{
if _displayLink === nil
{
_displayLink = NSUIDisplayLink(target: self, selector: #selector(ChartAnimator.animationLoop))
_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOption: the easing function for the animation
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
animate(yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
public func animate(yAxisDuration yAxisDuration: NSTimeInterval)
{
animate(yAxisDuration: yAxisDuration, easingOption: .EaseInOutSine)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/BarChartView.swift
================================================
//
// BarChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Chart that draws bars.
public class BarChartView: BarLineChartViewBase, BarChartDataProvider
{
/// flag that enables or disables the highlighting arrow
private var _drawHighlightArrowEnabled = false
/// if set to true, all values are drawn above their bars, instead of below their top
private var _drawValueAboveBarEnabled = true
/// if set to true, a grey area is drawn behind each bar that indicates the maximum value
private var _drawBarShadowEnabled = false
internal override func initialize()
{
super.initialize()
renderer = BarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
_xAxisRenderer = ChartXAxisRendererBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
self.highlighter = BarChartHighlighter(chart: self)
_xAxis._axisMinimum = -0.5
}
internal override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
let barData = data as! BarChartData
// increase deltax by 1 because the bars have a width of 1
_xAxis.axisRange += 0.5
// extend xDelta to make space for multiple datasets (if ther are one)
_xAxis.axisRange *= Double(data.dataSetCount)
let groupSpace = barData.groupSpace
_xAxis.axisRange += Double(barData.xValCount) * Double(groupSpace)
_xAxis._axisMaximum = _xAxis.axisRange - _xAxis._axisMinimum
}
/// - returns: the Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the BarChart.
public override func getHighlightByTouchPoint(pt: CGPoint) -> ChartHighlight?
{
if _data === nil
{
Swift.print("Can't select by touch. No data set.")
return nil
}
return self.highlighter?.getHighlight(x: Double(pt.x), y: Double(pt.y))
}
/// - returns: the bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be found in the charts data.
public func getBarBounds(e: BarChartDataEntry) -> CGRect
{
guard let
set = _data?.getDataSetForEntry(e) as? IBarChartDataSet
else { return CGRectNull }
let barspace = set.barSpace
let y = CGFloat(e.value)
let x = CGFloat(e.xIndex)
let barWidth: CGFloat = 0.5
let spaceHalf = barspace / 2.0
let left = x - barWidth + spaceHalf
let right = x + barWidth - spaceHalf
let top = y >= 0.0 ? y : 0.0
let bottom = y <= 0.0 ? y : 0.0
var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
getTransformer(set.axisDependency).rectValueToPixel(&bounds)
return bounds
}
public override var lowestVisibleXIndex: Int
{
let step = CGFloat(_data?.dataSetCount ?? 0)
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentBottom)
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int((pt.x <= CGFloat(chartXMin)) ? 0.0 : (pt.x / div) + 1.0)
}
public override var highestVisibleXIndex: Int
{
let step = CGFloat(_data?.dataSetCount ?? 0)
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
var pt = CGPoint(x: _viewPortHandler.contentRight, y: _viewPortHandler.contentBottom)
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int((pt.x >= CGFloat(chartXMax)) ? CGFloat(chartXMax) / div : (pt.x / div))
}
// MARK: Accessors
/// flag that enables or disables the highlighting arrow
public var drawHighlightArrowEnabled: Bool
{
get { return _drawHighlightArrowEnabled; }
set
{
_drawHighlightArrowEnabled = newValue
setNeedsDisplay()
}
}
/// if set to true, all values are drawn above their bars, instead of below their top
public var drawValueAboveBarEnabled: Bool
{
get { return _drawValueAboveBarEnabled; }
set
{
_drawValueAboveBarEnabled = newValue
setNeedsDisplay()
}
}
/// if set to true, a grey area is drawn behind each bar that indicates the maximum value
public var drawBarShadowEnabled: Bool
{
get { return _drawBarShadowEnabled; }
set
{
_drawBarShadowEnabled = newValue
setNeedsDisplay()
}
}
// MARK: - BarChartDataProbider
public var barData: BarChartData? { return _data as? BarChartData }
/// - returns: true if drawing the highlighting arrow is enabled, false if not
public var isDrawHighlightArrowEnabled: Bool { return drawHighlightArrowEnabled }
/// - returns: true if drawing values above bars is enabled, false if not
public var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled }
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
public var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/BarLineChartViewBase.swift
================================================
//
// BarLineChartViewBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart.
public class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartDataProvider, NSUIGestureRecognizerDelegate
{
/// the maximum number of entries to which values will be drawn
/// (entry numbers greater than this value will cause value-labels to disappear)
internal var _maxVisibleValueCount = 100
/// flag that indicates if auto scaling on the y axis is enabled
private var _autoScaleMinMaxEnabled = false
private var _autoScaleLastLowestVisibleXIndex: Int!
private var _autoScaleLastHighestVisibleXIndex: Int!
private var _pinchZoomEnabled = false
private var _doubleTapToZoomEnabled = true
private var _dragEnabled = true
private var _scaleXEnabled = true
private var _scaleYEnabled = true
/// the color for the background of the chart-drawing area (everything behind the grid lines).
public var gridBackgroundColor = NSUIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
public var borderColor = NSUIColor.blackColor()
public var borderLineWidth: CGFloat = 1.0
/// flag indicating if the grid background should be drawn or not
public var drawGridBackgroundEnabled = false
/// Sets drawing the borders rectangle to true. If this is enabled, there is no point drawing the axis-lines of x- and y-axis.
public var drawBordersEnabled = false
/// Sets the minimum offset (padding) around the chart, defaults to 10
public var minOffset = CGFloat(10.0)
/// Sets whether the chart should keep its position (zoom / scroll) after a rotation (orientation change)
/// **default**: false
public var keepPositionOnRotation: Bool = false
/// the object representing the left y-axis
internal var _leftAxis: ChartYAxis!
/// the object representing the right y-axis
internal var _rightAxis: ChartYAxis!
internal var _leftYAxisRenderer: ChartYAxisRenderer!
internal var _rightYAxisRenderer: ChartYAxisRenderer!
internal var _leftAxisTransformer: ChartTransformer!
internal var _rightAxisTransformer: ChartTransformer!
internal var _xAxisRenderer: ChartXAxisRenderer!
internal var _tapGestureRecognizer: NSUITapGestureRecognizer!
internal var _doubleTapGestureRecognizer: NSUITapGestureRecognizer!
#if !os(tvOS)
internal var _pinchGestureRecognizer: NSUIPinchGestureRecognizer!
#endif
internal var _panGestureRecognizer: NSUIPanGestureRecognizer!
/// flag that indicates if a custom viewport offset has been set
private var _customViewPortEnabled = false
public override init(frame: CGRect)
{
super.init(frame: frame)
}
public required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
deinit
{
stopDeceleration()
}
internal override func initialize()
{
super.initialize()
_leftAxis = ChartYAxis(position: .Left)
_rightAxis = ChartYAxis(position: .Right)
_leftAxisTransformer = ChartTransformer(viewPortHandler: _viewPortHandler)
_rightAxisTransformer = ChartTransformer(viewPortHandler: _viewPortHandler)
_leftYAxisRenderer = ChartYAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: _leftAxis, transformer: _leftAxisTransformer)
_rightYAxisRenderer = ChartYAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: _rightAxis, transformer: _rightAxisTransformer)
_xAxisRenderer = ChartXAxisRenderer(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer)
self.highlighter = ChartHighlighter(chart: self)
_tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.tapGestureRecognized(_:)))
_doubleTapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.doubleTapGestureRecognized(_:)))
_doubleTapGestureRecognizer.nsuiNumberOfTapsRequired = 2
_panGestureRecognizer = NSUIPanGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.panGestureRecognized(_:)))
_panGestureRecognizer.delegate = self
self.addGestureRecognizer(_tapGestureRecognizer)
self.addGestureRecognizer(_doubleTapGestureRecognizer)
self.addGestureRecognizer(_panGestureRecognizer)
_doubleTapGestureRecognizer.enabled = _doubleTapToZoomEnabled
_panGestureRecognizer.enabled = _dragEnabled
#if !os(tvOS)
_pinchGestureRecognizer = NSUIPinchGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.pinchGestureRecognized(_:)))
_pinchGestureRecognizer.delegate = self
self.addGestureRecognizer(_pinchGestureRecognizer)
_pinchGestureRecognizer.enabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
#endif
}
public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer)
{
// Saving current position of chart.
var oldPoint: CGPoint?
if (keepPositionOnRotation && (keyPath == "frame" || keyPath == "bounds"))
{
oldPoint = viewPortHandler.contentRect.origin
getTransformer(.Left).pixelToValue(&oldPoint!)
}
// Superclass transforms chart.
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
// Restoring old position of chart
if var newPoint = oldPoint where keepPositionOnRotation
{
getTransformer(.Left).pointValueToPixel(&newPoint)
viewPortHandler.centerViewPort(pt: newPoint, chart: self)
}
else
{
viewPortHandler.refresh(newMatrix: viewPortHandler.touchMatrix, chart: self, invalidate: true)
}
}
public override func drawRect(rect: CGRect)
{
super.drawRect(rect)
if _data === nil
{
return
}
let optionalContext = NSUIGraphicsGetCurrentContext()
guard let context = optionalContext else { return }
calcModulus()
if (_xAxisRenderer !== nil)
{
_xAxisRenderer!.calcXBounds(chart: self, xAxisModulus: _xAxis.axisLabelModulus)
}
if (renderer !== nil)
{
renderer!.calcXBounds(chart: self, xAxisModulus: _xAxis.axisLabelModulus)
}
// execute all drawing commands
drawGridBackground(context: context)
if (_leftAxis.isEnabled)
{
_leftYAxisRenderer?.computeAxis(yMin: _leftAxis._axisMinimum, yMax: _leftAxis._axisMaximum)
}
if (_rightAxis.isEnabled)
{
_rightYAxisRenderer?.computeAxis(yMin: _rightAxis._axisMinimum, yMax: _rightAxis._axisMaximum)
}
_xAxisRenderer?.renderAxisLine(context: context)
_leftYAxisRenderer?.renderAxisLine(context: context)
_rightYAxisRenderer?.renderAxisLine(context: context)
if (_autoScaleMinMaxEnabled)
{
let lowestVisibleXIndex = self.lowestVisibleXIndex,
highestVisibleXIndex = self.highestVisibleXIndex
if (_autoScaleLastLowestVisibleXIndex == nil || _autoScaleLastLowestVisibleXIndex != lowestVisibleXIndex ||
_autoScaleLastHighestVisibleXIndex == nil || _autoScaleLastHighestVisibleXIndex != highestVisibleXIndex)
{
calcMinMax()
calculateOffsets()
_autoScaleLastLowestVisibleXIndex = lowestVisibleXIndex
_autoScaleLastHighestVisibleXIndex = highestVisibleXIndex
}
}
// make sure the graph values and grid cannot be drawn outside the content-rect
CGContextSaveGState(context)
CGContextClipToRect(context, _viewPortHandler.contentRect)
_xAxisRenderer?.renderGridLines(context: context)
_leftYAxisRenderer?.renderGridLines(context: context)
_rightYAxisRenderer?.renderGridLines(context: context)
if (_xAxis.isDrawLimitLinesBehindDataEnabled)
{
_xAxisRenderer?.renderLimitLines(context: context)
}
if (_leftAxis.isDrawLimitLinesBehindDataEnabled)
{
_leftYAxisRenderer?.renderLimitLines(context: context)
}
if (_rightAxis.isDrawLimitLinesBehindDataEnabled)
{
_rightYAxisRenderer?.renderLimitLines(context: context)
}
renderer?.drawData(context: context)
// if highlighting is enabled
if (valuesToHighlight())
{
renderer?.drawHighlighted(context: context, indices: _indicesToHighlight)
}
// Removes clipping rectangle
CGContextRestoreGState(context)
renderer!.drawExtras(context: context)
if (!_xAxis.isDrawLimitLinesBehindDataEnabled)
{
_xAxisRenderer?.renderLimitLines(context: context)
}
if (!_leftAxis.isDrawLimitLinesBehindDataEnabled)
{
_leftYAxisRenderer?.renderLimitLines(context: context)
}
if (!_rightAxis.isDrawLimitLinesBehindDataEnabled)
{
_rightYAxisRenderer?.renderLimitLines(context: context)
}
_xAxisRenderer.renderAxisLabels(context: context)
_leftYAxisRenderer.renderAxisLabels(context: context)
_rightYAxisRenderer.renderAxisLabels(context: context)
renderer!.drawValues(context: context)
_legendRenderer.renderLegend(context: context)
// drawLegend()
drawMarkers(context: context)
drawDescription(context: context)
}
internal func prepareValuePxMatrix()
{
_rightAxisTransformer.prepareMatrixValuePx(chartXMin: _xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(_rightAxis.axisRange), chartYMin: _rightAxis._axisMinimum)
_leftAxisTransformer.prepareMatrixValuePx(chartXMin: xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(_leftAxis.axisRange), chartYMin: _leftAxis._axisMinimum)
}
internal func prepareOffsetMatrix()
{
_rightAxisTransformer.prepareMatrixOffset(_rightAxis.isInverted)
_leftAxisTransformer.prepareMatrixOffset(_leftAxis.isInverted)
}
public override func notifyDataSetChanged()
{
calcMinMax()
_leftAxis?._defaultValueFormatter = _defaultValueFormatter
_rightAxis?._defaultValueFormatter = _defaultValueFormatter
_leftYAxisRenderer?.computeAxis(yMin: _leftAxis._axisMinimum, yMax: _leftAxis._axisMaximum)
_rightYAxisRenderer?.computeAxis(yMin: _rightAxis._axisMinimum, yMax: _rightAxis._axisMaximum)
if let data = _data
{
_xAxisRenderer?.computeAxis(xValAverageLength: data.xValAverageLength, xValues: data.xVals)
if (_legend !== nil)
{
_legendRenderer?.computeLegend(data)
}
}
calculateOffsets()
setNeedsDisplay()
}
internal override func calcMinMax()
{
if (_autoScaleMinMaxEnabled)
{
_data?.calcMinMax(start: lowestVisibleXIndex, end: highestVisibleXIndex)
}
// calculate / set x-axis range
_xAxis._axisMaximum = Double((_data?.xVals.count ?? 0) - 1)
_xAxis.axisRange = .abs(_xAxis._axisMaximum - _xAxis._axisMinimum);
// calculate axis range (min / max) according to provided data
_leftAxis.calcMinMax(min: _data?.getYMin(.Left) ?? 0.0, max: _data?.getYMax(.Left) ?? 0.0)
_rightAxis.calcMinMax(min: _data?.getYMin(.Right) ?? 0.0, max: _data?.getYMax(.Right) ?? 0.0)
}
internal override func calculateOffsets()
{
if (!_customViewPortEnabled)
{
var offsetLeft = CGFloat(0.0)
var offsetRight = CGFloat(0.0)
var offsetTop = CGFloat(0.0)
var offsetBottom = CGFloat(0.0)
// setup offsets for legend
if (_legend !== nil && _legend.isEnabled)
{
if (_legend.position == .RightOfChart
|| _legend.position == .RightOfChartCenter)
{
offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
}
if (_legend.position == .LeftOfChart
|| _legend.position == .LeftOfChartCenter)
{
offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
}
else if (_legend.position == .BelowChartLeft
|| _legend.position == .BelowChartRight
|| _legend.position == .BelowChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = _legend.textHeightMax
offsetBottom += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
else if (_legend.position == .AboveChartLeft
|| _legend.position == .AboveChartRight
|| _legend.position == .AboveChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = _legend.textHeightMax
offsetTop += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
}
// offsets for y-labels
if (leftAxis.needsOffset)
{
offsetLeft += leftAxis.requiredSize().width
}
if (rightAxis.needsOffset)
{
offsetRight += rightAxis.requiredSize().width
}
if (xAxis.isEnabled && xAxis.isDrawLabelsEnabled)
{
let xlabelheight = xAxis.labelRotatedHeight + xAxis.yOffset
// offsets for x-labels
if (xAxis.labelPosition == .Bottom)
{
offsetBottom += xlabelheight
}
else if (xAxis.labelPosition == .Top)
{
offsetTop += xlabelheight
}
else if (xAxis.labelPosition == .BothSided)
{
offsetBottom += xlabelheight
offsetTop += xlabelheight
}
}
offsetTop += self.extraTopOffset
offsetRight += self.extraRightOffset
offsetBottom += self.extraBottomOffset
offsetLeft += self.extraLeftOffset
_viewPortHandler.restrainViewPort(
offsetLeft: max(self.minOffset, offsetLeft),
offsetTop: max(self.minOffset, offsetTop),
offsetRight: max(self.minOffset, offsetRight),
offsetBottom: max(self.minOffset, offsetBottom))
}
prepareOffsetMatrix()
prepareValuePxMatrix()
}
/// calculates the modulus for x-labels and grid
internal func calcModulus()
{
if (_xAxis === nil || !_xAxis.isEnabled)
{
return
}
if (!_xAxis.isAxisModulusCustom)
{
_xAxis.axisLabelModulus = Int(ceil((CGFloat(_data?.xValCount ?? 0) * _xAxis.labelRotatedWidth) / (_viewPortHandler.contentWidth * _viewPortHandler.touchMatrix.a)))
}
if (_xAxis.axisLabelModulus < 1)
{
_xAxis.axisLabelModulus = 1
}
}
public override func getMarkerPosition(entry e: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
{
guard let data = _data else { return CGPointZero }
let dataSetIndex = highlight.dataSetIndex
var xPos = CGFloat(e.xIndex)
var yPos = CGFloat(e.value)
if (self.isKindOfClass(BarChartView))
{
let bd = _data as! BarChartData
let space = bd.groupSpace
let setCount = data.dataSetCount
let i = e.xIndex
if self is HorizontalBarChartView
{
// calculate the x-position, depending on datasetcount
let y = CGFloat(i + i * (setCount - 1) + dataSetIndex) + space * CGFloat(i) + space / 2.0
yPos = y
if let entry = e as? BarChartDataEntry
{
if entry.values != nil && highlight.range !== nil
{
xPos = CGFloat(highlight.range!.to)
}
else
{
xPos = CGFloat(e.value)
}
}
}
else
{
let x = CGFloat(i + i * (setCount - 1) + dataSetIndex) + space * CGFloat(i) + space / 2.0
xPos = x
if let entry = e as? BarChartDataEntry
{
if entry.values != nil && highlight.range !== nil
{
yPos = CGFloat(highlight.range!.to)
}
else
{
yPos = CGFloat(e.value)
}
}
}
}
// position of the marker depends on selected value index and value
var pt = CGPoint(x: xPos, y: yPos * _animator.phaseY)
getTransformer(data.getDataSetByIndex(dataSetIndex)!.axisDependency).pointValueToPixel(&pt)
return pt
}
/// draws the grid background
internal func drawGridBackground(context context: CGContext)
{
if (drawGridBackgroundEnabled || drawBordersEnabled)
{
CGContextSaveGState(context)
}
if (drawGridBackgroundEnabled)
{
// draw the grid background
CGContextSetFillColorWithColor(context, gridBackgroundColor.CGColor)
CGContextFillRect(context, _viewPortHandler.contentRect)
}
if (drawBordersEnabled)
{
CGContextSetLineWidth(context, borderLineWidth)
CGContextSetStrokeColorWithColor(context, borderColor.CGColor)
CGContextStrokeRect(context, _viewPortHandler.contentRect)
}
if (drawGridBackgroundEnabled || drawBordersEnabled)
{
CGContextRestoreGState(context)
}
}
// MARK: - Gestures
private enum GestureScaleAxis
{
case Both
case X
case Y
}
private var _isDragging = false
private var _isScaling = false
private var _gestureScaleAxis = GestureScaleAxis.Both
private var _closestDataSetToTouch: IChartDataSet!
private var _panGestureReachedEdge: Bool = false
private weak var _outerScrollView: NSUIScrollView?
private var _lastPanPoint = CGPoint() /// This is to prevent using setTranslation which resets velocity
private var _decelerationLastTime: NSTimeInterval = 0.0
private var _decelerationDisplayLink: NSUIDisplayLink!
private var _decelerationVelocity = CGPoint()
@objc private func tapGestureRecognized(recognizer: NSUITapGestureRecognizer)
{
if _data === nil
{
return
}
if (recognizer.state == NSUIGestureRecognizerState.Ended)
{
if !self.isHighLightPerTapEnabled { return }
let h = getHighlightByTouchPoint(recognizer.locationInView(self))
if (h === nil || h!.isEqual(self.lastHighlighted))
{
self.highlightValue(highlight: nil, callDelegate: true)
self.lastHighlighted = nil
}
else
{
self.lastHighlighted = h
self.highlightValue(highlight: h, callDelegate: true)
}
}
}
@objc private func doubleTapGestureRecognized(recognizer: NSUITapGestureRecognizer)
{
if _data === nil
{
return
}
if (recognizer.state == NSUIGestureRecognizerState.Ended)
{
if _data !== nil && _doubleTapToZoomEnabled
{
var location = recognizer.locationInView(self)
location.x = location.x - _viewPortHandler.offsetLeft
if (isAnyAxisInverted && _closestDataSetToTouch !== nil && getAxis(_closestDataSetToTouch.axisDependency).isInverted)
{
location.y = -(location.y - _viewPortHandler.offsetTop)
}
else
{
location.y = -(self.bounds.size.height - location.y - _viewPortHandler.offsetBottom)
}
self.zoom(isScaleXEnabled ? 1.4 : 1.0, scaleY: isScaleYEnabled ? 1.4 : 1.0, x: location.x, y: location.y)
}
}
}
#if !os(tvOS)
@objc private func pinchGestureRecognized(recognizer: NSUIPinchGestureRecognizer)
{
if (recognizer.state == NSUIGestureRecognizerState.Began)
{
stopDeceleration()
if _data !== nil && (_pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled)
{
_isScaling = true
if (_pinchZoomEnabled)
{
_gestureScaleAxis = .Both
}
else
{
let x = abs(recognizer.locationInView(self).x - recognizer.nsuiLocationOfTouch(1, inView: self).x)
let y = abs(recognizer.locationInView(self).y - recognizer.nsuiLocationOfTouch(1, inView: self).y)
if (x > y)
{
_gestureScaleAxis = .X
}
else
{
_gestureScaleAxis = .Y
}
}
}
}
else if (recognizer.state == NSUIGestureRecognizerState.Ended ||
recognizer.state == NSUIGestureRecognizerState.Cancelled)
{
if (_isScaling)
{
_isScaling = false
// Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
calculateOffsets()
setNeedsDisplay()
}
}
else if (recognizer.state == NSUIGestureRecognizerState.Changed)
{
let isZoomingOut = (recognizer.nsuiScale < 1)
var canZoomMoreX = isZoomingOut ? _viewPortHandler.canZoomOutMoreX : _viewPortHandler.canZoomInMoreX
var canZoomMoreY = isZoomingOut ? _viewPortHandler.canZoomOutMoreY : _viewPortHandler.canZoomInMoreY
if (_isScaling)
{
canZoomMoreX = canZoomMoreX && _scaleXEnabled && (_gestureScaleAxis == .Both || _gestureScaleAxis == .X);
canZoomMoreY = canZoomMoreY && _scaleYEnabled && (_gestureScaleAxis == .Both || _gestureScaleAxis == .Y);
if canZoomMoreX || canZoomMoreY
{
var location = recognizer.locationInView(self)
location.x = location.x - _viewPortHandler.offsetLeft
if (isAnyAxisInverted && _closestDataSetToTouch !== nil && getAxis(_closestDataSetToTouch.axisDependency).isInverted)
{
location.y = -(location.y - _viewPortHandler.offsetTop)
}
else
{
location.y = -(_viewPortHandler.chartHeight - location.y - _viewPortHandler.offsetBottom)
}
let scaleX = canZoomMoreX ? recognizer.nsuiScale : 1.0
let scaleY = canZoomMoreY ? recognizer.nsuiScale : 1.0
var matrix = CGAffineTransformMakeTranslation(location.x, location.y)
matrix = CGAffineTransformScale(matrix, scaleX, scaleY)
matrix = CGAffineTransformTranslate(matrix,
-location.x, -location.y)
matrix = CGAffineTransformConcat(_viewPortHandler.touchMatrix, matrix)
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
if (delegate !== nil)
{
delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
}
}
recognizer.nsuiScale = 1.0
}
}
}
#endif
@objc private func panGestureRecognized(recognizer: NSUIPanGestureRecognizer)
{
if (recognizer.state == NSUIGestureRecognizerState.Began && recognizer.nsuiNumberOfTouches() > 0)
{
stopDeceleration()
if _data === nil
{ // If we have no data, we have nothing to pan and no data to highlight
return;
}
// If drag is enabled and we are in a position where there's something to drag:
// * If we're zoomed in, then obviously we have something to drag.
// * If we have a drag offset - we always have something to drag
if self.isDragEnabled &&
(!self.hasNoDragOffset || !self.isFullyZoomedOut)
{
_isDragging = true
_closestDataSetToTouch = getDataSetByTouchPoint(recognizer.nsuiLocationOfTouch(0, inView: self))
let translation = recognizer.translationInView(self)
let didUserDrag = (self is HorizontalBarChartView) ? translation.y != 0.0 : translation.x != 0.0
// Check to see if user dragged at all and if so, can the chart be dragged by the given amount
if (didUserDrag && !performPanChange(translation: translation))
{
if (_outerScrollView !== nil)
{
// We can stop dragging right now, and let the scroll view take control
_outerScrollView = nil
_isDragging = false
}
}
else
{
if (_outerScrollView !== nil)
{
// Prevent the parent scroll view from scrolling
_outerScrollView?.scrollEnabled = false
}
}
_lastPanPoint = recognizer.translationInView(self)
}
else if self.isHighlightPerDragEnabled
{
// We will only handle highlights on NSUIGestureRecognizerState.Changed
_isDragging = false
}
}
else if (recognizer.state == NSUIGestureRecognizerState.Changed)
{
if (_isDragging)
{
let originalTranslation = recognizer.translationInView(self)
let translation = CGPoint(x: originalTranslation.x - _lastPanPoint.x, y: originalTranslation.y - _lastPanPoint.y)
performPanChange(translation: translation)
_lastPanPoint = originalTranslation
}
else if (isHighlightPerDragEnabled)
{
let h = getHighlightByTouchPoint(recognizer.locationInView(self))
let lastHighlighted = self.lastHighlighted
if ((h === nil && lastHighlighted !== nil) ||
(h !== nil && lastHighlighted === nil) ||
(h !== nil && lastHighlighted !== nil && !h!.isEqual(lastHighlighted)))
{
self.lastHighlighted = h
self.highlightValue(highlight: h, callDelegate: true)
}
}
}
else if (recognizer.state == NSUIGestureRecognizerState.Ended || recognizer.state == NSUIGestureRecognizerState.Cancelled)
{
if (_isDragging)
{
if (recognizer.state == NSUIGestureRecognizerState.Ended && isDragDecelerationEnabled)
{
stopDeceleration()
_decelerationLastTime = CACurrentMediaTime()
_decelerationVelocity = recognizer.velocityInView(self)
_decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(BarLineChartViewBase.decelerationLoop))
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
_isDragging = false
}
if (_outerScrollView !== nil)
{
_outerScrollView?.scrollEnabled = true
_outerScrollView = nil
}
}
}
private func performPanChange(translation translation: CGPoint) -> Bool
{
var translation = translation
if (isAnyAxisInverted && _closestDataSetToTouch !== nil
&& getAxis(_closestDataSetToTouch.axisDependency).isInverted)
{
if (self is HorizontalBarChartView)
{
translation.x = -translation.x
}
else
{
translation.y = -translation.y
}
}
let originalMatrix = _viewPortHandler.touchMatrix
var matrix = CGAffineTransformMakeTranslation(translation.x, translation.y)
matrix = CGAffineTransformConcat(originalMatrix, matrix)
matrix = _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
if (delegate !== nil)
{
delegate?.chartTranslated?(self, dX: translation.x, dY: translation.y)
}
// Did we managed to actually drag or did we reach the edge?
return matrix.tx != originalMatrix.tx || matrix.ty != originalMatrix.ty
}
public func stopDeceleration()
{
if (_decelerationDisplayLink !== nil)
{
_decelerationDisplayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
_decelerationDisplayLink = nil
}
}
@objc private func decelerationLoop()
{
let currentTime = CACurrentMediaTime()
_decelerationVelocity.x *= self.dragDecelerationFrictionCoef
_decelerationVelocity.y *= self.dragDecelerationFrictionCoef
let timeInterval = CGFloat(currentTime - _decelerationLastTime)
let distance = CGPoint(
x: _decelerationVelocity.x * timeInterval,
y: _decelerationVelocity.y * timeInterval
)
if (!performPanChange(translation: distance))
{
// We reached the edge, stop
_decelerationVelocity.x = 0.0
_decelerationVelocity.y = 0.0
}
_decelerationLastTime = currentTime
if (abs(_decelerationVelocity.x) < 0.001 && abs(_decelerationVelocity.y) < 0.001)
{
stopDeceleration()
// Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
calculateOffsets()
setNeedsDisplay()
}
}
private func nsuiGestureRecognizerShouldBegin(gestureRecognizer: NSUIGestureRecognizer) -> Bool
{
if (gestureRecognizer == _panGestureRecognizer)
{
if _data === nil || !_dragEnabled ||
(self.hasNoDragOffset && self.isFullyZoomedOut && !self.isHighlightPerDragEnabled)
{
return false
}
}
else
{
#if !os(tvOS)
if (gestureRecognizer == _pinchGestureRecognizer)
{
if _data === nil || (!_pinchZoomEnabled && !_scaleXEnabled && !_scaleYEnabled)
{
return false
}
}
#endif
}
return true
}
#if !os(OSX)
public override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool
{
if (!super.gestureRecognizerShouldBegin(gestureRecognizer))
{
return false
}
return nsuiGestureRecognizerShouldBegin(gestureRecognizer)
}
#endif
#if os(OSX)
public func gestureRecognizerShouldBegin(gestureRecognizer: NSGestureRecognizer) -> Bool
{
return nsuiGestureRecognizerShouldBegin(gestureRecognizer)
}
#endif
public func gestureRecognizer(gestureRecognizer: NSUIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: NSUIGestureRecognizer) -> Bool
{
#if !os(tvOS)
if ((gestureRecognizer.isKindOfClass(NSUIPinchGestureRecognizer) &&
otherGestureRecognizer.isKindOfClass(NSUIPanGestureRecognizer)) ||
(gestureRecognizer.isKindOfClass(NSUIPanGestureRecognizer) &&
otherGestureRecognizer.isKindOfClass(NSUIPinchGestureRecognizer)))
{
return true
}
#endif
if (gestureRecognizer.isKindOfClass(NSUIPanGestureRecognizer) &&
otherGestureRecognizer.isKindOfClass(NSUIPanGestureRecognizer) && (
gestureRecognizer == _panGestureRecognizer
))
{
var scrollView = self.superview
while (scrollView !== nil && !scrollView!.isKindOfClass(NSUIScrollView))
{
scrollView = scrollView?.superview
}
// If there is two scrollview together, we pick the superview of the inner scrollview.
// In the case of UITableViewWrepperView, the superview will be UITableView
if let superViewOfScrollView = scrollView?.superview where superViewOfScrollView.isKindOfClass(NSUIScrollView)
{
scrollView = superViewOfScrollView
}
var foundScrollView = scrollView as? NSUIScrollView
if (foundScrollView !== nil && !foundScrollView!.scrollEnabled)
{
foundScrollView = nil
}
var scrollViewPanGestureRecognizer: NSUIGestureRecognizer!
if (foundScrollView !== nil)
{
for scrollRecognizer in foundScrollView!.nsuiGestureRecognizers!
{
if (scrollRecognizer.isKindOfClass(NSUIPanGestureRecognizer))
{
scrollViewPanGestureRecognizer = scrollRecognizer as! NSUIPanGestureRecognizer
break
}
}
}
if (otherGestureRecognizer === scrollViewPanGestureRecognizer)
{
_outerScrollView = foundScrollView
return true
}
}
return false
}
/// MARK: Viewport modifiers
/// Zooms in by 1.4, into the charts center. center.
public func zoomIn()
{
let center = _viewPortHandler.contentCenter
let matrix = _viewPortHandler.zoomIn(x: center.x, y: -center.y)
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
// Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
calculateOffsets()
setNeedsDisplay()
}
/// Zooms out by 0.7, from the charts center. center.
public func zoomOut()
{
let center = _viewPortHandler.contentCenter
let matrix = _viewPortHandler.zoomOut(x: center.x, y: -center.y)
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
// Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
calculateOffsets()
setNeedsDisplay()
}
/// Zooms in or out by the given scale factor. x and y are the coordinates
/// (in pixels) of the zoom center.
///
/// - parameter scaleX: if < 1 --> zoom out, if > 1 --> zoom in
/// - parameter scaleY: if < 1 --> zoom out, if > 1 --> zoom in
/// - parameter x:
/// - parameter y:
public func zoom(scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat)
{
let matrix = _viewPortHandler.zoom(scaleX: scaleX, scaleY: scaleY, x: x, y: y)
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
// Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
calculateOffsets()
setNeedsDisplay()
}
/// Zooms in or out by the given scale factor.
/// x and y are the values (**not pixels**) which to zoom to or from (the values of the zoom center).
///
/// - parameter scaleX: if < 1 --> zoom out, if > 1 --> zoom in
/// - parameter scaleY: if < 1 --> zoom out, if > 1 --> zoom in
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis:
public func zoom(
scaleX: CGFloat,
scaleY: CGFloat,
xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency)
{
let job = ZoomChartViewJob(viewPortHandler: viewPortHandler, scaleX: scaleX, scaleY: scaleY, xIndex: xIndex, yValue: yValue, transformer: getTransformer(axis), axis: axis, view: self)
addViewportJob(job)
}
/// Zooms by the specified scale factor to the specified values on the specified axis.
///
/// - parameter scaleX:
/// - parameter scaleY:
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func zoomAndCenterViewAnimated(
scaleX scaleX: CGFloat,
scaleY: CGFloat,
xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
let origin = getValueByTouchPoint(
pt: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
axis: axis)
let job = AnimatedZoomChartViewJob(
viewPortHandler: viewPortHandler,
transformer: getTransformer(axis),
view: self,
yAxis: getAxis(axis),
xValCount: _xAxis.values.count,
scaleX: scaleX,
scaleY: scaleY,
xOrigin: viewPortHandler.scaleX,
yOrigin: viewPortHandler.scaleY,
zoomCenterX: xIndex,
zoomCenterY: CGFloat(yValue),
zoomOriginX: origin.x,
zoomOriginY: origin.y,
duration: duration,
easing: easing)
addViewportJob(job)
}
/// Zooms by the specified scale factor to the specified values on the specified axis.
///
/// - parameter scaleX:
/// - parameter scaleY:
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func zoomAndCenterViewAnimated(
scaleX scaleX: CGFloat,
scaleY: CGFloat,
xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easingOption: ChartEasingOption)
{
zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
}
/// Zooms by the specified scale factor to the specified values on the specified axis.
///
/// - parameter scaleX:
/// - parameter scaleY:
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func zoomAndCenterViewAnimated(
scaleX scaleX: CGFloat,
scaleY: CGFloat,
xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval)
{
zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easingOption: .EaseInOutSine)
}
/// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
public func fitScreen()
{
let matrix = _viewPortHandler.fitScreen()
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
calculateOffsets()
setNeedsDisplay()
}
/// Sets the minimum scale value to which can be zoomed out. 1 = fitScreen
public func setScaleMinima(scaleX: CGFloat, scaleY: CGFloat)
{
_viewPortHandler.setMinimumScaleX(scaleX)
_viewPortHandler.setMinimumScaleY(scaleY)
}
/// Sets the size of the area (range on the x-axis) that should be maximum visible at once (no further zomming out allowed).
/// If this is e.g. set to 10, no more than 10 values on the x-axis can be viewed at once without scrolling.
public func setVisibleXRangeMaximum(maxXRange: CGFloat)
{
let xScale = CGFloat(_xAxis.axisRange) / maxXRange
_viewPortHandler.setMinimumScaleX(xScale)
}
/// Sets the size of the area (range on the x-axis) that should be minimum visible at once (no further zooming in allowed).
/// If this is e.g. set to 10, no less than 10 values on the x-axis can be viewed at once without scrolling.
public func setVisibleXRangeMinimum(minXRange: CGFloat)
{
let xScale = CGFloat(_xAxis.axisRange) / minXRange
_viewPortHandler.setMaximumScaleX(xScale)
}
/// Limits the maximum and minimum value count that can be visible by pinching and zooming.
/// e.g. minRange=10, maxRange=100 no less than 10 values and no more that 100 values can be viewed
/// at once without scrolling
public func setVisibleXRange(minXRange minXRange: CGFloat, maxXRange: CGFloat)
{
let maxScale = CGFloat(_xAxis.axisRange) / minXRange
let minScale = CGFloat(_xAxis.axisRange) / maxXRange
_viewPortHandler.setMinMaxScaleX(minScaleX: minScale, maxScaleX: maxScale)
}
/// Sets the size of the area (range on the y-axis) that should be maximum visible at once.
///
/// - parameter yRange:
/// - parameter axis: - the axis for which this limit should apply
public func setVisibleYRangeMaximum(maxYRange: CGFloat, axis: ChartYAxis.AxisDependency)
{
let yScale = getDeltaY(axis) / maxYRange
_viewPortHandler.setMinimumScaleY(yScale)
}
/// Moves the left side of the current viewport to the specified x-index.
/// This also refreshes the chart by calling setNeedsDisplay().
public func moveViewToX(xIndex: CGFloat)
{
let job = MoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: 0.0,
transformer: getTransformer(.Left),
view: self)
addViewportJob(job)
}
/// Centers the viewport to the specified y-value on the y-axis.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter yValue:
/// - parameter axis: - which axis should be used as a reference for the y-axis
public func moveViewToY(yValue: Double, axis: ChartYAxis.AxisDependency)
{
let valsInView = getDeltaY(axis) / _viewPortHandler.scaleY
let job = MoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: 0,
yValue: yValue + Double(valsInView) / 2.0,
transformer: getTransformer(axis),
view: self)
addViewportJob(job)
}
/// This will move the left side of the current viewport to the specified x-index on the x-axis, and center the viewport to the specified y-value on the y-axis.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: - which axis should be used as a reference for the y-axis
public func moveViewTo(xIndex xIndex: CGFloat, yValue: Double, axis: ChartYAxis.AxisDependency)
{
let valsInView = getDeltaY(axis) / _viewPortHandler.scaleY
let job = MoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue + Double(valsInView) / 2.0,
transformer: getTransformer(axis),
view: self)
addViewportJob(job)
}
/// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func moveViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
let bounds = getValueByTouchPoint(
pt: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
axis: axis)
let valsInView = getDeltaY(axis) / _viewPortHandler.scaleY
let job = AnimatedMoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue + Double(valsInView) / 2.0,
transformer: getTransformer(axis),
view: self,
xOrigin: bounds.x,
yOrigin: bounds.y,
duration: duration,
easing: easing)
addViewportJob(job)
}
/// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func moveViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easingOption: ChartEasingOption)
{
moveViewToAnimated(xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
}
/// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func moveViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval)
{
moveViewToAnimated(xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easingOption: .EaseInOutSine)
}
/// This will move the center of the current viewport to the specified x-index and y-value.
/// This also refreshes the chart by calling setNeedsDisplay().
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: - which axis should be used as a reference for the y-axis
public func centerViewTo(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency)
{
let valsInView = getDeltaY(axis) / _viewPortHandler.scaleY
let xsInView = CGFloat(xAxis.values.count) / _viewPortHandler.scaleX
let job = MoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: xIndex - xsInView / 2.0,
yValue: yValue + Double(valsInView) / 2.0,
transformer: getTransformer(axis),
view: self)
addViewportJob(job)
}
/// This will move the center of the current viewport to the specified x-value and y-value animated.
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func centerViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
let bounds = getValueByTouchPoint(
pt: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
axis: axis)
let valsInView = getDeltaY(axis) / _viewPortHandler.scaleY
let xsInView = CGFloat(xAxis.values.count) / _viewPortHandler.scaleX
let job = AnimatedMoveChartViewJob(
viewPortHandler: viewPortHandler,
xIndex: xIndex - xsInView / 2.0,
yValue: yValue + Double(valsInView) / 2.0,
transformer: getTransformer(axis),
view: self,
xOrigin: bounds.x,
yOrigin: bounds.y,
duration: duration,
easing: easing)
addViewportJob(job)
}
/// This will move the center of the current viewport to the specified x-value and y-value animated.
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func centerViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval,
easingOption: ChartEasingOption)
{
centerViewToAnimated(xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
}
/// This will move the center of the current viewport to the specified x-value and y-value animated.
///
/// - parameter xIndex:
/// - parameter yValue:
/// - parameter axis: which axis should be used as a reference for the y-axis
/// - parameter duration: the duration of the animation in seconds
/// - parameter easing:
public func centerViewToAnimated(
xIndex xIndex: CGFloat,
yValue: Double,
axis: ChartYAxis.AxisDependency,
duration: NSTimeInterval)
{
centerViewToAnimated(xIndex: xIndex, yValue: yValue, axis: axis, duration: duration, easingOption: .EaseInOutSine)
}
/// Sets custom offsets for the current `ChartViewPort` (the offsets on the sides of the actual chart window). Setting this will prevent the chart from automatically calculating it's offsets. Use `resetViewPortOffsets()` to undo this.
/// ONLY USE THIS WHEN YOU KNOW WHAT YOU ARE DOING, else use `setExtraOffsets(...)`.
public func setViewPortOffsets(left left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
{
_customViewPortEnabled = true
if (NSThread.isMainThread())
{
self._viewPortHandler.restrainViewPort(offsetLeft: left, offsetTop: top, offsetRight: right, offsetBottom: bottom)
prepareOffsetMatrix()
prepareValuePxMatrix()
}
else
{
dispatch_async(dispatch_get_main_queue(), {
self.setViewPortOffsets(left: left, top: top, right: right, bottom: bottom)
})
}
}
/// Resets all custom offsets set via `setViewPortOffsets(...)` method. Allows the chart to again calculate all offsets automatically.
public func resetViewPortOffsets()
{
_customViewPortEnabled = false
calculateOffsets()
}
// MARK: - Accessors
/// - returns: the delta-y value (y-value range) of the specified axis.
public func getDeltaY(axis: ChartYAxis.AxisDependency) -> CGFloat
{
if (axis == .Left)
{
return CGFloat(leftAxis.axisRange)
}
else
{
return CGFloat(rightAxis.axisRange)
}
}
/// - returns: the position (in pixels) the provided Entry has inside the chart view
public func getPosition(e: ChartDataEntry, axis: ChartYAxis.AxisDependency) -> CGPoint
{
var vals = CGPoint(x: CGFloat(e.xIndex), y: CGFloat(e.value))
getTransformer(axis).pointValueToPixel(&vals)
return vals
}
/// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling).
public var dragEnabled: Bool
{
get
{
return _dragEnabled
}
set
{
if (_dragEnabled != newValue)
{
_dragEnabled = newValue
}
}
}
/// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling).
public var isDragEnabled: Bool
{
return dragEnabled
}
/// is scaling enabled? (zooming in and out by gesture) for the chart (this does not affect dragging).
public func setScaleEnabled(enabled: Bool)
{
if (_scaleXEnabled != enabled || _scaleYEnabled != enabled)
{
_scaleXEnabled = enabled
_scaleYEnabled = enabled
#if !os(tvOS)
_pinchGestureRecognizer.enabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
#endif
}
}
public var scaleXEnabled: Bool
{
get
{
return _scaleXEnabled
}
set
{
if (_scaleXEnabled != newValue)
{
_scaleXEnabled = newValue
#if !os(tvOS)
_pinchGestureRecognizer.enabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
#endif
}
}
}
public var scaleYEnabled: Bool
{
get
{
return _scaleYEnabled
}
set
{
if (_scaleYEnabled != newValue)
{
_scaleYEnabled = newValue
#if !os(tvOS)
_pinchGestureRecognizer.enabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
#endif
}
}
}
public var isScaleXEnabled: Bool { return scaleXEnabled; }
public var isScaleYEnabled: Bool { return scaleYEnabled; }
/// flag that indicates if double tap zoom is enabled or not
public var doubleTapToZoomEnabled: Bool
{
get
{
return _doubleTapToZoomEnabled
}
set
{
if (_doubleTapToZoomEnabled != newValue)
{
_doubleTapToZoomEnabled = newValue
_doubleTapGestureRecognizer.enabled = _doubleTapToZoomEnabled
}
}
}
/// **default**: true
/// - returns: true if zooming via double-tap is enabled false if not.
public var isDoubleTapToZoomEnabled: Bool
{
return doubleTapToZoomEnabled
}
/// flag that indicates if highlighting per dragging over a fully zoomed out chart is enabled
public var highlightPerDragEnabled = true
/// If set to true, highlighting per dragging over a fully zoomed out chart is enabled
/// You might want to disable this when using inside a `NSUIScrollView`
///
/// **default**: true
public var isHighlightPerDragEnabled: Bool
{
return highlightPerDragEnabled
}
/// **default**: true
/// - returns: true if drawing the grid background is enabled, false if not.
public var isDrawGridBackgroundEnabled: Bool
{
return drawGridBackgroundEnabled
}
/// **default**: false
/// - returns: true if drawing the borders rectangle is enabled, false if not.
public var isDrawBordersEnabled: Bool
{
return drawBordersEnabled
}
/// - returns: the Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the Line-, Scatter-, or CandleStick-Chart.
public func getHighlightByTouchPoint(pt: CGPoint) -> ChartHighlight?
{
if _data === nil
{
Swift.print("Can't select by touch. No data set.")
return nil
}
return self.highlighter?.getHighlight(x: Double(pt.x), y: Double(pt.y))
}
/// - returns: the x and y values in the chart at the given touch point
/// (encapsulated in a `CGPoint`). This method transforms pixel coordinates to
/// coordinates / values in the chart. This is the opposite method to
/// `getPixelsForValues(...)`.
public func getValueByTouchPoint(pt pt: CGPoint, axis: ChartYAxis.AxisDependency) -> CGPoint
{
var pt = pt
getTransformer(axis).pixelToValue(&pt)
return pt
}
/// Transforms the given chart values into pixels. This is the opposite
/// method to `getValueByTouchPoint(...)`.
public func getPixelForValue(x: Double, y: Double, axis: ChartYAxis.AxisDependency) -> CGPoint
{
var pt = CGPoint(x: CGFloat(x), y: CGFloat(y))
getTransformer(axis).pointValueToPixel(&pt)
return pt
}
/// - returns: the y-value at the given touch position (must not necessarily be
/// a value contained in one of the datasets)
public func getYValueByTouchPoint(pt pt: CGPoint, axis: ChartYAxis.AxisDependency) -> CGFloat
{
return getValueByTouchPoint(pt: pt, axis: axis).y
}
/// - returns: the Entry object displayed at the touched position of the chart
public func getEntryByTouchPoint(pt: CGPoint) -> ChartDataEntry!
{
let h = getHighlightByTouchPoint(pt)
if (h !== nil)
{
return _data!.getEntryForHighlight(h!)
}
return nil
}
/// - returns: the DataSet object displayed at the touched position of the chart
public func getDataSetByTouchPoint(pt: CGPoint) -> IBarLineScatterCandleBubbleChartDataSet!
{
let h = getHighlightByTouchPoint(pt)
if (h !== nil)
{
return _data?.getDataSetByIndex(h!.dataSetIndex) as! IBarLineScatterCandleBubbleChartDataSet!
}
return nil
}
/// - returns: the current x-scale factor
public var scaleX: CGFloat
{
if (_viewPortHandler === nil)
{
return 1.0
}
return _viewPortHandler.scaleX
}
/// - returns: the current y-scale factor
public var scaleY: CGFloat
{
if (_viewPortHandler === nil)
{
return 1.0
}
return _viewPortHandler.scaleY
}
/// if the chart is fully zoomed out, return true
public var isFullyZoomedOut: Bool { return _viewPortHandler.isFullyZoomedOut; }
/// - returns: the left y-axis object. In the horizontal bar-chart, this is the
/// top axis.
public var leftAxis: ChartYAxis
{
return _leftAxis
}
/// - returns: the right y-axis object. In the horizontal bar-chart, this is the
/// bottom axis.
public var rightAxis: ChartYAxis { return _rightAxis; }
/// - returns: the y-axis object to the corresponding AxisDependency. In the
/// horizontal bar-chart, LEFT == top, RIGHT == BOTTOM
public func getAxis(axis: ChartYAxis.AxisDependency) -> ChartYAxis
{
if (axis == .Left)
{
return _leftAxis
}
else
{
return _rightAxis
}
}
/// flag that indicates if pinch-zoom is enabled. if true, both x and y axis can be scaled simultaneously with 2 fingers, if false, x and y axis can be scaled separately
public var pinchZoomEnabled: Bool
{
get
{
return _pinchZoomEnabled
}
set
{
if (_pinchZoomEnabled != newValue)
{
_pinchZoomEnabled = newValue
#if !os(tvOS)
_pinchGestureRecognizer.enabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
#endif
}
}
}
/// **default**: false
/// - returns: true if pinch-zoom is enabled, false if not
public var isPinchZoomEnabled: Bool { return pinchZoomEnabled; }
/// Set an offset in dp that allows the user to drag the chart over it's
/// bounds on the x-axis.
public func setDragOffsetX(offset: CGFloat)
{
_viewPortHandler.setDragOffsetX(offset)
}
/// Set an offset in dp that allows the user to drag the chart over it's
/// bounds on the y-axis.
public func setDragOffsetY(offset: CGFloat)
{
_viewPortHandler.setDragOffsetY(offset)
}
/// - returns: true if both drag offsets (x and y) are zero or smaller.
public var hasNoDragOffset: Bool { return _viewPortHandler.hasNoDragOffset; }
/// The X axis renderer. This is a read-write property so you can set your own custom renderer here.
/// **default**: An instance of ChartXAxisRenderer
/// - returns: The current set X axis renderer
public var xAxisRenderer: ChartXAxisRenderer
{
get { return _xAxisRenderer }
set { _xAxisRenderer = newValue }
}
/// The left Y axis renderer. This is a read-write property so you can set your own custom renderer here.
/// **default**: An instance of ChartYAxisRenderer
/// - returns: The current set left Y axis renderer
public var leftYAxisRenderer: ChartYAxisRenderer
{
get { return _leftYAxisRenderer }
set { _leftYAxisRenderer = newValue }
}
/// The right Y axis renderer. This is a read-write property so you can set your own custom renderer here.
/// **default**: An instance of ChartYAxisRenderer
/// - returns: The current set right Y axis renderer
public var rightYAxisRenderer: ChartYAxisRenderer
{
get { return _rightYAxisRenderer }
set { _rightYAxisRenderer = newValue }
}
public override var chartYMax: Double
{
return max(leftAxis._axisMaximum, rightAxis._axisMaximum)
}
public override var chartYMin: Double
{
return min(leftAxis._axisMinimum, rightAxis._axisMinimum)
}
/// - returns: true if either the left or the right or both axes are inverted.
public var isAnyAxisInverted: Bool
{
return _leftAxis.isInverted || _rightAxis.isInverted
}
/// flag that indicates if auto scaling on the y axis is enabled.
/// if yes, the y axis automatically adjusts to the min and max y values of the current x axis range whenever the viewport changes
public var autoScaleMinMaxEnabled: Bool
{
get { return _autoScaleMinMaxEnabled; }
set { _autoScaleMinMaxEnabled = newValue; }
}
/// **default**: false
/// - returns: true if auto scaling on the y axis is enabled.
public var isAutoScaleMinMaxEnabled : Bool { return autoScaleMinMaxEnabled; }
/// Sets a minimum width to the specified y axis.
public func setYAxisMinWidth(which: ChartYAxis.AxisDependency, width: CGFloat)
{
if (which == .Left)
{
_leftAxis.minWidth = width
}
else
{
_rightAxis.minWidth = width
}
}
/// **default**: 0.0
/// - returns: the (custom) minimum width of the specified Y axis.
public func getYAxisMinWidth(which: ChartYAxis.AxisDependency) -> CGFloat
{
if (which == .Left)
{
return _leftAxis.minWidth
}
else
{
return _rightAxis.minWidth
}
}
/// Sets a maximum width to the specified y axis.
/// Zero (0.0) means there's no maximum width
public func setYAxisMaxWidth(which: ChartYAxis.AxisDependency, width: CGFloat)
{
if (which == .Left)
{
_leftAxis.maxWidth = width
}
else
{
_rightAxis.maxWidth = width
}
}
/// Zero (0.0) means there's no maximum width
///
/// **default**: 0.0 (no maximum specified)
/// - returns: the (custom) maximum width of the specified Y axis.
public func getYAxisMaxWidth(which: ChartYAxis.AxisDependency) -> CGFloat
{
if (which == .Left)
{
return _leftAxis.maxWidth
}
else
{
return _rightAxis.maxWidth
}
}
/// - returns the width of the specified y axis.
public func getYAxisWidth(which: ChartYAxis.AxisDependency) -> CGFloat
{
if (which == .Left)
{
return _leftAxis.requiredSize().width
}
else
{
return _rightAxis.requiredSize().width
}
}
// MARK: - BarLineScatterCandleBubbleChartDataProvider
/// - returns: the Transformer class that contains all matrices and is
/// responsible for transforming values into pixels on the screen and
/// backwards.
public func getTransformer(which: ChartYAxis.AxisDependency) -> ChartTransformer
{
if (which == .Left)
{
return _leftAxisTransformer
}
else
{
return _rightAxisTransformer
}
}
/// the number of maximum visible drawn values on the chart
/// only active when `setDrawValues()` is enabled
public var maxVisibleValueCount: Int
{
get
{
return _maxVisibleValueCount
}
set
{
_maxVisibleValueCount = newValue
}
}
public func isInverted(axis: ChartYAxis.AxisDependency) -> Bool
{
return getAxis(axis).isInverted
}
/// - returns: the lowest x-index (value on the x-axis) that is still visible on he chart.
public var lowestVisibleXIndex: Int
{
var pt = CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)
getTransformer(.Left).pixelToValue(&pt)
return (pt.x <= 0.0) ? 0 : Int(round(pt.x + 1.0))
}
/// - returns: the highest x-index (value on the x-axis) that is still visible on the chart.
public var highestVisibleXIndex: Int
{
var pt = CGPoint(
x: viewPortHandler.contentRight,
y: viewPortHandler.contentBottom)
getTransformer(.Left).pixelToValue(&pt)
guard let
data = _data
else { return Int(round(pt.x)) }
return min(data.xValCount - 1, Int(round(pt.x)))
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/BubbleChartView.swift
================================================
//
// BubbleChartView.swift
// Charts
//
// Bubble chart implementation:
// Copyright 2015 Pierre-Marc Airoldi
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BubbleChartView: BarLineChartViewBase, BubbleChartDataProvider
{
public override func initialize()
{
super.initialize()
renderer = BubbleChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
}
public override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
if _xAxis.axisRange == 0.0 && data.yValCount > 0
{
_xAxis.axisRange = 1.0
}
_xAxis._axisMinimum = -0.5
_xAxis._axisMaximum = Double(data.xVals.count) - 0.5
if renderer as? BubbleChartRenderer !== nil,
let sets = data.dataSets as? [IBubbleChartDataSet]
{
for set in sets {
let xmin = set.xMin
let xmax = set.xMax
if (xmin < _xAxis._axisMinimum)
{
_xAxis._axisMinimum = xmin
}
if (xmax > _xAxis._axisMaximum)
{
_xAxis._axisMaximum = xmax
}
}
}
_xAxis.axisRange = abs(_xAxis._axisMaximum - _xAxis._axisMinimum)
}
// MARK: - BubbleChartDataProbider
public var bubbleData: BubbleChartData? { return _data as? BubbleChartData }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/CandleStickChartView.swift
================================================
//
// CandleStickChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Financial chart type that draws candle-sticks.
public class CandleStickChartView: BarLineChartViewBase, CandleChartDataProvider
{
internal override func initialize()
{
super.initialize()
renderer = CandleStickChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
_xAxis._axisMinimum = -0.5
}
internal override func calcMinMax()
{
super.calcMinMax()
_xAxis._axisMaximum += 0.5
_xAxis.axisRange = abs(_xAxis._axisMaximum - _xAxis._axisMinimum)
}
// MARK: - CandleChartDataProvider
public var candleData: CandleChartData?
{
return _data as? CandleChartData
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/ChartViewBase.swift
================================================
//
// ChartViewBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
// Based on https://github.com/PhilJay/MPAndroidChart/commit/c42b880
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
@objc
public protocol ChartViewDelegate
{
/// Called when a value has been selected inside the chart.
/// - parameter entry: The selected Entry.
/// - parameter dataSetIndex: The index in the datasets array of the data object the Entrys DataSet is in.
optional func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight)
// Called when nothing has been selected or an "un-select" has been made.
optional func chartValueNothingSelected(chartView: ChartViewBase)
// Callbacks when the chart is scaled / zoomed via pinch zoom gesture.
optional func chartScaled(chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat)
// Callbacks when the chart is moved / translated via drag gesture.
optional func chartTranslated(chartView: ChartViewBase, dX: CGFloat, dY: CGFloat)
}
public class ChartViewBase: NSUIView, ChartDataProvider, ChartAnimatorDelegate
{
// MARK: - Properties
/// - returns: the object representing all x-labels, this method can be used to
/// acquire the XAxis object and modify it (e.g. change the position of the
/// labels)
public var xAxis: ChartXAxis
{
return _xAxis
}
/// the default value formatter
internal var _defaultValueFormatter: NSNumberFormatter = ChartUtils.defaultValueFormatter()
/// object that holds all data that was originally set for the chart, before it was modified or any filtering algorithms had been applied
internal var _data: ChartData?
/// Flag that indicates if highlighting per tap (touch) is enabled
private var _highlightPerTapEnabled = true
/// If set to true, chart continues to scroll after touch up
public var dragDecelerationEnabled = true
/// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
/// 1 is an invalid value, and will be converted to 0.999 automatically.
private var _dragDecelerationFrictionCoef: CGFloat = 0.9
/// Font object used for drawing the description text (by default in the bottom right corner of the chart)
public var descriptionFont: NSUIFont? = NSUIFont(name: "HelveticaNeue", size: 9.0)
/// Text color used for drawing the description text
public var descriptionTextColor: NSUIColor? = NSUIColor.blackColor()
/// Text align used for drawing the description text
public var descriptionTextAlign: NSTextAlignment = NSTextAlignment.Right
/// Custom position for the description text in pixels on the screen.
public var descriptionTextPosition: CGPoint? = nil
/// font object for drawing the information text when there are no values in the chart
public var infoFont: NSUIFont! = NSUIFont(name: "HelveticaNeue", size: 12.0)
public var infoTextColor: NSUIColor! = NSUIColor(red: 247.0/255.0, green: 189.0/255.0, blue: 51.0/255.0, alpha: 1.0) // orange
/// description text that appears in the bottom right corner of the chart
public var descriptionText = "Description"
/// if true, units are drawn next to the values in the chart
internal var _drawUnitInChart = false
/// the object representing the labels on the x-axis
internal var _xAxis: ChartXAxis!
/// the legend object containing all data associated with the legend
internal var _legend: ChartLegend!
/// delegate to receive chart events
public weak var delegate: ChartViewDelegate?
/// text that is displayed when the chart is empty
public var noDataText = "No chart data available."
/// text that is displayed when the chart is empty that describes why the chart is empty
public var noDataTextDescription: String?
internal var _legendRenderer: ChartLegendRenderer!
/// object responsible for rendering the data
public var renderer: ChartDataRendererBase?
public var highlighter: ChartHighlighter?
/// object that manages the bounds and drawing constraints of the chart
internal var _viewPortHandler: ChartViewPortHandler!
/// object responsible for animations
internal var _animator: ChartAnimator!
/// flag that indicates if offsets calculation has already been done or not
private var _offsetsCalculated = false
/// array of Highlight objects that reference the highlighted slices in the chart
internal var _indicesToHighlight = [ChartHighlight]()
/// if set to true, the marker is drawn when a value is clicked
public var drawMarkers = true
/// the view that represents the marker
public var marker: ChartMarker?
private var _interceptTouchEvents = false
/// An extra offset to be appended to the viewport's top
public var extraTopOffset: CGFloat = 0.0
/// An extra offset to be appended to the viewport's right
public var extraRightOffset: CGFloat = 0.0
/// An extra offset to be appended to the viewport's bottom
public var extraBottomOffset: CGFloat = 0.0
/// An extra offset to be appended to the viewport's left
public var extraLeftOffset: CGFloat = 0.0
public func setExtraOffsets(left left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
{
extraLeftOffset = left
extraTopOffset = top
extraRightOffset = right
extraBottomOffset = bottom
}
// MARK: - Initializers
public override init(frame: CGRect)
{
super.init(frame: frame)
#if os(iOS)
self.backgroundColor = NSUIColor.clearColor()
#endif
initialize()
}
public required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
initialize()
}
deinit
{
self.removeObserver(self, forKeyPath: "bounds")
self.removeObserver(self, forKeyPath: "frame")
}
internal func initialize()
{
_animator = ChartAnimator()
_animator.delegate = self
_viewPortHandler = ChartViewPortHandler()
_viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
_legend = ChartLegend()
_legendRenderer = ChartLegendRenderer(viewPortHandler: _viewPortHandler, legend: _legend)
_xAxis = ChartXAxis()
self.addObserver(self, forKeyPath: "bounds", options: .New, context: nil)
self.addObserver(self, forKeyPath: "frame", options: .New, context: nil)
}
// MARK: - ChartViewBase
/// The data for the chart
public var data: ChartData?
{
get
{
return _data
}
set
{
_offsetsCalculated = false
_data = newValue
// calculate how many digits are needed
if let data = _data
{
calculateFormatter(min: data.getYMin(), max: data.getYMax())
}
notifyDataSetChanged()
}
}
/// Clears the chart from all data (sets it to null) and refreshes it (by calling setNeedsDisplay()).
public func clear()
{
_data = nil
_indicesToHighlight.removeAll()
setNeedsDisplay()
}
/// Removes all DataSets (and thereby Entries) from the chart. Does not remove the x-values. Also refreshes the chart by calling setNeedsDisplay().
public func clearValues()
{
_data?.clearValues()
setNeedsDisplay()
}
/// - returns: true if the chart is empty (meaning it's data object is either null or contains no entries).
public func isEmpty() -> Bool
{
guard let data = _data else { return true }
if (data.yValCount <= 0)
{
return true
}
else
{
return false
}
}
/// Lets the chart know its underlying data has changed and should perform all necessary recalculations.
/// It is crucial that this method is called everytime data is changed dynamically. Not calling this method can lead to crashes or unexpected behaviour.
public func notifyDataSetChanged()
{
fatalError("notifyDataSetChanged() cannot be called on ChartViewBase")
}
/// calculates the offsets of the chart to the border depending on the position of an eventual legend or depending on the length of the y-axis and x-axis labels and their position
internal func calculateOffsets()
{
fatalError("calculateOffsets() cannot be called on ChartViewBase")
}
/// calcualtes the y-min and y-max value and the y-delta and x-delta value
internal func calcMinMax()
{
fatalError("calcMinMax() cannot be called on ChartViewBase")
}
/// calculates the required number of digits for the values that might be drawn in the chart (if enabled), and creates the default value formatter
internal func calculateFormatter(min min: Double, max: Double)
{
// check if a custom formatter is set or not
var reference = Double(0.0)
if let data = _data where data.xValCount >= 2
{
reference = fabs(max - min)
}
else
{
let absMin = fabs(min)
let absMax = fabs(max)
reference = absMin > absMax ? absMin : absMax
}
let digits = ChartUtils.decimals(reference)
_defaultValueFormatter.maximumFractionDigits = digits
_defaultValueFormatter.minimumFractionDigits = digits
}
public override func drawRect(rect: CGRect)
{
let optionalContext = NSUIGraphicsGetCurrentContext()
guard let context = optionalContext else { return }
let frame = self.bounds
if _data === nil
{
CGContextSaveGState(context)
defer { CGContextRestoreGState(context) }
let hasText = noDataText.characters.count > 0
let hasDescription = noDataTextDescription?.characters.count > 0
var textHeight = hasText ? infoFont.lineHeight : 0.0
if hasDescription
{
textHeight += infoFont.lineHeight
}
// if no data, inform the user
var y = (frame.height - textHeight) / 2.0
if hasText
{
ChartUtils.drawText(
context: context,
text: noDataText,
point: CGPoint(x: frame.width / 2.0, y: y),
align: .Center,
attributes: [NSFontAttributeName: infoFont, NSForegroundColorAttributeName: infoTextColor]
)
y = y + infoFont.lineHeight
}
if (noDataTextDescription != nil && (noDataTextDescription!).characters.count > 0)
{
ChartUtils.drawText(context: context, text: noDataTextDescription!, point: CGPoint(x: frame.width / 2.0, y: y), align: .Center, attributes: [NSFontAttributeName: infoFont, NSForegroundColorAttributeName: infoTextColor])
}
return
}
if (!_offsetsCalculated)
{
calculateOffsets()
_offsetsCalculated = true
}
}
/// draws the description text in the bottom right corner of the chart
internal func drawDescription(context context: CGContext)
{
if (descriptionText.lengthOfBytesUsingEncoding(NSUTF16StringEncoding) == 0)
{
return
}
let frame = self.bounds
var attrs = [String : AnyObject]()
var font = descriptionFont
if (font == nil)
{
#if os(tvOS)
// 23 is the smallest recommened font size on the TV
font = NSUIFont.systemFontOfSize(23, weight: UIFontWeightMedium)
#else
font = NSUIFont.systemFontOfSize(NSUIFont.systemFontSize())
#endif
}
attrs[NSFontAttributeName] = font
attrs[NSForegroundColorAttributeName] = descriptionTextColor
if descriptionTextPosition == nil
{
ChartUtils.drawText(
context: context,
text: descriptionText,
point: CGPoint(
x: frame.width - _viewPortHandler.offsetRight - 10.0,
y: frame.height - _viewPortHandler.offsetBottom - 10.0 - (font?.lineHeight ?? 0.0)),
align: descriptionTextAlign,
attributes: attrs)
}
else
{
ChartUtils.drawText(
context: context,
text: descriptionText,
point: descriptionTextPosition!,
align: descriptionTextAlign,
attributes: attrs)
}
}
// MARK: - Highlighting
/// - returns: the array of currently highlighted values. This might an empty if nothing is highlighted.
public var highlighted: [ChartHighlight]
{
return _indicesToHighlight
}
/// Set this to false to prevent values from being highlighted by tap gesture.
/// Values can still be highlighted via drag or programmatically.
/// **default**: true
public var highlightPerTapEnabled: Bool
{
get { return _highlightPerTapEnabled }
set { _highlightPerTapEnabled = newValue }
}
/// Returns true if values can be highlighted via tap gesture, false if not.
public var isHighLightPerTapEnabled: Bool
{
return highlightPerTapEnabled
}
/// Checks if the highlight array is null, has a length of zero or if the first object is null.
/// - returns: true if there are values to highlight, false if there are no values to highlight.
public func valuesToHighlight() -> Bool
{
return _indicesToHighlight.count > 0
}
/// Highlights the values at the given indices in the given DataSets. Provide
/// null or an empty array to undo all highlighting.
/// This should be used to programmatically highlight values.
/// This DOES NOT generate a callback to the delegate.
public func highlightValues(highs: [ChartHighlight]?)
{
// set the indices to highlight
_indicesToHighlight = highs ?? [ChartHighlight]()
if (_indicesToHighlight.isEmpty)
{
self.lastHighlighted = nil
}
else
{
self.lastHighlighted = _indicesToHighlight[0];
}
// redraw the chart
setNeedsDisplay()
}
/// Highlights the values represented by the provided Highlight object
/// This DOES NOT generate a callback to the delegate.
/// - parameter highlight: contains information about which entry should be highlighted
public func highlightValue(highlight: ChartHighlight?)
{
highlightValue(highlight: highlight, callDelegate: false)
}
/// Highlights the value at the given x-index in the given DataSet.
/// Provide -1 as the x-index to undo all highlighting.
public func highlightValue(xIndex xIndex: Int, dataSetIndex: Int, callDelegate: Bool)
{
guard let data = _data else
{
Swift.print("Value not highlighted because data is nil")
return
}
if (xIndex < 0 || dataSetIndex < 0 || xIndex >= data.xValCount || dataSetIndex >= data.dataSetCount)
{
highlightValue(highlight: nil, callDelegate: callDelegate)
}
else
{
highlightValue(highlight: ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex), callDelegate: callDelegate)
}
}
/// Highlights the value selected by touch gesture.
public func highlightValue(highlight highlight: ChartHighlight?, callDelegate: Bool)
{
var entry: ChartDataEntry?
var h = highlight
if (h == nil)
{
_indicesToHighlight.removeAll(keepCapacity: false)
}
else
{
// set the indices to highlight
entry = _data?.getEntryForHighlight(h!)
if (entry === nil || entry!.xIndex != h?.xIndex)
{
h = nil
entry = nil
_indicesToHighlight.removeAll(keepCapacity: false)
}
else
{
_indicesToHighlight = [h!]
}
}
if (callDelegate && delegate != nil)
{
if (h == nil)
{
delegate!.chartValueNothingSelected?(self)
}
else
{
// notify the listener
delegate!.chartValueSelected?(self, entry: entry!, dataSetIndex: h!.dataSetIndex, highlight: h!)
}
}
// redraw the chart
setNeedsDisplay()
}
/// The last value that was highlighted via touch.
public var lastHighlighted: ChartHighlight?
// MARK: - Markers
/// draws all MarkerViews on the highlighted positions
internal func drawMarkers(context context: CGContext)
{
// if there is no marker view or drawing marker is disabled
if (marker === nil || !drawMarkers || !valuesToHighlight())
{
return
}
for i in 0 ..< _indicesToHighlight.count
{
let highlight = _indicesToHighlight[i]
let xIndex = highlight.xIndex
let deltaX = _xAxis.axisRange
if xIndex <= Int(deltaX) && xIndex <= Int(CGFloat(deltaX) * _animator.phaseX)
{
let e = _data?.getEntryForHighlight(highlight)
if (e === nil || e!.xIndex != highlight.xIndex)
{
continue
}
let pos = getMarkerPosition(entry: e!, highlight: highlight)
// check bounds
if (!_viewPortHandler.isInBounds(x: pos.x, y: pos.y))
{
continue
}
// callbacks to update the content
marker!.refreshContent(entry: e!, highlight: highlight)
let markerSize = marker!.size
if (pos.y - markerSize.height <= 0.0)
{
let y = markerSize.height - pos.y
marker!.draw(context: context, point: CGPoint(x: pos.x, y: pos.y + y))
}
else
{
marker!.draw(context: context, point: pos)
}
}
}
}
/// - returns: the actual position in pixels of the MarkerView for the given Entry in the given DataSet.
public func getMarkerPosition(entry entry: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
{
fatalError("getMarkerPosition() cannot be called on ChartViewBase")
}
// MARK: - Animation
/// - returns: the animator responsible for animating chart values.
public var chartAnimator: ChartAnimator!
{
return _animator
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingX: an easing function for the animation on the x axis
/// - parameter easingY: an easing function for the animation on the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
{
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY)
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOptionX: the easing function for the animation on the x axis
/// - parameter easingOptionY: the easing function for the animation on the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
{
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY)
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easing: an easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing)
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOption: the easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption)
}
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter yAxisDuration: duration for animating the y axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval)
{
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration)
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter easing: an easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
_animator.animate(xAxisDuration: xAxisDuration, easing: easing)
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
/// - parameter easingOption: the easing function for the animation
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
_animator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption)
}
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter xAxisDuration: duration for animating the x axis
public func animate(xAxisDuration xAxisDuration: NSTimeInterval)
{
_animator.animate(xAxisDuration: xAxisDuration)
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easing: an easing function for the animation
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
{
_animator.animate(yAxisDuration: yAxisDuration, easing: easing)
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
/// - parameter easingOption: the easing function for the animation
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
{
_animator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption)
}
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
/// - parameter yAxisDuration: duration for animating the y axis
public func animate(yAxisDuration yAxisDuration: NSTimeInterval)
{
_animator.animate(yAxisDuration: yAxisDuration)
}
// MARK: - Accessors
/// - returns: the current y-max value across all DataSets
public var chartYMax: Double
{
return _data?.yMax ?? 0.0
}
/// - returns: the current y-min value across all DataSets
public var chartYMin: Double
{
return _data?.yMin ?? 0.0
}
public var chartXMax: Double
{
return _xAxis._axisMaximum
}
public var chartXMin: Double
{
return _xAxis._axisMinimum
}
public var xValCount: Int
{
return _data?.xValCount ?? 0
}
/// - returns: the total number of (y) values the chart holds (across all DataSets)
public var valueCount: Int
{
return _data?.yValCount ?? 0
}
/// *Note: (Equivalent of getCenter() in MPAndroidChart, as center is already a standard in iOS that returns the center point relative to superview, and MPAndroidChart returns relative to self)*
/// - returns: the center point of the chart (the whole View) in pixels.
public var midPoint: CGPoint
{
let bounds = self.bounds
return CGPoint(x: bounds.origin.x + bounds.size.width / 2.0, y: bounds.origin.y + bounds.size.height / 2.0)
}
public func setDescriptionTextPosition(x x: CGFloat, y: CGFloat)
{
descriptionTextPosition = CGPoint(x: x, y: y)
}
/// - returns: the center of the chart taking offsets under consideration. (returns the center of the content rectangle)
public var centerOffsets: CGPoint
{
return _viewPortHandler.contentCenter
}
/// - returns: the Legend object of the chart. This method can be used to get an instance of the legend in order to customize the automatically generated Legend.
public var legend: ChartLegend
{
return _legend
}
/// - returns: the renderer object responsible for rendering / drawing the Legend.
public var legendRenderer: ChartLegendRenderer!
{
return _legendRenderer
}
/// - returns: the rectangle that defines the borders of the chart-value surface (into which the actual values are drawn).
public var contentRect: CGRect
{
return _viewPortHandler.contentRect
}
/// - returns: the x-value at the given index
public func getXValue(index: Int) -> String!
{
guard let data = _data where data.xValCount > index else
{
return nil
}
return data.xVals[index]
}
/// Get all Entry objects at the given index across all DataSets.
public func getEntriesAtIndex(xIndex: Int) -> [ChartDataEntry]
{
var vals = [ChartDataEntry]()
guard let data = _data else { return vals }
for i in 0 ..< data.dataSetCount
{
let set = data.getDataSetByIndex(i)
let e = set.entryForXIndex(xIndex)
if (e !== nil)
{
vals.append(e!)
}
}
return vals
}
/// - returns: the ViewPortHandler of the chart that is responsible for the
/// content area of the chart and its offsets and dimensions.
public var viewPortHandler: ChartViewPortHandler!
{
return _viewPortHandler
}
/// - returns: the bitmap that represents the chart.
public func getChartImage(transparent transparent: Bool) -> NSUIImage?
{
NSUIGraphicsBeginImageContextWithOptions(bounds.size, opaque || !transparent, NSUIMainScreen()?.nsuiScale ?? 1.0)
let context = NSUIGraphicsGetCurrentContext()
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
if (opaque || !transparent)
{
// Background color may be partially transparent, we must fill with white if we want to output an opaque image
CGContextSetFillColorWithColor(context, NSUIColor.whiteColor().CGColor)
CGContextFillRect(context, rect)
if (self.backgroundColor !== nil)
{
CGContextSetFillColorWithColor(context, self.backgroundColor?.CGColor)
CGContextFillRect(context, rect)
}
}
if let context = context
{
nsuiLayer?.renderInContext(context)
}
let image = NSUIGraphicsGetImageFromCurrentImageContext()
NSUIGraphicsEndImageContext()
return image
}
public enum ImageFormat
{
case JPEG
case PNG
}
/// Saves the current chart state with the given name to the given path on
/// the sdcard leaving the path empty "" will put the saved file directly on
/// the SD card chart is saved as a PNG image, example:
/// saveToPath("myfilename", "foldername1/foldername2")
///
/// - parameter filePath: path to the image to save
/// - parameter format: the format to save
/// - parameter compressionQuality: compression quality for lossless formats (JPEG)
///
/// - returns: true if the image was saved successfully
public func saveToPath(path: String, format: ImageFormat, compressionQuality: Double) -> Bool
{
if let image = getChartImage(transparent: format != .JPEG) {
var imageData: NSData!
switch (format)
{
case .PNG:
imageData = NSUIImagePNGRepresentation(image)
break
case .JPEG:
imageData = NSUIImageJPEGRepresentation(image, CGFloat(compressionQuality))
break
}
return imageData.writeToFile(path, atomically: true)
}
return false
}
#if !os(tvOS) && !os(OSX)
/// Saves the current state of the chart to the camera roll
public func saveToCameraRoll()
{
if let img = getChartImage(transparent: false) {
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil)
}
}
#endif
internal var _viewportJobs = [ChartViewPortJob]()
public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer)
{
if (keyPath == "bounds" || keyPath == "frame")
{
let bounds = self.bounds
if (_viewPortHandler !== nil &&
(bounds.size.width != _viewPortHandler.chartWidth ||
bounds.size.height != _viewPortHandler.chartHeight))
{
_viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
// Finish any pending viewport changes
while (!_viewportJobs.isEmpty)
{
let job = _viewportJobs.removeAtIndex(0)
job.doJob()
}
notifyDataSetChanged()
}
}
}
public func removeViewportJob(job: ChartViewPortJob)
{
if let index = _viewportJobs.indexOf({ $0 === job })
{
_viewportJobs.removeAtIndex(index)
}
}
public func clearAllViewportJobs()
{
_viewportJobs.removeAll(keepCapacity: false)
}
public func addViewportJob(job: ChartViewPortJob)
{
if (_viewPortHandler.hasChartDimens)
{
job.doJob()
}
else
{
_viewportJobs.append(job)
}
}
/// **default**: true
/// - returns: true if chart continues to scroll after touch up, false if not.
public var isDragDecelerationEnabled: Bool
{
return dragDecelerationEnabled
}
/// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
/// 1 is an invalid value, and will be converted to 0.999 automatically.
///
/// **default**: true
public var dragDecelerationFrictionCoef: CGFloat
{
get
{
return _dragDecelerationFrictionCoef
}
set
{
var val = newValue
if (val < 0.0)
{
val = 0.0
}
if (val >= 1.0)
{
val = 0.999
}
_dragDecelerationFrictionCoef = val
}
}
// MARK: - ChartAnimatorDelegate
public func chartAnimatorUpdated(chartAnimator: ChartAnimator)
{
setNeedsDisplay()
}
public func chartAnimatorStopped(chartAnimator: ChartAnimator)
{
}
// MARK: - Touches
public override func nsuiTouchesBegan(touches: Set, withEvent event: NSUIEvent?)
{
if (!_interceptTouchEvents)
{
super.nsuiTouchesBegan(touches, withEvent: event)
}
}
public override func nsuiTouchesMoved(touches: Set, withEvent event: NSUIEvent?)
{
if (!_interceptTouchEvents)
{
super.nsuiTouchesMoved(touches, withEvent: event)
}
}
public override func nsuiTouchesEnded(touches: Set, withEvent event: NSUIEvent?)
{
if (!_interceptTouchEvents)
{
super.nsuiTouchesEnded(touches, withEvent: event)
}
}
public override func nsuiTouchesCancelled(touches: Set?, withEvent event: NSUIEvent?)
{
if (!_interceptTouchEvents)
{
super.nsuiTouchesCancelled(touches, withEvent: event)
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/CombinedChartView.swift
================================================
//
// CombinedChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// This chart class allows the combination of lines, bars, scatter and candle data all displayed in one chart area.
public class CombinedChartView: BarLineChartViewBase, LineChartDataProvider, BarChartDataProvider, ScatterChartDataProvider, CandleChartDataProvider, BubbleChartDataProvider
{
/// the fill-formatter used for determining the position of the fill-line
internal var _fillFormatter: ChartFillFormatter!
/// enum that allows to specify the order in which the different data objects for the combined-chart are drawn
@objc
public enum CombinedChartDrawOrder: Int
{
case Bar
case Bubble
case Line
case Candle
case Scatter
}
public override func initialize()
{
super.initialize()
self.highlighter = CombinedHighlighter(chart: self)
/// WORKAROUND: Swift 2.0 compiler malfunctions when optimizations are enabled, and assigning directly to _fillFormatter causes a crash with a EXC_BAD_ACCESS. See https://github.com/danielgindi/ios-charts/issues/406
let workaroundFormatter = ChartDefaultFillFormatter()
_fillFormatter = workaroundFormatter
renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
}
override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
if (self.barData !== nil || self.candleData !== nil || self.bubbleData !== nil)
{
_xAxis._axisMinimum = -0.5
_xAxis._axisMaximum = Double(data.xVals.count) - 0.5
if (self.bubbleData !== nil)
{
for set in self.bubbleData?.dataSets as! [IBubbleChartDataSet]
{
let xmin = set.xMin
let xmax = set.xMax
if (xmin < chartXMin)
{
_xAxis._axisMinimum = xmin
}
if (xmax > chartXMax)
{
_xAxis._axisMaximum = xmax
}
}
}
}
_xAxis.axisRange = abs(_xAxis._axisMaximum - _xAxis._axisMinimum)
if _xAxis.axisRange == 0.0 && self.lineData?.yValCount > 0
{
_xAxis.axisRange = 1.0
}
}
public override var data: ChartData?
{
get
{
return super.data
}
set
{
super.data = newValue
(renderer as! CombinedChartRenderer?)!.createRenderers()
}
}
public var fillFormatter: ChartFillFormatter
{
get
{
return _fillFormatter
}
set
{
_fillFormatter = newValue
if (_fillFormatter == nil)
{
_fillFormatter = ChartDefaultFillFormatter()
}
}
}
// MARK: - LineChartDataProvider
public var lineData: LineChartData?
{
get
{
if (_data === nil)
{
return nil
}
return (_data as! CombinedChartData!).lineData
}
}
// MARK: - BarChartDataProvider
public var barData: BarChartData?
{
get
{
if (_data === nil)
{
return nil
}
return (_data as! CombinedChartData!).barData
}
}
// MARK: - ScatterChartDataProvider
public var scatterData: ScatterChartData?
{
get
{
if (_data === nil)
{
return nil
}
return (_data as! CombinedChartData!).scatterData
}
}
// MARK: - CandleChartDataProvider
public var candleData: CandleChartData?
{
get
{
if (_data === nil)
{
return nil
}
return (_data as! CombinedChartData!).candleData
}
}
// MARK: - BubbleChartDataProvider
public var bubbleData: BubbleChartData?
{
get
{
if (_data === nil)
{
return nil
}
return (_data as! CombinedChartData!).bubbleData
}
}
// MARK: - Accessors
/// flag that enables or disables the highlighting arrow
public var drawHighlightArrowEnabled: Bool
{
get { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled }
set { (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled = newValue }
}
/// if set to true, all values are drawn above their bars, instead of below their top
public var drawValueAboveBarEnabled: Bool
{
get { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled }
set { (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled = newValue }
}
/// if set to true, a grey area is drawn behind each bar that indicates the maximum value
public var drawBarShadowEnabled: Bool
{
get { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled }
set { (renderer as! CombinedChartRenderer!).drawBarShadowEnabled = newValue }
}
/// - returns: true if drawing the highlighting arrow is enabled, false if not
public var isDrawHighlightArrowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled; }
/// - returns: true if drawing values above bars is enabled, false if not
public var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled; }
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
public var isDrawBarShadowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled; }
/// the order in which the provided data objects should be drawn.
/// The earlier you place them in the provided array, the further they will be in the background.
/// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
public var drawOrder: [Int]
{
get
{
return (renderer as! CombinedChartRenderer!).drawOrder.map { $0.rawValue }
}
set
{
(renderer as! CombinedChartRenderer!).drawOrder = newValue.map { CombinedChartDrawOrder(rawValue: $0)! }
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/HorizontalBarChartView.swift
================================================
//
// HorizontalBarChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched.
public class HorizontalBarChartView: BarChartView
{
internal override func initialize()
{
super.initialize()
_leftAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
_rightAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
renderer = HorizontalBarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
_leftYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _leftAxis, transformer: _leftAxisTransformer)
_rightYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _rightAxis, transformer: _rightAxisTransformer)
_xAxisRenderer = ChartXAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
self.highlighter = HorizontalBarChartHighlighter(chart: self)
}
internal override func calculateOffsets()
{
var offsetLeft: CGFloat = 0.0,
offsetRight: CGFloat = 0.0,
offsetTop: CGFloat = 0.0,
offsetBottom: CGFloat = 0.0
// setup offsets for legend
if (_legend !== nil && _legend.isEnabled)
{
if (_legend.position == .RightOfChart
|| _legend.position == .RightOfChartCenter)
{
offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
}
else if (_legend.position == .LeftOfChart
|| _legend.position == .LeftOfChartCenter)
{
offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
}
else if (_legend.position == .BelowChartLeft
|| _legend.position == .BelowChartRight
|| _legend.position == .BelowChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = _legend.textHeightMax + 2.5 * 2.0
offsetBottom += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
else if (_legend.position == .AboveChartLeft
|| _legend.position == .AboveChartRight
|| _legend.position == .AboveChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = _legend.textHeightMax
offsetTop += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
}
// offsets for y-labels
if (_leftAxis.needsOffset)
{
offsetTop += _leftAxis.getRequiredHeightSpace()
}
if (_rightAxis.needsOffset)
{
offsetBottom += _rightAxis.getRequiredHeightSpace()
}
let xlabelwidth = _xAxis.labelRotatedWidth
if (_xAxis.isEnabled)
{
// offsets for x-labels
if (_xAxis.labelPosition == .Bottom)
{
offsetLeft += xlabelwidth
}
else if (_xAxis.labelPosition == .Top)
{
offsetRight += xlabelwidth
}
else if (_xAxis.labelPosition == .BothSided)
{
offsetLeft += xlabelwidth
offsetRight += xlabelwidth
}
}
offsetTop += self.extraTopOffset
offsetRight += self.extraRightOffset
offsetBottom += self.extraBottomOffset
offsetLeft += self.extraLeftOffset
_viewPortHandler.restrainViewPort(
offsetLeft: max(self.minOffset, offsetLeft),
offsetTop: max(self.minOffset, offsetTop),
offsetRight: max(self.minOffset, offsetRight),
offsetBottom: max(self.minOffset, offsetBottom))
prepareOffsetMatrix()
prepareValuePxMatrix()
}
internal override func prepareValuePxMatrix()
{
_rightAxisTransformer.prepareMatrixValuePx(chartXMin: _rightAxis._axisMinimum, deltaX: CGFloat(_rightAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
_leftAxisTransformer.prepareMatrixValuePx(chartXMin: _leftAxis._axisMinimum, deltaX: CGFloat(_leftAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
}
internal override func calcModulus()
{
if let data = _data
{
_xAxis.axisLabelModulus = Int(ceil((CGFloat(data.xValCount) * _xAxis.labelRotatedHeight) / (_viewPortHandler.contentHeight * viewPortHandler.touchMatrix.d)))
}
else
{
_xAxis.axisLabelModulus = 1
}
if (_xAxis.axisLabelModulus < 1)
{
_xAxis.axisLabelModulus = 1
}
}
public override func getBarBounds(e: BarChartDataEntry) -> CGRect
{
guard let
set = _data?.getDataSetForEntry(e) as? IBarChartDataSet
else { return CGRectNull }
let barspace = set.barSpace
let y = CGFloat(e.value)
let x = CGFloat(e.xIndex)
let spaceHalf = barspace / 2.0
let top = x - 0.5 + spaceHalf
let bottom = x + 0.5 - spaceHalf
let left = y >= 0.0 ? y : 0.0
let right = y <= 0.0 ? y : 0.0
var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
getTransformer(set.axisDependency).rectValueToPixel(&bounds)
return bounds
}
public override func getPosition(e: ChartDataEntry, axis: ChartYAxis.AxisDependency) -> CGPoint
{
var vals = CGPoint(x: CGFloat(e.value), y: CGFloat(e.xIndex))
getTransformer(axis).pointValueToPixel(&vals)
return vals
}
public override func getHighlightByTouchPoint(pt: CGPoint) -> ChartHighlight?
{
if _data === nil
{
Swift.print("Can't select by touch. No data set.", terminator: "\n")
return nil
}
return self.highlighter?.getHighlight(x: Double(pt.y), y: Double(pt.x))
}
public override var lowestVisibleXIndex: Int
{
let step = CGFloat(_data?.dataSetCount ?? 0)
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentBottom)
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int(((pt.y <= 0.0) ? 0.0 : pt.y / div) + 1.0)
}
public override var highestVisibleXIndex: Int
{
let step = CGFloat(_data?.dataSetCount ?? 0)
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentTop)
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int((pt.y >= CGFloat(chartXMax)) ? CGFloat(chartXMax) / div : (pt.y / div))
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/LineChartView.swift
================================================
//
// LineChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Chart that draws lines, surfaces, circles, ...
public class LineChartView: BarLineChartViewBase, LineChartDataProvider
{
internal override func initialize()
{
super.initialize()
renderer = LineChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
}
internal override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
if _xAxis.axisRange == 0.0 && data.yValCount > 0
{
_xAxis.axisRange = 1.0
}
}
// MARK: - LineChartDataProvider
public var lineData: LineChartData? { return _data as? LineChartData }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/PieChartView.swift
================================================
//
// PieChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// View that represents a pie chart. Draws cake like slices.
public class PieChartView: PieRadarChartViewBase
{
/// rect object that represents the bounds of the piechart, needed for drawing the circle
private var _circleBox = CGRect()
private var _drawXLabelsEnabled = true
/// array that holds the width of each pie-slice in degrees
private var _drawAngles = [CGFloat]()
/// array that holds the absolute angle in degrees of each slice
private var _absoluteAngles = [CGFloat]()
/// if true, the hole inside the chart will be drawn
private var _drawHoleEnabled = true
private var _holeColor: NSUIColor? = NSUIColor.whiteColor()
/// if true, the hole will see-through to the inner tips of the slices
private var _drawSlicesUnderHoleEnabled = false
/// if true, the values inside the piechart are drawn as percent values
private var _usePercentValuesEnabled = false
/// variable for the text that is drawn in the center of the pie-chart
private var _centerAttributedText: NSAttributedString?
/// indicates the size of the hole in the center of the piechart
///
/// **default**: `0.5`
private var _holeRadiusPercent = CGFloat(0.5)
private var _transparentCircleColor: NSUIColor? = NSUIColor(white: 1.0, alpha: 105.0/255.0)
/// the radius of the transparent circle next to the chart-hole in the center
private var _transparentCircleRadiusPercent = CGFloat(0.55)
/// if enabled, centertext is drawn
private var _drawCenterTextEnabled = true
private var _centerTextRadiusPercent: CGFloat = 1.0
/// maximum angle for this pie
private var _maxAngle: CGFloat = 360.0
public override init(frame: CGRect)
{
super.init(frame: frame)
}
public required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
internal override func initialize()
{
super.initialize()
renderer = PieChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
_xAxis = nil
}
public override func drawRect(rect: CGRect)
{
super.drawRect(rect)
if _data === nil
{
return
}
let optionalContext = NSUIGraphicsGetCurrentContext()
guard let context = optionalContext else { return }
renderer!.drawData(context: context)
if (valuesToHighlight())
{
renderer!.drawHighlighted(context: context, indices: _indicesToHighlight)
}
renderer!.drawExtras(context: context)
renderer!.drawValues(context: context)
_legendRenderer.renderLegend(context: context)
drawDescription(context: context)
drawMarkers(context: context)
}
internal override func calculateOffsets()
{
super.calculateOffsets()
// prevent nullpointer when no data set
if _data === nil
{
return
}
let radius = diameter / 2.0
let c = self.centerOffsets
let shift = (data as? PieChartData)?.dataSet?.selectionShift ?? 0.0
// create the circle box that will contain the pie-chart (the bounds of the pie-chart)
_circleBox.origin.x = (c.x - radius) + shift
_circleBox.origin.y = (c.y - radius) + shift
_circleBox.size.width = diameter - shift * 2.0
_circleBox.size.height = diameter - shift * 2.0
}
internal override func calcMinMax()
{
calcAngles()
}
public override func getMarkerPosition(entry e: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
{
let center = self.centerCircleBox
var r = self.radius
var off = r / 10.0 * 3.6
if self.isDrawHoleEnabled
{
off = (r - (r * self.holeRadiusPercent)) / 2.0
}
r -= off // offset to keep things inside the chart
let rotationAngle = self.rotationAngle
let i = e.xIndex
// offset needed to center the drawn text in the slice
let offset = drawAngles[i] / 2.0
// calculate the text position
let x: CGFloat = (r * cos(((rotationAngle + absoluteAngles[i] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.x)
let y: CGFloat = (r * sin(((rotationAngle + absoluteAngles[i] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.y)
return CGPoint(x: x, y: y)
}
/// calculates the needed angles for the chart slices
private func calcAngles()
{
_drawAngles = [CGFloat]()
_absoluteAngles = [CGFloat]()
guard let data = _data else { return }
_drawAngles.reserveCapacity(data.yValCount)
_absoluteAngles.reserveCapacity(data.yValCount)
let yValueSum = (_data as! PieChartData).yValueSum
var dataSets = data.dataSets
var cnt = 0
for i in 0 ..< data.dataSetCount
{
let set = dataSets[i]
let entryCount = set.entryCount
for j in 0 ..< entryCount
{
guard let e = set.entryForIndex(j) else { continue }
_drawAngles.append(calcAngle(abs(e.value), yValueSum: yValueSum))
if (cnt == 0)
{
_absoluteAngles.append(_drawAngles[cnt])
}
else
{
_absoluteAngles.append(_absoluteAngles[cnt - 1] + _drawAngles[cnt])
}
cnt += 1
}
}
}
/// checks if the given index in the given DataSet is set for highlighting or not
public func needsHighlight(xIndex xIndex: Int, dataSetIndex: Int) -> Bool
{
// no highlight
if (!valuesToHighlight() || dataSetIndex < 0)
{
return false
}
for i in 0 ..< _indicesToHighlight.count
{
// check if the xvalue for the given dataset needs highlight
if (_indicesToHighlight[i].xIndex == xIndex
&& _indicesToHighlight[i].dataSetIndex == dataSetIndex)
{
return true
}
}
return false
}
/// calculates the needed angle for a given value
private func calcAngle(value: Double) -> CGFloat
{
return calcAngle(value, yValueSum: (_data as! PieChartData).yValueSum)
}
/// calculates the needed angle for a given value
private func calcAngle(value: Double, yValueSum: Double) -> CGFloat
{
return CGFloat(value) / CGFloat(yValueSum) * _maxAngle
}
/// This will throw an exception, PieChart has no XAxis object.
public override var xAxis: ChartXAxis
{
fatalError("PieChart has no XAxis")
}
public override func indexForAngle(angle: CGFloat) -> Int
{
// take the current angle of the chart into consideration
let a = ChartUtils.normalizedAngleFromAngle(angle - self.rotationAngle)
for i in 0 ..< _absoluteAngles.count
{
if (_absoluteAngles[i] > a)
{
return i
}
}
return -1; // return -1 if no index found
}
/// - returns: the index of the DataSet this x-index belongs to.
public func dataSetIndexForIndex(xIndex: Int) -> Int
{
var dataSets = _data?.dataSets ?? []
for i in 0 ..< dataSets.count
{
if (dataSets[i].entryForXIndex(xIndex) !== nil)
{
return i
}
}
return -1
}
/// - returns: an integer array of all the different angles the chart slices
/// have the angles in the returned array determine how much space (of 360°)
/// each slice takes
public var drawAngles: [CGFloat]
{
return _drawAngles
}
/// - returns: the absolute angles of the different chart slices (where the
/// slices end)
public var absoluteAngles: [CGFloat]
{
return _absoluteAngles
}
/// The color for the hole that is drawn in the center of the PieChart (if enabled).
///
/// *Note: Use holeTransparent with holeColor = nil to make the hole transparent.*
public var holeColor: NSUIColor?
{
get
{
return _holeColor
}
set
{
_holeColor = newValue
setNeedsDisplay()
}
}
/// if true, the hole will see-through to the inner tips of the slices
///
/// **default**: `false`
public var drawSlicesUnderHoleEnabled: Bool
{
get
{
return _drawSlicesUnderHoleEnabled
}
set
{
_drawSlicesUnderHoleEnabled = newValue
setNeedsDisplay()
}
}
/// - returns: `true` if the inner tips of the slices are visible behind the hole, `false` if not.
public var isDrawSlicesUnderHoleEnabled: Bool
{
return drawSlicesUnderHoleEnabled
}
/// true if the hole in the center of the pie-chart is set to be visible, false if not
public var drawHoleEnabled: Bool
{
get
{
return _drawHoleEnabled
}
set
{
_drawHoleEnabled = newValue
setNeedsDisplay()
}
}
/// - returns: true if the hole in the center of the pie-chart is set to be visible, false if not
public var isDrawHoleEnabled: Bool
{
get
{
return drawHoleEnabled
}
}
/// the text that is displayed in the center of the pie-chart
public var centerText: String?
{
get
{
return self.centerAttributedText?.string
}
set
{
var attrString: NSMutableAttributedString?
if newValue == nil
{
attrString = nil
}
else
{
let paragraphStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.lineBreakMode = NSLineBreakMode.ByTruncatingTail
paragraphStyle.alignment = .Center
attrString = NSMutableAttributedString(string: newValue!)
attrString?.setAttributes([
NSForegroundColorAttributeName: NSUIColor.blackColor(),
NSFontAttributeName: NSUIFont.systemFontOfSize(12.0),
NSParagraphStyleAttributeName: paragraphStyle
], range: NSMakeRange(0, attrString!.length))
}
self.centerAttributedText = attrString
}
}
/// the text that is displayed in the center of the pie-chart
public var centerAttributedText: NSAttributedString?
{
get
{
return _centerAttributedText
}
set
{
_centerAttributedText = newValue
setNeedsDisplay()
}
}
/// true if drawing the center text is enabled
public var drawCenterTextEnabled: Bool
{
get
{
return _drawCenterTextEnabled
}
set
{
_drawCenterTextEnabled = newValue
setNeedsDisplay()
}
}
/// - returns: true if drawing the center text is enabled
public var isDrawCenterTextEnabled: Bool
{
get
{
return drawCenterTextEnabled
}
}
internal override var requiredLegendOffset: CGFloat
{
return _legend.font.pointSize * 2.0
}
internal override var requiredBaseOffset: CGFloat
{
return 0.0
}
public override var radius: CGFloat
{
return _circleBox.width / 2.0
}
/// - returns: the circlebox, the boundingbox of the pie-chart slices
public var circleBox: CGRect
{
return _circleBox
}
/// - returns: the center of the circlebox
public var centerCircleBox: CGPoint
{
return CGPoint(x: _circleBox.midX, y: _circleBox.midY)
}
/// the radius of the hole in the center of the piechart in percent of the maximum radius (max = the radius of the whole chart)
///
/// **default**: 0.5 (50%) (half the pie)
public var holeRadiusPercent: CGFloat
{
get
{
return _holeRadiusPercent
}
set
{
_holeRadiusPercent = newValue
setNeedsDisplay()
}
}
/// The color that the transparent-circle should have.
///
/// **default**: `nil`
public var transparentCircleColor: NSUIColor?
{
get
{
return _transparentCircleColor
}
set
{
_transparentCircleColor = newValue
setNeedsDisplay()
}
}
/// the radius of the transparent circle that is drawn next to the hole in the piechart in percent of the maximum radius (max = the radius of the whole chart)
///
/// **default**: 0.55 (55%) -> means 5% larger than the center-hole by default
public var transparentCircleRadiusPercent: CGFloat
{
get
{
return _transparentCircleRadiusPercent
}
set
{
_transparentCircleRadiusPercent = newValue
setNeedsDisplay()
}
}
/// set this to true to draw the x-value text into the pie slices
public var drawSliceTextEnabled: Bool
{
get
{
return _drawXLabelsEnabled
}
set
{
_drawXLabelsEnabled = newValue
setNeedsDisplay()
}
}
/// - returns: true if drawing x-values is enabled, false if not
public var isDrawSliceTextEnabled: Bool
{
get
{
return drawSliceTextEnabled
}
}
/// If this is enabled, values inside the PieChart are drawn in percent and not with their original value. Values provided for the ValueFormatter to format are then provided in percent.
public var usePercentValuesEnabled: Bool
{
get
{
return _usePercentValuesEnabled
}
set
{
_usePercentValuesEnabled = newValue
setNeedsDisplay()
}
}
/// - returns: true if drawing x-values is enabled, false if not
public var isUsePercentValuesEnabled: Bool
{
get
{
return usePercentValuesEnabled
}
}
/// the rectangular radius of the bounding box for the center text, as a percentage of the pie hole
public var centerTextRadiusPercent: CGFloat
{
get
{
return _centerTextRadiusPercent
}
set
{
_centerTextRadiusPercent = newValue
setNeedsDisplay()
}
}
/// The max angle that is used for calculating the pie-circle.
/// 360 means it's a full pie-chart, 180 results in a half-pie-chart.
/// **default**: 360.0
public var maxAngle: CGFloat
{
get
{
return _maxAngle
}
set
{
_maxAngle = newValue
if _maxAngle > 360.0
{
_maxAngle = 360.0
}
if _maxAngle < 90.0
{
_maxAngle = 90.0
}
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/PieRadarChartViewBase.swift
================================================
//
// PieRadarChartViewBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// Base class of PieChartView and RadarChartView.
public class PieRadarChartViewBase: ChartViewBase
{
/// holds the normalized version of the current rotation angle of the chart
private var _rotationAngle = CGFloat(270.0)
/// holds the raw version of the current rotation angle of the chart
private var _rawRotationAngle = CGFloat(270.0)
/// flag that indicates if rotation is enabled or not
public var rotationEnabled = true
/// Sets the minimum offset (padding) around the chart, defaults to 0.0
public var minOffset = CGFloat(0.0)
/// iOS && OSX only: Enabled multi-touch rotation using two fingers.
private var _rotationWithTwoFingers = false
private var _tapGestureRecognizer: NSUITapGestureRecognizer!
#if !os(tvOS)
private var _rotationGestureRecognizer: NSUIRotationGestureRecognizer!
#endif
public override init(frame: CGRect)
{
super.init(frame: frame)
}
public required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
deinit
{
stopDeceleration()
}
internal override func initialize()
{
super.initialize()
_tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(PieRadarChartViewBase.tapGestureRecognized(_:)))
self.addGestureRecognizer(_tapGestureRecognizer)
#if !os(tvOS)
_rotationGestureRecognizer = NSUIRotationGestureRecognizer(target: self, action: #selector(PieRadarChartViewBase.rotationGestureRecognized(_:)))
self.addGestureRecognizer(_rotationGestureRecognizer)
_rotationGestureRecognizer.enabled = rotationWithTwoFingers
#endif
}
internal override func calcMinMax()
{
_xAxis.axisRange = Double((_data?.xVals.count ?? 0) - 1)
}
public override func notifyDataSetChanged()
{
calcMinMax()
if let data = _data where _legend !== nil
{
_legendRenderer.computeLegend(data)
}
calculateOffsets()
setNeedsDisplay()
}
internal override func calculateOffsets()
{
var legendLeft = CGFloat(0.0)
var legendRight = CGFloat(0.0)
var legendBottom = CGFloat(0.0)
var legendTop = CGFloat(0.0)
if (_legend != nil && _legend.enabled)
{
var fullLegendWidth = min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent)
fullLegendWidth += _legend.formSize + _legend.formToTextSpace
if (_legend.position == .RightOfChartCenter)
{
// this is the space between the legend and the chart
let spacing = CGFloat(13.0)
legendRight = fullLegendWidth + spacing
}
else if (_legend.position == .RightOfChart)
{
// this is the space between the legend and the chart
let spacing = CGFloat(8.0)
let legendWidth = fullLegendWidth + spacing
let legendHeight = _legend.neededHeight + _legend.textHeightMax
let c = self.midPoint
let bottomRight = CGPoint(x: self.bounds.width - legendWidth + 15.0, y: legendHeight + 15)
let distLegend = distanceToCenter(x: bottomRight.x, y: bottomRight.y)
let reference = getPosition(center: c, dist: self.radius,
angle: angleForPoint(x: bottomRight.x, y: bottomRight.y))
let distReference = distanceToCenter(x: reference.x, y: reference.y)
let minOffset = CGFloat(5.0)
if (distLegend < distReference)
{
let diff = distReference - distLegend
legendRight = minOffset + diff
}
if (bottomRight.y >= c.y && self.bounds.height - legendWidth > self.bounds.width)
{
legendRight = legendWidth
}
}
else if (_legend.position == .LeftOfChartCenter)
{
// this is the space between the legend and the chart
let spacing = CGFloat(13.0)
legendLeft = fullLegendWidth + spacing
}
else if (_legend.position == .LeftOfChart)
{
// this is the space between the legend and the chart
let spacing = CGFloat(8.0)
let legendWidth = fullLegendWidth + spacing
let legendHeight = _legend.neededHeight + _legend.textHeightMax
let c = self.midPoint
let bottomLeft = CGPoint(x: legendWidth - 15.0, y: legendHeight + 15)
let distLegend = distanceToCenter(x: bottomLeft.x, y: bottomLeft.y)
let reference = getPosition(center: c, dist: self.radius,
angle: angleForPoint(x: bottomLeft.x, y: bottomLeft.y))
let distReference = distanceToCenter(x: reference.x, y: reference.y)
let min = CGFloat(5.0)
if (distLegend < distReference)
{
let diff = distReference - distLegend
legendLeft = min + diff
}
if (bottomLeft.y >= c.y && self.bounds.height - legendWidth > self.bounds.width)
{
legendLeft = legendWidth
}
}
else if (_legend.position == .BelowChartLeft
|| _legend.position == .BelowChartRight
|| _legend.position == .BelowChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = self.requiredLegendOffset
legendBottom = min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
else if (_legend.position == .AboveChartLeft
|| _legend.position == .AboveChartRight
|| _legend.position == .AboveChartCenter)
{
// It's possible that we do not need this offset anymore as it
// is available through the extraOffsets, but changing it can mean
// changing default visibility for existing apps.
let yOffset = self.requiredLegendOffset
legendTop = min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
}
legendLeft += self.requiredBaseOffset
legendRight += self.requiredBaseOffset
legendTop += self.requiredBaseOffset
}
legendTop += self.extraTopOffset
legendRight += self.extraRightOffset
legendBottom += self.extraBottomOffset
legendLeft += self.extraLeftOffset
var minOffset = self.minOffset
if (self.isKindOfClass(RadarChartView))
{
let x = (self as! RadarChartView).xAxis
if x.isEnabled && x.drawLabelsEnabled
{
minOffset = max(minOffset, x.labelRotatedWidth)
}
}
let offsetLeft = max(minOffset, legendLeft)
let offsetTop = max(minOffset, legendTop)
let offsetRight = max(minOffset, legendRight)
let offsetBottom = max(minOffset, max(self.requiredBaseOffset, legendBottom))
_viewPortHandler.restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom)
}
/// - returns: the angle relative to the chart center for the given point on the chart in degrees.
/// The angle is always between 0 and 360°, 0° is NORTH, 90° is EAST, ...
public func angleForPoint(x x: CGFloat, y: CGFloat) -> CGFloat
{
let c = centerOffsets
let tx = Double(x - c.x)
let ty = Double(y - c.y)
let length = sqrt(tx * tx + ty * ty)
let r = acos(ty / length)
var angle = r * ChartUtils.Math.RAD2DEG
if (x > c.x)
{
angle = 360.0 - angle
}
// add 90° because chart starts EAST
angle = angle + 90.0
// neutralize overflow
if (angle > 360.0)
{
angle = angle - 360.0
}
return CGFloat(angle)
}
/// Calculates the position around a center point, depending on the distance
/// from the center, and the angle of the position around the center.
internal func getPosition(center center: CGPoint, dist: CGFloat, angle: CGFloat) -> CGPoint
{
return CGPoint(x: center.x + dist * cos(angle * ChartUtils.Math.FDEG2RAD),
y: center.y + dist * sin(angle * ChartUtils.Math.FDEG2RAD))
}
/// - returns: the distance of a certain point on the chart to the center of the chart.
public func distanceToCenter(x x: CGFloat, y: CGFloat) -> CGFloat
{
let c = self.centerOffsets
var dist = CGFloat(0.0)
var xDist = CGFloat(0.0)
var yDist = CGFloat(0.0)
if (x > c.x)
{
xDist = x - c.x
}
else
{
xDist = c.x - x
}
if (y > c.y)
{
yDist = y - c.y
}
else
{
yDist = c.y - y
}
// pythagoras
dist = sqrt(pow(xDist, 2.0) + pow(yDist, 2.0))
return dist
}
/// - returns: the xIndex for the given angle around the center of the chart.
/// -1 if not found / outofbounds.
public func indexForAngle(angle: CGFloat) -> Int
{
fatalError("indexForAngle() cannot be called on PieRadarChartViewBase")
}
/// current rotation angle of the pie chart
///
/// **default**: 270 --> top (NORTH)
/// - returns: will always return a normalized value, which will be between 0.0 < 360.0
public var rotationAngle: CGFloat
{
get
{
return _rotationAngle
}
set
{
_rawRotationAngle = newValue
_rotationAngle = ChartUtils.normalizedAngleFromAngle(newValue)
setNeedsDisplay()
}
}
/// gets the raw version of the current rotation angle of the pie chart the returned value could be any value, negative or positive, outside of the 360 degrees.
/// this is used when working with rotation direction, mainly by gestures and animations.
public var rawRotationAngle: CGFloat
{
return _rawRotationAngle
}
/// - returns: the diameter of the pie- or radar-chart
public var diameter: CGFloat
{
let content = _viewPortHandler.contentRect
return min(content.width, content.height)
}
/// - returns: the radius of the chart in pixels.
public var radius: CGFloat
{
fatalError("radius cannot be called on PieRadarChartViewBase")
}
/// - returns: the required offset for the chart legend.
internal var requiredLegendOffset: CGFloat
{
fatalError("requiredLegendOffset cannot be called on PieRadarChartViewBase")
}
/// - returns: the base offset needed for the chart without calculating the
/// legend size.
internal var requiredBaseOffset: CGFloat
{
fatalError("requiredBaseOffset cannot be called on PieRadarChartViewBase")
}
public override var chartYMax: Double
{
return 0.0
}
public override var chartYMin: Double
{
return 0.0
}
/// The SelectionDetail objects give information about the value at the selected index and the DataSet it belongs to.
/// - returns: an array of SelectionDetail objects for the given x-index.
public func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
{
var vals = [ChartSelectionDetail]()
guard let data = _data else { return vals }
for i in 0 ..< data.dataSetCount
{
guard let dataSet = data.getDataSetByIndex(i) else { continue }
if !dataSet.isHighlightEnabled
{
continue
}
// extract all y-values from all DataSets at the given x-index
let yVal = dataSet.yValForXIndex(xIndex)
if (yVal.isNaN)
{
continue
}
vals.append(ChartSelectionDetail(value: yVal, dataSetIndex: i, dataSet: dataSet))
}
return vals
}
public var isRotationEnabled: Bool { return rotationEnabled; }
/// flag that indicates if rotation is done with two fingers or one.
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
///
/// On iOS this will disable one-finger rotation.
/// On OSX this will keep two-finger multitouch rotation, and one-pointer mouse rotation.
///
/// **default**: false
public var rotationWithTwoFingers: Bool
{
get
{
return _rotationWithTwoFingers
}
set
{
_rotationWithTwoFingers = newValue
#if !os(tvOS)
_rotationGestureRecognizer.enabled = _rotationWithTwoFingers
#endif
}
}
/// flag that indicates if rotation is done with two fingers or one.
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
///
/// On iOS this will disable one-finger rotation.
/// On OSX this will keep two-finger multitouch rotation, and one-pointer mouse rotation.
///
/// **default**: false
public var isRotationWithTwoFingers: Bool
{
return _rotationWithTwoFingers
}
// MARK: - Animation
private var _spinAnimator: ChartAnimator!
/// Applys a spin animation to the Chart.
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easing: ChartEasingFunctionBlock?)
{
if (_spinAnimator != nil)
{
_spinAnimator.stop()
}
_spinAnimator = ChartAnimator()
_spinAnimator.updateBlock = {
self.rotationAngle = (toAngle - fromAngle) * self._spinAnimator.phaseX + fromAngle
}
_spinAnimator.stopBlock = { self._spinAnimator = nil; }
_spinAnimator.animate(xAxisDuration: duration, easing: easing)
}
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easingOption: ChartEasingOption)
{
spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: easingFunctionFromOption(easingOption))
}
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat)
{
spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: nil)
}
public func stopSpinAnimation()
{
if (_spinAnimator != nil)
{
_spinAnimator.stop()
}
}
// MARK: - Gestures
private var _rotationGestureStartPoint: CGPoint!
private var _isRotating = false
private var _startAngle = CGFloat(0.0)
private struct AngularVelocitySample
{
var time: NSTimeInterval
var angle: CGFloat
}
private var _velocitySamples = [AngularVelocitySample]()
private var _decelerationLastTime: NSTimeInterval = 0.0
private var _decelerationDisplayLink: NSUIDisplayLink!
private var _decelerationAngularVelocity: CGFloat = 0.0
internal final func processRotationGestureBegan(location location: CGPoint)
{
self.resetVelocity()
if rotationEnabled
{
self.sampleVelocity(touchLocation: location)
}
self.setGestureStartAngle(x: location.x, y: location.y)
_rotationGestureStartPoint = location
}
internal final func processRotationGestureMoved(location location: CGPoint)
{
if isDragDecelerationEnabled
{
sampleVelocity(touchLocation: location)
}
if !_isRotating &&
distance(
eventX: location.x,
startX: _rotationGestureStartPoint.x,
eventY: location.y,
startY: _rotationGestureStartPoint.y) > CGFloat(8.0)
{
_isRotating = true
}
else
{
self.updateGestureRotation(x: location.x, y: location.y)
setNeedsDisplay()
}
}
internal final func processRotationGestureEnded(location location: CGPoint)
{
if isDragDecelerationEnabled
{
stopDeceleration()
sampleVelocity(touchLocation: location)
_decelerationAngularVelocity = calculateVelocity()
if _decelerationAngularVelocity != 0.0
{
_decelerationLastTime = CACurrentMediaTime()
_decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(PieRadarChartViewBase.decelerationLoop))
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
}
internal final func processRotationGestureCancelled()
{
if (_isRotating)
{
_isRotating = false
}
}
#if !os(OSX)
public override func nsuiTouchesBegan(touches: Set, withEvent event: NSUIEvent?)
{
// if rotation by touch is enabled
if (rotationEnabled)
{
stopDeceleration()
if (!rotationWithTwoFingers)
{
let touch = touches.first as NSUITouch!
let touchLocation = touch.locationInView(self)
processRotationGestureBegan(location: touchLocation)
}
}
if (!_isRotating)
{
super.nsuiTouchesBegan(touches, withEvent: event)
}
}
public override func nsuiTouchesMoved(touches: Set, withEvent event: NSUIEvent?)
{
if (rotationEnabled && !rotationWithTwoFingers)
{
let touch = touches.first as NSUITouch!
let touchLocation = touch.locationInView(self)
processRotationGestureMoved(location: touchLocation)
}
if (!_isRotating)
{
super.nsuiTouchesMoved(touches, withEvent: event)
}
}
public override func nsuiTouchesEnded(touches: Set, withEvent event: NSUIEvent?)
{
if (!_isRotating)
{
super.nsuiTouchesEnded(touches, withEvent: event)
}
if (rotationEnabled && !rotationWithTwoFingers)
{
let touch = touches.first as NSUITouch!
let touchLocation = touch.locationInView(self)
processRotationGestureEnded(location: touchLocation)
}
if (_isRotating)
{
_isRotating = false
}
}
public override func nsuiTouchesCancelled(touches: Set?, withEvent event: NSUIEvent?)
{
super.nsuiTouchesCancelled(touches, withEvent: event)
processRotationGestureCancelled()
}
#endif
#if os(OSX)
public override func mouseDown(theEvent: NSEvent)
{
// if rotation by touch is enabled
if rotationEnabled
{
stopDeceleration()
let location = self.convertPoint(theEvent.locationInWindow, fromView: nil)
processRotationGestureBegan(location: location)
}
if !_isRotating
{
super.mouseDown(theEvent)
}
}
public override func mouseDragged(theEvent: NSEvent)
{
if rotationEnabled
{
let location = self.convertPoint(theEvent.locationInWindow, fromView: nil)
processRotationGestureMoved(location: location)
}
if !_isRotating
{
super.mouseDragged(theEvent)
}
}
public override func mouseUp(theEvent: NSEvent)
{
if !_isRotating
{
super.mouseUp(theEvent)
}
if rotationEnabled
{
let location = self.convertPoint(theEvent.locationInWindow, fromView: nil)
processRotationGestureEnded(location: location)
}
if _isRotating
{
_isRotating = false
}
}
#endif
private func resetVelocity()
{
_velocitySamples.removeAll(keepCapacity: false)
}
private func sampleVelocity(touchLocation touchLocation: CGPoint)
{
let currentTime = CACurrentMediaTime()
_velocitySamples.append(AngularVelocitySample(time: currentTime, angle: angleForPoint(x: touchLocation.x, y: touchLocation.y)))
// Remove samples older than our sample time - 1 seconds
var i = 0, count = _velocitySamples.count
while (i < count - 2)
{
if (currentTime - _velocitySamples[i].time > 1.0)
{
_velocitySamples.removeAtIndex(0)
i -= 1
count -= 1
}
else
{
break
}
i += 1
}
}
private func calculateVelocity() -> CGFloat
{
if (_velocitySamples.isEmpty)
{
return 0.0
}
var firstSample = _velocitySamples[0]
var lastSample = _velocitySamples[_velocitySamples.count - 1]
// Look for a sample that's closest to the latest sample, but not the same, so we can deduce the direction
var beforeLastSample = firstSample
for i in (_velocitySamples.count - 1).stride(through: 0, by: -1)
{
beforeLastSample = _velocitySamples[i]
if (beforeLastSample.angle != lastSample.angle)
{
break
}
}
// Calculate the sampling time
var timeDelta = lastSample.time - firstSample.time
if (timeDelta == 0.0)
{
timeDelta = 0.1
}
// Calculate clockwise/ccw by choosing two values that should be closest to each other,
// so if the angles are two far from each other we know they are inverted "for sure"
var clockwise = lastSample.angle >= beforeLastSample.angle
if (abs(lastSample.angle - beforeLastSample.angle) > 270.0)
{
clockwise = !clockwise
}
// Now if the "gesture" is over a too big of an angle - then we know the angles are inverted, and we need to move them closer to each other from both sides of the 360.0 wrapping point
if (lastSample.angle - firstSample.angle > 180.0)
{
firstSample.angle += 360.0
}
else if (firstSample.angle - lastSample.angle > 180.0)
{
lastSample.angle += 360.0
}
// The velocity
var velocity = abs((lastSample.angle - firstSample.angle) / CGFloat(timeDelta))
// Direction?
if (!clockwise)
{
velocity = -velocity
}
return velocity
}
/// sets the starting angle of the rotation, this is only used by the touch listener, x and y is the touch position
private func setGestureStartAngle(x x: CGFloat, y: CGFloat)
{
_startAngle = angleForPoint(x: x, y: y)
// take the current angle into consideration when starting a new drag
_startAngle -= _rotationAngle
}
/// updates the view rotation depending on the given touch position, also takes the starting angle into consideration
private func updateGestureRotation(x x: CGFloat, y: CGFloat)
{
self.rotationAngle = angleForPoint(x: x, y: y) - _startAngle
}
public func stopDeceleration()
{
if (_decelerationDisplayLink !== nil)
{
_decelerationDisplayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
_decelerationDisplayLink = nil
}
}
@objc private func decelerationLoop()
{
let currentTime = CACurrentMediaTime()
_decelerationAngularVelocity *= self.dragDecelerationFrictionCoef
let timeInterval = CGFloat(currentTime - _decelerationLastTime)
self.rotationAngle += _decelerationAngularVelocity * timeInterval
_decelerationLastTime = currentTime
if(abs(_decelerationAngularVelocity) < 0.001)
{
stopDeceleration()
}
}
/// - returns: the distance between two points
private func distance(eventX eventX: CGFloat, startX: CGFloat, eventY: CGFloat, startY: CGFloat) -> CGFloat
{
let dx = eventX - startX
let dy = eventY - startY
return sqrt(dx * dx + dy * dy)
}
/// - returns: the distance between two points
private func distance(from from: CGPoint, to: CGPoint) -> CGFloat
{
let dx = from.x - to.x
let dy = from.y - to.y
return sqrt(dx * dx + dy * dy)
}
/// reference to the last highlighted object
private var _lastHighlight: ChartHighlight!
@objc private func tapGestureRecognized(recognizer: NSUITapGestureRecognizer)
{
if (recognizer.state == NSUIGestureRecognizerState.Ended)
{
if !self.isHighLightPerTapEnabled { return }
let location = recognizer.locationInView(self)
let distance = distanceToCenter(x: location.x, y: location.y)
// check if a slice was touched
if (distance > self.radius)
{
// if no slice was touched, highlight nothing
self.highlightValues(nil)
if _lastHighlight == nil
{
self.highlightValues(nil) // do not call delegate
}
else
{
self.highlightValue(highlight: nil, callDelegate: true) // call delegate
}
_lastHighlight = nil
}
else
{
var angle = angleForPoint(x: location.x, y: location.y)
if (self.isKindOfClass(PieChartView))
{
angle /= _animator.phaseY
}
let index = indexForAngle(angle)
// check if the index could be found
if (index < 0)
{
self.highlightValues(nil)
_lastHighlight = nil
}
else
{
let valsAtIndex = getSelectionDetailsAtIndex(index)
var dataSetIndex = 0
// get the dataset that is closest to the selection (PieChart only has one DataSet)
if (self.isKindOfClass(RadarChartView))
{
dataSetIndex = ChartUtils.closestDataSetIndex(valsAtIndex, value: Double(distance / (self as! RadarChartView).factor), axis: nil)
}
if (dataSetIndex < 0)
{
self.highlightValues(nil)
_lastHighlight = nil
}
else
{
let h = ChartHighlight(xIndex: index, dataSetIndex: dataSetIndex)
if (_lastHighlight !== nil && h == _lastHighlight)
{
self.highlightValue(highlight: nil, callDelegate: true)
_lastHighlight = nil
}
else
{
self.highlightValue(highlight: h, callDelegate: true)
_lastHighlight = h
}
}
}
}
}
}
#if !os(tvOS)
@objc private func rotationGestureRecognized(recognizer: NSUIRotationGestureRecognizer)
{
if (recognizer.state == NSUIGestureRecognizerState.Began)
{
stopDeceleration()
_startAngle = self.rawRotationAngle
}
if (recognizer.state == NSUIGestureRecognizerState.Began || recognizer.state == NSUIGestureRecognizerState.Changed)
{
let angle = ChartUtils.Math.FRAD2DEG * recognizer.nsuiRotation
self.rotationAngle = _startAngle + angle
setNeedsDisplay()
}
else if (recognizer.state == NSUIGestureRecognizerState.Ended)
{
let angle = ChartUtils.Math.FRAD2DEG * recognizer.nsuiRotation
self.rotationAngle = _startAngle + angle
setNeedsDisplay()
if (isDragDecelerationEnabled)
{
stopDeceleration()
_decelerationAngularVelocity = ChartUtils.Math.FRAD2DEG * recognizer.velocity
if (_decelerationAngularVelocity != 0.0)
{
_decelerationLastTime = CACurrentMediaTime()
_decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(PieRadarChartViewBase.decelerationLoop))
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
}
}
#endif
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/RadarChartView.swift
================================================
//
// RadarChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Implementation of the RadarChart, a "spidernet"-like chart. It works best
/// when displaying 5-10 entries per DataSet.
public class RadarChartView: PieRadarChartViewBase
{
/// width of the web lines that come from the center.
public var webLineWidth = CGFloat(1.5)
/// width of the web lines that are in between the lines coming from the center
public var innerWebLineWidth = CGFloat(0.75)
/// color for the web lines that come from the center
public var webColor = NSUIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
/// color for the web lines in between the lines that come from the center.
public var innerWebColor = NSUIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
/// transparency the grid is drawn with (0.0 - 1.0)
public var webAlpha: CGFloat = 150.0 / 255.0
/// flag indicating if the web lines should be drawn or not
public var drawWeb = true
/// modulus that determines how many labels and web-lines are skipped before the next is drawn
private var _skipWebLineCount = 0
/// the object reprsenting the y-axis labels
private var _yAxis: ChartYAxis!
internal var _yAxisRenderer: ChartYAxisRendererRadarChart!
internal var _xAxisRenderer: ChartXAxisRendererRadarChart!
public override init(frame: CGRect)
{
super.init(frame: frame)
}
public required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
internal override func initialize()
{
super.initialize()
_yAxis = ChartYAxis(position: .Left)
_xAxis.spaceBetweenLabels = 0
renderer = RadarChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
_yAxisRenderer = ChartYAxisRendererRadarChart(viewPortHandler: _viewPortHandler, yAxis: _yAxis, chart: self)
_xAxisRenderer = ChartXAxisRendererRadarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, chart: self)
}
internal override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
// calculate / set x-axis range
_xAxis._axisMaximum = Double(data.xVals.count) - 1.0
_xAxis.axisRange = Double(abs(_xAxis._axisMaximum - _xAxis._axisMinimum))
_yAxis.calcMinMax(min: data.getYMin(.Left), max: data.getYMax(.Left))
}
public override func getMarkerPosition(entry entry: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
{
let angle = self.sliceAngle * CGFloat(entry.xIndex) + self.rotationAngle
let val = CGFloat(entry.value) * self.factor
let c = self.centerOffsets
let p = CGPoint(x: c.x + val * cos(angle * ChartUtils.Math.FDEG2RAD),
y: c.y + val * sin(angle * ChartUtils.Math.FDEG2RAD))
return p
}
public override func notifyDataSetChanged()
{
calcMinMax()
_yAxis?._defaultValueFormatter = _defaultValueFormatter
_yAxisRenderer?.computeAxis(yMin: _yAxis._axisMinimum, yMax: _yAxis._axisMaximum)
_xAxisRenderer?.computeAxis(xValAverageLength: data?.xValAverageLength ?? 0, xValues: data?.xVals ?? [])
if let data = _data, legend = _legend where !legend.isLegendCustom
{
_legendRenderer?.computeLegend(data)
}
calculateOffsets()
setNeedsDisplay()
}
public override func drawRect(rect: CGRect)
{
super.drawRect(rect)
if _data === nil
{
return
}
let optionalContext = NSUIGraphicsGetCurrentContext()
guard let context = optionalContext else { return }
_xAxisRenderer?.renderAxisLabels(context: context)
if (drawWeb)
{
renderer!.drawExtras(context: context)
}
_yAxisRenderer.renderLimitLines(context: context)
renderer!.drawData(context: context)
if (valuesToHighlight())
{
renderer!.drawHighlighted(context: context, indices: _indicesToHighlight)
}
_yAxisRenderer.renderAxisLabels(context: context)
renderer!.drawValues(context: context)
_legendRenderer.renderLegend(context: context)
drawDescription(context: context)
drawMarkers(context: context)
}
/// - returns: the factor that is needed to transform values into pixels.
public var factor: CGFloat
{
let content = _viewPortHandler.contentRect
return min(content.width / 2.0, content.height / 2.0)
/ CGFloat(_yAxis.axisRange)
}
/// - returns: the angle that each slice in the radar chart occupies.
public var sliceAngle: CGFloat
{
return 360.0 / CGFloat(_data?.xValCount ?? 0)
}
public override func indexForAngle(angle: CGFloat) -> Int
{
// take the current angle of the chart into consideration
let a = ChartUtils.normalizedAngleFromAngle(angle - self.rotationAngle)
let sliceAngle = self.sliceAngle
for i in 0 ..< (_data?.xValCount ?? 0)
{
if (sliceAngle * CGFloat(i + 1) - sliceAngle / 2.0 > a)
{
return i
}
}
return 0
}
/// - returns: the object that represents all y-labels of the RadarChart.
public var yAxis: ChartYAxis
{
return _yAxis
}
/// Sets the number of web-lines that should be skipped on chart web before the next one is drawn. This targets the lines that come from the center of the RadarChart.
/// if count = 1 -> 1 line is skipped in between
public var skipWebLineCount: Int
{
get
{
return _skipWebLineCount
}
set
{
_skipWebLineCount = max(0, newValue)
}
}
internal override var requiredLegendOffset: CGFloat
{
return _legend.font.pointSize * 4.0
}
internal override var requiredBaseOffset: CGFloat
{
return _xAxis.isEnabled && _xAxis.isDrawLabelsEnabled ? _xAxis.labelRotatedWidth : 10.0
}
public override var radius: CGFloat
{
let content = _viewPortHandler.contentRect
return min(content.width / 2.0, content.height / 2.0)
}
/// - returns: the maximum value this chart can display on it's y-axis.
public override var chartYMax: Double { return _yAxis._axisMaximum; }
/// - returns: the minimum value this chart can display on it's y-axis.
public override var chartYMin: Double { return _yAxis._axisMinimum; }
/// - returns: the range of y-values this chart can display.
public var yRange: Double { return _yAxis.axisRange}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Charts/ScatterChartView.swift
================================================
//
// ScatterChartView.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// The ScatterChart. Draws dots, triangles, squares and custom shapes into the chartview.
public class ScatterChartView: BarLineChartViewBase, ScatterChartDataProvider
{
public override func initialize()
{
super.initialize()
renderer = ScatterChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
_xAxis._axisMinimum = -0.5
}
public override func calcMinMax()
{
super.calcMinMax()
guard let data = _data else { return }
if _xAxis.axisRange == 0.0 && data.yValCount > 0
{
_xAxis.axisRange = 1.0
}
_xAxis._axisMaximum += 0.5
_xAxis.axisRange = abs(_xAxis._axisMaximum - _xAxis._axisMinimum)
}
// MARK: - ScatterChartDataProbider
public var scatterData: ScatterChartData? { return _data as? ScatterChartData }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartAxisBase.swift
================================================
//
// ChartAxisBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Base class for all axes
public class ChartAxisBase: ChartComponentBase
{
public var labelFont = NSUIFont.systemFontOfSize(10.0)
public var labelTextColor = NSUIColor.blackColor()
public var axisLineColor = NSUIColor.grayColor()
public var axisLineWidth = CGFloat(0.5)
public var axisLineDashPhase = CGFloat(0.0)
public var axisLineDashLengths: [CGFloat]!
public var gridColor = NSUIColor.grayColor().colorWithAlphaComponent(0.9)
public var gridLineWidth = CGFloat(0.5)
public var gridLineDashPhase = CGFloat(0.0)
public var gridLineDashLengths: [CGFloat]!
public var gridLineCap = CGLineCap.Butt
public var drawGridLinesEnabled = true
public var drawAxisLineEnabled = true
/// flag that indicates of the labels of this axis should be drawn or not
public var drawLabelsEnabled = true
/// array of limitlines that can be set for the axis
private var _limitLines = [ChartLimitLine]()
/// Are the LimitLines drawn behind the data or in front of the data?
///
/// **default**: false
public var drawLimitLinesBehindDataEnabled = false
/// the flag can be used to turn off the antialias for grid lines
public var gridAntialiasEnabled = true
public override init()
{
super.init()
}
public func getLongestLabel() -> String
{
fatalError("getLongestLabel() cannot be called on ChartAxisBase")
}
public var isDrawGridLinesEnabled: Bool { return drawGridLinesEnabled; }
public var isDrawAxisLineEnabled: Bool { return drawAxisLineEnabled; }
public var isDrawLabelsEnabled: Bool { return drawLabelsEnabled; }
/// Are the LimitLines drawn behind the data or in front of the data?
///
/// **default**: false
public var isDrawLimitLinesBehindDataEnabled: Bool { return drawLimitLinesBehindDataEnabled; }
/// Flag indicating that the axis-min value has been customized
internal var _customAxisMin: Bool = false
/// Flag indicating that the axis-max value has been customized
internal var _customAxisMax: Bool = false
/// Do not touch this directly, instead, use axisMinValue.
/// This is automatically calculated to represent the real min value,
/// and is used when calculating the effective minimum.
public var _axisMinimum = Double(0)
/// Do not touch this directly, instead, use axisMaxValue.
/// This is automatically calculated to represent the real max value,
/// and is used when calculating the effective maximum.
public var _axisMaximum = Double(0)
/// the total range of values this axis covers
public var axisRange = Double(0)
/// Adds a new ChartLimitLine to this axis.
public func addLimitLine(line: ChartLimitLine)
{
_limitLines.append(line)
}
/// Removes the specified ChartLimitLine from the axis.
public func removeLimitLine(line: ChartLimitLine)
{
for i in 0 ..< _limitLines.count
{
if (_limitLines[i] === line)
{
_limitLines.removeAtIndex(i)
return
}
}
}
/// Removes all LimitLines from the axis.
public func removeAllLimitLines()
{
_limitLines.removeAll(keepCapacity: false)
}
/// - returns: the LimitLines of this axis.
public var limitLines : [ChartLimitLine]
{
return _limitLines
}
// MARK: Custom axis ranges
/// By calling this method, any custom minimum value that has been previously set is reseted, and the calculation is done automatically.
public func resetCustomAxisMin()
{
_customAxisMin = false
}
public var isAxisMinCustom: Bool { return _customAxisMin }
/// By calling this method, any custom maximum value that has been previously set is reseted, and the calculation is done automatically.
public func resetCustomAxisMax()
{
_customAxisMax = false
}
public var isAxisMaxCustom: Bool { return _customAxisMax }
/// The minimum value for this axis.
/// If set, this value will not be calculated automatically depending on the provided data.
/// Use `resetCustomAxisMin()` to undo this.
public var axisMinValue: Double
{
get
{
return _axisMinimum
}
set
{
_customAxisMin = true
_axisMinimum = newValue
}
}
/// The maximum value for this axis.
/// If set, this value will not be calculated automatically depending on the provided data.
/// Use `resetCustomAxisMin()` to undo this.
public var axisMaxValue: Double
{
get
{
return _axisMaximum
}
set
{
_customAxisMax = true
_axisMaximum = newValue
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartComponentBase.swift
================================================
//
// ChartComponentBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 16/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// This class encapsulates everything both Axis, Legend and LimitLines have in common
public class ChartComponentBase: NSObject
{
/// flag that indicates if this component is enabled or not
public var enabled = true
/// Sets the used x-axis offset for the labels on this axis.
/// **default**: 5.0
public var xOffset = CGFloat(5.0)
/// Sets the used y-axis offset for the labels on this axis.
/// **default**: 5.0 (or 0.0 on ChartYAxis)
public var yOffset = CGFloat(5.0)
public override init()
{
super.init()
}
public var isEnabled: Bool { return enabled; }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartLegend.swift
================================================
//
// ChartLegend.swift
// Charts
//
// Created by Daniel Cohen Gindi on 24/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartLegend: ChartComponentBase
{
@objc
public enum ChartLegendPosition: Int
{
case RightOfChart
case RightOfChartCenter
case RightOfChartInside
case LeftOfChart
case LeftOfChartCenter
case LeftOfChartInside
case BelowChartLeft
case BelowChartRight
case BelowChartCenter
case AboveChartLeft
case AboveChartRight
case AboveChartCenter
case PiechartCenter
}
@objc
public enum ChartLegendForm: Int
{
case Square
case Circle
case Line
}
@objc
public enum ChartLegendDirection: Int
{
case LeftToRight
case RightToLeft
}
/// the legend colors array, each color is for the form drawn at the same index
public var colors = [NSUIColor?]()
// the legend text array. a nil label will start a group.
public var labels = [String?]()
internal var _extraColors = [NSUIColor?]()
internal var _extraLabels = [String?]()
/// colors that will be appended to the end of the colors array after calculating the legend.
public var extraColors: [NSUIColor?] { return _extraColors; }
/// labels that will be appended to the end of the labels array after calculating the legend. a nil label will start a group.
public var extraLabels: [String?] { return _extraLabels; }
/// Are the legend labels/colors a custom value or auto calculated? If false, then it's auto, if true, then custom.
///
/// **default**: false (automatic legend)
private var _isLegendCustom = false
public var position = ChartLegendPosition.BelowChartLeft
public var direction = ChartLegendDirection.LeftToRight
public var font: NSUIFont = NSUIFont.systemFontOfSize(10.0)
public var textColor = NSUIColor.blackColor()
public var form = ChartLegendForm.Square
public var formSize = CGFloat(8.0)
public var formLineWidth = CGFloat(1.5)
public var xEntrySpace = CGFloat(6.0)
public var yEntrySpace = CGFloat(0.0)
public var formToTextSpace = CGFloat(5.0)
public var stackSpace = CGFloat(3.0)
public var calculatedLabelSizes = [CGSize]()
public var calculatedLabelBreakPoints = [Bool]()
public var calculatedLineSizes = [CGSize]()
public override init()
{
super.init()
self.xOffset = 5.0
self.yOffset = 4.0
}
public init(colors: [NSUIColor?], labels: [String?])
{
super.init()
self.colors = colors
self.labels = labels
}
public init(colors: [NSObject], labels: [NSObject])
{
super.init()
self.colorsObjc = colors
self.labelsObjc = labels
}
public func getMaximumEntrySize(font: NSUIFont) -> CGSize
{
var maxW = CGFloat(0.0)
var maxH = CGFloat(0.0)
var labels = self.labels
for i in 0 ..< labels.count
{
if (labels[i] == nil)
{
continue
}
let size = (labels[i] as NSString!).sizeWithAttributes([NSFontAttributeName: font])
if (size.width > maxW)
{
maxW = size.width
}
if (size.height > maxH)
{
maxH = size.height
}
}
return CGSize(
width: maxW + formSize + formToTextSpace,
height: maxH
)
}
public func getLabel(index: Int) -> String?
{
return labels[index]
}
public func getFullSize(labelFont: NSUIFont) -> CGSize
{
var width = CGFloat(0.0)
var height = CGFloat(0.0)
var labels = self.labels
let count = labels.count
for i in 0 ..< count
{
if (labels[i] != nil)
{
// make a step to the left
if (colors[i] != nil)
{
width += formSize + formToTextSpace
}
let size = (labels[i] as NSString!).sizeWithAttributes([NSFontAttributeName: labelFont])
width += size.width
height += size.height
if (i < count - 1)
{
width += xEntrySpace
height += yEntrySpace
}
}
else
{
width += formSize + stackSpace
if (i < count - 1)
{
width += stackSpace
}
}
}
return CGSize(width: width, height: height)
}
public var neededWidth = CGFloat(0.0)
public var neededHeight = CGFloat(0.0)
public var textWidthMax = CGFloat(0.0)
public var textHeightMax = CGFloat(0.0)
/// flag that indicates if word wrapping is enabled
/// this is currently supported only for: `BelowChartLeft`, `BelowChartRight`, `BelowChartCenter`.
/// note that word wrapping a legend takes a toll on performance.
/// you may want to set maxSizePercent when word wrapping, to set the point where the text wraps.
///
/// **default**: false
public var wordWrapEnabled = false
/// if this is set, then word wrapping the legend is enabled.
public var isWordWrapEnabled: Bool { return wordWrapEnabled }
/// The maximum relative size out of the whole chart view in percent.
/// If the legend is to the right/left of the chart, then this affects the width of the legend.
/// If the legend is to the top/bottom of the chart, then this affects the height of the legend.
/// If the legend is the center of the piechart, then this defines the size of the rectangular bounds out of the size of the "hole".
///
/// **default**: 0.95 (95%)
public var maxSizePercent: CGFloat = 0.95
public func calculateDimensions(labelFont labelFont: NSUIFont, viewPortHandler: ChartViewPortHandler)
{
if (position == .RightOfChart
|| position == .RightOfChartCenter
|| position == .LeftOfChart
|| position == .LeftOfChartCenter
|| position == .PiechartCenter)
{
let maxEntrySize = getMaximumEntrySize(labelFont)
let fullSize = getFullSize(labelFont)
neededWidth = maxEntrySize.width
neededHeight = fullSize.height
textWidthMax = maxEntrySize.width
textHeightMax = maxEntrySize.height
}
else if (position == .BelowChartLeft
|| position == .BelowChartRight
|| position == .BelowChartCenter
|| position == .AboveChartLeft
|| position == .AboveChartRight
|| position == .AboveChartCenter)
{
var labels = self.labels
var colors = self.colors
let labelCount = labels.count
let labelLineHeight = labelFont.lineHeight
let formSize = self.formSize
let formToTextSpace = self.formToTextSpace
let xEntrySpace = self.xEntrySpace
let stackSpace = self.stackSpace
let wordWrapEnabled = self.wordWrapEnabled
let contentWidth: CGFloat = viewPortHandler.contentWidth
// Prepare arrays for calculated layout
if (calculatedLabelSizes.count != labelCount)
{
calculatedLabelSizes = [CGSize](count: labelCount, repeatedValue: CGSize())
}
if (calculatedLabelBreakPoints.count != labelCount)
{
calculatedLabelBreakPoints = [Bool](count: labelCount, repeatedValue: false)
}
calculatedLineSizes.removeAll(keepCapacity: true)
// Start calculating layout
let labelAttrs = [NSFontAttributeName: labelFont]
var maxLineWidth: CGFloat = 0.0
var currentLineWidth: CGFloat = 0.0
var requiredWidth: CGFloat = 0.0
var stackedStartIndex: Int = -1
for i in 0 ..< labelCount
{
let drawingForm = colors[i] != nil
calculatedLabelBreakPoints[i] = false
if (stackedStartIndex == -1)
{
// we are not stacking, so required width is for this label only
requiredWidth = 0.0
}
else
{
// add the spacing appropriate for stacked labels/forms
requiredWidth += stackSpace
}
// grouped forms have null labels
if (labels[i] != nil)
{
calculatedLabelSizes[i] = (labels[i] as NSString!).sizeWithAttributes(labelAttrs)
requiredWidth += drawingForm ? formToTextSpace + formSize : 0.0
requiredWidth += calculatedLabelSizes[i].width
}
else
{
calculatedLabelSizes[i] = CGSize()
requiredWidth += drawingForm ? formSize : 0.0
if (stackedStartIndex == -1)
{
// mark this index as we might want to break here later
stackedStartIndex = i
}
}
if (labels[i] != nil || i == labelCount - 1)
{
let requiredSpacing = currentLineWidth == 0.0 ? 0.0 : xEntrySpace
if (!wordWrapEnabled || // No word wrapping, it must fit.
currentLineWidth == 0.0 || // The line is empty, it must fit.
(contentWidth - currentLineWidth >= requiredSpacing + requiredWidth)) // It simply fits
{
// Expand current line
currentLineWidth += requiredSpacing + requiredWidth
}
else
{ // It doesn't fit, we need to wrap a line
// Add current line size to array
calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight))
maxLineWidth = max(maxLineWidth, currentLineWidth)
// Start a new line
calculatedLabelBreakPoints[stackedStartIndex > -1 ? stackedStartIndex : i] = true
currentLineWidth = requiredWidth
}
if (i == labelCount - 1)
{ // Add last line size to array
calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight))
maxLineWidth = max(maxLineWidth, currentLineWidth)
}
}
stackedStartIndex = labels[i] != nil ? -1 : stackedStartIndex
}
let maxEntrySize = getMaximumEntrySize(labelFont)
textWidthMax = maxEntrySize.width
textHeightMax = maxEntrySize.height
neededWidth = maxLineWidth
neededHeight = labelLineHeight * CGFloat(calculatedLineSizes.count) +
yEntrySpace * CGFloat(calculatedLineSizes.count == 0 ? 0 : (calculatedLineSizes.count - 1))
}
else
{
let maxEntrySize = getMaximumEntrySize(labelFont)
let fullSize = getFullSize(labelFont)
/* RightOfChartInside, LeftOfChartInside */
neededWidth = fullSize.width
neededHeight = maxEntrySize.height
textWidthMax = maxEntrySize.width
textHeightMax = maxEntrySize.height
}
}
/// MARK: - Custom legend
/// colors and labels that will be appended to the end of the auto calculated colors and labels after calculating the legend.
/// (if the legend has already been calculated, you will need to call notifyDataSetChanged() to let the changes take effect)
public func setExtra(colors colors: [NSUIColor?], labels: [String?])
{
self._extraLabels = labels
self._extraColors = colors
}
/// Sets a custom legend's labels and colors arrays.
/// The colors count should match the labels count.
/// * Each color is for the form drawn at the same index.
/// * A nil label will start a group.
/// * A nil color will avoid drawing a form, and a clearColor will leave a space for the form.
/// This will disable the feature that automatically calculates the legend labels and colors from the datasets.
/// Call `resetCustom(...)` to re-enable automatic calculation (and then `notifyDataSetChanged()` is needed).
public func setCustom(colors colors: [NSUIColor?], labels: [String?])
{
self.labels = labels
self.colors = colors
_isLegendCustom = true
}
/// Calling this will disable the custom legend labels (set by `setLegend(...)`). Instead, the labels will again be calculated automatically (after `notifyDataSetChanged()` is called).
public func resetCustom()
{
_isLegendCustom = false
}
/// **default**: false (automatic legend)
/// - returns: true if a custom legend labels and colors has been set
public var isLegendCustom: Bool
{
return _isLegendCustom
}
/// MARK: - ObjC compatibility
/// colors that will be appended to the end of the colors array after calculating the legend.
public var extraColorsObjc: [NSObject] { return ChartUtils.bridgedObjCGetNSUIColorArray(swift: _extraColors); }
/// labels that will be appended to the end of the labels array after calculating the legend. a nil label will start a group.
public var extraLabelsObjc: [NSObject] { return ChartUtils.bridgedObjCGetStringArray(swift: _extraLabels); }
/// the legend colors array, each color is for the form drawn at the same index
/// (ObjC bridging functions, as Swift 1.2 does not bridge optionals in array to `NSNull`s)
public var colorsObjc: [NSObject]
{
get { return ChartUtils.bridgedObjCGetNSUIColorArray(swift: colors); }
set { self.colors = ChartUtils.bridgedObjCGetNSUIColorArray(objc: newValue); }
}
// the legend text array. a nil label will start a group.
/// (ObjC bridging functions, as Swift 1.2 does not bridge optionals in array to `NSNull`s)
public var labelsObjc: [NSObject]
{
get { return ChartUtils.bridgedObjCGetStringArray(swift: labels); }
set { self.labels = ChartUtils.bridgedObjCGetStringArray(objc: newValue); }
}
/// colors and labels that will be appended to the end of the auto calculated colors and labels after calculating the legend.
/// (if the legend has already been calculated, you will need to call `notifyDataSetChanged()` to let the changes take effect)
public func setExtra(colors colors: [NSObject], labels: [NSObject])
{
if (colors.count != labels.count)
{
fatalError("ChartLegend:setExtra() - colors array and labels array need to be of same size")
}
self._extraLabels = ChartUtils.bridgedObjCGetStringArray(objc: labels)
self._extraColors = ChartUtils.bridgedObjCGetNSUIColorArray(objc: colors)
}
/// Sets a custom legend's labels and colors arrays.
/// The colors count should match the labels count.
/// * Each color is for the form drawn at the same index.
/// * A nil label will start a group.
/// * A nil color will avoid drawing a form, and a clearColor will leave a space for the form.
/// This will disable the feature that automatically calculates the legend labels and colors from the datasets.
/// Call `resetLegendToAuto(...)` to re-enable automatic calculation, and then if needed - call `notifyDataSetChanged()` on the chart to make it refresh the data.
public func setCustom(colors colors: [NSObject], labels: [NSObject])
{
if (colors.count != labels.count)
{
fatalError("ChartLegend:setCustom() - colors array and labels array need to be of same size")
}
self.labelsObjc = labels
self.colorsObjc = colors
_isLegendCustom = true
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartLimitLine.swift
================================================
//
// ChartLimitLine.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// The limit line is an additional feature for all Line, Bar and ScatterCharts.
/// It allows the displaying of an additional line in the chart that marks a certain maximum / limit on the specified axis (x- or y-axis).
public class ChartLimitLine: ChartComponentBase
{
@objc
public enum ChartLimitLabelPosition: Int
{
case LeftTop
case LeftBottom
case RightTop
case RightBottom
}
/// limit / maximum (the y-value or xIndex)
public var limit = Double(0.0)
private var _lineWidth = CGFloat(2.0)
public var lineColor = NSUIColor(red: 237.0/255.0, green: 91.0/255.0, blue: 91.0/255.0, alpha: 1.0)
public var lineDashPhase = CGFloat(0.0)
public var lineDashLengths: [CGFloat]?
public var valueTextColor = NSUIColor.blackColor()
public var valueFont = NSUIFont.systemFontOfSize(13.0)
public var label = ""
public var labelPosition = ChartLimitLabelPosition.RightTop
public override init()
{
super.init()
}
public init(limit: Double)
{
super.init()
self.limit = limit
}
public init(limit: Double, label: String)
{
super.init()
self.limit = limit
self.label = label
}
/// set the line width of the chart (min = 0.2, max = 12); default 2
public var lineWidth: CGFloat
{
get
{
return _lineWidth
}
set
{
if (newValue < 0.2)
{
_lineWidth = 0.2
}
else if (newValue > 12.0)
{
_lineWidth = 12.0
}
else
{
_lineWidth = newValue
}
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartMarker.swift
================================================
//
// ChartMarker.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartMarker: ChartComponentBase
{
/// The marker image to render
public var image: NSUIImage?
/// Use this to return the desired offset you wish the MarkerView to have on the x-axis.
public var offset: CGPoint = CGPoint()
/// The marker's size
public var size: CGSize
{
get
{
return image!.size
}
}
public override init()
{
super.init()
}
/// Returns the offset for drawing at the specific `point`
///
/// - parameter point: This is the point at which the marker wants to be drawn. You can adjust the offset conditionally based on this argument.
/// - By default returns the self.offset property. You can return any other value to override that.
public func offsetForDrawingAtPos(point: CGPoint) -> CGPoint
{
return offset;
}
/// Draws the ChartMarker on the given position on the given context
public func draw(context context: CGContext, point: CGPoint)
{
let offset = self.offsetForDrawingAtPos(point)
let size = self.size
let rect = CGRect(x: point.x + offset.x, y: point.y + offset.y, width: size.width, height: size.height)
NSUIGraphicsPushContext(context)
image!.drawInRect(rect)
NSUIGraphicsPopContext()
}
/// This method enables a custom ChartMarker to update it's content everytime the MarkerView is redrawn according to the data entry it points to.
///
/// - parameter highlight: the highlight object contains information about the highlighted value such as it's dataset-index, the selected range or stack-index (only stacked bar entries).
public func refreshContent(entry entry: ChartDataEntry, highlight: ChartHighlight)
{
// Do nothing here...
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartXAxis.swift
================================================
//
// ChartXAxis.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartXAxis: ChartAxisBase
{
@objc
public enum XAxisLabelPosition: Int
{
case Top
case Bottom
case BothSided
case TopInside
case BottomInside
}
public var values = [String?]()
/// width of the x-axis labels in pixels - this is automatically calculated by the computeAxis() methods in the renderers
public var labelWidth = CGFloat(1.0)
/// height of the x-axis labels in pixels - this is automatically calculated by the computeAxis() methods in the renderers
public var labelHeight = CGFloat(1.0)
/// width of the (rotated) x-axis labels in pixels - this is automatically calculated by the computeAxis() methods in the renderers
public var labelRotatedWidth = CGFloat(1.0)
/// height of the (rotated) x-axis labels in pixels - this is automatically calculated by the computeAxis() methods in the renderers
public var labelRotatedHeight = CGFloat(1.0)
/// This is the angle for drawing the X axis labels (in degrees)
public var labelRotationAngle = CGFloat(0.0)
/// the space that should be left out (in characters) between the x-axis labels
/// This only applies if the number of labels that will be skipped in between drawn axis labels is not custom set.
///
/// **default**: 4
public var spaceBetweenLabels = Int(4)
/// the modulus that indicates if a value at a specified index in an array(list) for the x-axis-labels is drawn or not. Draw when `(index % modulus) == 0`.
public var axisLabelModulus = Int(1)
/// Is axisLabelModulus a custom value or auto calculated? If false, then it's auto, if true, then custom.
///
/// **default**: false (automatic modulus)
private var _isAxisModulusCustom = false
/// the modulus that indicates if a value at a specified index in an array(list) for the y-axis-labels is drawn or not. Draw when `(index % modulus) == 0`.
/// Used only for Horizontal BarChart
public var yAxisLabelModulus = Int(1)
/// if set to true, the chart will avoid that the first and last label entry in the chart "clip" off the edge of the chart
public var avoidFirstLastClippingEnabled = false
/// Custom formatter for adjusting x-value strings
private var _xAxisValueFormatter: ChartXAxisValueFormatter = ChartDefaultXAxisValueFormatter()
/// Custom XValueFormatter for the data object that allows custom-formatting of all x-values before rendering them.
/// Provide null to reset back to the default formatting.
public var valueFormatter: ChartXAxisValueFormatter?
{
get
{
return _xAxisValueFormatter
}
set
{
_xAxisValueFormatter = newValue ?? ChartDefaultXAxisValueFormatter()
}
}
/// the position of the x-labels relative to the chart
public var labelPosition = XAxisLabelPosition.Top
/// if set to true, word wrapping the labels will be enabled.
/// word wrapping is done using `(value width * labelRotatedWidth)`
///
/// *Note: currently supports all charts except pie/radar/horizontal-bar*
public var wordWrapEnabled = false
/// - returns: true if word wrapping the labels is enabled
public var isWordWrapEnabled: Bool { return wordWrapEnabled }
/// the width for wrapping the labels, as percentage out of one value width.
/// used only when isWordWrapEnabled = true.
///
/// **default**: 1.0
public var wordWrapWidthPercent: CGFloat = 1.0
public override init()
{
super.init()
self.yOffset = 4.0;
}
public override func getLongestLabel() -> String
{
var longest = ""
for i in 0 ..< values.count
{
let text = values[i]
if (text != nil && longest.characters.count < (text!).characters.count)
{
longest = text!
}
}
return longest
}
public var isAvoidFirstLastClippingEnabled: Bool
{
return avoidFirstLastClippingEnabled
}
/// Sets the number of labels that should be skipped on the axis before the next label is drawn.
/// This will disable the feature that automatically calculates an adequate space between the axis labels and set the number of labels to be skipped to the fixed number provided by this method.
/// Call `resetLabelsToSkip(...)` to re-enable automatic calculation.
public func setLabelsToSkip(count: Int)
{
_isAxisModulusCustom = true
if (count < 0)
{
axisLabelModulus = 1
}
else
{
axisLabelModulus = count + 1
}
}
/// Calling this will disable a custom number of labels to be skipped (set by `setLabelsToSkip(...)`) while drawing the x-axis. Instead, the number of values to skip will again be calculated automatically.
public func resetLabelsToSkip()
{
_isAxisModulusCustom = false
}
/// - returns: true if a custom axis-modulus has been set that determines the number of labels to skip when drawing.
public var isAxisModulusCustom: Bool
{
return _isAxisModulusCustom
}
public var valuesObjc: [NSObject]
{
get { return ChartUtils.bridgedObjCGetStringArray(swift: values); }
set { self.values = ChartUtils.bridgedObjCGetStringArray(objc: newValue); }
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Components/ChartYAxis.swift
================================================
//
// ChartYAxis.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// Class representing the y-axis labels settings and its entries.
/// Be aware that not all features the YLabels class provides are suitable for the RadarChart.
/// Customizations that affect the value range of the axis need to be applied before setting data for the chart.
public class ChartYAxis: ChartAxisBase
{
@objc
public enum YAxisLabelPosition: Int
{
case OutsideChart
case InsideChart
}
/// Enum that specifies the axis a DataSet should be plotted against, either Left or Right.
@objc
public enum AxisDependency: Int
{
case Left
case Right
}
public var entries = [Double]()
public var entryCount: Int { return entries.count; }
/// the number of y-label entries the y-labels should have, default 6
private var _labelCount = Int(6)
/// indicates if the top y-label entry is drawn or not
public var drawTopYLabelEntryEnabled = true
/// if true, the y-labels show only the minimum and maximum value
public var showOnlyMinMaxEnabled = false
/// flag that indicates if the axis is inverted or not
public var inverted = false
/// This property is deprecated - Use `customAxisMin` instead.
public var startAtZeroEnabled: Bool
{
get
{
return isAxisMinCustom && _axisMinimum == 0.0
}
set
{
if newValue
{
axisMinValue = 0.0
}
else
{
resetCustomAxisMin()
}
}
}
/// if true, the set number of y-labels will be forced
public var forceLabelsEnabled = false
/// flag that indicates if the zero-line should be drawn regardless of other grid lines
public var drawZeroLineEnabled = false
/// Color of the zero line
public var zeroLineColor: NSUIColor? = NSUIColor.grayColor()
/// Width of the zero line
public var zeroLineWidth: CGFloat = 1.0
/// This is how much (in pixels) into the dash pattern are we starting from.
public var zeroLineDashPhase = CGFloat(0.0)
/// This is the actual dash pattern.
/// I.e. [2, 3] will paint [-- -- ]
/// [1, 3, 4, 2] will paint [- ---- - ---- ]
public var zeroLineDashLengths: [CGFloat]?
/// the formatter used to customly format the y-labels
public var valueFormatter: NSNumberFormatter?
/// the formatter used to customly format the y-labels
internal var _defaultValueFormatter = NSNumberFormatter()
/// axis space from the largest value to the top in percent of the total axis range
public var spaceTop = CGFloat(0.1)
/// axis space from the smallest value to the bottom in percent of the total axis range
public var spaceBottom = CGFloat(0.1)
/// the position of the y-labels relative to the chart
public var labelPosition = YAxisLabelPosition.OutsideChart
/// the side this axis object represents
private var _axisDependency = AxisDependency.Left
/// the minimum width that the axis should take
///
/// **default**: 0.0
public var minWidth = CGFloat(0)
/// the maximum width that the axis can take.
/// use Infinity for disabling the maximum.
///
/// **default**: CGFloat.infinity
public var maxWidth = CGFloat(CGFloat.infinity)
/// When true, axis labels are controlled by the `granularity` property.
/// When false, axis values could possibly be repeated.
/// This could happen if two adjacent axis values are rounded to same value.
/// If using granularity this could be avoided by having fewer axis values visible.
public var granularityEnabled = true
/// The minimum interval between axis values.
/// This can be used to avoid label duplicating when zooming in.
///
/// **default**: 1.0
public var granularity = Double(1.0)
public override init()
{
super.init()
_defaultValueFormatter.minimumIntegerDigits = 1
_defaultValueFormatter.maximumFractionDigits = 1
_defaultValueFormatter.minimumFractionDigits = 1
_defaultValueFormatter.usesGroupingSeparator = true
self.yOffset = 0.0
}
public init(position: AxisDependency)
{
super.init()
_axisDependency = position
_defaultValueFormatter.minimumIntegerDigits = 1
_defaultValueFormatter.maximumFractionDigits = 1
_defaultValueFormatter.minimumFractionDigits = 1
_defaultValueFormatter.usesGroupingSeparator = true
self.yOffset = 0.0
}
public var axisDependency: AxisDependency
{
return _axisDependency
}
public func setLabelCount(count: Int, force: Bool)
{
_labelCount = count
if (_labelCount > 25)
{
_labelCount = 25
}
if (_labelCount < 2)
{
_labelCount = 2
}
forceLabelsEnabled = force
}
/// the number of label entries the y-axis should have
/// max = 25,
/// min = 2,
/// default = 6,
/// be aware that this number is not fixed and can only be approximated
public var labelCount: Int
{
get
{
return _labelCount
}
set
{
setLabelCount(newValue, force: false);
}
}
public func requiredSize() -> CGSize
{
let label = getLongestLabel() as NSString
var size = label.sizeWithAttributes([NSFontAttributeName: labelFont])
size.width += xOffset * 2.0
size.height += yOffset * 2.0
size.width = max(minWidth, min(size.width, maxWidth > 0.0 ? maxWidth : size.width))
return size
}
public func getRequiredHeightSpace() -> CGFloat
{
return requiredSize().height
}
public override func getLongestLabel() -> String
{
var longest = ""
for i in 0 ..< entries.count
{
let text = getFormattedLabel(i)
if (longest.characters.count < text.characters.count)
{
longest = text
}
}
return longest
}
/// - returns: the formatted y-label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set).
public func getFormattedLabel(index: Int) -> String
{
if (index < 0 || index >= entries.count)
{
return ""
}
return (valueFormatter ?? _defaultValueFormatter).stringFromNumber(entries[index])!
}
/// - returns: true if this axis needs horizontal offset, false if no offset is needed.
public var needsOffset: Bool
{
if (isEnabled && isDrawLabelsEnabled && labelPosition == .OutsideChart)
{
return true
}
else
{
return false
}
}
public var isInverted: Bool { return inverted; }
/// This is deprecated now, use `customAxisMin`
@available(*, deprecated=1.0, message="Use customAxisMin instead.")
public var isStartAtZeroEnabled: Bool { return startAtZeroEnabled }
/// - returns: true if focing the y-label count is enabled. Default: false
public var isForceLabelsEnabled: Bool { return forceLabelsEnabled }
public var isShowOnlyMinMaxEnabled: Bool { return showOnlyMinMaxEnabled; }
public var isDrawTopYLabelEntryEnabled: Bool { return drawTopYLabelEntryEnabled; }
/// Calculates the minimum, maximum and range values of the YAxis with the given minimum and maximum values from the chart data.
/// - parameter dataMin: the y-min value according to chart data
/// - parameter dataMax: the y-max value according to chart
public func calcMinMax(min dataMin: Double, max dataMax: Double)
{
// if custom, use value as is, else use data value
var min = _customAxisMin ? _axisMinimum : dataMin
var max = _customAxisMax ? _axisMaximum : dataMax
// temporary range (before calculations)
let range = abs(max - min)
// in case all values are equal
if range == 0.0
{
max = max + 1.0
min = min - 1.0
}
// bottom-space only effects non-custom min
if !_customAxisMin
{
let bottomSpace = range * Double(spaceBottom)
_axisMinimum = min - bottomSpace
}
// top-space only effects non-custom max
if !_customAxisMax
{
let topSpace = range * Double(spaceTop)
_axisMaximum = max + topSpace
}
// calc actual range
axisRange = abs(_axisMaximum - _axisMinimum)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/ChartBaseDataSet.swift
================================================
//
// BaseDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 16/1/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartBaseDataSet: NSObject, IChartDataSet
{
public required override init()
{
super.init()
// default color
colors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
valueColors.append(NSUIColor.blackColor())
}
public init(label: String?)
{
super.init()
// default color
colors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
valueColors.append(NSUIColor.blackColor())
self.label = label
}
// MARK: - Data functions and accessors
/// Use this method to tell the data set that the underlying data has changed
public func notifyDataSetChanged()
{
calcMinMax(start: 0, end: entryCount - 1)
}
public func calcMinMax(start start: Int, end: Int)
{
fatalError("calcMinMax is not implemented in ChartBaseDataSet")
}
public var yMin: Double
{
fatalError("yMin is not implemented in ChartBaseDataSet")
}
public var yMax: Double
{
fatalError("yMax is not implemented in ChartBaseDataSet")
}
public var entryCount: Int
{
fatalError("entryCount is not implemented in ChartBaseDataSet")
}
public func yValForXIndex(x: Int) -> Double
{
fatalError("yValForXIndex is not implemented in ChartBaseDataSet")
}
public func entryForIndex(i: Int) -> ChartDataEntry?
{
fatalError("entryForIndex is not implemented in ChartBaseDataSet")
}
public func entryForXIndex(x: Int, rounding: ChartDataSetRounding) -> ChartDataEntry?
{
fatalError("entryForXIndex is not implemented in ChartBaseDataSet")
}
public func entryForXIndex(x: Int) -> ChartDataEntry?
{
fatalError("entryForXIndex is not implemented in ChartBaseDataSet")
}
public func entryIndex(xIndex x: Int, rounding: ChartDataSetRounding) -> Int
{
fatalError("entryIndex is not implemented in ChartBaseDataSet")
}
public func entryIndex(entry e: ChartDataEntry) -> Int
{
fatalError("entryIndex is not implemented in ChartBaseDataSet")
}
public func addEntry(e: ChartDataEntry) -> Bool
{
fatalError("addEntry is not implemented in ChartBaseDataSet")
}
public func addEntryOrdered(e: ChartDataEntry) -> Bool
{
fatalError("addEntryOrdered is not implemented in ChartBaseDataSet")
}
public func removeEntry(entry: ChartDataEntry) -> Bool
{
fatalError("removeEntry is not implemented in ChartBaseDataSet")
}
public func removeEntry(xIndex xIndex: Int) -> Bool
{
if let entry = entryForXIndex(xIndex)
{
return removeEntry(entry)
}
return false
}
public func removeFirst() -> Bool
{
if let entry = entryForIndex(0)
{
return removeEntry(entry)
}
return false
}
public func removeLast() -> Bool
{
if let entry = entryForIndex(entryCount - 1)
{
return removeEntry(entry)
}
return false
}
public func contains(e: ChartDataEntry) -> Bool
{
fatalError("removeEntry is not implemented in ChartBaseDataSet")
}
public func clear()
{
fatalError("clear is not implemented in ChartBaseDataSet")
}
// MARK: - Styling functions and accessors
/// All the colors that are used for this DataSet.
/// Colors are reused as soon as the number of Entries the DataSet represents is higher than the size of the colors array.
public var colors = [NSUIColor]()
/// List representing all colors that are used for drawing the actual values for this DataSet
public var valueColors = [NSUIColor]()
/// The label string that describes the DataSet.
public var label: String? = "DataSet"
/// The axis this DataSet should be plotted against.
public var axisDependency = ChartYAxis.AxisDependency.Left
/// - returns: the color at the given index of the DataSet's color array.
/// This prevents out-of-bounds by performing a modulus on the color index, so colours will repeat themselves.
public func colorAt(index: Int) -> NSUIColor
{
var index = index
if (index < 0)
{
index = 0
}
return colors[index % colors.count]
}
/// Resets all colors of this DataSet and recreates the colors array.
public func resetColors()
{
colors.removeAll(keepCapacity: false)
}
/// Adds a new color to the colors array of the DataSet.
/// - parameter color: the color to add
public func addColor(color: NSUIColor)
{
colors.append(color)
}
/// Sets the one and **only** color that should be used for this DataSet.
/// Internally, this recreates the colors array and adds the specified color.
/// - parameter color: the color to set
public func setColor(color: NSUIColor)
{
colors.removeAll(keepCapacity: false)
colors.append(color)
}
/// Sets colors to a single color a specific alpha value.
/// - parameter color: the color to set
/// - parameter alpha: alpha to apply to the set `color`
public func setColor(color: NSUIColor, alpha: CGFloat)
{
setColor(color.colorWithAlphaComponent(alpha))
}
/// Sets colors with a specific alpha value.
/// - parameter colors: the colors to set
/// - parameter alpha: alpha to apply to the set `colors`
public func setColors(colors: [NSUIColor], alpha: CGFloat)
{
var colorsWithAlpha = colors
for i in 0 ..< colorsWithAlpha.count
{
colorsWithAlpha[i] = colorsWithAlpha[i] .colorWithAlphaComponent(alpha)
}
self.colors = colorsWithAlpha
}
/// if true, value highlighting is enabled
public var highlightEnabled = true
/// - returns: true if value highlighting is enabled for this dataset
public var isHighlightEnabled: Bool { return highlightEnabled }
/// the formatter used to customly format the values
internal var _valueFormatter: NSNumberFormatter? = ChartUtils.defaultValueFormatter()
/// The formatter used to customly format the values
public var valueFormatter: NSNumberFormatter?
{
get
{
return _valueFormatter
}
set
{
if newValue == nil
{
_valueFormatter = ChartUtils.defaultValueFormatter()
}
else
{
_valueFormatter = newValue
}
}
}
/// Sets/get a single color for value text.
/// Setting the color clears the colors array and adds a single color.
/// Getting will return the first color in the array.
public var valueTextColor: NSUIColor
{
get
{
return valueColors[0]
}
set
{
valueColors.removeAll(keepCapacity: false)
valueColors.append(newValue)
}
}
/// - returns: the color at the specified index that is used for drawing the values inside the chart. Uses modulus internally.
public func valueTextColorAt(index: Int) -> NSUIColor
{
var index = index
if (index < 0)
{
index = 0
}
return valueColors[index % valueColors.count]
}
/// the font for the value-text labels
public var valueFont: NSUIFont = NSUIFont.systemFontOfSize(7.0)
/// Set this to true to draw y-values on the chart
public var drawValuesEnabled = true
/// Returns true if y-value drawing is enabled, false if not
public var isDrawValuesEnabled: Bool
{
return drawValuesEnabled
}
/// Set the visibility of this DataSet. If not visible, the DataSet will not be drawn to the chart upon refreshing it.
public var visible = true
/// Returns true if this DataSet is visible inside the chart, or false if it is currently hidden.
public var isVisible: Bool
{
return visible
}
// MARK: - NSObject
public override var description: String
{
return String(format: "%@, label: %@, %i entries", arguments: [NSStringFromClass(self.dynamicType), self.label ?? "", self.entryCount])
}
public override var debugDescription: String
{
var desc = description + ":"
for i in 0 ..< self.entryCount
{
desc += "\n" + (self.entryForIndex(i)?.description ?? "")
}
return desc
}
// MARK: - NSCopying
public func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = self.dynamicType.init()
copy.colors = colors
copy.valueColors = valueColors
copy.label = label
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BarChartData.swift
================================================
//
// BarChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BarChartData: BarLineScatterCandleBubbleChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
private var _groupSpace = CGFloat(0.8)
/// The spacing is relative to a full bar width
public var groupSpace: CGFloat
{
get
{
if (_dataSets.count <= 1)
{
return 0.0
}
return _groupSpace
}
set
{
_groupSpace = newValue
}
}
/// - returns: true if this BarData object contains grouped DataSets (more than 1 DataSet).
public var isGrouped: Bool
{
return _dataSets.count > 1 ? true : false
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BarChartDataEntry.swift
================================================
//
// BarChartDataEntry.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class BarChartDataEntry: ChartDataEntry
{
/// the values the stacked barchart holds
private var _values: [Double]?
/// the sum of all negative values this entry (if stacked) contains
private var _negativeSum: Double = 0.0
/// the sum of all positive values this entry (if stacked) contains
private var _positiveSum: Double = 0.0
public required init()
{
super.init()
}
/// Constructor for stacked bar entries.
public init(values: [Double], xIndex: Int)
{
super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex)
self.values = values
calcPosNegSum()
}
/// Constructor for normal bars (not stacked).
public override init(value: Double, xIndex: Int)
{
super.init(value: value, xIndex: xIndex)
}
/// Constructor for stacked bar entries.
public init(values: [Double], xIndex: Int, label: String)
{
super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex, data: label)
self.values = values
}
/// Constructor for normal bars (not stacked).
public override init(value: Double, xIndex: Int, data: AnyObject?)
{
super.init(value: value, xIndex: xIndex, data: data)
}
public func getBelowSum(stackIndex :Int) -> Double
{
if (values == nil)
{
return 0
}
var remainder: Double = 0.0
var index = values!.count - 1
while (index > stackIndex && index >= 0)
{
remainder += values![index]
index -= 1
}
return remainder
}
/// - returns: the sum of all negative values this entry (if stacked) contains. (this is a positive number)
public var negativeSum: Double
{
return _negativeSum
}
/// - returns: the sum of all positive values this entry (if stacked) contains.
public var positiveSum: Double
{
return _positiveSum
}
public func calcPosNegSum()
{
if _values == nil
{
_positiveSum = 0.0
_negativeSum = 0.0
return
}
var sumNeg: Double = 0.0
var sumPos: Double = 0.0
for f in _values!
{
if f < 0.0
{
sumNeg += -f
}
else
{
sumPos += f
}
}
_negativeSum = sumNeg
_positiveSum = sumPos
}
// MARK: Accessors
/// the values the stacked barchart holds
public var isStacked: Bool { return _values != nil }
/// the values the stacked barchart holds
public var values: [Double]?
{
get { return self._values }
set
{
self.value = BarChartDataEntry.calcSum(newValue)
self._values = newValue
calcPosNegSum()
}
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! BarChartDataEntry
copy._values = _values
copy.value = value
copy._negativeSum = _negativeSum
return copy
}
/// Calculates the sum across all values of the given stack.
///
/// - parameter vals:
/// - returns:
private static func calcSum(vals: [Double]?) -> Double
{
if vals == nil
{
return 0.0
}
var sum = 0.0
for f in vals!
{
sum += f
}
return sum
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift
================================================
//
// BarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDataSet
{
private func initialize()
{
self.highlightColor = NSUIColor.blackColor()
self.calcStackSize(yVals as! [BarChartDataEntry])
self.calcEntryCountIncludingStacks(yVals as! [BarChartDataEntry])
}
public required init()
{
super.init()
initialize()
}
public override init(yVals: [ChartDataEntry]?, label: String?)
{
super.init(yVals: yVals, label: label)
initialize()
}
// MARK: - Data functions and accessors
/// the maximum number of bars that are stacked upon each other, this value
/// is calculated from the Entries that are added to the DataSet
private var _stackSize = 1
/// the overall entry count, including counting each stack-value individually
private var _entryCountStacks = 0
/// Calculates the total number of entries this DataSet represents, including
/// stacks. All values belonging to a stack are calculated separately.
private func calcEntryCountIncludingStacks(yVals: [BarChartDataEntry]!)
{
_entryCountStacks = 0
for i in 0 ..< yVals.count
{
let vals = yVals[i].values
if (vals == nil)
{
_entryCountStacks += 1
}
else
{
_entryCountStacks += vals!.count
}
}
}
/// calculates the maximum stacksize that occurs in the Entries array of this DataSet
private func calcStackSize(yVals: [BarChartDataEntry]!)
{
for i in 0 ..< yVals.count
{
if let vals = yVals[i].values
{
if vals.count > _stackSize
{
_stackSize = vals.count
}
}
}
}
public override func calcMinMax(start start : Int, end: Int)
{
let yValCount = _yVals.count
if yValCount == 0
{
return
}
var endValue : Int
if end == 0 || end >= yValCount
{
endValue = yValCount - 1
}
else
{
endValue = end
}
_lastStart = start
_lastEnd = endValue
_yMin = DBL_MAX
_yMax = -DBL_MAX
for i in start ... endValue
{
if let e = _yVals[i] as? BarChartDataEntry
{
if !e.value.isNaN
{
if e.values == nil
{
if e.value < _yMin
{
_yMin = e.value
}
if e.value > _yMax
{
_yMax = e.value
}
}
else
{
if -e.negativeSum < _yMin
{
_yMin = -e.negativeSum
}
if e.positiveSum > _yMax
{
_yMax = e.positiveSum
}
}
}
}
}
if (_yMin == DBL_MAX)
{
_yMin = 0.0
_yMax = 0.0
}
}
/// - returns: the maximum number of bars that can be stacked upon another in this DataSet.
public var stackSize: Int
{
return _stackSize
}
/// - returns: true if this DataSet is stacked (stacksize > 1) or not.
public var isStacked: Bool
{
return _stackSize > 1 ? true : false
}
/// - returns: the overall entry count, including counting each stack-value individually
public var entryCountStacks: Int
{
return _entryCountStacks
}
/// array of labels used to describe the different values of the stacked bars
public var stackLabels: [String] = ["Stack"]
// MARK: - Styling functions and accessors
/// space indicator between the bars in percentage of the whole width of one value (0.15 == 15% of bar width)
public var barSpace: CGFloat = 0.15
/// the color used for drawing the bar-shadows. The bar shadows is a surface behind the bar that indicates the maximum value
public var barShadowColor = NSUIColor(red: 215.0/255.0, green: 215.0/255.0, blue: 215.0/255.0, alpha: 1.0)
/// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque)
public var highlightAlpha = CGFloat(120.0 / 255.0)
// MARK: - NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! BarChartDataSet
copy._stackSize = _stackSize
copy._entryCountStacks = _entryCountStacks
copy.stackLabels = stackLabels
copy.barSpace = barSpace
copy.barShadowColor = barShadowColor
copy.highlightAlpha = highlightAlpha
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift
================================================
//
// BarLineScatterCandleBubbleChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class BarLineScatterCandleBubbleChartData: ChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift
================================================
//
// BarLineScatterCandleBubbleChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BarLineScatterCandleBubbleChartDataSet: ChartDataSet, IBarLineScatterCandleBubbleChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
public var highlightColor = NSUIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
public var highlightLineWidth = CGFloat(0.5)
public var highlightLineDashPhase = CGFloat(0.0)
public var highlightLineDashLengths: [CGFloat]?
// MARK: - NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! BarLineScatterCandleBubbleChartDataSet
copy.highlightColor = highlightColor
copy.highlightLineWidth = highlightLineWidth
copy.highlightLineDashPhase = highlightLineDashPhase
copy.highlightLineDashLengths = highlightLineDashLengths
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BubbleChartData.swift
================================================
//
// BubbleChartData.swift
// Charts
//
// Bubble chart implementation:
// Copyright 2015 Pierre-Marc Airoldi
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BubbleChartData: BarLineScatterCandleBubbleChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
/// Sets the width of the circle that surrounds the bubble when highlighted for all DataSet objects this data object contains
public func setHighlightCircleWidth(width: CGFloat)
{
for set in _dataSets as! [IBubbleChartDataSet]!
{
set.highlightCircleWidth = width
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BubbleChartDataEntry.swift
================================================
//
// BubbleDataEntry.swift
// Charts
//
// Bubble chart implementation:
// Copyright 2015 Pierre-Marc Airoldi
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BubbleChartDataEntry: ChartDataEntry
{
/// The size of the bubble.
public var size = CGFloat(0.0)
public required init()
{
super.init()
}
/// - parameter xIndex: The index on the x-axis.
/// - parameter val: The value on the y-axis.
/// - parameter size: The size of the bubble.
public init(xIndex: Int, value: Double, size: CGFloat)
{
super.init(value: value, xIndex: xIndex)
self.size = size
}
/// - parameter xIndex: The index on the x-axis.
/// - parameter val: The value on the y-axis.
/// - parameter size: The size of the bubble.
/// - parameter data: Spot for additional data this Entry represents.
public init(xIndex: Int, value: Double, size: CGFloat, data: AnyObject?)
{
super.init(value: value, xIndex: xIndex, data: data)
self.size = size
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! BubbleChartDataEntry
copy.size = size
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift
================================================
//
// BubbleChartDataSet.swift
// Charts
//
// Bubble chart implementation:
// Copyright 2015 Pierre-Marc Airoldi
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBubbleChartDataSet
{
// MARK: - Data functions and accessors
internal var _xMax = Double(0.0)
internal var _xMin = Double(0.0)
internal var _maxSize = CGFloat(0.0)
public var xMin: Double { return _xMin }
public var xMax: Double { return _xMax }
public var maxSize: CGFloat { return _maxSize }
public override func calcMinMax(start start: Int, end: Int)
{
let yValCount = self.entryCount
if yValCount == 0
{
return
}
let entries = yVals as! [BubbleChartDataEntry]
// need chart width to guess this properly
var endValue : Int
if end == 0 || end >= yValCount
{
endValue = yValCount - 1
}
else
{
endValue = end
}
_lastStart = start
_lastEnd = end
_yMin = yMin(entries[start])
_yMax = yMax(entries[start])
for i in start ... endValue
{
let entry = entries[i]
let ymin = yMin(entry)
let ymax = yMax(entry)
if (ymin < _yMin)
{
_yMin = ymin
}
if (ymax > _yMax)
{
_yMax = ymax
}
let xmin = xMin(entry)
let xmax = xMax(entry)
if (xmin < _xMin)
{
_xMin = xmin
}
if (xmax > _xMax)
{
_xMax = xmax
}
let size = largestSize(entry)
if (size > _maxSize)
{
_maxSize = size
}
}
}
private func yMin(entry: BubbleChartDataEntry) -> Double
{
return entry.value
}
private func yMax(entry: BubbleChartDataEntry) -> Double
{
return entry.value
}
private func xMin(entry: BubbleChartDataEntry) -> Double
{
return Double(entry.xIndex)
}
private func xMax(entry: BubbleChartDataEntry) -> Double
{
return Double(entry.xIndex)
}
private func largestSize(entry: BubbleChartDataEntry) -> CGFloat
{
return entry.size
}
// MARK: - Styling functions and accessors
/// Sets/gets the width of the circle that surrounds the bubble when highlighted
public var highlightCircleWidth: CGFloat = 2.5
// MARK: - NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! BubbleChartDataSet
copy._xMin = _xMin
copy._xMax = _xMax
copy._maxSize = _maxSize
copy.highlightCircleWidth = highlightCircleWidth
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/CandleChartData.swift
================================================
//
// CandleChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class CandleChartData: BarLineScatterCandleBubbleChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/CandleChartDataEntry.swift
================================================
//
// CandleChartDataEntry.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class CandleChartDataEntry: ChartDataEntry
{
/// shadow-high value
public var high = Double(0.0)
/// shadow-low value
public var low = Double(0.0)
/// close value
public var close = Double(0.0)
/// open value
public var open = Double(0.0)
public required init()
{
super.init()
}
public init(xIndex: Int, shadowH: Double, shadowL: Double, open: Double, close: Double)
{
super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex)
self.high = shadowH
self.low = shadowL
self.open = open
self.close = close
}
public init(xIndex: Int, shadowH: Double, shadowL: Double, open: Double, close: Double, data: AnyObject?)
{
super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex, data: data)
self.high = shadowH
self.low = shadowL
self.open = open
self.close = close
}
/// - returns: the overall range (difference) between shadow-high and shadow-low.
public var shadowRange: Double
{
return abs(high - low)
}
/// - returns: the body size (difference between open and close).
public var bodyRange: Double
{
return abs(open - close)
}
/// the center value of the candle. (Middle value between high and low)
public override var value: Double
{
get
{
return super.value
}
set
{
super.value = (high + low) / 2.0
}
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! CandleChartDataEntry
copy.high = high
copy.high = low
copy.high = open
copy.high = close
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift
================================================
//
// CandleChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartDataSet
{
public required init()
{
super.init()
}
public override init(yVals: [ChartDataEntry]?, label: String?)
{
super.init(yVals: yVals, label: label)
}
// MARK: - Data functions and accessors
public override func calcMinMax(start start: Int, end: Int)
{
let yValCount = self.entryCount
if yValCount == 0
{
return
}
var entries = yVals as! [CandleChartDataEntry]
var endValue : Int
if end == 0 || end >= yValCount
{
endValue = yValCount - 1
}
else
{
endValue = end
}
_lastStart = start
_lastEnd = end
_yMin = DBL_MAX
_yMax = -DBL_MAX
for i in start ... endValue
{
let e = entries[i]
if (e.low < _yMin)
{
_yMin = e.low
}
if (e.high > _yMax)
{
_yMax = e.high
}
}
}
// MARK: - Styling functions and accessors
/// the space between the candle entries
///
/// **default**: 0.1 (10%)
private var _barSpace = CGFloat(0.1)
/// the space that is left out on the left and right side of each candle,
/// **default**: 0.1 (10%), max 0.45, min 0.0
public var barSpace: CGFloat
{
set
{
if (newValue < 0.0)
{
_barSpace = 0.0
}
else if (newValue > 0.45)
{
_barSpace = 0.45
}
else
{
_barSpace = newValue
}
}
get
{
return _barSpace
}
}
/// should the candle bars show?
/// when false, only "ticks" will show
///
/// **default**: true
public var showCandleBar: Bool = true
/// the width of the candle-shadow-line in pixels.
///
/// **default**: 1.5
public var shadowWidth = CGFloat(1.5)
/// the color of the shadow line
public var shadowColor: NSUIColor?
/// use candle color for the shadow
public var shadowColorSameAsCandle = false
/// Is the shadow color same as the candle color?
public var isShadowColorSameAsCandle: Bool { return shadowColorSameAsCandle }
/// color for open == close
public var neutralColor: NSUIColor?
/// color for open > close
public var increasingColor: NSUIColor?
/// color for open < close
public var decreasingColor: NSUIColor?
/// Are increasing values drawn as filled?
/// increasing candlesticks are traditionally hollow
public var increasingFilled = false
/// Are increasing values drawn as filled?
public var isIncreasingFilled: Bool { return increasingFilled }
/// Are decreasing values drawn as filled?
/// descreasing candlesticks are traditionally filled
public var decreasingFilled = true
/// Are decreasing values drawn as filled?
public var isDecreasingFilled: Bool { return decreasingFilled }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/ChartData.swift
================================================
//
// ChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartData: NSObject
{
internal var _yMax = Double(0.0)
internal var _yMin = Double(0.0)
internal var _leftAxisMax = Double(0.0)
internal var _leftAxisMin = Double(0.0)
internal var _rightAxisMax = Double(0.0)
internal var _rightAxisMin = Double(0.0)
private var _yValCount = Int(0)
/// the last start value used for calcMinMax
internal var _lastStart: Int = 0
/// the last end value used for calcMinMax
internal var _lastEnd: Int = 0
/// the average length (in characters) across all x-value strings
private var _xValAverageLength = Double(0.0)
internal var _xVals: [String?]!
internal var _dataSets: [IChartDataSet]!
public override init()
{
super.init()
_xVals = [String?]()
_dataSets = [IChartDataSet]()
}
public init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init()
_xVals = xVals == nil ? [String?]() : xVals
_dataSets = dataSets == nil ? [IChartDataSet]() : dataSets
self.initialize(_dataSets)
}
public init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init()
_xVals = xVals == nil ? [String?]() : ChartUtils.bridgedObjCGetStringArray(objc: xVals!)
_dataSets = dataSets == nil ? [IChartDataSet]() : dataSets
self.initialize(_dataSets)
}
public convenience init(xVals: [String?]?)
{
self.init(xVals: xVals, dataSets: [IChartDataSet]())
}
public convenience init(xVals: [NSObject]?)
{
self.init(xVals: xVals, dataSets: [IChartDataSet]())
}
public convenience init(xVals: [String?]?, dataSet: IChartDataSet?)
{
self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
}
public convenience init(xVals: [NSObject]?, dataSet: IChartDataSet?)
{
self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
}
internal func initialize(dataSets: [IChartDataSet])
{
checkIsLegal(dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
// calculates the average length (in characters) across all x-value strings
internal func calcXValAverageLength()
{
if (_xVals.count == 0)
{
_xValAverageLength = 1
return
}
var sum = 1
for i in 0 ..< _xVals.count
{
sum += _xVals[i] == nil ? 0 : (_xVals[i]!).characters.count
}
_xValAverageLength = Double(sum) / Double(_xVals.count)
}
// Checks if the combination of x-values array and DataSet array is legal or not.
// :param: dataSets
internal func checkIsLegal(dataSets: [IChartDataSet]!)
{
if (dataSets == nil)
{
return
}
if self is ScatterChartData
{ // In scatter chart it makes sense to have more than one y-value value for an x-index
return
}
for i in 0 ..< dataSets.count
{
if (dataSets[i].entryCount > _xVals.count)
{
print("One or more of the DataSet Entry arrays are longer than the x-values array of this Data object.", terminator: "\n")
return
}
}
}
/// Call this method to let the ChartData know that the underlying data has changed.
/// Calling this performs all necessary recalculations needed when the contained data has changed.
public func notifyDataChanged()
{
initialize(_dataSets)
}
/// calc minimum and maximum y value over all datasets
internal func calcMinMax(start start: Int, end: Int)
{
if (_dataSets == nil || _dataSets.count < 1)
{
_yMax = 0.0
_yMin = 0.0
}
else
{
_lastStart = start
_lastEnd = end
_yMin = DBL_MAX
_yMax = -DBL_MAX
for i in 0 ..< _dataSets.count
{
_dataSets[i].calcMinMax(start: start, end: end)
if (_dataSets[i].yMin < _yMin)
{
_yMin = _dataSets[i].yMin
}
if (_dataSets[i].yMax > _yMax)
{
_yMax = _dataSets[i].yMax
}
}
if (_yMin == DBL_MAX)
{
_yMin = 0.0
_yMax = 0.0
}
// left axis
let firstLeft = getFirstLeft()
if (firstLeft !== nil)
{
_leftAxisMax = firstLeft!.yMax
_leftAxisMin = firstLeft!.yMin
for dataSet in _dataSets
{
if (dataSet.axisDependency == .Left)
{
if (dataSet.yMin < _leftAxisMin)
{
_leftAxisMin = dataSet.yMin
}
if (dataSet.yMax > _leftAxisMax)
{
_leftAxisMax = dataSet.yMax
}
}
}
}
// right axis
let firstRight = getFirstRight()
if (firstRight !== nil)
{
_rightAxisMax = firstRight!.yMax
_rightAxisMin = firstRight!.yMin
for dataSet in _dataSets
{
if (dataSet.axisDependency == .Right)
{
if (dataSet.yMin < _rightAxisMin)
{
_rightAxisMin = dataSet.yMin
}
if (dataSet.yMax > _rightAxisMax)
{
_rightAxisMax = dataSet.yMax
}
}
}
}
// in case there is only one axis, adjust the second axis
handleEmptyAxis(firstLeft, firstRight: firstRight)
}
}
/// Calculates the total number of y-values across all ChartDataSets the ChartData represents.
internal func calcYValueCount()
{
_yValCount = 0
if (_dataSets == nil)
{
return
}
var count = 0
for i in 0 ..< _dataSets.count
{
count += _dataSets[i].entryCount
}
_yValCount = count
}
/// - returns: the number of LineDataSets this object contains
public var dataSetCount: Int
{
if (_dataSets == nil)
{
return 0
}
return _dataSets.count
}
/// - returns: the smallest y-value the data object contains.
public var yMin: Double
{
return _yMin
}
public func getYMin() -> Double
{
return _yMin
}
public func getYMin(axis: ChartYAxis.AxisDependency) -> Double
{
if (axis == .Left)
{
return _leftAxisMin
}
else
{
return _rightAxisMin
}
}
/// - returns: the greatest y-value the data object contains.
public var yMax: Double
{
return _yMax
}
public func getYMax() -> Double
{
return _yMax
}
public func getYMax(axis: ChartYAxis.AxisDependency) -> Double
{
if (axis == .Left)
{
return _leftAxisMax
}
else
{
return _rightAxisMax
}
}
/// - returns: the average length (in characters) across all values in the x-vals array
public var xValAverageLength: Double
{
return _xValAverageLength
}
/// - returns: the total number of y-values across all DataSet objects the this object represents.
public var yValCount: Int
{
return _yValCount
}
/// - returns: the x-values the chart represents
public var xVals: [String?]
{
return _xVals
}
///Adds a new x-value to the chart data.
public func addXValue(xVal: String?)
{
_xVals.append(xVal)
}
/// Removes the x-value at the specified index.
public func removeXValue(index: Int)
{
_xVals.removeAtIndex(index)
}
/// - returns: the array of ChartDataSets this object holds.
public var dataSets: [IChartDataSet]
{
get
{
return _dataSets
}
set
{
_dataSets = newValue
initialize(_dataSets)
}
}
/// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not.
///
/// **IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.**
///
/// - parameter dataSets: the DataSet array to search
/// - parameter type:
/// - parameter ignorecase: if true, the search is not case-sensitive
/// - returns: the index of the DataSet Object with the given label. Sensitive or not.
internal func getDataSetIndexByLabel(label: String, ignorecase: Bool) -> Int
{
if (ignorecase)
{
for i in 0 ..< dataSets.count
{
if (dataSets[i].label == nil)
{
continue
}
if (label.caseInsensitiveCompare(dataSets[i].label!) == NSComparisonResult.OrderedSame)
{
return i
}
}
}
else
{
for i in 0 ..< dataSets.count
{
if (label == dataSets[i].label)
{
return i
}
}
}
return -1
}
/// - returns: the total number of x-values this ChartData object represents (the size of the x-values array)
public var xValCount: Int
{
return _xVals.count
}
/// - returns: the labels of all DataSets as a string array.
internal func dataSetLabels() -> [String]
{
var types = [String]()
for i in 0 ..< _dataSets.count
{
if (dataSets[i].label == nil)
{
continue
}
types[i] = _dataSets[i].label!
}
return types
}
/// Get the Entry for a corresponding highlight object
///
/// - parameter highlight:
/// - returns: the entry that is highlighted
public func getEntryForHighlight(highlight: ChartHighlight) -> ChartDataEntry?
{
if highlight.dataSetIndex >= dataSets.count
{
return nil
}
else
{
return _dataSets[highlight.dataSetIndex].entryForXIndex(highlight.xIndex)
}
}
/// **IMPORTANT: This method does calculations at runtime. Use with care in performance critical situations.**
///
/// - parameter label:
/// - parameter ignorecase:
/// - returns: the DataSet Object with the given label. Sensitive or not.
public func getDataSetByLabel(label: String, ignorecase: Bool) -> IChartDataSet?
{
let index = getDataSetIndexByLabel(label, ignorecase: ignorecase)
if (index < 0 || index >= _dataSets.count)
{
return nil
}
else
{
return _dataSets[index]
}
}
public func getDataSetByIndex(index: Int) -> IChartDataSet!
{
if (_dataSets == nil || index < 0 || index >= _dataSets.count)
{
return nil
}
return _dataSets[index]
}
public func addDataSet(d: IChartDataSet!)
{
if (_dataSets == nil)
{
return
}
_yValCount += d.entryCount
if (_dataSets.count == 0)
{
_yMax = d.yMax
_yMin = d.yMin
if (d.axisDependency == .Left)
{
_leftAxisMax = d.yMax
_leftAxisMin = d.yMin
}
else
{
_rightAxisMax = d.yMax
_rightAxisMin = d.yMin
}
}
else
{
if (_yMax < d.yMax)
{
_yMax = d.yMax
}
if (_yMin > d.yMin)
{
_yMin = d.yMin
}
if (d.axisDependency == .Left)
{
if (_leftAxisMax < d.yMax)
{
_leftAxisMax = d.yMax
}
if (_leftAxisMin > d.yMin)
{
_leftAxisMin = d.yMin
}
}
else
{
if (_rightAxisMax < d.yMax)
{
_rightAxisMax = d.yMax
}
if (_rightAxisMin > d.yMin)
{
_rightAxisMin = d.yMin
}
}
}
_dataSets.append(d)
handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
}
public func handleEmptyAxis(firstLeft: IChartDataSet?, firstRight: IChartDataSet?)
{
// in case there is only one axis, adjust the second axis
if (firstLeft === nil)
{
_leftAxisMax = _rightAxisMax
_leftAxisMin = _rightAxisMin
}
else if (firstRight === nil)
{
_rightAxisMax = _leftAxisMax
_rightAxisMin = _leftAxisMin
}
}
/// Removes the given DataSet from this data object.
/// Also recalculates all minimum and maximum values.
///
/// - returns: true if a DataSet was removed, false if no DataSet could be removed.
public func removeDataSet(dataSet: IChartDataSet!) -> Bool
{
if (_dataSets == nil || dataSet === nil)
{
return false
}
for i in 0 ..< _dataSets.count
{
if (_dataSets[i] === dataSet)
{
return removeDataSetByIndex(i)
}
}
return false
}
/// Removes the DataSet at the given index in the DataSet array from the data object.
/// Also recalculates all minimum and maximum values.
///
/// - returns: true if a DataSet was removed, false if no DataSet could be removed.
public func removeDataSetByIndex(index: Int) -> Bool
{
if (_dataSets == nil || index >= _dataSets.count || index < 0)
{
return false
}
let d = _dataSets.removeAtIndex(index)
_yValCount -= d.entryCount
calcMinMax(start: _lastStart, end: _lastEnd)
return true
}
/// Adds an Entry to the DataSet at the specified index. Entries are added to the end of the list.
public func addEntry(e: ChartDataEntry, dataSetIndex: Int)
{
if _dataSets != nil && _dataSets.count > dataSetIndex && dataSetIndex >= 0
{
let val = e.value
let set = _dataSets[dataSetIndex]
if !set.addEntry(e) { return }
if (_yValCount == 0)
{
_yMin = val
_yMax = val
if (set.axisDependency == .Left)
{
_leftAxisMax = e.value
_leftAxisMin = e.value
}
else
{
_rightAxisMax = e.value
_rightAxisMin = e.value
}
}
else
{
if (_yMax < val)
{
_yMax = val
}
if (_yMin > val)
{
_yMin = val
}
if (set.axisDependency == .Left)
{
if (_leftAxisMax < e.value)
{
_leftAxisMax = e.value
}
if (_leftAxisMin > e.value)
{
_leftAxisMin = e.value
}
}
else
{
if (_rightAxisMax < e.value)
{
_rightAxisMax = e.value
}
if (_rightAxisMin > e.value)
{
_rightAxisMin = e.value
}
}
}
_yValCount += 1
handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
}
else
{
print("ChartData.addEntry() - dataSetIndex our of range.", terminator: "\n")
}
}
/// Removes the given Entry object from the DataSet at the specified index.
public func removeEntry(entry: ChartDataEntry!, dataSetIndex: Int) -> Bool
{
// entry null, outofbounds
if (entry === nil || dataSetIndex >= _dataSets.count)
{
return false
}
// remove the entry from the dataset
let removed = _dataSets[dataSetIndex].removeEntry(entry)
if (removed)
{
_yValCount -= 1
calcMinMax(start: _lastStart, end: _lastEnd)
}
return removed
}
/// Removes the Entry object at the given xIndex from the ChartDataSet at the
/// specified index.
/// - returns: true if an entry was removed, false if no Entry was found that meets the specified requirements.
public func removeEntryByXIndex(xIndex: Int, dataSetIndex: Int) -> Bool
{
if (dataSetIndex >= _dataSets.count)
{
return false
}
let entry = _dataSets[dataSetIndex].entryForXIndex(xIndex)
if (entry?.xIndex != xIndex)
{
return false
}
return removeEntry(entry, dataSetIndex: dataSetIndex)
}
/// - returns: the DataSet that contains the provided Entry, or null, if no DataSet contains this entry.
public func getDataSetForEntry(e: ChartDataEntry!) -> IChartDataSet?
{
if (e == nil)
{
return nil
}
for i in 0 ..< _dataSets.count
{
let set = _dataSets[i]
if (e === set.entryForXIndex(e.xIndex))
{
return set
}
}
return nil
}
/// - returns: the index of the provided DataSet inside the DataSets array of this data object. -1 if the DataSet was not found.
public func indexOfDataSet(dataSet: IChartDataSet) -> Int
{
for i in 0 ..< _dataSets.count
{
if (_dataSets[i] === dataSet)
{
return i
}
}
return -1
}
/// - returns: the first DataSet from the datasets-array that has it's dependency on the left axis. Returns null if no DataSet with left dependency could be found.
public func getFirstLeft() -> IChartDataSet?
{
for dataSet in _dataSets
{
if (dataSet.axisDependency == .Left)
{
return dataSet
}
}
return nil
}
/// - returns: the first DataSet from the datasets-array that has it's dependency on the right axis. Returns null if no DataSet with right dependency could be found.
public func getFirstRight() -> IChartDataSet?
{
for dataSet in _dataSets
{
if (dataSet.axisDependency == .Right)
{
return dataSet
}
}
return nil
}
/// - returns: all colors used across all DataSet objects this object represents.
public func getColors() -> [NSUIColor]?
{
if (_dataSets == nil)
{
return nil
}
var clrcnt = 0
for i in 0 ..< _dataSets.count
{
clrcnt += _dataSets[i].colors.count
}
var colors = [NSUIColor]()
for i in 0 ..< _dataSets.count
{
let clrs = _dataSets[i].colors
for clr in clrs
{
colors.append(clr)
}
}
return colors
}
/// Generates an x-values array filled with numbers in range specified by the parameters. Can be used for convenience.
public func generateXVals(from: Int, to: Int) -> [String]
{
var xvals = [String]()
for i in from ..< to
{
xvals.append(String(i))
}
return xvals
}
/// Sets a custom ValueFormatter for all DataSets this data object contains.
public func setValueFormatter(formatter: NSNumberFormatter!)
{
for set in dataSets
{
set.valueFormatter = formatter
}
}
/// Sets the color of the value-text (color in which the value-labels are drawn) for all DataSets this data object contains.
public func setValueTextColor(color: NSUIColor!)
{
for set in dataSets
{
set.valueTextColor = color ?? set.valueTextColor
}
}
/// Sets the font for all value-labels for all DataSets this data object contains.
public func setValueFont(font: NSUIFont!)
{
for set in dataSets
{
set.valueFont = font ?? set.valueFont
}
}
/// Enables / disables drawing values (value-text) for all DataSets this data object contains.
public func setDrawValues(enabled: Bool)
{
for set in dataSets
{
set.drawValuesEnabled = enabled
}
}
/// Enables / disables highlighting values for all DataSets this data object contains.
/// If set to true, this means that values can be highlighted programmatically or by touch gesture.
public var highlightEnabled: Bool
{
get
{
for set in dataSets
{
if (!set.highlightEnabled)
{
return false
}
}
return true
}
set
{
for set in dataSets
{
set.highlightEnabled = newValue
}
}
}
/// if true, value highlightning is enabled
public var isHighlightEnabled: Bool { return highlightEnabled }
/// Clears this data object from all DataSets and removes all Entries.
/// Don't forget to invalidate the chart after this.
public func clearValues()
{
dataSets.removeAll(keepCapacity: false)
notifyDataChanged()
}
/// Checks if this data object contains the specified Entry.
/// - returns: true if so, false if not.
public func contains(entry entry: ChartDataEntry) -> Bool
{
for set in dataSets
{
if set.contains(entry)
{
return true
}
}
return false
}
/// Checks if this data object contains the specified DataSet.
/// - returns: true if so, false if not.
public func contains(dataSet dataSet: IChartDataSet) -> Bool
{
for set in dataSets
{
if set === dataSet
{
return true
}
}
return false
}
/// MARK: - ObjC compatibility
/// - returns: the average length (in characters) across all values in the x-vals array
public var xValsObjc: [NSObject] { return ChartUtils.bridgedObjCGetStringArray(swift: _xVals); }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/ChartDataEntry.swift
================================================
//
// ChartDataEntry.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartDataEntry: NSObject
{
/// the actual value (y axis)
public var value = Double(0.0)
/// the index on the x-axis
public var xIndex = Int(0)
/// optional spot for additional data this Entry represents
public var data: AnyObject?
public override required init()
{
super.init()
}
public init(value: Double, xIndex: Int)
{
super.init()
self.value = value
self.xIndex = xIndex
}
public init(value: Double, xIndex: Int, data: AnyObject?)
{
super.init()
self.value = value
self.xIndex = xIndex
self.data = data
}
// MARK: NSObject
public override func isEqual(object: AnyObject?) -> Bool
{
if (object === nil)
{
return false
}
if (!object!.isKindOfClass(self.dynamicType))
{
return false
}
if (object!.data !== data && !object!.data.isEqual(self.data))
{
return false
}
if (object!.xIndex != xIndex)
{
return false
}
if (fabs(object!.value - value) > 0.00001)
{
return false
}
return true
}
// MARK: NSObject
public override var description: String
{
return "ChartDataEntry, xIndex: \(xIndex), value \(value)"
}
// MARK: NSCopying
public func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = self.dynamicType.init()
copy.value = value
copy.xIndex = xIndex
copy.data = data
return copy
}
}
public func ==(lhs: ChartDataEntry, rhs: ChartDataEntry) -> Bool
{
if (lhs === rhs)
{
return true
}
if (!lhs.isKindOfClass(rhs.dynamicType))
{
return false
}
if (lhs.data !== rhs.data && !lhs.data!.isEqual(rhs.data))
{
return false
}
if (lhs.xIndex != rhs.xIndex)
{
return false
}
if (fabs(lhs.value - rhs.value) > 0.00001)
{
return false
}
return true
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift
================================================
//
// ChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
@objc
public enum ChartDataSetRounding: Int
{
case Up = 0
case Down = 1
case Closest = 2
}
public class ChartDataSet: ChartBaseDataSet
{
public required init()
{
super.init()
_yVals = [ChartDataEntry]()
}
public override init(label: String?)
{
super.init(label: label)
_yVals = [ChartDataEntry]()
}
public init(yVals: [ChartDataEntry]?, label: String?)
{
super.init(label: label)
_yVals = yVals == nil ? [ChartDataEntry]() : yVals
self.calcMinMax(start: _lastStart, end: _lastEnd)
}
public convenience init(yVals: [ChartDataEntry]?)
{
self.init(yVals: yVals, label: "DataSet")
}
// MARK: - Data functions and accessors
internal var _yVals: [ChartDataEntry]!
internal var _yMax = Double(0.0)
internal var _yMin = Double(0.0)
/// the last start value used for calcMinMax
internal var _lastStart: Int = 0
/// the last end value used for calcMinMax
internal var _lastEnd: Int = 0
public var yVals: [ChartDataEntry] { return _yVals }
/// Use this method to tell the data set that the underlying data has changed
public override func notifyDataSetChanged()
{
calcMinMax(start: _lastStart, end: _lastEnd)
}
public override func calcMinMax(start start: Int, end: Int)
{
let yValCount = _yVals.count
if yValCount == 0
{
return
}
var endValue : Int
if end == 0 || end >= yValCount
{
endValue = yValCount - 1
}
else
{
endValue = end
}
_lastStart = start
_lastEnd = endValue
_yMin = DBL_MAX
_yMax = -DBL_MAX
for i in start ... endValue
{
let e = _yVals[i]
if (!e.value.isNaN)
{
if (e.value < _yMin)
{
_yMin = e.value
}
if (e.value > _yMax)
{
_yMax = e.value
}
}
}
if (_yMin == DBL_MAX)
{
_yMin = 0.0
_yMax = 0.0
}
}
/// - returns: the minimum y-value this DataSet holds
public override var yMin: Double { return _yMin }
/// - returns: the maximum y-value this DataSet holds
public override var yMax: Double { return _yMax }
/// - returns: the number of y-values this DataSet represents
public override var entryCount: Int { return _yVals?.count ?? 0 }
/// - returns: the value of the Entry object at the given xIndex. Returns NaN if no value is at the given x-index.
public override func yValForXIndex(x: Int) -> Double
{
let e = self.entryForXIndex(x)
if (e !== nil && e!.xIndex == x) { return e!.value }
else { return Double.NaN }
}
/// - returns: the entry object found at the given index (not x-index!)
/// - throws: out of bounds
/// if `i` is out of bounds, it may throw an out-of-bounds exception
public override func entryForIndex(i: Int) -> ChartDataEntry?
{
return _yVals[i]
}
/// - returns: the first Entry object found at the given xIndex with binary search.
/// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index.
/// nil if no Entry object at that index.
public override func entryForXIndex(x: Int, rounding: ChartDataSetRounding) -> ChartDataEntry?
{
let index = self.entryIndex(xIndex: x, rounding: rounding)
if (index > -1)
{
return _yVals[index]
}
return nil
}
/// - returns: the first Entry object found at the given xIndex with binary search.
/// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index.
/// nil if no Entry object at that index.
public override func entryForXIndex(x: Int) -> ChartDataEntry?
{
return entryForXIndex(x, rounding: .Closest)
}
public func entriesForXIndex(x: Int) -> [ChartDataEntry]
{
var entries = [ChartDataEntry]()
var low = 0
var high = _yVals.count - 1
while (low <= high)
{
var m = Int((high + low) / 2)
var entry = _yVals[m]
if (x == entry.xIndex)
{
while (m > 0 && _yVals[m - 1].xIndex == x)
{
m -= 1
}
high = _yVals.count
while (m < high)
{
entry = _yVals[m]
if (entry.xIndex == x)
{
entries.append(entry)
}
else
{
break
}
m += 1
}
}
if (x > _yVals[m].xIndex)
{
low = m + 1
}
else
{
high = m - 1
}
}
return entries
}
/// - returns: the array-index of the specified entry
///
/// - parameter x: x-index of the entry to search for
/// - parameter rounding: x-index of the entry to search for
public override func entryIndex(xIndex x: Int, rounding: ChartDataSetRounding) -> Int
{
var low = 0
var high = _yVals.count - 1
var closest = -1
while (low <= high)
{
var m = (high + low) / 2
let entry = _yVals[m]
if (x == entry.xIndex)
{
while (m > 0 && _yVals[m - 1].xIndex == x)
{
m -= 1
}
return m
}
if (x > entry.xIndex)
{
low = m + 1
}
else
{
high = m - 1
}
closest = m
}
if closest != -1
{
if rounding == .Up
{
let closestXIndex = _yVals[closest].xIndex
if closestXIndex < x && closest < _yVals.count - 1
{
closest = closest + 1
}
}
else if rounding == .Down
{
let closestXIndex = _yVals[closest].xIndex
if closestXIndex > x && closest > 0
{
closest = closest - 1
}
}
}
return closest
}
/// - returns: the array-index of the specified entry
///
/// - parameter e: the entry to search for
public override func entryIndex(entry e: ChartDataEntry) -> Int
{
for i in 0 ..< _yVals.count
{
if _yVals[i] === e
{
return i
}
}
return -1
}
/// Adds an Entry to the DataSet dynamically.
/// Entries are added to the end of the list.
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
/// - parameter e: the entry to add
/// - returns: true
public override func addEntry(e: ChartDataEntry) -> Bool
{
let val = e.value
if (_yVals == nil)
{
_yVals = [ChartDataEntry]()
}
if (_yVals.count == 0)
{
_yMax = val
_yMin = val
}
else
{
if (_yMax < val)
{
_yMax = val
}
if (_yMin > val)
{
_yMin = val
}
}
_yVals.append(e)
return true
}
/// Adds an Entry to the DataSet dynamically.
/// Entries are added to their appropriate index respective to it's x-index.
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
/// - parameter e: the entry to add
/// - returns: true
public override func addEntryOrdered(e: ChartDataEntry) -> Bool
{
let val = e.value
if (_yVals == nil)
{
_yVals = [ChartDataEntry]()
}
if (_yVals.count == 0)
{
_yMax = val
_yMin = val
}
else
{
if (_yMax < val)
{
_yMax = val
}
if (_yMin > val)
{
_yMin = val
}
}
if _yVals.last?.xIndex > e.xIndex
{
var closestIndex = entryIndex(xIndex: e.xIndex, rounding: .Closest)
if _yVals[closestIndex].xIndex < e.xIndex
{
closestIndex += 1
}
_yVals.insert(e, atIndex: closestIndex)
return true
}
_yVals.append(e)
return true
}
/// Removes an Entry from the DataSet dynamically.
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
/// - parameter entry: the entry to remove
/// - returns: true if the entry was removed successfully, else if the entry does not exist
public override func removeEntry(entry: ChartDataEntry) -> Bool
{
var removed = false
for i in 0 ..< _yVals.count
{
if (_yVals[i] === entry)
{
_yVals.removeAtIndex(i)
removed = true
break
}
}
if (removed)
{
calcMinMax(start: _lastStart, end: _lastEnd)
}
return removed
}
/// Removes the first Entry (at index 0) of this DataSet from the entries array.
///
/// - returns: true if successful, false if not.
public override func removeFirst() -> Bool
{
let entry: ChartDataEntry? = _yVals.isEmpty ? nil : _yVals.removeFirst()
let removed = entry != nil
if (removed)
{
calcMinMax(start: _lastStart, end: _lastEnd)
}
return removed;
}
/// Removes the last Entry (at index size-1) of this DataSet from the entries array.
///
/// - returns: true if successful, false if not.
public override func removeLast() -> Bool
{
let entry: ChartDataEntry? = _yVals.isEmpty ? nil : _yVals.removeLast()
let removed = entry != nil
if (removed)
{
calcMinMax(start: _lastStart, end: _lastEnd)
}
return removed;
}
/// Checks if this DataSet contains the specified Entry.
/// - returns: true if contains the entry, false if not.
public override func contains(e: ChartDataEntry) -> Bool
{
for entry in _yVals
{
if (entry.isEqual(e))
{
return true
}
}
return false
}
/// Removes all values from this DataSet and recalculates min and max value.
public override func clear()
{
_yVals.removeAll(keepCapacity: true)
_lastStart = 0
_lastEnd = 0
notifyDataSetChanged()
}
// MARK: - Data functions and accessors
/// - returns: the number of entries this DataSet holds.
public var valueCount: Int { return _yVals.count }
// MARK: - NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! ChartDataSet
copy._yVals = _yVals
copy._yMax = _yMax
copy._yMin = _yMin
copy._lastStart = _lastStart
copy._lastEnd = _lastEnd
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift
================================================
//
// CombinedChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class CombinedChartData: BarLineScatterCandleBubbleChartData
{
private var _lineData: LineChartData!
private var _barData: BarChartData!
private var _scatterData: ScatterChartData!
private var _candleData: CandleChartData!
private var _bubbleData: BubbleChartData!
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public var lineData: LineChartData!
{
get
{
return _lineData
}
set
{
_lineData = newValue
for dataSet in newValue.dataSets
{
_dataSets.append(dataSet)
}
checkIsLegal(newValue.dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
}
public var barData: BarChartData!
{
get
{
return _barData
}
set
{
_barData = newValue
for dataSet in newValue.dataSets
{
_dataSets.append(dataSet)
}
checkIsLegal(newValue.dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
}
public var scatterData: ScatterChartData!
{
get
{
return _scatterData
}
set
{
_scatterData = newValue
for dataSet in newValue.dataSets
{
_dataSets.append(dataSet)
}
checkIsLegal(newValue.dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
}
public var candleData: CandleChartData!
{
get
{
return _candleData
}
set
{
_candleData = newValue
for dataSet in newValue.dataSets
{
_dataSets.append(dataSet)
}
checkIsLegal(newValue.dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
}
public var bubbleData: BubbleChartData!
{
get
{
return _bubbleData
}
set
{
_bubbleData = newValue
for dataSet in newValue.dataSets
{
_dataSets.append(dataSet)
}
checkIsLegal(newValue.dataSets)
calcMinMax(start: _lastStart, end: _lastEnd)
calcYValueCount()
calcXValAverageLength()
}
}
/// - returns: all data objects in row: line-bar-scatter-candle-bubble if not null.
public var allData: [ChartData]
{
var data = [ChartData]()
if lineData !== nil
{
data.append(lineData)
}
if barData !== nil
{
data.append(barData)
}
if scatterData !== nil
{
data.append(scatterData)
}
if candleData !== nil
{
data.append(candleData)
}
if bubbleData !== nil
{
data.append(bubbleData)
}
return data;
}
public override func notifyDataChanged()
{
if (_lineData !== nil)
{
_lineData.notifyDataChanged()
}
if (_barData !== nil)
{
_barData.notifyDataChanged()
}
if (_scatterData !== nil)
{
_scatterData.notifyDataChanged()
}
if (_candleData !== nil)
{
_candleData.notifyDataChanged()
}
if (_bubbleData !== nil)
{
_bubbleData.notifyDataChanged()
}
super.notifyDataChanged() // recalculate everything
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/LineChartData.swift
================================================
//
// LineChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
/// Data object that encapsulates all data associated with a LineChart.
public class LineChartData: ChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift
================================================
//
// LineChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet
{
private func initialize()
{
// default color
circleColors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
}
public required init()
{
super.init()
initialize()
}
public override init(yVals: [ChartDataEntry]?, label: String?)
{
super.init(yVals: yVals, label: label)
initialize()
}
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
private var _cubicIntensity = CGFloat(0.2)
/// Intensity for cubic lines (min = 0.05, max = 1)
///
/// **default**: 0.2
public var cubicIntensity: CGFloat
{
get
{
return _cubicIntensity
}
set
{
_cubicIntensity = newValue
if (_cubicIntensity > 1.0)
{
_cubicIntensity = 1.0
}
if (_cubicIntensity < 0.05)
{
_cubicIntensity = 0.05
}
}
}
/// If true, cubic lines are drawn instead of linear
public var drawCubicEnabled = false
/// - returns: true if drawing cubic lines is enabled, false if not.
public var isDrawCubicEnabled: Bool { return drawCubicEnabled }
/// If true, stepped lines are drawn instead of linear
public var drawSteppedEnabled = false
/// - returns: true if drawing stepped lines is enabled, false if not.
public var isDrawSteppedEnabled: Bool { return drawSteppedEnabled }
/// The radius of the drawn circles.
public var circleRadius = CGFloat(8.0)
public var circleColors = [NSUIColor]()
/// - returns: the color at the given index of the DataSet's circle-color array.
/// Performs a IndexOutOfBounds check by modulus.
public func getCircleColor(index: Int) -> NSUIColor?
{
let size = circleColors.count
let index = index % size
if (index >= size)
{
return nil
}
return circleColors[index]
}
/// Sets the one and ONLY color that should be used for this DataSet.
/// Internally, this recreates the colors array and adds the specified color.
public func setCircleColor(color: NSUIColor)
{
circleColors.removeAll(keepCapacity: false)
circleColors.append(color)
}
/// Resets the circle-colors array and creates a new one
public func resetCircleColors(index: Int)
{
circleColors.removeAll(keepCapacity: false)
}
/// If true, drawing circles is enabled
public var drawCirclesEnabled = true
/// - returns: true if drawing circles for this DataSet is enabled, false if not
public var isDrawCirclesEnabled: Bool { return drawCirclesEnabled }
/// The color of the inner circle (the circle-hole).
public var circleHoleColor = NSUIColor.whiteColor()
/// True if drawing circles for this DataSet is enabled, false if not
public var drawCircleHoleEnabled = true
/// - returns: true if drawing the circle-holes is enabled, false if not.
public var isDrawCircleHoleEnabled: Bool { return drawCircleHoleEnabled }
/// This is how much (in pixels) into the dash pattern are we starting from.
public var lineDashPhase = CGFloat(0.0)
/// This is the actual dash pattern.
/// I.e. [2, 3] will paint [-- -- ]
/// [1, 3, 4, 2] will paint [- ---- - ---- ]
public var lineDashLengths: [CGFloat]?
/// Line cap type, default is CGLineCap.Butt
public var lineCapType = CGLineCap.Butt
/// formatter for customizing the position of the fill-line
private var _fillFormatter: ChartFillFormatter = ChartDefaultFillFormatter()
/// Sets a custom FillFormatter to the chart that handles the position of the filled-line for each DataSet. Set this to null to use the default logic.
public var fillFormatter: ChartFillFormatter?
{
get
{
return _fillFormatter
}
set
{
if newValue == nil
{
_fillFormatter = ChartDefaultFillFormatter()
}
else
{
_fillFormatter = newValue!
}
}
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! LineChartDataSet
copy.circleColors = circleColors
copy.circleRadius = circleRadius
copy.cubicIntensity = cubicIntensity
copy.lineDashPhase = lineDashPhase
copy.lineDashLengths = lineDashLengths
copy.drawCirclesEnabled = drawCirclesEnabled
copy.drawCubicEnabled = drawCubicEnabled
copy.drawSteppedEnabled = drawSteppedEnabled
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/LineRadarChartDataSet.swift
================================================
//
// LineRadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class LineRadarChartDataSet: LineScatterCandleRadarChartDataSet, ILineRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// The color that is used for filling the line surface area.
private var _fillColor = NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)
/// The color that is used for filling the line surface area.
public var fillColor: NSUIColor
{
get { return _fillColor }
set
{
_fillColor = newValue
fill = nil
}
}
/// The object that is used for filling the area below the line.
/// **default**: nil
public var fill: ChartFill?
/// The alpha value that is used for filling the line surface,
/// **default**: 0.33
public var fillAlpha = CGFloat(0.33)
private var _lineWidth = CGFloat(1.0)
/// line width of the chart (min = 0.2, max = 10)
///
/// **default**: 1
public var lineWidth: CGFloat
{
get
{
return _lineWidth
}
set
{
if (newValue < 0.2)
{
_lineWidth = 0.2
}
else if (newValue > 10.0)
{
_lineWidth = 10.0
}
else
{
_lineWidth = newValue
}
}
}
/// Set to true if the DataSet should be drawn filled (surface), and not just as a line.
/// Disabling this will give great performance boost.
/// Please note that this method uses the path clipping for drawing the filled area (with images, gradients and layers).
public var drawFilledEnabled = false
/// Returns true if filled drawing is enabled, false if not
public var isDrawFilledEnabled: Bool
{
return drawFilledEnabled
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! LineRadarChartDataSet
copy.fillColor = fillColor
copy._lineWidth = _lineWidth
copy.drawFilledEnabled = drawFilledEnabled
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift
================================================
//
// LineScatterCandleRadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 29/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class LineScatterCandleRadarChartDataSet: BarLineScatterCandleBubbleChartDataSet, ILineScatterCandleRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// Enables / disables the horizontal highlight-indicator. If disabled, the indicator is not drawn.
public var drawHorizontalHighlightIndicatorEnabled = true
/// Enables / disables the vertical highlight-indicator. If disabled, the indicator is not drawn.
public var drawVerticalHighlightIndicatorEnabled = true
/// - returns: true if horizontal highlight indicator lines are enabled (drawn)
public var isHorizontalHighlightIndicatorEnabled: Bool { return drawHorizontalHighlightIndicatorEnabled }
/// - returns: true if vertical highlight indicator lines are enabled (drawn)
public var isVerticalHighlightIndicatorEnabled: Bool { return drawVerticalHighlightIndicatorEnabled }
/// Enables / disables both vertical and horizontal highlight-indicators.
/// :param: enabled
public func setDrawHighlightIndicators(enabled: Bool)
{
drawHorizontalHighlightIndicatorEnabled = enabled
drawVerticalHighlightIndicatorEnabled = enabled
}
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! LineScatterCandleRadarChartDataSet
copy.drawHorizontalHighlightIndicatorEnabled = drawHorizontalHighlightIndicatorEnabled
copy.drawVerticalHighlightIndicatorEnabled = drawVerticalHighlightIndicatorEnabled
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/PieChartData.swift
================================================
//
// PieData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 24/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class PieChartData: ChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
var dataSet: IPieChartDataSet?
{
get
{
return dataSets.count > 0 ? dataSets[0] as? IPieChartDataSet : nil
}
set
{
if (newValue != nil)
{
dataSets = [newValue!]
}
else
{
dataSets = []
}
}
}
public override func getDataSetByIndex(index: Int) -> IChartDataSet?
{
if (index != 0)
{
return nil
}
return super.getDataSetByIndex(index)
}
public override func getDataSetByLabel(label: String, ignorecase: Bool) -> IChartDataSet?
{
if (dataSets.count == 0 || dataSets[0].label == nil)
{
return nil
}
if (ignorecase)
{
if (label.caseInsensitiveCompare(dataSets[0].label!) == NSComparisonResult.OrderedSame)
{
return dataSets[0]
}
}
else
{
if (label == dataSets[0].label)
{
return dataSets[0]
}
}
return nil
}
public override func addDataSet(d: IChartDataSet!)
{
if (_dataSets == nil)
{
return
}
super.addDataSet(d)
}
/// Removes the DataSet at the given index in the DataSet array from the data object.
/// Also recalculates all minimum and maximum values.
///
/// - returns: true if a DataSet was removed, false if no DataSet could be removed.
public override func removeDataSetByIndex(index: Int) -> Bool
{
if (_dataSets == nil || index >= _dataSets.count || index < 0)
{
return false
}
return false
}
/// - returns: the total y-value sum across all DataSet objects the this object represents.
public var yValueSum: Double
{
guard let dataSet = dataSet else { return 0.0 }
var yValueSum: Double = 0.0
for i in 0.. 20.0)
{
space = 20.0
}
if (space < 0.0)
{
space = 0.0
}
_sliceSpace = space
}
}
/// indicates the selection distance of a pie slice
public var selectionShift = CGFloat(18.0)
// MARK: - NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! PieChartDataSet
copy._sliceSpace = _sliceSpace
copy.selectionShift = selectionShift
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/RadarChartData.swift
================================================
//
// RadarChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class RadarChartData: ChartData
{
public var highlightColor = NSUIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
public var highlightLineWidth = CGFloat(1.0)
public var highlightLineDashPhase = CGFloat(0.0)
public var highlightLineDashLengths: [CGFloat]?
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/RadarChartDataSet.swift
================================================
//
// RadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 24/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class RadarChartDataSet: LineRadarChartDataSet, IRadarChartDataSet
{
private func initialize()
{
self.valueFont = NSUIFont.systemFontOfSize(13.0)
}
public required init()
{
super.init()
initialize()
}
public override init(yVals: [ChartDataEntry]?, label: String?)
{
super.init(yVals: yVals, label: label)
initialize()
}
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// flag indicating whether highlight circle should be drawn or not
/// **default**: false
public var drawHighlightCircleEnabled: Bool = false
/// - returns: true if highlight circle should be drawn, false if not
public var isDrawHighlightCircleEnabled: Bool { return drawHighlightCircleEnabled }
public var highlightCircleFillColor: NSUIColor? = NSUIColor.whiteColor()
/// The stroke color for highlight circle.
/// If `nil`, the color of the dataset is taken.
public var highlightCircleStrokeColor: NSUIColor?
public var highlightCircleStrokeAlpha: CGFloat = 0.3
public var highlightCircleInnerRadius: CGFloat = 3.0
public var highlightCircleOuterRadius: CGFloat = 4.0
public var highlightCircleStrokeWidth: CGFloat = 2.0
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/ScatterChartData.swift
================================================
//
// ScatterChartData.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ScatterChartData: BarLineScatterCandleBubbleChartData
{
public override init()
{
super.init()
}
public override init(xVals: [String?]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
public override init(xVals: [NSObject]?, dataSets: [IChartDataSet]?)
{
super.init(xVals: xVals, dataSets: dataSets)
}
/// - returns: the maximum shape-size across all DataSets.
public func getGreatestShapeSize() -> CGFloat
{
var max = CGFloat(0.0)
for set in _dataSets
{
let scatterDataSet = set as? IScatterChartDataSet
if (scatterDataSet == nil)
{
print("ScatterChartData: Found a DataSet which is not a ScatterChartDataSet", terminator: "\n")
}
else
{
let size = scatterDataSet!.scatterShapeSize
if (size > max)
{
max = size
}
}
}
return max
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Implementations/Standard/ScatterChartDataSet.swift
================================================
//
// ScatterChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, IScatterChartDataSet
{
@objc
public enum ScatterShape: Int
{
case Square
case Circle
case Triangle
case Cross
case X
case Custom
}
// The size the scatter shape will have
public var scatterShapeSize = CGFloat(10.0)
// The type of shape that is set to be drawn where the values are at
// **default**: .Square
public var scatterShape = ScatterChartDataSet.ScatterShape.Square
// The radius of the hole in the shape (applies to Square, Circle and Triangle)
// **default**: 0.0
public var scatterShapeHoleRadius: CGFloat = 0.0
// Color for the hole in the shape. Setting to `nil` will behave as transparent.
// **default**: nil
public var scatterShapeHoleColor: NSUIColor? = nil
// Custom path object to draw where the values are at.
// This is used when shape is set to Custom.
public var customScatterShape: CGPath?
// MARK: NSCopying
public override func copyWithZone(zone: NSZone) -> AnyObject
{
let copy = super.copyWithZone(zone) as! ScatterChartDataSet
copy.scatterShapeSize = scatterShapeSize
copy.scatterShape = scatterShape
copy.customScatterShape = customScatterShape
return copy
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IBarChartDataSet.swift
================================================
//
// IBarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol IBarChartDataSet: IBarLineScatterCandleBubbleChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// space indicator between the bars in percentage of the whole width of one value (0.15 == 15% of bar width)
var barSpace: CGFloat { get set }
/// - returns: true if this DataSet is stacked (stacksize > 1) or not.
var isStacked: Bool { get }
/// - returns: the maximum number of bars that can be stacked upon another in this DataSet.
var stackSize: Int { get }
/// the color used for drawing the bar-shadows. The bar shadows is a surface behind the bar that indicates the maximum value
var barShadowColor: NSUIColor { get set }
/// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque)
var highlightAlpha: CGFloat { get set }
/// array of labels used to describe the different values of the stacked bars
var stackLabels: [String] { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift
================================================
//
// IBarLineScatterCandleBubbleChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol IBarLineScatterCandleBubbleChartDataSet: IChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
var highlightColor: NSUIColor { get set }
var highlightLineWidth: CGFloat { get set }
var highlightLineDashPhase: CGFloat { get set }
var highlightLineDashLengths: [CGFloat]? { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IBubbleChartDataSet.swift
================================================
//
// IBubbleChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol IBubbleChartDataSet: IBarLineScatterCandleBubbleChartDataSet
{
// MARK: - Data functions and accessors
var xMin: Double { get }
var xMax: Double { get }
var maxSize: CGFloat { get }
// MARK: - Styling functions and accessors
/// Sets/gets the width of the circle that surrounds the bubble when highlighted
var highlightCircleWidth: CGFloat { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/ICandleChartDataSet.swift
================================================
//
// ICandleChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol ICandleChartDataSet: ILineScatterCandleRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// the space that is left out on the left and right side of each candle,
/// **default**: 0.1 (10%), max 0.45, min 0.0
var barSpace: CGFloat { get set }
/// should the candle bars show?
/// when false, only "ticks" will show
///
/// **default**: true
var showCandleBar: Bool { get set }
/// the width of the candle-shadow-line in pixels.
///
/// **default**: 3.0
var shadowWidth: CGFloat { get set }
/// the color of the shadow line
var shadowColor: NSUIColor? { get set }
/// use candle color for the shadow
var shadowColorSameAsCandle: Bool { get set }
/// Is the shadow color same as the candle color?
var isShadowColorSameAsCandle: Bool { get }
/// color for open == close
var neutralColor: NSUIColor? { get set }
/// color for open > close
var increasingColor: NSUIColor? { get set }
/// color for open < close
var decreasingColor: NSUIColor? { get set }
/// Are increasing values drawn as filled?
var increasingFilled: Bool { get set }
/// Are increasing values drawn as filled?
var isIncreasingFilled: Bool { get }
/// Are decreasing values drawn as filled?
var decreasingFilled: Bool { get set }
/// Are decreasing values drawn as filled?
var isDecreasingFilled: Bool { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IChartDataSet.swift
================================================
//
// IChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
@objc
public protocol IChartDataSet
{
// MARK: - Data functions and accessors
/// Use this method to tell the data set that the underlying data has changed
func notifyDataSetChanged()
/// This is an opportunity to calculate the minimum and maximum y value in the specified range.
/// If your data is in an array, you might loop over them to find the values.
/// If your data is in a database, you might query for the min/max and put them in variables.
/// - parameter start: the index of the first y entry to calculate
/// - parameter end: the index of the last y entry to calculate
func calcMinMax(start start: Int, end: Int)
/// - returns: the minimum y-value this DataSet holds
var yMin: Double { get }
/// - returns: the maximum y-value this DataSet holds
var yMax: Double { get }
/// - returns: the number of y-values this DataSet represents
var entryCount: Int { get }
/// - returns: the value of the Entry object at the given xIndex. Returns NaN if no value is at the given x-index.
func yValForXIndex(x: Int) -> Double
/// - returns: the entry object found at the given index (not x-index!)
/// - throws: out of bounds
/// if `i` is out of bounds, it may throw an out-of-bounds exception
func entryForIndex(i: Int) -> ChartDataEntry?
/// - returns: the first Entry object found at the given xIndex with binary search.
/// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index.
/// nil if no Entry object at that index.
func entryForXIndex(x: Int, rounding: ChartDataSetRounding) -> ChartDataEntry?
/// - returns: the first Entry object found at the given xIndex with binary search.
/// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index.
/// nil if no Entry object at that index.
func entryForXIndex(x: Int) -> ChartDataEntry?
/// - returns: the array-index of the specified entry
///
/// - parameter x: x-index of the entry to search for
/// - parameter rounding: x-index of the entry to search for
func entryIndex(xIndex x: Int, rounding: ChartDataSetRounding) -> Int
/// - returns: the array-index of the specified entry
///
/// - parameter e: the entry to search for
func entryIndex(entry e: ChartDataEntry) -> Int
/// Adds an Entry to the DataSet dynamically.
///
/// *optional feature, can return false if not implemented*
///
/// Entries are added to the end of the list.
/// - parameter e: the entry to add
/// - returns: true if the entry was added successfully, false if this feature is not supported
func addEntry(e: ChartDataEntry) -> Bool
/// Adds an Entry to the DataSet dynamically.
/// Entries are added to their appropriate index respective to it's x-index.
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
///
/// *optional feature, can return false if not implemented*
///
/// Entries are added to the end of the list.
/// - parameter e: the entry to add
/// - returns: true if the entry was added successfully, false if this feature is not supported
func addEntryOrdered(e: ChartDataEntry) -> Bool
/// Removes an Entry from the DataSet dynamically.
///
/// *optional feature, can return false if not implemented*
///
/// - parameter entry: the entry to remove
/// - returns: true if the entry was removed successfully, false if the entry does not exist or if this feature is not supported
func removeEntry(entry: ChartDataEntry) -> Bool
/// Removes the Entry object that has the given xIndex from the DataSet.
///
/// *optional feature, can return false if not implemented*
///
/// - parameter xIndex: the xIndex to remove
/// - returns: true if the entry was removed successfully, false if the entry does not exist or if this feature is not supported
func removeEntry(xIndex xIndex: Int) -> Bool
/// Removes the first Entry (at index 0) of this DataSet from the entries array.
///
/// *optional feature, can return false if not implemented*
///
/// - returns: true if the entry was removed successfully, false if the entry does not exist or if this feature is not supported
func removeFirst() -> Bool
/// Removes the last Entry (at index 0) of this DataSet from the entries array.
///
/// *optional feature, can return false if not implemented*
///
/// - returns: true if the entry was removed successfully, false if the entry does not exist or if this feature is not supported
func removeLast() -> Bool
/// Checks if this DataSet contains the specified Entry.
///
/// - returns: true if contains the entry, false if not.
func contains(e: ChartDataEntry) -> Bool
/// Removes all values from this DataSet and does all necessary recalculations.
///
/// *optional feature, could throw if not implemented*
func clear()
// MARK: - Styling functions and accessors
/// The label string that describes the DataSet.
var label: String? { get }
/// The axis this DataSet should be plotted against.
var axisDependency: ChartYAxis.AxisDependency { get }
/// List representing all colors that are used for drawing the actual values for this DataSet
var valueColors: [NSUIColor] { get }
/// All the colors that are used for this DataSet.
/// Colors are reused as soon as the number of Entries the DataSet represents is higher than the size of the colors array.
var colors: [NSUIColor] { get }
/// - returns: the color at the given index of the DataSet's color array.
/// This prevents out-of-bounds by performing a modulus on the color index, so colours will repeat themselves.
func colorAt(index: Int) -> NSUIColor
func resetColors()
func addColor(color: NSUIColor)
func setColor(color: NSUIColor)
/// if true, value highlighting is enabled
var highlightEnabled: Bool { get set }
/// - returns: true if value highlighting is enabled for this dataset
var isHighlightEnabled: Bool { get }
/// The formatter used to customly format the values
var valueFormatter: NSNumberFormatter? { get set }
/// Sets/get a single color for value text.
/// Setting the color clears the colors array and adds a single color.
/// Getting will return the first color in the array.
var valueTextColor: NSUIColor { get set }
/// - returns: the color at the specified index that is used for drawing the values inside the chart. Uses modulus internally.
func valueTextColorAt(index: Int) -> NSUIColor
/// the font for the value-text labels
var valueFont: NSUIFont { get set }
/// Set this to true to draw y-values on the chart
var drawValuesEnabled: Bool { get set }
/// Returns true if y-value drawing is enabled, false if not
var isDrawValuesEnabled: Bool { get }
/// Set the visibility of this DataSet. If not visible, the DataSet will not be drawn to the chart upon refreshing it.
var visible: Bool { get set }
/// Returns true if this DataSet is visible inside the chart, or false if it is currently hidden.
var isVisible: Bool { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/ILineChartDataSet.swift
================================================
//
// ILineChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol ILineChartDataSet: ILineRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// Intensity for cubic lines (min = 0.05, max = 1)
///
/// **default**: 0.2
var cubicIntensity: CGFloat { get set }
/// If true, cubic lines are drawn instead of linear
var drawCubicEnabled: Bool { get set }
/// - returns: true if drawing cubic lines is enabled, false if not.
var isDrawCubicEnabled: Bool { get }
/// If true, stepped lines are drawn instead of linear
var drawSteppedEnabled: Bool { get set }
/// - returns: true if drawing stepped lines is enabled, false if not.
var isDrawSteppedEnabled: Bool { get }
/// The radius of the drawn circles.
var circleRadius: CGFloat { get set }
var circleColors: [NSUIColor] { get set }
/// - returns: the color at the given index of the DataSet's circle-color array.
/// Performs a IndexOutOfBounds check by modulus.
func getCircleColor(index: Int) -> NSUIColor?
/// Sets the one and ONLY color that should be used for this DataSet.
/// Internally, this recreates the colors array and adds the specified color.
func setCircleColor(color: NSUIColor)
/// Resets the circle-colors array and creates a new one
func resetCircleColors(index: Int)
/// If true, drawing circles is enabled
var drawCirclesEnabled: Bool { get set }
/// - returns: true if drawing circles for this DataSet is enabled, false if not
var isDrawCirclesEnabled: Bool { get }
/// The color of the inner circle (the circle-hole).
var circleHoleColor: NSUIColor { get set }
/// True if drawing circles for this DataSet is enabled, false if not
var drawCircleHoleEnabled: Bool { get set }
/// - returns: true if drawing the circle-holes is enabled, false if not.
var isDrawCircleHoleEnabled: Bool { get }
/// This is how much (in pixels) into the dash pattern are we starting from.
var lineDashPhase: CGFloat { get }
/// This is the actual dash pattern.
/// I.e. [2, 3] will paint [-- -- ]
/// [1, 3, 4, 2] will paint [- ---- - ---- ]
var lineDashLengths: [CGFloat]? { get set }
/// Line cap type, default is CGLineCap.Butt
var lineCapType: CGLineCap { get set }
/// Sets a custom FillFormatter to the chart that handles the position of the filled-line for each DataSet. Set this to null to use the default logic.
var fillFormatter: ChartFillFormatter? { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/ILineRadarChartDataSet.swift
================================================
//
// ILineRadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol ILineRadarChartDataSet: ILineScatterCandleRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// The color that is used for filling the line surface area.
var fillColor: NSUIColor { get set }
/// Returns the object that is used for filling the area below the line.
/// **default**: nil
var fill: ChartFill? { get set }
/// The alpha value that is used for filling the line surface.
/// **default**: 0.33
var fillAlpha: CGFloat { get set }
/// line width of the chart (min = 0.2, max = 10)
///
/// **default**: 1
var lineWidth: CGFloat { get set }
/// Set to true if the DataSet should be drawn filled (surface), and not just as a line.
/// Disabling this will give great performance boost.
/// Please note that this method uses the path clipping for drawing the filled area (with images, gradients and layers).
var drawFilledEnabled: Bool { get set }
/// Returns true if filled drawing is enabled, false if not
var isDrawFilledEnabled: Bool { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift
================================================
//
// ILineScatterCandleRadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
@objc
public protocol ILineScatterCandleRadarChartDataSet: IBarLineScatterCandleBubbleChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// Enables / disables the horizontal highlight-indicator. If disabled, the indicator is not drawn.
var drawHorizontalHighlightIndicatorEnabled: Bool { get set }
/// Enables / disables the vertical highlight-indicator. If disabled, the indicator is not drawn.
var drawVerticalHighlightIndicatorEnabled: Bool { get set }
/// - returns: true if horizontal highlight indicator lines are enabled (drawn)
var isHorizontalHighlightIndicatorEnabled: Bool { get }
/// - returns: true if vertical highlight indicator lines are enabled (drawn)
var isVerticalHighlightIndicatorEnabled: Bool { get }
/// Enables / disables both vertical and horizontal highlight-indicators.
/// :param: enabled
func setDrawHighlightIndicators(enabled: Bool)
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IPieChartDataSet.swift
================================================
//
// IPieChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
@objc
public protocol IPieChartDataSet: IChartDataSet
{
// MARK: - Styling functions and accessors
/// the space in pixels between the pie-slices
/// **default**: 0
/// **maximum**: 20
var sliceSpace: CGFloat { get set }
/// indicates the selection distance of a pie slice
var selectionShift: CGFloat { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IRadarChartDataSet.swift
================================================
//
// IRadarChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
@objc
public protocol IRadarChartDataSet: ILineRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
/// flag indicating whether highlight circle should be drawn or not
var drawHighlightCircleEnabled: Bool { get set }
var isDrawHighlightCircleEnabled: Bool { get }
var highlightCircleFillColor: NSUIColor? { get set }
/// The stroke color for highlight circle.
/// If `nil`, the color of the dataset is taken.
var highlightCircleStrokeColor: NSUIColor? { get set }
var highlightCircleStrokeAlpha: CGFloat { get set }
var highlightCircleInnerRadius: CGFloat { get set }
var highlightCircleOuterRadius: CGFloat { get set }
var highlightCircleStrokeWidth: CGFloat { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Data/Interfaces/IScatterChartDataSet.swift
================================================
//
// IScatterChartDataSet.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol IScatterChartDataSet: ILineScatterCandleRadarChartDataSet
{
// MARK: - Data functions and accessors
// MARK: - Styling functions and accessors
// The size the scatter shape will have
var scatterShapeSize: CGFloat { get set }
// The type of shape that is set to be drawn where the values are at
// **default**: .Square
var scatterShape: ScatterChartDataSet.ScatterShape { get set }
// The radius of the hole in the shape (applies to Square, Circle and Triangle)
// Set this to <= 0 to remove holes.
// **default**: 0.0
var scatterShapeHoleRadius: CGFloat { get set }
// Color for the hole in the shape. Setting to `nil` will behave as transparent.
// **default**: nil
var scatterShapeHoleColor: NSUIColor? { get set }
// Custom path object to draw where the values are at.
// This is used when shape is set to Custom.
var customScatterShape: CGPath? { get set }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Filters/ChartDataApproximatorFilter.swift
================================================
//
// ChartDataApproximator.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartDataApproximatorFilter: ChartDataBaseFilter
{
@objc
public enum ApproximatorType: Int
{
case None
case RamerDouglasPeucker
}
/// the type of filtering algorithm to use
public var type = ApproximatorType.None
/// the tolerance to be filtered with
/// When using the Douglas-Peucker-Algorithm, the tolerance is an angle in degrees, that will trigger the filtering
public var tolerance = Double(0.0)
public var scaleRatio = Double(1.0)
public var deltaRatio = Double(1.0)
public override init()
{
super.init()
}
/// Initializes the approximator with the given type and tolerance.
/// If toleranec <= 0, no filtering will be done.
public init(type: ApproximatorType, tolerance: Double)
{
super.init()
setup(type, tolerance: tolerance)
}
/// Sets type and tolerance.
/// If tolerance <= 0, no filtering will be done.
public func setup(type: ApproximatorType, tolerance: Double)
{
self.type = type
self.tolerance = tolerance
}
/// Sets the ratios for x- and y-axis, as well as the ratio of the scale levels
public func setRatios(deltaRatio: Double, scaleRatio: Double)
{
self.deltaRatio = deltaRatio
self.scaleRatio = scaleRatio
}
/// Filters according to type. Uses the pre set set tolerance
///
/// - parameter points: the points to filter
public override func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
{
return filter(points, tolerance: tolerance)
}
/// Filters according to type.
///
/// - parameter points: the points to filter
/// - parameter tolerance: the angle in degrees that will trigger the filtering
public func filter(points: [ChartDataEntry], tolerance: Double) -> [ChartDataEntry]
{
if (tolerance <= 0)
{
return points
}
switch (type)
{
case .RamerDouglasPeucker:
return reduceWithDouglasPeuker(points, epsilon: tolerance)
case .None:
return points
}
}
/// uses the douglas peuker algorithm to reduce the given arraylist of entries
private func reduceWithDouglasPeuker(entries: [ChartDataEntry], epsilon: Double) -> [ChartDataEntry]
{
// if a shape has 2 or less points it cannot be reduced
if (epsilon <= 0 || entries.count < 3)
{
return entries
}
var keep = [Bool](count: entries.count, repeatedValue: false)
// first and last always stay
keep[0] = true
keep[entries.count - 1] = true
// first and last entry are entry point to recursion
algorithmDouglasPeucker(entries, epsilon: epsilon, start: 0, end: entries.count - 1, keep: &keep)
// create a new array with series, only take the kept ones
var reducedEntries = [ChartDataEntry]()
for i in 0 ..< entries.count
{
if (keep[i])
{
let curEntry = entries[i]
reducedEntries.append(ChartDataEntry(value: curEntry.value, xIndex: curEntry.xIndex))
}
}
return reducedEntries
}
/// apply the Douglas-Peucker-Reduction to an ArrayList of Entry with a given epsilon (tolerance)
///
/// - parameter entries:
/// - parameter epsilon: as y-value
/// - parameter start:
/// - parameter end:
private func algorithmDouglasPeucker(entries: [ChartDataEntry], epsilon: Double, start: Int, end: Int, inout keep: [Bool])
{
if (end <= start + 1)
{
// recursion finished
return
}
// find the greatest distance between start and endpoint
var maxDistIndex = Int(0)
var distMax = Double(0.0)
let firstEntry = entries[start]
let lastEntry = entries[end]
for i in start + 1 ..< end
{
let dist = calcAngleBetweenLines(firstEntry, end1: lastEntry, start2: firstEntry, end2: entries[i])
// keep the point with the greatest distance
if (dist > distMax)
{
distMax = dist
maxDistIndex = i
}
}
if (distMax > epsilon)
{
// keep max dist point
keep[maxDistIndex] = true
// recursive call
algorithmDouglasPeucker(entries, epsilon: epsilon, start: start, end: maxDistIndex, keep: &keep)
algorithmDouglasPeucker(entries, epsilon: epsilon, start: maxDistIndex, end: end, keep: &keep)
} // else don't keep the point...
}
/// calculate the distance between a line between two entries and an entry (point)
///
/// - parameter startEntry: line startpoint
/// - parameter endEntry: line endpoint
/// - parameter entryPoint: the point to which the distance is measured from the line
private func calcPointToLineDistance(startEntry: ChartDataEntry, endEntry: ChartDataEntry, entryPoint: ChartDataEntry) -> Double
{
let xDiffEndStart = Double(endEntry.xIndex) - Double(startEntry.xIndex)
let xDiffEntryStart = Double(entryPoint.xIndex) - Double(startEntry.xIndex)
let normalLength = sqrt((xDiffEndStart)
* (xDiffEndStart)
+ (endEntry.value - startEntry.value)
* (endEntry.value - startEntry.value))
return Double(fabs((xDiffEntryStart)
* (endEntry.value - startEntry.value)
- (entryPoint.value - startEntry.value)
* (xDiffEndStart))) / Double(normalLength)
}
/// Calculates the angle between two given lines. The provided entries mark the starting and end points of the lines.
private func calcAngleBetweenLines(start1: ChartDataEntry, end1: ChartDataEntry, start2: ChartDataEntry, end2: ChartDataEntry) -> Double
{
let angle1 = calcAngleWithRatios(start1, p2: end1)
let angle2 = calcAngleWithRatios(start2, p2: end2)
return fabs(angle1 - angle2)
}
/// calculates the angle between two entries (points) in the chart taking ratios into consideration
private func calcAngleWithRatios(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
{
let dx = Double(p2.xIndex) * Double(deltaRatio) - Double(p1.xIndex) * Double(deltaRatio)
let dy = p2.value * scaleRatio - p1.value * scaleRatio
return atan2(Double(dy), dx) * ChartUtils.Math.RAD2DEG
}
// calculates the angle between two entries (points) in the chart
private func calcAngle(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
{
let dx = p2.xIndex - p1.xIndex
let dy = p2.value - p1.value
return atan2(Double(dy), Double(dx)) * ChartUtils.Math.RAD2DEG
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Filters/ChartDataBaseFilter.swift
================================================
//
// ChartDataFilter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartDataBaseFilter: NSObject
{
public override init()
{
super.init()
}
public func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
{
fatalError("filter() cannot be called on ChartDataBaseFilter")
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Formatters/ChartDefaultFillFormatter.swift
================================================
//
// ChartDefaultFillFormatter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 04/02/2016.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
/// Default formatter that calculates the position of the filled line.
public class ChartDefaultFillFormatter: NSObject, ChartFillFormatter
{
public override init()
{
}
public func getFillLinePosition(dataSet dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat
{
var fillMin = CGFloat(0.0)
if (dataSet.yMax > 0.0 && dataSet.yMin < 0.0)
{
fillMin = 0.0
}
else
{
if let data = dataProvider.data
{
var max: Double, min: Double
if (data.yMax > 0.0)
{
max = 0.0
}
else
{
max = dataProvider.chartYMax
}
if (data.yMin < 0.0)
{
min = 0.0
}
else
{
min = dataProvider.chartYMin
}
fillMin = CGFloat(dataSet.yMin >= 0.0 ? min : max)
}
}
return fillMin
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Formatters/ChartDefaultXAxisValueFormatter.swift
================================================
//
// ChartDefaultXAxisValueFormatter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
/// An interface for providing custom x-axis Strings.
public class ChartDefaultXAxisValueFormatter: NSObject, ChartXAxisValueFormatter
{
public func stringForXValue(index: Int, original: String, viewPortHandler: ChartViewPortHandler) -> String
{
return original // just return original, no adjustments
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Formatters/ChartFillFormatter.swift
================================================
//
// ChartFillFormatter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 6/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Protocol for providing a custom logic to where the filling line of a LineDataSet should end. This of course only works if setFillEnabled(...) is set to true.
@objc
public protocol ChartFillFormatter
{
/// - returns: the vertical (y-axis) position where the filled-line of the LineDataSet should end.
func getFillLinePosition(dataSet dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Formatters/ChartXAxisValueFormatter.swift
================================================
//
// ChartXAxisValueFormatter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
/// An interface for providing custom x-axis Strings.
@objc
public protocol ChartXAxisValueFormatter
{
/// For performance reasons, avoid excessive calculations and memory allocations inside this method.
///
/// - returns: the customized label that is drawn on the x-axis.
/// - parameter index: the x-index that is currently being drawn
/// - parameter original: the original x-axis label to be drawn
/// - parameter viewPortHandler: provides information about the current chart state (scale, translation, ...)
///
func stringForXValue(index: Int, original: String, viewPortHandler: ChartViewPortHandler) -> String
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/BarChartHighlighter.swift
================================================
//
// ChartBarHighlighter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class BarChartHighlighter: ChartHighlighter
{
public override func getHighlight(x x: Double, y: Double) -> ChartHighlight?
{
let h = super.getHighlight(x: x, y: y)
if h === nil
{
return h
}
else
{
if let set = self.chart?.data?.getDataSetByIndex(h!.dataSetIndex) as? BarChartDataSet
{
if set.isStacked
{
// create an array of the touch-point
var pt = CGPoint()
pt.y = CGFloat(y)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(set.axisDependency).pixelToValue(&pt)
return getStackedHighlight(old: h, set: set, xIndex: h!.xIndex, dataSetIndex: h!.dataSetIndex, yValue: Double(pt.y))
}
}
return h
}
}
public override func getXIndex(x: Double) -> Int
{
if let barChartData = self.chart?.data as? BarChartData
{
if !barChartData.isGrouped
{
return super.getXIndex(x)
}
else
{
let baseNoSpace = getBase(x)
let setCount = barChartData.dataSetCount
var xIndex = Int(baseNoSpace) / setCount
let valCount = barChartData.xValCount
if xIndex < 0
{
xIndex = 0
}
else if xIndex >= valCount
{
xIndex = valCount - 1
}
return xIndex
}
}
else
{
return 0
}
}
public override func getDataSetIndex(xIndex xIndex: Int, x: Double, y: Double) -> Int
{
if let barChartData = self.chart?.data as? BarChartData
{
if !barChartData.isGrouped
{
return 0
}
else
{
let baseNoSpace = getBase(x)
let setCount = barChartData.dataSetCount
var dataSetIndex = Int(baseNoSpace) % setCount
if dataSetIndex < 0
{
dataSetIndex = 0
}
else if dataSetIndex >= setCount
{
dataSetIndex = setCount - 1
}
return dataSetIndex
}
}
else
{
return 0
}
}
/// This method creates the Highlight object that also indicates which value of a stacked BarEntry has been selected.
/// - parameter old: the old highlight object before looking for stacked values
/// - parameter set:
/// - parameter xIndex:
/// - parameter dataSetIndex:
/// - parameter yValue:
/// - returns:
public func getStackedHighlight(old old: ChartHighlight?, set: BarChartDataSet, xIndex: Int, dataSetIndex: Int, yValue: Double) -> ChartHighlight?
{
let entry = set.entryForXIndex(xIndex) as? BarChartDataEntry
if entry?.values === nil
{
return old
}
if let ranges = getRanges(entry: entry!)
where ranges.count > 0
{
let stackIndex = getClosestStackIndex(ranges: ranges, value: yValue)
let h = ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex, stackIndex: stackIndex, range: ranges[stackIndex])
return h
}
return nil
}
/// Returns the index of the closest value inside the values array / ranges (stacked barchart) to the value given as a parameter.
/// - parameter entry:
/// - parameter value:
/// - returns:
public func getClosestStackIndex(ranges ranges: [ChartRange]?, value: Double) -> Int
{
if ranges == nil
{
return 0
}
var stackIndex = 0
for range in ranges!
{
if range.contains(value)
{
return stackIndex
}
else
{
stackIndex += 1
}
}
let length = max(ranges!.count - 1, 0)
return (value > ranges![length].to) ? length : 0
}
/// Returns the base x-value to the corresponding x-touch value in pixels.
/// - parameter x:
/// - returns:
public func getBase(x: Double) -> Double
{
if let barChartData = self.chart?.data as? BarChartData
{
// create an array of the touch-point
var pt = CGPoint()
pt.x = CGFloat(x)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
let xVal = Double(pt.x)
let setCount = barChartData.dataSetCount ?? 0
// calculate how often the group-space appears
let steps = Int(xVal / (Double(setCount) + Double(barChartData.groupSpace)))
let groupSpaceSum = Double(barChartData.groupSpace) * Double(steps)
let baseNoSpace = xVal - groupSpaceSum
return baseNoSpace
}
else
{
return 0.0
}
}
/// Splits up the stack-values of the given bar-entry into Range objects.
/// - parameter entry:
/// - returns:
public func getRanges(entry entry: BarChartDataEntry) -> [ChartRange]?
{
let values = entry.values
if (values == nil)
{
return nil
}
var negRemain = -entry.negativeSum
var posRemain: Double = 0.0
var ranges = [ChartRange]()
ranges.reserveCapacity(values!.count)
for i in 0 ..< values!.count
{
let value = values![i]
if value < 0
{
ranges.append(ChartRange(from: negRemain, to: negRemain + abs(value)))
negRemain += abs(value)
}
else
{
ranges.append(ChartRange(from: posRemain, to: posRemain+value))
posRemain += value
}
}
return ranges
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/ChartHighlight.swift
================================================
//
// ChartHighlight.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartHighlight: NSObject
{
/// the x-index of the highlighted value
private var _xIndex = Int(0)
/// the index of the dataset the highlighted value is in
private var _dataSetIndex = Int(0)
/// index which value of a stacked bar entry is highlighted
///
/// **default**: -1
private var _stackIndex = Int(-1)
/// the range of the bar that is selected (only for stacked-barchart)
private var _range: ChartRange?
public override init()
{
super.init()
}
public init(xIndex x: Int, dataSetIndex: Int)
{
super.init()
_xIndex = x
_dataSetIndex = dataSetIndex
}
public init(xIndex x: Int, dataSetIndex: Int, stackIndex: Int)
{
super.init()
_xIndex = x
_dataSetIndex = dataSetIndex
_stackIndex = stackIndex
}
/// Constructor, only used for stacked-barchart.
///
/// - parameter x: the index of the highlighted value on the x-axis
/// - parameter dataSet: the index of the DataSet the highlighted value belongs to
/// - parameter stackIndex: references which value of a stacked-bar entry has been selected
/// - parameter range: the range the selected stack-value is in
public convenience init(xIndex x: Int, dataSetIndex: Int, stackIndex: Int, range: ChartRange)
{
self.init(xIndex: x, dataSetIndex: dataSetIndex, stackIndex: stackIndex)
_range = range
}
public var dataSetIndex: Int { return _dataSetIndex; }
public var xIndex: Int { return _xIndex; }
public var stackIndex: Int { return _stackIndex; }
/// - returns: the range of values the selected value of a stacked bar is in. (this is only relevant for stacked-barchart)
public var range: ChartRange? { return _range }
// MARK: NSObject
public override var description: String
{
return "Highlight, xIndex: \(_xIndex), dataSetIndex: \(_dataSetIndex), stackIndex (only stacked barentry): \(_stackIndex)"
}
public override func isEqual(object: AnyObject?) -> Bool
{
if (object === nil)
{
return false
}
if (!object!.isKindOfClass(self.dynamicType))
{
return false
}
if (object!.xIndex != _xIndex)
{
return false
}
if (object!.dataSetIndex != _dataSetIndex)
{
return false
}
if (object!.stackIndex != _stackIndex)
{
return false
}
return true
}
}
func ==(lhs: ChartHighlight, rhs: ChartHighlight) -> Bool
{
if (lhs === rhs)
{
return true
}
if (!lhs.isKindOfClass(rhs.dynamicType))
{
return false
}
if (lhs._xIndex != rhs._xIndex)
{
return false
}
if (lhs._dataSetIndex != rhs._dataSetIndex)
{
return false
}
if (lhs._stackIndex != rhs._stackIndex)
{
return false
}
return true
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/ChartHighlighter.swift
================================================
//
// ChartHighlighter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartHighlighter : NSObject
{
/// instance of the data-provider
public weak var chart: BarLineChartViewBase?
public init(chart: BarLineChartViewBase)
{
self.chart = chart
}
/// Returns a Highlight object corresponding to the given x- and y- touch positions in pixels.
/// - parameter x:
/// - parameter y:
/// - returns:
public func getHighlight(x x: Double, y: Double) -> ChartHighlight?
{
let xIndex = getXIndex(x)
if (xIndex == -Int.max)
{
return nil
}
let dataSetIndex = getDataSetIndex(xIndex: xIndex, x: x, y: y)
if (dataSetIndex == -Int.max)
{
return nil
}
return ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex)
}
/// Returns the corresponding x-index for a given touch-position in pixels.
/// - parameter x:
/// - returns:
public func getXIndex(x: Double) -> Int
{
// create an array of the touch-point
var pt = CGPoint(x: x, y: 0.0)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int(round(pt.x))
}
/// Returns the corresponding dataset-index for a given xIndex and xy-touch position in pixels.
/// - parameter xIndex:
/// - parameter x:
/// - parameter y:
/// - returns:
public func getDataSetIndex(xIndex xIndex: Int, x: Double, y: Double) -> Int
{
let valsAtIndex = getSelectionDetailsAtIndex(xIndex)
let leftdist = ChartUtils.getMinimumDistance(valsAtIndex, val: y, axis: ChartYAxis.AxisDependency.Left)
let rightdist = ChartUtils.getMinimumDistance(valsAtIndex, val: y, axis: ChartYAxis.AxisDependency.Right)
let axis = leftdist < rightdist ? ChartYAxis.AxisDependency.Left : ChartYAxis.AxisDependency.Right
let dataSetIndex = ChartUtils.closestDataSetIndex(valsAtIndex, value: y, axis: axis)
return dataSetIndex
}
/// Returns a list of SelectionDetail object corresponding to the given xIndex.
/// - parameter xIndex:
/// - returns:
public func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
{
var vals = [ChartSelectionDetail]()
var pt = CGPoint()
for i in 0 ..< (self.chart?.data?.dataSetCount ?? 0)
{
let dataSet = self.chart!.data!.getDataSetByIndex(i)
// dont include datasets that cannot be highlighted
if !dataSet.isHighlightEnabled
{
continue
}
// extract all y-values from all DataSets at the given x-index
let yVal: Double = dataSet.yValForXIndex(xIndex)
if yVal.isNaN
{
continue
}
pt.y = CGFloat(yVal)
self.chart!.getTransformer(dataSet.axisDependency).pointValueToPixel(&pt)
if !pt.y.isNaN
{
vals.append(ChartSelectionDetail(value: Double(pt.y), dataSetIndex: i, dataSet: dataSet))
}
}
return vals
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/ChartRange.swift
================================================
//
// ChartRange.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartRange: NSObject
{
public var from: Double
public var to: Double
public init(from: Double, to: Double)
{
self.from = from
self.to = to
super.init()
}
/// Returns true if this range contains (if the value is in between) the given value, false if not.
/// - parameter value:
public func contains(value: Double) -> Bool
{
if value > from && value <= to
{
return true
}
else
{
return false
}
}
public func isLarger(value: Double) -> Bool
{
return value > to
}
public func isSmaller(value: Double) -> Bool
{
return value < from
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/CombinedHighlighter.swift
================================================
//
// CombinedHighlighter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class CombinedHighlighter: ChartHighlighter
{
/// Returns a list of SelectionDetail object corresponding to the given xIndex.
/// - parameter xIndex:
/// - returns:
public override func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
{
var vals = [ChartSelectionDetail]()
if let data = self.chart?.data as? CombinedChartData
{
// get all chartdata objects
var dataObjects = data.allData
var pt = CGPoint()
for i in 0 ..< dataObjects.count
{
for j in 0 ..< dataObjects[i].dataSetCount
{
let dataSet = dataObjects[i].getDataSetByIndex(j)
// dont include datasets that cannot be highlighted
if !dataSet.isHighlightEnabled
{
continue
}
// extract all y-values from all DataSets at the given x-index
let yVal = dataSet.yValForXIndex(xIndex)
if yVal.isNaN
{
continue
}
pt.y = CGFloat(yVal)
self.chart!.getTransformer(dataSet.axisDependency).pointValueToPixel(&pt)
if !pt.y.isNaN
{
vals.append(ChartSelectionDetail(value: Double(pt.y), dataSetIndex: j, dataSet: dataSet))
}
}
}
}
return vals
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Highlight/HorizontalBarChartHighlighter.swift
================================================
//
// HorizontalBarChartHighlighter.swift
// Charts
//
// Created by Daniel Cohen Gindi on 26/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class HorizontalBarChartHighlighter: BarChartHighlighter
{
public override func getHighlight(x x: Double, y: Double) -> ChartHighlight?
{
let h = super.getHighlight(x: x, y: y)
if h === nil
{
return h
}
else
{
if let set = self.chart?.data?.getDataSetByIndex(h!.dataSetIndex) as? BarChartDataSet
{
if set.isStacked
{
// create an array of the touch-point
var pt = CGPoint()
pt.x = CGFloat(y)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(set.axisDependency).pixelToValue(&pt)
return getStackedHighlight(old: h, set: set, xIndex: h!.xIndex, dataSetIndex: h!.dataSetIndex, yValue: Double(pt.x))
}
}
return h
}
}
public override func getXIndex(x: Double) -> Int
{
if let barChartData = self.chart?.data as? BarChartData
{
if !barChartData.isGrouped
{
// create an array of the touch-point
var pt = CGPoint(x: 0.0, y: x)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
return Int(round(pt.y))
}
else
{
let baseNoSpace = getBase(x)
let setCount = barChartData.dataSetCount
var xIndex = Int(baseNoSpace) / setCount
let valCount = barChartData.xValCount
if xIndex < 0
{
xIndex = 0
}
else if xIndex >= valCount
{
xIndex = valCount - 1
}
return xIndex
}
}
else
{
return 0
}
}
/// Returns the base y-value to the corresponding x-touch value in pixels.
/// - parameter y:
/// - returns:
public override func getBase(y: Double) -> Double
{
if let barChartData = self.chart?.data as? BarChartData
{
// create an array of the touch-point
var pt = CGPoint()
pt.y = CGFloat(y)
// take any transformer to determine the x-axis value
self.chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
let yVal = Double(pt.y)
let setCount = barChartData.dataSetCount ?? 0
// calculate how often the group-space appears
let steps = Int(yVal / (Double(setCount) + Double(barChartData.groupSpace)))
let groupSpaceSum = Double(barChartData.groupSpace) * Double(steps)
let baseNoSpace = yVal - groupSpaceSum
return baseNoSpace
}
else
{
return 0.0
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/BarChartDataProvider.swift
================================================
//
// BarChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol BarChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
var barData: BarChartData? { get }
var isDrawBarShadowEnabled: Bool { get }
var isDrawValueAboveBarEnabled: Bool { get }
var isDrawHighlightArrowEnabled: Bool { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift
================================================
//
// BarLineScatterCandleBubbleChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol BarLineScatterCandleBubbleChartDataProvider: ChartDataProvider
{
func getTransformer(which: ChartYAxis.AxisDependency) -> ChartTransformer
var maxVisibleValueCount: Int { get }
func isInverted(axis: ChartYAxis.AxisDependency) -> Bool
var lowestVisibleXIndex: Int { get }
var highestVisibleXIndex: Int { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/BubbleChartDataProvider.swift
================================================
//
// BubbleChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol BubbleChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
var bubbleData: BubbleChartData? { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/CandleChartDataProvider.swift
================================================
//
// CandleChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol CandleChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
var candleData: CandleChartData? { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/ChartDataProvider.swift
================================================
//
// ChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol ChartDataProvider
{
/// - returns: the minimum x-value of the chart, regardless of zoom or translation.
var chartXMin: Double { get }
/// - returns: the maximum x-value of the chart, regardless of zoom or translation.
var chartXMax: Double { get }
/// - returns: the minimum y-value of the chart, regardless of zoom or translation.
var chartYMin: Double { get }
/// - returns: the maximum y-value of the chart, regardless of zoom or translation.
var chartYMax: Double { get }
var xValCount: Int { get }
var centerOffsets: CGPoint { get }
var data: ChartData? { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/LineChartDataProvider.swift
================================================
//
// LineChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol LineChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
var lineData: LineChartData? { get }
func getAxis(axis: ChartYAxis.AxisDependency) -> ChartYAxis
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Interfaces/ScatterChartDataProvider.swift
================================================
//
// ScatterChartDataProvider.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
@objc
public protocol ScatterChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
var scatterData: ScatterChartData? { get }
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/AnimatedMoveViewJob.swift
================================================
//
// AnimatedMoveChartViewJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class AnimatedMoveChartViewJob: AnimatedViewPortJob
{
public override init(
viewPortHandler: ChartViewPortHandler,
xIndex: CGFloat,
yValue: Double,
transformer: ChartTransformer,
view: ChartViewBase,
xOrigin: CGFloat,
yOrigin: CGFloat,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
super.init(viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue,
transformer: transformer,
view: view,
xOrigin: xOrigin,
yOrigin: yOrigin,
duration: duration,
easing: easing)
}
internal override func animationUpdate()
{
guard let
viewPortHandler = viewPortHandler,
transformer = transformer,
view = view
else { return }
var pt = CGPoint(
x: xOrigin + (xIndex - xOrigin) * phase,
y: yOrigin + (CGFloat(yValue) - yOrigin) * phase
);
transformer.pointValueToPixel(&pt)
viewPortHandler.centerViewPort(pt: pt, chart: view)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/AnimatedViewPortJob.swift
================================================
//
// AnimatedViewPortJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class AnimatedViewPortJob: ChartViewPortJob
{
internal var phase: CGFloat = 1.0
internal var xOrigin: CGFloat = 0.0
internal var yOrigin: CGFloat = 0.0
private var _startTime: NSTimeInterval = 0.0
private var _displayLink: NSUIDisplayLink!
private var _duration: NSTimeInterval = 0.0
private var _endTime: NSTimeInterval = 0.0
private var _easing: ChartEasingFunctionBlock?
public init(
viewPortHandler: ChartViewPortHandler,
xIndex: CGFloat,
yValue: Double,
transformer: ChartTransformer,
view: ChartViewBase,
xOrigin: CGFloat,
yOrigin: CGFloat,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
super.init(viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue,
transformer: transformer,
view: view)
self.xOrigin = xOrigin
self.yOrigin = yOrigin
self._duration = duration
self._easing = easing
}
deinit
{
stop(finish: false)
}
public override func doJob()
{
start()
}
public func start()
{
_startTime = CACurrentMediaTime()
_endTime = _startTime + _duration
_endTime = _endTime > _endTime ? _endTime : _endTime
updateAnimationPhase(_startTime)
_displayLink = NSUIDisplayLink(target: self, selector: #selector(AnimatedViewPortJob.animationLoop))
_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
public func stop(finish finish: Bool)
{
if (_displayLink != nil)
{
_displayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
_displayLink = nil
if finish
{
if phase != 1.0
{
phase = 1.0
phase = 1.0
animationUpdate()
}
animationEnd()
}
}
}
private func updateAnimationPhase(currentTime: NSTimeInterval)
{
let elapsedTime: NSTimeInterval = currentTime - _startTime
let duration: NSTimeInterval = _duration
var elapsed: NSTimeInterval = elapsedTime
if elapsed > duration
{
elapsed = duration
}
if _easing != nil
{
phase = _easing!(elapsed: elapsed, duration: duration)
}
else
{
phase = CGFloat(elapsed / duration)
}
}
@objc private func animationLoop()
{
let currentTime: NSTimeInterval = CACurrentMediaTime()
updateAnimationPhase(currentTime)
animationUpdate()
if (currentTime >= _endTime)
{
stop(finish: true)
}
}
internal func animationUpdate()
{
// Override this
}
internal func animationEnd()
{
// Override this
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/AnimatedZoomViewJob.swift
================================================
//
// AnimatedZoomChartViewJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class AnimatedZoomChartViewJob: AnimatedViewPortJob
{
internal var yAxis: ChartYAxis?
internal var xValCount: Int = 0
internal var scaleX: CGFloat = 0.0
internal var scaleY: CGFloat = 0.0
internal var zoomOriginX: CGFloat = 0.0
internal var zoomOriginY: CGFloat = 0.0
internal var zoomCenterX: CGFloat = 0.0
internal var zoomCenterY: CGFloat = 0.0
public init(
viewPortHandler: ChartViewPortHandler,
transformer: ChartTransformer,
view: ChartViewBase,
yAxis: ChartYAxis,
xValCount: Int,
scaleX: CGFloat,
scaleY: CGFloat,
xOrigin: CGFloat,
yOrigin: CGFloat,
zoomCenterX: CGFloat,
zoomCenterY: CGFloat,
zoomOriginX: CGFloat,
zoomOriginY: CGFloat,
duration: NSTimeInterval,
easing: ChartEasingFunctionBlock?)
{
super.init(viewPortHandler: viewPortHandler,
xIndex: 0.0,
yValue: 0.0,
transformer: transformer,
view: view,
xOrigin: xOrigin,
yOrigin: yOrigin,
duration: duration,
easing: easing)
self.yAxis = yAxis
self.xValCount = xValCount
self.scaleX = scaleX
self.scaleY = scaleY
self.zoomCenterX = zoomCenterX
self.zoomCenterY = zoomCenterY
self.zoomOriginX = zoomOriginX
self.zoomOriginY = zoomOriginY
}
internal override func animationUpdate()
{
guard let
viewPortHandler = viewPortHandler,
transformer = transformer,
view = view
else { return }
let scaleX = xOrigin + (self.scaleX - xOrigin) * phase
let scaleY = yOrigin + (self.scaleY - yOrigin) * phase
var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY)
viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false)
let valsInView = CGFloat(yAxis?.axisRange ?? 0.0) / viewPortHandler.scaleY
let xsInView = CGFloat(xValCount) / viewPortHandler.scaleX
var pt = CGPoint(
x: zoomOriginX + ((zoomCenterX - xsInView / 2.0) - zoomOriginX) * phase,
y: zoomOriginY + ((zoomCenterY + valsInView / 2.0) - zoomOriginY) * phase
)
transformer.pointValueToPixel(&pt)
matrix = viewPortHandler.translate(pt: pt)
viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: true)
}
internal override func animationEnd()
{
(view as? BarLineChartViewBase)?.calculateOffsets()
view?.setNeedsDisplay()
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/ChartViewPortJob.swift
================================================
//
// ChartViewPortJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
// This defines a viewport modification job, used for delaying or animating viewport changes
public class ChartViewPortJob
{
internal var point: CGPoint = CGPoint()
internal weak var viewPortHandler: ChartViewPortHandler?
internal var xIndex: CGFloat = 0.0
internal var yValue: Double = 0.0
internal weak var transformer: ChartTransformer?
internal weak var view: ChartViewBase?
public init(
viewPortHandler: ChartViewPortHandler,
xIndex: CGFloat,
yValue: Double,
transformer: ChartTransformer,
view: ChartViewBase)
{
self.viewPortHandler = viewPortHandler
self.xIndex = xIndex
self.yValue = yValue
self.transformer = transformer
self.view = view
}
public func doJob()
{
// Override this
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/MoveChartViewJob.swift
================================================
//
// MoveChartViewJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class MoveChartViewJob: ChartViewPortJob
{
public override init(
viewPortHandler: ChartViewPortHandler,
xIndex: CGFloat,
yValue: Double,
transformer: ChartTransformer,
view: ChartViewBase)
{
super.init(
viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue,
transformer: transformer,
view: view)
}
public override func doJob()
{
guard let
viewPortHandler = viewPortHandler,
transformer = transformer,
view = view
else { return }
var pt = CGPoint(
x: xIndex,
y: CGFloat(yValue)
);
transformer.pointValueToPixel(&pt)
viewPortHandler.centerViewPort(pt: pt, chart: view)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Jobs/ZoomChartViewJob.swift
================================================
//
// ZoomChartViewJob.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ZoomChartViewJob: ChartViewPortJob
{
internal var scaleX: CGFloat = 0.0
internal var scaleY: CGFloat = 0.0
internal var axisDependency: ChartYAxis.AxisDependency = ChartYAxis.AxisDependency.Left
public init(
viewPortHandler: ChartViewPortHandler,
scaleX: CGFloat,
scaleY: CGFloat,
xIndex: CGFloat,
yValue: Double,
transformer: ChartTransformer,
axis: ChartYAxis.AxisDependency,
view: ChartViewBase)
{
super.init(
viewPortHandler: viewPortHandler,
xIndex: xIndex,
yValue: yValue,
transformer: transformer,
view: view)
self.scaleX = scaleX
self.scaleY = scaleY
self.axisDependency = axis
}
public override func doJob()
{
guard let
viewPortHandler = viewPortHandler,
transformer = transformer,
view = view
else { return }
var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY)
viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false)
let valsInView = (view as! BarLineChartViewBase).getDeltaY(axisDependency) / viewPortHandler.scaleY
let xsInView = CGFloat((view as! BarLineChartViewBase).xAxis.values.count) / viewPortHandler.scaleX
var pt = CGPoint(
x: xIndex - xsInView / 2.0,
y: CGFloat(yValue) + valsInView / 2.0
)
transformer.pointValueToPixel(&pt)
matrix = viewPortHandler.translate(pt: pt)
viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false)
(view as! BarLineChartViewBase).calculateOffsets()
view.setNeedsDisplay()
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/BarChartRenderer.swift
================================================
//
// BarChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class BarChartRenderer: ChartDataRendererBase
{
public weak var dataProvider: BarChartDataProvider?
public init(dataProvider: BarChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.dataProvider = dataProvider
}
public override func drawData(context context: CGContext)
{
guard let dataProvider = dataProvider, barData = dataProvider.barData else { return }
for i in 0 ..< barData.dataSetCount
{
guard let set = barData.getDataSetByIndex(i) else { continue }
if set.isVisible && set.entryCount > 0
{
if !(set is IBarChartDataSet)
{
fatalError("Datasets for BarChartRenderer must conform to IBarChartDataset")
}
drawDataSet(context: context, dataSet: set as! IBarChartDataSet, index: i)
}
}
}
public func drawDataSet(context context: CGContext, dataSet: IBarChartDataSet, index: Int)
{
guard let
dataProvider = dataProvider,
barData = dataProvider.barData,
animator = animator
else { return }
CGContextSaveGState(context)
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let drawBarShadowEnabled: Bool = dataProvider.isDrawBarShadowEnabled
let dataSetOffset = (barData.dataSetCount - 1)
let groupSpace = barData.groupSpace
let groupSpaceHalf = groupSpace / 2.0
let barSpace = dataSet.barSpace
let barSpaceHalf = barSpace / 2.0
let containsStacks = dataSet.isStacked
let isInverted = dataProvider.isInverted(dataSet.axisDependency)
let barWidth: CGFloat = 0.5
let phaseY = animator.phaseY
var barRect = CGRect()
var barShadow = CGRect()
var y: Double
// do the drawing
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
// calculate the x-position, depending on datasetcount
let x = CGFloat(e.xIndex + e.xIndex * dataSetOffset) + CGFloat(index)
+ groupSpace * CGFloat(e.xIndex) + groupSpaceHalf
var vals = e.values
if (!containsStacks || vals == nil)
{
y = e.value
let left = x - barWidth + barSpaceHalf
let right = x + barWidth - barSpaceHalf
var top = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
var bottom = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
// multiply the height of the rect with the phase
if (top > 0)
{
top *= phaseY
}
else
{
bottom *= phaseY
}
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
{
continue
}
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
{
break
}
// if drawing the bar shadow is enabled
if (drawBarShadowEnabled)
{
barShadow.origin.x = barRect.origin.x
barShadow.origin.y = viewPortHandler.contentTop
barShadow.size.width = barRect.size.width
barShadow.size.height = viewPortHandler.contentHeight
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
CGContextFillRect(context, barShadow)
}
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
CGContextFillRect(context, barRect)
}
else
{
var posY = 0.0
var negY = -e.negativeSum
var yStart = 0.0
// if drawing the bar shadow is enabled
if (drawBarShadowEnabled)
{
y = e.value
let left = x - barWidth + barSpaceHalf
let right = x + barWidth - barSpaceHalf
var top = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
var bottom = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
// multiply the height of the rect with the phase
if (top > 0)
{
top *= phaseY
}
else
{
bottom *= phaseY
}
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
barShadow.origin.x = barRect.origin.x
barShadow.origin.y = viewPortHandler.contentTop
barShadow.size.width = barRect.size.width
barShadow.size.height = viewPortHandler.contentHeight
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
CGContextFillRect(context, barShadow)
}
// fill the stack
for k in 0 ..< vals!.count
{
let value = vals![k]
if value >= 0.0
{
y = posY
yStart = posY + value
posY = yStart
}
else
{
y = negY
yStart = negY + abs(value)
negY += abs(value)
}
let left = x - barWidth + barSpaceHalf
let right = x + barWidth - barSpaceHalf
var top: CGFloat, bottom: CGFloat
if isInverted
{
bottom = y >= yStart ? CGFloat(y) : CGFloat(yStart)
top = y <= yStart ? CGFloat(y) : CGFloat(yStart)
}
else
{
top = y >= yStart ? CGFloat(y) : CGFloat(yStart)
bottom = y <= yStart ? CGFloat(y) : CGFloat(yStart)
}
// multiply the height of the rect with the phase
top *= phaseY
bottom *= phaseY
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
if (k == 0 && !viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
{
// Skip to next bar
break
}
// avoid drawing outofbounds values
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
{
break
}
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
CGContextSetFillColorWithColor(context, dataSet.colorAt(k).CGColor)
CGContextFillRect(context, barRect)
}
}
}
CGContextRestoreGState(context)
}
/// Prepares a bar for being highlighted.
public func prepareBarHighlight(x x: CGFloat, y1: Double, y2: Double, barspacehalf: CGFloat, trans: ChartTransformer, inout rect: CGRect)
{
let barWidth: CGFloat = 0.5
let left = x - barWidth + barspacehalf
let right = x + barWidth - barspacehalf
let top = CGFloat(y1)
let bottom = CGFloat(y2)
rect.origin.x = left
rect.origin.y = top
rect.size.width = right - left
rect.size.height = bottom - top
trans.rectValueToPixel(&rect, phaseY: animator?.phaseY ?? 1.0)
}
public override func drawValues(context context: CGContext)
{
// if values are drawn
if (passesCheck())
{
guard let
dataProvider = dataProvider,
barData = dataProvider.barData,
animator = animator
else { return }
var dataSets = barData.dataSets
let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled
var posOffset: CGFloat
var negOffset: CGFloat
for dataSetIndex in 0 ..< barData.dataSetCount
{
guard let dataSet = dataSets[dataSetIndex] as? IBarChartDataSet else { continue }
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let isInverted = dataProvider.isInverted(dataSet.axisDependency)
// calculate the correct offset depending on the draw position of the value
let valueOffsetPlus: CGFloat = 4.5
let valueFont = dataSet.valueFont
let valueTextHeight = valueFont.lineHeight
posOffset = (drawValueAboveBar ? -(valueTextHeight + valueOffsetPlus) : valueOffsetPlus)
negOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextHeight + valueOffsetPlus))
if (isInverted)
{
posOffset = -posOffset - valueTextHeight
negOffset = -negOffset - valueTextHeight
}
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let phaseY = animator.phaseY
let dataSetCount = barData.dataSetCount
let groupSpace = barData.groupSpace
// if only single values are drawn (sum)
if (!dataSet.isStacked)
{
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
let valuePoint = trans.getTransformedValueBarChart(
entry: e,
xIndex: e.xIndex,
dataSetIndex: dataSetIndex,
phaseY: phaseY,
dataSetCount: dataSetCount,
groupSpace: groupSpace
)
if (!viewPortHandler.isInBoundsRight(valuePoint.x))
{
break
}
if (!viewPortHandler.isInBoundsY(valuePoint.y)
|| !viewPortHandler.isInBoundsLeft(valuePoint.x))
{
continue
}
let val = e.value
drawValue(context: context,
value: formatter.stringFromNumber(val)!,
xPos: valuePoint.x,
yPos: valuePoint.y + (val >= 0.0 ? posOffset : negOffset),
font: valueFont,
align: .Center,
color: dataSet.valueTextColorAt(j))
}
}
else
{
// if we have stacks
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
let values = e.values
let valuePoint = trans.getTransformedValueBarChart(entry: e, xIndex: e.xIndex, dataSetIndex: dataSetIndex, phaseY: phaseY, dataSetCount: dataSetCount, groupSpace: groupSpace)
// we still draw stacked bars, but there is one non-stacked in between
if (values == nil)
{
if (!viewPortHandler.isInBoundsRight(valuePoint.x))
{
break
}
if (!viewPortHandler.isInBoundsY(valuePoint.y)
|| !viewPortHandler.isInBoundsLeft(valuePoint.x))
{
continue
}
drawValue(context: context,
value: formatter.stringFromNumber(e.value)!,
xPos: valuePoint.x,
yPos: valuePoint.y + (e.value >= 0.0 ? posOffset : negOffset),
font: valueFont,
align: .Center,
color: dataSet.valueTextColorAt(j))
}
else
{
// draw stack values
let vals = values!
var transformed = [CGPoint]()
var posY = 0.0
var negY = -e.negativeSum
for k in 0 ..< vals.count
{
let value = vals[k]
var y: Double
if value >= 0.0
{
posY += value
y = posY
}
else
{
y = negY
negY -= value
}
transformed.append(CGPoint(x: 0.0, y: CGFloat(y) * animator.phaseY))
}
trans.pointValuesToPixel(&transformed)
for k in 0 ..< transformed.count
{
let x = valuePoint.x
let y = transformed[k].y + (vals[k] >= 0 ? posOffset : negOffset)
if (!viewPortHandler.isInBoundsRight(x))
{
break
}
if (!viewPortHandler.isInBoundsY(y) || !viewPortHandler.isInBoundsLeft(x))
{
continue
}
drawValue(context: context,
value: formatter.stringFromNumber(vals[k])!,
xPos: x,
yPos: y,
font: valueFont,
align: .Center,
color: dataSet.valueTextColorAt(j))
}
}
}
}
}
}
}
/// Draws a value at the specified x and y position.
public func drawValue(context context: CGContext, value: String, xPos: CGFloat, yPos: CGFloat, font: NSUIFont, align: NSTextAlignment, color: NSUIColor)
{
ChartUtils.drawText(context: context, text: value, point: CGPoint(x: xPos, y: yPos), align: align, attributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
}
public override func drawExtras(context context: CGContext)
{
}
private var _highlightArrowPtsBuffer = [CGPoint](count: 3, repeatedValue: CGPoint())
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
dataProvider = dataProvider,
barData = dataProvider.barData,
animator = animator
else { return }
CGContextSaveGState(context)
let setCount = barData.dataSetCount
let drawHighlightArrowEnabled = dataProvider.isDrawHighlightArrowEnabled
var barRect = CGRect()
for i in 0 ..< indices.count
{
let h = indices[i]
let index = h.xIndex
let dataSetIndex = h.dataSetIndex
guard let set = barData.getDataSetByIndex(dataSetIndex) as? IBarChartDataSet else { continue }
if (!set.isHighlightEnabled)
{
continue
}
let barspaceHalf = set.barSpace / 2.0
let trans = dataProvider.getTransformer(set.axisDependency)
CGContextSetFillColorWithColor(context, set.highlightColor.CGColor)
CGContextSetAlpha(context, set.highlightAlpha)
// check outofbounds
if (CGFloat(index) < (CGFloat(dataProvider.chartXMax) * animator.phaseX) / CGFloat(setCount))
{
let e = set.entryForXIndex(index) as! BarChartDataEntry!
if (e === nil || e.xIndex != index)
{
continue
}
let groupspace = barData.groupSpace
let isStack = h.stackIndex < 0 ? false : true
// calculate the correct x-position
let x = CGFloat(index * setCount + dataSetIndex) + groupspace / 2.0 + groupspace * CGFloat(index)
let y1: Double
let y2: Double
if (isStack)
{
y1 = h.range?.from ?? 0.0
y2 = h.range?.to ?? 0.0
}
else
{
y1 = e.value
y2 = 0.0
}
prepareBarHighlight(x: x, y1: y1, y2: y2, barspacehalf: barspaceHalf, trans: trans, rect: &barRect)
CGContextFillRect(context, barRect)
if (drawHighlightArrowEnabled)
{
CGContextSetAlpha(context, 1.0)
// distance between highlight arrow and bar
let offsetY = animator.phaseY * 0.07
CGContextSaveGState(context)
let pixelToValueMatrix = trans.pixelToValueMatrix
let xToYRel = abs(sqrt(pixelToValueMatrix.b * pixelToValueMatrix.b + pixelToValueMatrix.d * pixelToValueMatrix.d) / sqrt(pixelToValueMatrix.a * pixelToValueMatrix.a + pixelToValueMatrix.c * pixelToValueMatrix.c))
let arrowWidth = set.barSpace / 2.0
let arrowHeight = arrowWidth * xToYRel
let yArrow = (y1 > -y2 ? y1 : y1) * Double(animator.phaseY)
_highlightArrowPtsBuffer[0].x = CGFloat(x) + 0.4
_highlightArrowPtsBuffer[0].y = CGFloat(yArrow) + offsetY
_highlightArrowPtsBuffer[1].x = CGFloat(x) + 0.4 + arrowWidth
_highlightArrowPtsBuffer[1].y = CGFloat(yArrow) + offsetY - arrowHeight
_highlightArrowPtsBuffer[2].x = CGFloat(x) + 0.4 + arrowWidth
_highlightArrowPtsBuffer[2].y = CGFloat(yArrow) + offsetY + arrowHeight
trans.pointValuesToPixel(&_highlightArrowPtsBuffer)
CGContextBeginPath(context)
CGContextMoveToPoint(context, _highlightArrowPtsBuffer[0].x, _highlightArrowPtsBuffer[0].y)
CGContextAddLineToPoint(context, _highlightArrowPtsBuffer[1].x, _highlightArrowPtsBuffer[1].y)
CGContextAddLineToPoint(context, _highlightArrowPtsBuffer[2].x, _highlightArrowPtsBuffer[2].y)
CGContextClosePath(context)
CGContextFillPath(context)
CGContextRestoreGState(context)
}
}
}
CGContextRestoreGState(context)
}
internal func passesCheck() -> Bool
{
guard let dataProvider = dataProvider, barData = dataProvider.barData else { return false }
return CGFloat(barData.yValCount) < CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleX
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/BubbleChartRenderer.swift
================================================
//
// BubbleChartRenderer.swift
// Charts
//
// Bubble chart implementation:
// Copyright 2015 Pierre-Marc Airoldi
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class BubbleChartRenderer: ChartDataRendererBase
{
public weak var dataProvider: BubbleChartDataProvider?
public init(dataProvider: BubbleChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.dataProvider = dataProvider
}
public override func drawData(context context: CGContext)
{
guard let dataProvider = dataProvider, bubbleData = dataProvider.bubbleData else { return }
for set in bubbleData.dataSets as! [IBubbleChartDataSet]
{
if set.isVisible && set.entryCount > 0
{
drawDataSet(context: context, dataSet: set)
}
}
}
private func getShapeSize(entrySize entrySize: CGFloat, maxSize: CGFloat, reference: CGFloat) -> CGFloat
{
let factor: CGFloat = (maxSize == 0.0) ? 1.0 : sqrt(entrySize / maxSize)
let shapeSize: CGFloat = reference * factor
return shapeSize
}
private var _pointBuffer = CGPoint()
private var _sizeBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public func drawDataSet(context context: CGContext, dataSet: IBubbleChartDataSet)
{
guard let
dataProvider = dataProvider,
animator = animator
else { return }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let entryCount = dataSet.entryCount
let valueToPixelMatrix = trans.valueToPixelMatrix
guard let
entryFrom = dataSet.entryForXIndex(self.minX),
entryTo = dataSet.entryForXIndex(self.maxX)
else { return }
let minx = max(dataSet.entryIndex(entry: entryFrom), 0)
let maxx = min(dataSet.entryIndex(entry: entryTo) + 1, entryCount)
_sizeBuffer[0].x = 0.0
_sizeBuffer[0].y = 0.0
_sizeBuffer[1].x = 1.0
_sizeBuffer[1].y = 0.0
trans.pointValuesToPixel(&_sizeBuffer)
CGContextSaveGState(context)
// calcualte the full width of 1 step on the x-axis
let maxBubbleWidth: CGFloat = abs(_sizeBuffer[1].x - _sizeBuffer[0].x)
let maxBubbleHeight: CGFloat = abs(viewPortHandler.contentBottom - viewPortHandler.contentTop)
let referenceSize: CGFloat = min(maxBubbleHeight, maxBubbleWidth)
for j in minx ..< maxx
{
guard let entry = dataSet.entryForIndex(j) as? BubbleChartDataEntry else { continue }
_pointBuffer.x = CGFloat(entry.xIndex - minx) * phaseX + CGFloat(minx)
_pointBuffer.y = CGFloat(entry.value) * phaseY
_pointBuffer = CGPointApplyAffineTransform(_pointBuffer, valueToPixelMatrix)
let shapeSize = getShapeSize(entrySize: entry.size, maxSize: dataSet.maxSize, reference: referenceSize)
let shapeHalf = shapeSize / 2.0
if (!viewPortHandler.isInBoundsTop(_pointBuffer.y + shapeHalf)
|| !viewPortHandler.isInBoundsBottom(_pointBuffer.y - shapeHalf))
{
continue
}
if (!viewPortHandler.isInBoundsLeft(_pointBuffer.x + shapeHalf))
{
continue
}
if (!viewPortHandler.isInBoundsRight(_pointBuffer.x - shapeHalf))
{
break
}
let color = dataSet.colorAt(entry.xIndex)
let rect = CGRect(
x: _pointBuffer.x - shapeHalf,
y: _pointBuffer.y - shapeHalf,
width: shapeSize,
height: shapeSize
)
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillEllipseInRect(context, rect)
}
CGContextRestoreGState(context)
}
public override func drawValues(context context: CGContext)
{
guard let
dataProvider = dataProvider,
bubbleData = dataProvider.bubbleData,
animator = animator
else { return }
// if values are drawn
if (bubbleData.yValCount < Int(ceil(CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleX)))
{
guard let dataSets = bubbleData.dataSets as? [IBubbleChartDataSet] else { return }
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var pt = CGPoint()
for dataSet in dataSets
{
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let alpha = phaseX == 1 ? phaseY : phaseX
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let entryCount = dataSet.entryCount
guard let
entryFrom = dataSet.entryForXIndex(self.minX),
entryTo = dataSet.entryForXIndex(self.maxX)
else { continue }
let minx = max(dataSet.entryIndex(entry: entryFrom), 0)
let maxx = min(dataSet.entryIndex(entry: entryTo) + 1, entryCount)
for j in minx ..< maxx
{
guard let e = dataSet.entryForIndex(j) as? BubbleChartDataEntry else { break }
let valueTextColor = dataSet.valueTextColorAt(j).colorWithAlphaComponent(alpha)
pt.x = CGFloat(e.xIndex - minx) * phaseX + CGFloat(minx)
pt.y = CGFloat(e.value) * phaseY
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if ((!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y)))
{
continue
}
let text = formatter.stringFromNumber(e.size)
// Larger font for larger bubbles?
let valueFont = dataSet.valueFont
let lineHeight = valueFont.lineHeight
ChartUtils.drawText(
context: context,
text: text!,
point: CGPoint(
x: pt.x,
y: pt.y - (0.5 * lineHeight)),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
}
}
}
}
public override func drawExtras(context context: CGContext)
{
}
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
dataProvider = dataProvider,
bubbleData = dataProvider.bubbleData,
animator = animator
else { return }
CGContextSaveGState(context)
let phaseX = animator.phaseX
let phaseY = animator.phaseY
for indice in indices
{
guard let dataSet = bubbleData.getDataSetByIndex(indice.dataSetIndex) as? IBubbleChartDataSet else { continue }
if (!dataSet.isHighlightEnabled)
{
continue
}
let entryFrom = dataSet.entryForXIndex(self.minX)
let entryTo = dataSet.entryForXIndex(self.maxX)
let minx = max(dataSet.entryIndex(entry: entryFrom!), 0)
let maxx = min(dataSet.entryIndex(entry: entryTo!) + 1, dataSet.entryCount)
let entry: BubbleChartDataEntry! = bubbleData.getEntryForHighlight(indice) as! BubbleChartDataEntry
if (entry === nil || entry.xIndex != indice.xIndex)
{
continue
}
let trans = dataProvider.getTransformer(dataSet.axisDependency)
_sizeBuffer[0].x = 0.0
_sizeBuffer[0].y = 0.0
_sizeBuffer[1].x = 1.0
_sizeBuffer[1].y = 0.0
trans.pointValuesToPixel(&_sizeBuffer)
// calcualte the full width of 1 step on the x-axis
let maxBubbleWidth: CGFloat = abs(_sizeBuffer[1].x - _sizeBuffer[0].x)
let maxBubbleHeight: CGFloat = abs(viewPortHandler.contentBottom - viewPortHandler.contentTop)
let referenceSize: CGFloat = min(maxBubbleHeight, maxBubbleWidth)
_pointBuffer.x = CGFloat(entry.xIndex - minx) * phaseX + CGFloat(minx)
_pointBuffer.y = CGFloat(entry.value) * phaseY
trans.pointValueToPixel(&_pointBuffer)
let shapeSize = getShapeSize(entrySize: entry.size, maxSize: dataSet.maxSize, reference: referenceSize)
let shapeHalf = shapeSize / 2.0
if (!viewPortHandler.isInBoundsTop(_pointBuffer.y + shapeHalf)
|| !viewPortHandler.isInBoundsBottom(_pointBuffer.y - shapeHalf))
{
continue
}
if (!viewPortHandler.isInBoundsLeft(_pointBuffer.x + shapeHalf))
{
continue
}
if (!viewPortHandler.isInBoundsRight(_pointBuffer.x - shapeHalf))
{
break
}
if (indice.xIndex < minx || indice.xIndex >= maxx)
{
continue
}
let originalColor = dataSet.colorAt(entry.xIndex)
var h: CGFloat = 0.0
var s: CGFloat = 0.0
var b: CGFloat = 0.0
var a: CGFloat = 0.0
originalColor.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
let color = NSUIColor(hue: h, saturation: s, brightness: b * 0.5, alpha: a)
let rect = CGRect(
x: _pointBuffer.x - shapeHalf,
y: _pointBuffer.y - shapeHalf,
width: shapeSize,
height: shapeSize)
CGContextSetLineWidth(context, dataSet.highlightCircleWidth)
CGContextSetStrokeColorWithColor(context, color.CGColor)
CGContextStrokeEllipseInRect(context, rect)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/CandleStickChartRenderer.swift
================================================
//
// CandleStickChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class CandleStickChartRenderer: LineScatterCandleRadarChartRenderer
{
public weak var dataProvider: CandleChartDataProvider?
public init(dataProvider: CandleChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.dataProvider = dataProvider
}
public override func drawData(context context: CGContext)
{
guard let dataProvider = dataProvider, candleData = dataProvider.candleData else { return }
for set in candleData.dataSets as! [ICandleChartDataSet]
{
if set.isVisible && set.entryCount > 0
{
drawDataSet(context: context, dataSet: set)
}
}
}
private var _shadowPoints = [CGPoint](count: 4, repeatedValue: CGPoint())
private var _rangePoints = [CGPoint](count: 2, repeatedValue: CGPoint())
private var _openPoints = [CGPoint](count: 2, repeatedValue: CGPoint())
private var _closePoints = [CGPoint](count: 2, repeatedValue: CGPoint())
private var _bodyRect = CGRect()
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
public func drawDataSet(context context: CGContext, dataSet: ICandleChartDataSet)
{
guard let
trans = dataProvider?.getTransformer(dataSet.axisDependency),
animator = animator
else { return }
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let barSpace = dataSet.barSpace
let showCandleBar = dataSet.showCandleBar
let entryCount = dataSet.entryCount
let minx = max(self.minX, 0)
let maxx = min(self.maxX + 1, entryCount)
CGContextSaveGState(context)
CGContextSetLineWidth(context, dataSet.shadowWidth)
for j in minx ..< Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
{
// get the entry
guard let e = dataSet.entryForIndex(j) as? CandleChartDataEntry else { continue }
let xIndex = e.xIndex
if (xIndex < minx || xIndex >= maxx)
{
continue
}
let open = e.open
let close = e.close
let high = e.high
let low = e.low
if (showCandleBar)
{
// calculate the shadow
_shadowPoints[0].x = CGFloat(xIndex)
_shadowPoints[1].x = CGFloat(xIndex)
_shadowPoints[2].x = CGFloat(xIndex)
_shadowPoints[3].x = CGFloat(xIndex)
if (open > close)
{
_shadowPoints[0].y = CGFloat(high) * phaseY
_shadowPoints[1].y = CGFloat(open) * phaseY
_shadowPoints[2].y = CGFloat(low) * phaseY
_shadowPoints[3].y = CGFloat(close) * phaseY
}
else if (open < close)
{
_shadowPoints[0].y = CGFloat(high) * phaseY
_shadowPoints[1].y = CGFloat(close) * phaseY
_shadowPoints[2].y = CGFloat(low) * phaseY
_shadowPoints[3].y = CGFloat(open) * phaseY
}
else
{
_shadowPoints[0].y = CGFloat(high) * phaseY
_shadowPoints[1].y = CGFloat(open) * phaseY
_shadowPoints[2].y = CGFloat(low) * phaseY
_shadowPoints[3].y = _shadowPoints[1].y
}
trans.pointValuesToPixel(&_shadowPoints)
// draw the shadows
var shadowColor: NSUIColor! = nil
if (dataSet.shadowColorSameAsCandle)
{
if (open > close)
{
shadowColor = dataSet.decreasingColor ?? dataSet.colorAt(j)
}
else if (open < close)
{
shadowColor = dataSet.increasingColor ?? dataSet.colorAt(j)
}
else
{
shadowColor = dataSet.neutralColor ?? dataSet.colorAt(j)
}
}
if (shadowColor === nil)
{
shadowColor = dataSet.shadowColor ?? dataSet.colorAt(j);
}
CGContextSetStrokeColorWithColor(context, shadowColor.CGColor)
CGContextStrokeLineSegments(context, _shadowPoints, 4)
// calculate the body
_bodyRect.origin.x = CGFloat(xIndex) - 0.5 + barSpace
_bodyRect.origin.y = CGFloat(close) * phaseY
_bodyRect.size.width = (CGFloat(xIndex) + 0.5 - barSpace) - _bodyRect.origin.x
_bodyRect.size.height = (CGFloat(open) * phaseY) - _bodyRect.origin.y
trans.rectValueToPixel(&_bodyRect)
// draw body differently for increasing and decreasing entry
if (open > close)
{
let color = dataSet.decreasingColor ?? dataSet.colorAt(j)
if (dataSet.isDecreasingFilled)
{
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, _bodyRect)
}
else
{
CGContextSetStrokeColorWithColor(context, color.CGColor)
CGContextStrokeRect(context, _bodyRect)
}
}
else if (open < close)
{
let color = dataSet.increasingColor ?? dataSet.colorAt(j)
if (dataSet.isIncreasingFilled)
{
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, _bodyRect)
}
else
{
CGContextSetStrokeColorWithColor(context, color.CGColor)
CGContextStrokeRect(context, _bodyRect)
}
}
else
{
let color = dataSet.neutralColor ?? dataSet.colorAt(j)
CGContextSetStrokeColorWithColor(context, color.CGColor)
CGContextStrokeRect(context, _bodyRect)
}
}
else
{
_rangePoints[0].x = CGFloat(xIndex)
_rangePoints[0].y = CGFloat(high) * phaseY
_rangePoints[1].x = CGFloat(xIndex)
_rangePoints[1].y = CGFloat(low) * phaseY
_openPoints[0].x = CGFloat(xIndex) - 0.5 + barSpace
_openPoints[0].y = CGFloat(open) * phaseY
_openPoints[1].x = CGFloat(xIndex)
_openPoints[1].y = CGFloat(open) * phaseY
_closePoints[0].x = CGFloat(xIndex) + 0.5 - barSpace
_closePoints[0].y = CGFloat(close) * phaseY
_closePoints[1].x = CGFloat(xIndex)
_closePoints[1].y = CGFloat(close) * phaseY
trans.pointValuesToPixel(&_rangePoints)
trans.pointValuesToPixel(&_openPoints)
trans.pointValuesToPixel(&_closePoints)
// draw the ranges
var barColor: NSUIColor! = nil
if (open > close)
{
barColor = dataSet.decreasingColor ?? dataSet.colorAt(j)
}
else if (open < close)
{
barColor = dataSet.increasingColor ?? dataSet.colorAt(j)
}
else
{
barColor = dataSet.neutralColor ?? dataSet.colorAt(j)
}
CGContextSetStrokeColorWithColor(context, barColor.CGColor)
CGContextStrokeLineSegments(context, _rangePoints, 2)
CGContextStrokeLineSegments(context, _openPoints, 2)
CGContextStrokeLineSegments(context, _closePoints, 2)
}
}
CGContextRestoreGState(context)
}
public override func drawValues(context context: CGContext)
{
guard let
dataProvider = dataProvider,
candleData = dataProvider.candleData,
animator = animator
else { return }
// if values are drawn
if (candleData.yValCount < Int(ceil(CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleX)))
{
var dataSets = candleData.dataSets
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< dataSets.count
{
let dataSet = dataSets[i]
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let entryCount = dataSet.entryCount
let minx = max(self.minX, 0)
let maxx = min(self.maxX + 1, entryCount)
let lineHeight = valueFont.lineHeight
let yOffset: CGFloat = lineHeight + 5.0
for j in minx ..< Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
{
guard let e = dataSet.entryForIndex(j) as? CandleChartDataEntry else { break }
pt.x = CGFloat(e.xIndex)
pt.y = CGFloat(e.high) * phaseY
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
ChartUtils.drawText(
context: context,
text: formatter.stringFromNumber(e.high)!,
point: CGPoint(
x: pt.x,
y: pt.y - yOffset),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)])
}
}
}
}
public override func drawExtras(context context: CGContext)
{
}
private var _highlightPointBuffer = CGPoint()
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
dataProvider = dataProvider,
candleData = dataProvider.candleData,
animator = animator
else { return }
CGContextSaveGState(context)
for i in 0 ..< indices.count
{
let xIndex = indices[i].xIndex; // get the x-position
guard let set = candleData.getDataSetByIndex(indices[i].dataSetIndex) as? ICandleChartDataSet else { continue }
if (!set.isHighlightEnabled)
{
continue
}
guard let e = set.entryForXIndex(xIndex) as? CandleChartDataEntry else { continue }
if e.xIndex != xIndex
{
continue
}
let trans = dataProvider.getTransformer(set.axisDependency)
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
CGContextSetLineWidth(context, set.highlightLineWidth)
if (set.highlightLineDashLengths != nil)
{
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let low = CGFloat(e.low) * animator.phaseY
let high = CGFloat(e.high) * animator.phaseY
let y = (low + high) / 2.0
_highlightPointBuffer.x = CGFloat(xIndex)
_highlightPointBuffer.y = y
trans.pointValueToPixel(&_highlightPointBuffer)
// draw the lines
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartAxisRendererBase.swift
================================================
//
// ChartAxisRendererBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartAxisRendererBase: ChartRendererBase
{
public var transformer: ChartTransformer!
public override init()
{
super.init()
}
public init(viewPortHandler: ChartViewPortHandler, transformer: ChartTransformer!)
{
super.init(viewPortHandler: viewPortHandler)
self.transformer = transformer
}
/// Draws the axis labels on the specified context
public func renderAxisLabels(context context: CGContext)
{
fatalError("renderAxisLabels() cannot be called on ChartAxisRendererBase")
}
/// Draws the grid lines belonging to the axis.
public func renderGridLines(context context: CGContext)
{
fatalError("renderGridLines() cannot be called on ChartAxisRendererBase")
}
/// Draws the line that goes alongside the axis.
public func renderAxisLine(context context: CGContext)
{
fatalError("renderAxisLine() cannot be called on ChartAxisRendererBase")
}
/// Draws the LimitLines associated with this axis to the screen.
public func renderLimitLines(context context: CGContext)
{
fatalError("renderLimitLines() cannot be called on ChartAxisRendererBase")
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartDataRendererBase.swift
================================================
//
// ChartDataRendererBase.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartDataRendererBase: ChartRendererBase
{
public var animator: ChartAnimator?
public init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(viewPortHandler: viewPortHandler)
self.animator = animator
}
public func drawData(context context: CGContext)
{
fatalError("drawData() cannot be called on ChartDataRendererBase")
}
public func drawValues(context context: CGContext)
{
fatalError("drawValues() cannot be called on ChartDataRendererBase")
}
public func drawExtras(context context: CGContext)
{
fatalError("drawExtras() cannot be called on ChartDataRendererBase")
}
/// Draws all highlight indicators for the values that are currently highlighted.
///
/// - parameter indices: the highlighted values
public func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
fatalError("drawHighlighted() cannot be called on ChartDataRendererBase")
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartLegendRenderer.swift
================================================
//
// ChartLegendRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartLegendRenderer: ChartRendererBase
{
/// the legend object this renderer renders
public var legend: ChartLegend?
public init(viewPortHandler: ChartViewPortHandler, legend: ChartLegend?)
{
super.init(viewPortHandler: viewPortHandler)
self.legend = legend
}
/// Prepares the legend and calculates all needed forms, labels and colors.
public func computeLegend(data: ChartData)
{
guard let legend = legend else { return }
if (!legend.isLegendCustom)
{
var labels = [String?]()
var colors = [NSUIColor?]()
// loop for building up the colors and labels used in the legend
for i in 0.. 1)
{
let width = labelns.boundingRectWithSize(labelMaxSize, options: .UsesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
if (width > viewPortHandler.offsetRight * 2.0
&& position.x + width > viewPortHandler.chartWidth)
{
position.x -= width / 2.0
}
}
else if (i == 0)
{ // avoid clipping of the first
let width = labelns.boundingRectWithSize(labelMaxSize, options: .UsesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
position.x += width / 2.0
}
}
drawLabel(context: context, label: label!, xIndex: i, x: position.x, y: pos, attributes: labelAttrs, constrainedToSize: labelMaxSize, anchor: anchor, angleRadians: labelRotationAngleRadians)
}
}
}
public func drawLabel(context context: CGContext, label: String, xIndex: Int, x: CGFloat, y: CGFloat, attributes: [String: NSObject], constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat)
{
guard let xAxis = xAxis else { return }
let formattedLabel = xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
ChartUtils.drawMultilineText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), attributes: attributes, constrainedToSize: constrainedToSize, anchor: anchor, angleRadians: angleRadians)
}
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderGridLines(context context: CGContext)
{
guard let xAxis = xAxis else { return }
if (!xAxis.isDrawGridLinesEnabled || !xAxis.isEnabled)
{
return
}
CGContextSaveGState(context)
CGContextSetShouldAntialias(context, xAxis.gridAntialiasEnabled)
CGContextSetStrokeColorWithColor(context, xAxis.gridColor.CGColor)
CGContextSetLineWidth(context, xAxis.gridLineWidth)
CGContextSetLineCap(context, xAxis.gridLineCap)
if (xAxis.gridLineDashLengths != nil)
{
CGContextSetLineDash(context, xAxis.gridLineDashPhase, xAxis.gridLineDashLengths, xAxis.gridLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in self.minX.stride(to: self.maxX, by: xAxis.axisLabelModulus)
{
position.x = CGFloat(i)
position.y = 0.0
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
if (position.x >= viewPortHandler.offsetLeft
&& position.x <= viewPortHandler.chartWidth)
{
_gridLineSegmentsBuffer[0].x = position.x
_gridLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_gridLineSegmentsBuffer[1].x = position.x
_gridLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
}
}
CGContextRestoreGState(context)
}
public override func renderLimitLines(context context: CGContext)
{
guard let xAxis = xAxis else { return }
var limitLines = xAxis.limitLines
if (limitLines.count == 0)
{
return
}
CGContextSaveGState(context)
let trans = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in 0 ..< limitLines.count
{
let l = limitLines[i]
if !l.isEnabled
{
continue
}
position.x = CGFloat(l.limit)
position.y = 0.0
position = CGPointApplyAffineTransform(position, trans)
renderLimitLineLine(context: context, limitLine: l, position: position)
renderLimitLineLabel(context: context, limitLine: l, position: position, yOffset: 2.0 + l.yOffset)
}
CGContextRestoreGState(context)
}
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public func renderLimitLineLine(context context: CGContext, limitLine: ChartLimitLine, position: CGPoint)
{
_limitLineSegmentsBuffer[0].x = position.x
_limitLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_limitLineSegmentsBuffer[1].x = position.x
_limitLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextSetStrokeColorWithColor(context, limitLine.lineColor.CGColor)
CGContextSetLineWidth(context, limitLine.lineWidth)
if (limitLine.lineDashLengths != nil)
{
CGContextSetLineDash(context, limitLine.lineDashPhase, limitLine.lineDashLengths!, limitLine.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
}
public func renderLimitLineLabel(context context: CGContext, limitLine: ChartLimitLine, position: CGPoint, yOffset: CGFloat)
{
let label = limitLine.label
// if drawing the limit-value label is enabled
if (label.characters.count > 0)
{
let labelLineHeight = limitLine.valueFont.lineHeight
let xOffset: CGFloat = limitLine.lineWidth + limitLine.xOffset
if (limitLine.labelPosition == .RightTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x + xOffset,
y: viewPortHandler.contentTop + yOffset),
align: .Left,
attributes: [NSFontAttributeName: limitLine.valueFont, NSForegroundColorAttributeName: limitLine.valueTextColor])
}
else if (limitLine.labelPosition == .RightBottom)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x + xOffset,
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
align: .Left,
attributes: [NSFontAttributeName: limitLine.valueFont, NSForegroundColorAttributeName: limitLine.valueTextColor])
}
else if (limitLine.labelPosition == .LeftTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x - xOffset,
y: viewPortHandler.contentTop + yOffset),
align: .Right,
attributes: [NSFontAttributeName: limitLine.valueFont, NSForegroundColorAttributeName: limitLine.valueTextColor])
}
else
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x - xOffset,
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
align: .Right,
attributes: [NSFontAttributeName: limitLine.valueFont, NSForegroundColorAttributeName: limitLine.valueTextColor])
}
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartXAxisRendererBarChart.swift
================================================
//
// ChartXAxisRendererBarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartXAxisRendererBarChart: ChartXAxisRenderer
{
public weak var chart: BarChartView?
public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!, chart: BarChartView)
{
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer)
self.chart = chart
}
/// draws the x-labels on the specified y-position
public override func drawLabels(context context: CGContext, pos: CGFloat, anchor: CGPoint)
{
guard let
xAxis = xAxis,
barData = chart?.data as? BarChartData
else { return }
let paraStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
paraStyle.alignment = .Center
let labelAttrs = [NSFontAttributeName: xAxis.labelFont,
NSForegroundColorAttributeName: xAxis.labelTextColor,
NSParagraphStyleAttributeName: paraStyle]
let labelRotationAngleRadians = xAxis.labelRotationAngle * ChartUtils.Math.FDEG2RAD
let step = barData.dataSetCount
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
var labelMaxSize = CGSize()
if (xAxis.isWordWrapEnabled)
{
labelMaxSize.width = xAxis.wordWrapWidthPercent * valueToPixelMatrix.a
}
for i in self.minX.stride(to: min(self.maxX + 1, xAxis.values.count), by: xAxis.axisLabelModulus)
{
let label = i >= 0 && i < xAxis.values.count ? xAxis.values[i] : nil
if (label == nil)
{
continue
}
position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace + barData.groupSpace / 2.0
position.y = 0.0
// consider groups (center label for each group)
if (step > 1)
{
position.x += (CGFloat(step) - 1.0) / 2.0
}
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
if (viewPortHandler.isInBoundsX(position.x))
{
if (xAxis.isAvoidFirstLastClippingEnabled)
{
// avoid clipping of the last
if (i == xAxis.values.count - 1)
{
let width = label!.sizeWithAttributes(labelAttrs).width
if (position.x + width / 2.0 > viewPortHandler.contentRight)
{
position.x = viewPortHandler.contentRight - (width / 2.0)
}
}
else if (i == 0)
{ // avoid clipping of the first
let width = label!.sizeWithAttributes(labelAttrs).width
if (position.x - width / 2.0 < viewPortHandler.contentLeft)
{
position.x = viewPortHandler.contentLeft + (width / 2.0)
}
}
}
drawLabel(context: context, label: label!, xIndex: i, x: position.x, y: pos, attributes: labelAttrs, constrainedToSize: labelMaxSize, anchor: anchor, angleRadians: labelRotationAngleRadians)
}
}
}
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderGridLines(context context: CGContext)
{
guard let
xAxis = xAxis,
barData = chart?.data as? BarChartData
else { return }
if (!xAxis.isDrawGridLinesEnabled || !xAxis.isEnabled)
{
return
}
let step = barData.dataSetCount
CGContextSaveGState(context)
CGContextSetShouldAntialias(context, xAxis.gridAntialiasEnabled)
CGContextSetStrokeColorWithColor(context, xAxis.gridColor.CGColor)
CGContextSetLineWidth(context, xAxis.gridLineWidth)
CGContextSetLineCap(context, xAxis.gridLineCap)
if (xAxis.gridLineDashLengths != nil)
{
CGContextSetLineDash(context, xAxis.gridLineDashPhase, xAxis.gridLineDashLengths, xAxis.gridLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in self.minX.stride(to: self.maxX, by: xAxis.axisLabelModulus)
{
position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace - 0.5
position.y = 0.0
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
if (viewPortHandler.isInBoundsX(position.x))
{
_gridLineSegmentsBuffer[0].x = position.x
_gridLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_gridLineSegmentsBuffer[1].x = position.x
_gridLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
}
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartXAxisRendererHorizontalBarChart.swift
================================================
//
// ChartXAxisRendererHorizontalBarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartXAxisRendererHorizontalBarChart: ChartXAxisRendererBarChart
{
public override init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!, chart: BarChartView)
{
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer, chart: chart)
}
public override func computeAxis(xValAverageLength xValAverageLength: Double, xValues: [String?])
{
guard let xAxis = xAxis else { return }
xAxis.values = xValues
let longest = xAxis.getLongestLabel() as NSString
let labelSize = longest.sizeWithAttributes([NSFontAttributeName: xAxis.labelFont])
let labelWidth = floor(labelSize.width + xAxis.xOffset * 3.5)
let labelHeight = labelSize.height
let labelRotatedSize = ChartUtils.sizeOfRotatedRectangle(rectangleWidth: labelSize.width, rectangleHeight: labelHeight, degrees: xAxis.labelRotationAngle)
xAxis.labelWidth = labelWidth
xAxis.labelHeight = labelHeight
xAxis.labelRotatedWidth = round(labelRotatedSize.width + xAxis.xOffset * 3.5)
xAxis.labelRotatedHeight = round(labelRotatedSize.height)
}
public override func renderAxisLabels(context context: CGContext)
{
guard let xAxis = xAxis else { return }
if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled || chart?.data === nil
{
return
}
let xoffset = xAxis.xOffset
if (xAxis.labelPosition == .Top)
{
drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
}
else if (xAxis.labelPosition == .TopInside)
{
drawLabels(context: context, pos: viewPortHandler.contentRight - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
}
else if (xAxis.labelPosition == .Bottom)
{
drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
}
else if (xAxis.labelPosition == .BottomInside)
{
drawLabels(context: context, pos: viewPortHandler.contentLeft + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
}
else
{ // BOTH SIDED
drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
}
}
/// draws the x-labels on the specified y-position
public override func drawLabels(context context: CGContext, pos: CGFloat, anchor: CGPoint)
{
guard let
xAxis = xAxis,
bd = chart?.data as? BarChartData
else { return }
let labelFont = xAxis.labelFont
let labelTextColor = xAxis.labelTextColor
let labelRotationAngleRadians = xAxis.labelRotationAngle * ChartUtils.Math.FDEG2RAD
// pre allocate to save performance (dont allocate in loop)
var position = CGPoint(x: 0.0, y: 0.0)
let step = bd.dataSetCount
for i in self.minX.stride(to: min(self.maxX + 1, xAxis.values.count), by: xAxis.axisLabelModulus)
{
let label = xAxis.values[i]
if (label == nil)
{
continue
}
position.x = 0.0
position.y = CGFloat(i * step) + CGFloat(i) * bd.groupSpace + bd.groupSpace / 2.0
// consider groups (center label for each group)
if (step > 1)
{
position.y += (CGFloat(step) - 1.0) / 2.0
}
transformer.pointValueToPixel(&position)
if (viewPortHandler.isInBoundsY(position.y))
{
drawLabel(context: context, label: label!, xIndex: i, x: pos, y: position.y, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor], anchor: anchor, angleRadians: labelRotationAngleRadians)
}
}
}
public func drawLabel(context context: CGContext, label: String, xIndex: Int, x: CGFloat, y: CGFloat, attributes: [String: NSObject], anchor: CGPoint, angleRadians: CGFloat)
{
guard let xAxis = xAxis else { return }
let formattedLabel = xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
ChartUtils.drawText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), attributes: attributes, anchor: anchor, angleRadians: angleRadians)
}
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderGridLines(context context: CGContext)
{
guard let
xAxis = xAxis,
bd = chart?.data as? BarChartData
else { return }
if !xAxis.isEnabled || !xAxis.isDrawGridLinesEnabled
{
return
}
CGContextSaveGState(context)
CGContextSetShouldAntialias(context, xAxis.gridAntialiasEnabled)
CGContextSetStrokeColorWithColor(context, xAxis.gridColor.CGColor)
CGContextSetLineWidth(context, xAxis.gridLineWidth)
CGContextSetLineCap(context, xAxis.gridLineCap)
if (xAxis.gridLineDashLengths != nil)
{
CGContextSetLineDash(context, xAxis.gridLineDashPhase, xAxis.gridLineDashLengths, xAxis.gridLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
var position = CGPoint(x: 0.0, y: 0.0)
// take into consideration that multiple DataSets increase _deltaX
let step = bd.dataSetCount
for i in self.minX.stride(to: min(self.maxX + 1, xAxis.values.count), by: xAxis.axisLabelModulus)
{
position.x = 0.0
position.y = CGFloat(i * step) + CGFloat(i) * bd.groupSpace - 0.5
transformer.pointValueToPixel(&position)
if (viewPortHandler.isInBoundsY(position.y))
{
_gridLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_gridLineSegmentsBuffer[0].y = position.y
_gridLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_gridLineSegmentsBuffer[1].y = position.y
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
}
}
CGContextRestoreGState(context)
}
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderAxisLine(context context: CGContext)
{
guard let xAxis = xAxis else { return }
if (!xAxis.isEnabled || !xAxis.isDrawAxisLineEnabled)
{
return
}
CGContextSaveGState(context)
CGContextSetStrokeColorWithColor(context, xAxis.axisLineColor.CGColor)
CGContextSetLineWidth(context, xAxis.axisLineWidth)
if (xAxis.axisLineDashLengths != nil)
{
CGContextSetLineDash(context, xAxis.axisLineDashPhase, xAxis.axisLineDashLengths, xAxis.axisLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
if (xAxis.labelPosition == .Top
|| xAxis.labelPosition == .TopInside
|| xAxis.labelPosition == .BothSided)
{
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentRight
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
}
if (xAxis.labelPosition == .Bottom
|| xAxis.labelPosition == .BottomInside
|| xAxis.labelPosition == .BothSided)
{
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentLeft
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
}
CGContextRestoreGState(context)
}
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderLimitLines(context context: CGContext)
{
guard let xAxis = xAxis else { return }
var limitLines = xAxis.limitLines
if (limitLines.count == 0)
{
return
}
CGContextSaveGState(context)
let trans = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in 0 ..< limitLines.count
{
let l = limitLines[i]
if !l.isEnabled
{
continue
}
position.x = 0.0
position.y = CGFloat(l.limit)
position = CGPointApplyAffineTransform(position, trans)
_limitLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_limitLineSegmentsBuffer[0].y = position.y
_limitLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_limitLineSegmentsBuffer[1].y = position.y
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
CGContextSetLineWidth(context, l.lineWidth)
if (l.lineDashLengths != nil)
{
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
let label = l.label
// if drawing the limit-value label is enabled
if (label.characters.count > 0)
{
let labelLineHeight = l.valueFont.lineHeight
let xOffset: CGFloat = 4.0 + l.xOffset
let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset
if (l.labelPosition == .RightTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentRight - xOffset,
y: position.y - yOffset),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .RightBottom)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentRight - xOffset,
y: position.y + yOffset - labelLineHeight),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .LeftTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentLeft + xOffset,
y: position.y - yOffset),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentLeft + xOffset,
y: position.y + yOffset - labelLineHeight),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
}
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartXAxisRendererRadarChart.swift
================================================
//
// ChartXAxisRendererRadarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartXAxisRendererRadarChart: ChartXAxisRenderer
{
public weak var chart: RadarChartView?
public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, chart: RadarChartView)
{
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: nil)
self.chart = chart
}
public override func renderAxisLabels(context context: CGContext)
{
guard let
xAxis = xAxis,
chart = chart
else { return }
if (!xAxis.isEnabled || !xAxis.isDrawLabelsEnabled)
{
return
}
let labelFont = xAxis.labelFont
let labelTextColor = xAxis.labelTextColor
let labelRotationAngleRadians = xAxis.labelRotationAngle * ChartUtils.Math.FDEG2RAD
let drawLabelAnchor = CGPoint(x: 0.5, y: 0.0)
let sliceangle = chart.sliceAngle
// calculate the factor that is needed for transforming the value to pixels
let factor = chart.factor
let center = chart.centerOffsets
let modulus = xAxis.axisLabelModulus
for i in 0.stride(to: xAxis.values.count, by: modulus)
{
let label = xAxis.values[i]
if (label == nil)
{
continue
}
let angle = (sliceangle * CGFloat(i) + chart.rotationAngle) % 360.0
let p = ChartUtils.getPosition(center: center, dist: CGFloat(chart.yRange) * factor + xAxis.labelRotatedWidth / 2.0, angle: angle)
drawLabel(context: context, label: label!, xIndex: i, x: p.x, y: p.y - xAxis.labelRotatedHeight / 2.0, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor], anchor: drawLabelAnchor, angleRadians: labelRotationAngleRadians)
}
}
public func drawLabel(context context: CGContext, label: String, xIndex: Int, x: CGFloat, y: CGFloat, attributes: [String: NSObject], anchor: CGPoint, angleRadians: CGFloat)
{
guard let xAxis = xAxis else { return }
let formattedLabel = xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
ChartUtils.drawText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), attributes: attributes, anchor: anchor, angleRadians: angleRadians)
}
public override func renderLimitLines(context context: CGContext)
{
/// XAxis LimitLines on RadarChart not yet supported.
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartYAxisRenderer.swift
================================================
//
// ChartYAxisRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartYAxisRenderer: ChartAxisRendererBase
{
public var yAxis: ChartYAxis?
public init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, transformer: ChartTransformer!)
{
super.init(viewPortHandler: viewPortHandler, transformer: transformer)
self.yAxis = yAxis
}
/// Computes the axis values.
public func computeAxis(yMin yMin: Double, yMax: Double)
{
guard let yAxis = yAxis else { return }
var yMin = yMin, yMax = yMax
// calculate the starting and entry point of the y-labels (depending on
// zoom / contentrect bounds)
if (viewPortHandler.contentWidth > 10.0 && !viewPortHandler.isFullyZoomedOutY)
{
let p1 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
let p2 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
if (!yAxis.isInverted)
{
yMin = Double(p2.y)
yMax = Double(p1.y)
}
else
{
yMin = Double(p1.y)
yMax = Double(p2.y)
}
}
computeAxisValues(min: yMin, max: yMax)
}
/// Sets up the y-axis labels. Computes the desired number of labels between
/// the two given extremes. Unlike the papareXLabels() method, this method
/// needs to be called upon every refresh of the view.
public func computeAxisValues(min min: Double, max: Double)
{
guard let yAxis = yAxis else { return }
let yMin = min
let yMax = max
let labelCount = yAxis.labelCount
let range = abs(yMax - yMin)
if (labelCount == 0 || range <= 0)
{
yAxis.entries = [Double]()
return
}
// Find out how much spacing (in y value space) between axis values
let rawInterval = range / Double(labelCount)
var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
// If granularity is enabled, then do not allow the interval to go below specified granularity.
// This is used to avoid repeated values when rounding values for display.
if yAxis.granularityEnabled
{
interval = interval < yAxis.granularity ? yAxis.granularity : interval
}
// Normalize interval
let intervalMagnitude = ChartUtils.roundToNextSignificant(number: pow(10.0, floor(log10(interval))))
let intervalSigDigit = (interval / intervalMagnitude)
if (intervalSigDigit > 5)
{
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
interval = floor(10.0 * intervalMagnitude)
}
// force label count
if yAxis.isForceLabelsEnabled
{
let step = Double(range) / Double(labelCount - 1)
if yAxis.entries.count < labelCount
{
// Ensure stops contains at least numStops elements.
yAxis.entries.removeAll(keepCapacity: true)
}
else
{
yAxis.entries = [Double]()
yAxis.entries.reserveCapacity(labelCount)
}
var v = yMin
for _ in 0 ..< labelCount
{
yAxis.entries.append(v)
v += step
}
}
else
{
// no forced count
// if the labels should only show min and max
if (yAxis.isShowOnlyMinMaxEnabled)
{
yAxis.entries = [yMin, yMax]
}
else
{
let first = ceil(Double(yMin) / interval) * interval
let last = ChartUtils.nextUp(floor(Double(yMax) / interval) * interval)
var n = 0
for _ in first.stride(through: last, by: interval)
{
n += 1
}
if (yAxis.entries.count < n)
{
// Ensure stops contains at least numStops elements.
yAxis.entries = [Double](count: n, repeatedValue: 0.0)
}
else if (yAxis.entries.count > n)
{
yAxis.entries.removeRange(n..= yAxis.entryCount - 1)
{
break
}
pt.x = 0
pt.y = CGFloat(yAxis.entries[i])
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
pt.x = fixedPosition
pt.y += offset
ChartUtils.drawText(context: context, text: text, point: pt, align: textAlign, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
}
}
private var _gridLineBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderGridLines(context context: CGContext)
{
guard let yAxis = yAxis else { return }
if !yAxis.isEnabled
{
return
}
if yAxis.drawGridLinesEnabled
{
CGContextSaveGState(context)
CGContextSetShouldAntialias(context, yAxis.gridAntialiasEnabled)
CGContextSetStrokeColorWithColor(context, yAxis.gridColor.CGColor)
CGContextSetLineWidth(context, yAxis.gridLineWidth)
CGContextSetLineCap(context, yAxis.gridLineCap)
if (yAxis.gridLineDashLengths != nil)
{
CGContextSetLineDash(context, yAxis.gridLineDashPhase, yAxis.gridLineDashLengths, yAxis.gridLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
// draw the horizontal grid
for i in 0 ..< yAxis.entryCount
{
position.x = 0.0
position.y = CGFloat(yAxis.entries[i])
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
_gridLineBuffer[0].x = viewPortHandler.contentLeft
_gridLineBuffer[0].y = position.y
_gridLineBuffer[1].x = viewPortHandler.contentRight
_gridLineBuffer[1].y = position.y
CGContextStrokeLineSegments(context, _gridLineBuffer, 2)
}
CGContextRestoreGState(context)
}
if yAxis.drawZeroLineEnabled
{
// draw zero line
var position = CGPoint(x: 0.0, y: 0.0)
transformer.pointValueToPixel(&position)
drawZeroLine(context: context,
x1: viewPortHandler.contentLeft,
x2: viewPortHandler.contentRight,
y1: position.y,
y2: position.y);
}
}
/// Draws the zero line at the specified position.
public func drawZeroLine(
context context: CGContext,
x1: CGFloat,
x2: CGFloat,
y1: CGFloat,
y2: CGFloat)
{
guard let
yAxis = yAxis,
zeroLineColor = yAxis.zeroLineColor
else { return }
CGContextSaveGState(context)
CGContextSetStrokeColorWithColor(context, zeroLineColor.CGColor)
CGContextSetLineWidth(context, yAxis.zeroLineWidth)
if (yAxis.zeroLineDashLengths != nil)
{
CGContextSetLineDash(context, yAxis.zeroLineDashPhase, yAxis.zeroLineDashLengths!, yAxis.zeroLineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
CGContextMoveToPoint(context, x1, y1)
CGContextAddLineToPoint(context, x2, y2)
CGContextDrawPath(context, CGPathDrawingMode.Stroke)
CGContextRestoreGState(context)
}
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderLimitLines(context context: CGContext)
{
guard let yAxis = yAxis else { return }
var limitLines = yAxis.limitLines
if (limitLines.count == 0)
{
return
}
CGContextSaveGState(context)
let trans = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in 0 ..< limitLines.count
{
let l = limitLines[i]
if !l.isEnabled
{
continue
}
position.x = 0.0
position.y = CGFloat(l.limit)
position = CGPointApplyAffineTransform(position, trans)
_limitLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_limitLineSegmentsBuffer[0].y = position.y
_limitLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_limitLineSegmentsBuffer[1].y = position.y
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
CGContextSetLineWidth(context, l.lineWidth)
if (l.lineDashLengths != nil)
{
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
let label = l.label
// if drawing the limit-value label is enabled
if (label.characters.count > 0)
{
let labelLineHeight = l.valueFont.lineHeight
let xOffset: CGFloat = 4.0 + l.xOffset
let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset
if (l.labelPosition == .RightTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentRight - xOffset,
y: position.y - yOffset),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .RightBottom)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentRight - xOffset,
y: position.y + yOffset - labelLineHeight),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .LeftTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentLeft + xOffset,
y: position.y - yOffset),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: viewPortHandler.contentLeft + xOffset,
y: position.y + yOffset - labelLineHeight),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
}
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartYAxisRendererHorizontalBarChart.swift
================================================
//
// ChartYAxisRendererHorizontalBarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartYAxisRendererHorizontalBarChart: ChartYAxisRenderer
{
public override init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, transformer: ChartTransformer!)
{
super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: transformer)
}
/// Computes the axis values.
public override func computeAxis(yMin yMin: Double, yMax: Double)
{
guard let yAxis = yAxis else { return }
var yMin = yMin, yMax = yMax
// calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds)
if (viewPortHandler.contentHeight > 10.0 && !viewPortHandler.isFullyZoomedOutX)
{
let p1 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
let p2 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
if (!yAxis.isInverted)
{
yMin = Double(p1.x)
yMax = Double(p2.x)
}
else
{
yMin = Double(p2.x)
yMax = Double(p1.x)
}
}
computeAxisValues(min: yMin, max: yMax)
}
/// draws the y-axis labels to the screen
public override func renderAxisLabels(context context: CGContext)
{
guard let yAxis = yAxis else { return }
if (!yAxis.isEnabled || !yAxis.isDrawLabelsEnabled)
{
return
}
var positions = [CGPoint]()
positions.reserveCapacity(yAxis.entries.count)
for i in 0 ..< yAxis.entries.count
{
positions.append(CGPoint(x: CGFloat(yAxis.entries[i]), y: 0.0))
}
transformer.pointValuesToPixel(&positions)
let lineHeight = yAxis.labelFont.lineHeight
let baseYOffset: CGFloat = 2.5
let dependency = yAxis.axisDependency
let labelPosition = yAxis.labelPosition
var yPos: CGFloat = 0.0
if (dependency == .Left)
{
if (labelPosition == .OutsideChart)
{
yPos = viewPortHandler.contentTop - baseYOffset
}
else
{
yPos = viewPortHandler.contentTop - baseYOffset
}
}
else
{
if (labelPosition == .OutsideChart)
{
yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
}
else
{
yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
}
}
// For compatibility with Android code, we keep above calculation the same,
// And here we pull the line back up
yPos -= lineHeight
drawYLabels(context: context, fixedPosition: yPos, positions: positions, offset: yAxis.yOffset)
}
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderAxisLine(context context: CGContext)
{
guard let yAxis = yAxis else { return }
if (!yAxis.isEnabled || !yAxis.drawAxisLineEnabled)
{
return
}
CGContextSaveGState(context)
CGContextSetStrokeColorWithColor(context, yAxis.axisLineColor.CGColor)
CGContextSetLineWidth(context, yAxis.axisLineWidth)
if (yAxis.axisLineDashLengths != nil)
{
CGContextSetLineDash(context, yAxis.axisLineDashPhase, yAxis.axisLineDashLengths, yAxis.axisLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
if (yAxis.axisDependency == .Left)
{
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
}
else
{
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
}
CGContextRestoreGState(context)
}
/// draws the y-labels on the specified x-position
public func drawYLabels(context context: CGContext, fixedPosition: CGFloat, positions: [CGPoint], offset: CGFloat)
{
guard let yAxis = yAxis else { return }
let labelFont = yAxis.labelFont
let labelTextColor = yAxis.labelTextColor
for i in 0 ..< yAxis.entryCount
{
let text = yAxis.getFormattedLabel(i)
if (!yAxis.isDrawTopYLabelEntryEnabled && i >= yAxis.entryCount - 1)
{
return
}
ChartUtils.drawText(context: context, text: text, point: CGPoint(x: positions[i].x, y: fixedPosition - offset), align: .Center, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
}
}
public override func renderGridLines(context context: CGContext)
{
guard let yAxis = yAxis else { return }
if !yAxis.isEnabled
{
return
}
if yAxis.isDrawGridLinesEnabled
{
CGContextSaveGState(context)
// pre alloc
var position = CGPoint()
CGContextSetShouldAntialias(context, yAxis.gridAntialiasEnabled)
CGContextSetStrokeColorWithColor(context, yAxis.gridColor.CGColor)
CGContextSetLineWidth(context, yAxis.gridLineWidth)
CGContextSetLineCap(context, yAxis.gridLineCap)
if (yAxis.gridLineDashLengths != nil)
{
CGContextSetLineDash(context, yAxis.gridLineDashPhase, yAxis.gridLineDashLengths, yAxis.gridLineDashLengths.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
// draw the horizontal grid
for i in 0 ..< yAxis.entryCount
{
position.x = CGFloat(yAxis.entries[i])
position.y = 0.0
transformer.pointValueToPixel(&position)
CGContextBeginPath(context)
CGContextMoveToPoint(context, position.x, viewPortHandler.contentTop)
CGContextAddLineToPoint(context, position.x, viewPortHandler.contentBottom)
CGContextStrokePath(context)
}
CGContextRestoreGState(context)
}
if yAxis.drawZeroLineEnabled
{
// draw zero line
var position = CGPoint(x: 0.0, y: 0.0)
transformer.pointValueToPixel(&position)
drawZeroLine(context: context,
x1: position.x,
x2: position.x,
y1: viewPortHandler.contentTop,
y2: viewPortHandler.contentBottom);
}
}
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public override func renderLimitLines(context context: CGContext)
{
guard let yAxis = yAxis else { return }
var limitLines = yAxis.limitLines
if (limitLines.count <= 0)
{
return
}
CGContextSaveGState(context)
let trans = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
for i in 0 ..< limitLines.count
{
let l = limitLines[i]
if !l.isEnabled
{
continue
}
position.x = CGFloat(l.limit)
position.y = 0.0
position = CGPointApplyAffineTransform(position, trans)
_limitLineSegmentsBuffer[0].x = position.x
_limitLineSegmentsBuffer[0].y = viewPortHandler.contentTop
_limitLineSegmentsBuffer[1].x = position.x
_limitLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
CGContextSetLineWidth(context, l.lineWidth)
if (l.lineDashLengths != nil)
{
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
let label = l.label
// if drawing the limit-value label is enabled
if (label.characters.count > 0)
{
let labelLineHeight = l.valueFont.lineHeight
let xOffset: CGFloat = l.lineWidth + l.xOffset
let yOffset: CGFloat = 2.0 + l.yOffset
if (l.labelPosition == .RightTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x + xOffset,
y: viewPortHandler.contentTop + yOffset),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .RightBottom)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x + xOffset,
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
align: .Left,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else if (l.labelPosition == .LeftTop)
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x - xOffset,
y: viewPortHandler.contentTop + yOffset),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
else
{
ChartUtils.drawText(context: context,
text: label,
point: CGPoint(
x: position.x - xOffset,
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
align: .Right,
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
}
}
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ChartYAxisRendererRadarChart.swift
================================================
//
// ChartYAxisRendererRadarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 3/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartYAxisRendererRadarChart: ChartYAxisRenderer
{
private weak var chart: RadarChartView?
public init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, chart: RadarChartView)
{
super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: nil)
self.chart = chart
}
public override func computeAxis(yMin yMin: Double, yMax: Double)
{
computeAxisValues(min: yMin, max: yMax)
}
public override func computeAxisValues(min yMin: Double, max yMax: Double)
{
guard let yAxis = yAxis else { return }
let labelCount = yAxis.labelCount
let range = abs(yMax - yMin)
if (labelCount == 0 || range <= 0)
{
yAxis.entries = [Double]()
return
}
let rawInterval = range / Double(labelCount)
var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
let intervalMagnitude = pow(10.0, round(log10(interval)))
let intervalSigDigit = Int(interval / intervalMagnitude)
if (intervalSigDigit > 5)
{
// Use one order of magnitude higher, to avoid intervals like 0.9 or
// 90
interval = floor(10 * intervalMagnitude)
}
// force label count
if yAxis.isForceLabelsEnabled
{
let step = Double(range) / Double(labelCount - 1)
if yAxis.entries.count < labelCount
{
// Ensure stops contains at least numStops elements.
yAxis.entries.removeAll(keepCapacity: true)
}
else
{
yAxis.entries = [Double]()
yAxis.entries.reserveCapacity(labelCount)
}
var v = yMin
for _ in 0 ..< labelCount
{
yAxis.entries.append(v)
v += step
}
}
else
{
// no forced count
// clean old values
if (yAxis.entries.count > 0)
{
yAxis.entries.removeAll(keepCapacity: false)
}
// if the labels should only show min and max
if (yAxis.isShowOnlyMinMaxEnabled)
{
yAxis.entries = [Double]()
yAxis.entries.append(yMin)
yAxis.entries.append(yMax)
}
else
{
let rawCount = Double(yMin) / interval
var first = rawCount < 0.0 ? floor(rawCount) * interval : ceil(rawCount) * interval;
if (first == 0.0)
{ // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
first = 0.0
}
let last = ChartUtils.nextUp(floor(Double(yMax) / interval) * interval)
var n = 0
for _ in first.stride(through: last, by: interval)
{
n += 1
}
if !yAxis.isAxisMaxCustom
{
n += 1
}
if (yAxis.entries.count < n)
{
// Ensure stops contains at least numStops elements.
yAxis.entries = [Double](count: n, repeatedValue: 0.0)
}
var f = first
var i = 0
while (i < n)
{
yAxis.entries[i] = Double(f)
f += interval
i += 1
}
}
}
if yAxis.entries[0] < yMin
{
// If startAtZero is disabled, and the first label is lower that the axis minimum,
// Then adjust the axis minimum
yAxis._axisMinimum = yAxis.entries[0]
}
yAxis._axisMaximum = yAxis.entries[yAxis.entryCount - 1]
yAxis.axisRange = abs(yAxis._axisMaximum - yAxis._axisMinimum)
}
public override func renderAxisLabels(context context: CGContext)
{
guard let
yAxis = yAxis,
chart = chart
else { return }
if (!yAxis.isEnabled || !yAxis.isDrawLabelsEnabled)
{
return
}
let labelFont = yAxis.labelFont
let labelTextColor = yAxis.labelTextColor
let center = chart.centerOffsets
let factor = chart.factor
let labelCount = yAxis.entryCount
let labelLineHeight = yAxis.labelFont.lineHeight
for j in 0 ..< labelCount
{
if (j == labelCount - 1 && yAxis.isDrawTopYLabelEntryEnabled == false)
{
break
}
let r = CGFloat(yAxis.entries[j] - yAxis._axisMinimum) * factor
let p = ChartUtils.getPosition(center: center, dist: r, angle: chart.rotationAngle)
let label = yAxis.getFormattedLabel(j)
ChartUtils.drawText(context: context, text: label, point: CGPoint(x: p.x + 10.0, y: p.y - labelLineHeight), align: .Left, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
}
}
public override func renderLimitLines(context context: CGContext)
{
guard let
yAxis = yAxis,
chart = chart
else { return }
var limitLines = yAxis.limitLines
if (limitLines.count == 0)
{
return
}
CGContextSaveGState(context)
let sliceangle = chart.sliceAngle
// calculate the factor that is needed for transforming the value to pixels
let factor = chart.factor
let center = chart.centerOffsets
for i in 0 ..< limitLines.count
{
let l = limitLines[i]
if !l.isEnabled
{
continue
}
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
CGContextSetLineWidth(context, l.lineWidth)
if (l.lineDashLengths != nil)
{
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let r = CGFloat(l.limit - chart.chartYMin) * factor
CGContextBeginPath(context)
for j in 0 ..< chart.data!.xValCount
{
let p = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(j) + chart.rotationAngle)
if (j == 0)
{
CGContextMoveToPoint(context, p.x, p.y)
}
else
{
CGContextAddLineToPoint(context, p.x, p.y)
}
}
CGContextClosePath(context)
CGContextStrokePath(context)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/CombinedChartRenderer.swift
================================================
//
// CombinedChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class CombinedChartRenderer: ChartDataRendererBase
{
public weak var chart: CombinedChartView?
/// flag that enables or disables the highlighting arrow
public var drawHighlightArrowEnabled = false
/// if set to true, all values are drawn above their bars, instead of below their top
public var drawValueAboveBarEnabled = true
/// if set to true, a grey area is drawn behind each bar that indicates the maximum value
public var drawBarShadowEnabled = true
internal var _renderers = [ChartDataRendererBase]()
internal var _drawOrder: [CombinedChartView.CombinedChartDrawOrder] = [.Bar, .Bubble, .Line, .Candle, .Scatter]
public init(chart: CombinedChartView, animator: ChartAnimator, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.chart = chart
createRenderers()
}
/// Creates the renderers needed for this combined-renderer in the required order. Also takes the DrawOrder into consideration.
internal func createRenderers()
{
_renderers = [ChartDataRendererBase]()
guard let
chart = chart,
animator = animator
else { return }
for order in drawOrder
{
switch (order)
{
case .Bar:
if (chart.barData !== nil)
{
_renderers.append(BarChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
}
break
case .Line:
if (chart.lineData !== nil)
{
_renderers.append(LineChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
}
break
case .Candle:
if (chart.candleData !== nil)
{
_renderers.append(CandleStickChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
}
break
case .Scatter:
if (chart.scatterData !== nil)
{
_renderers.append(ScatterChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
}
break
case .Bubble:
if (chart.bubbleData !== nil)
{
_renderers.append(BubbleChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
}
break
}
}
}
public override func drawData(context context: CGContext)
{
for renderer in _renderers
{
renderer.drawData(context: context)
}
}
public override func drawValues(context context: CGContext)
{
for renderer in _renderers
{
renderer.drawValues(context: context)
}
}
public override func drawExtras(context context: CGContext)
{
for renderer in _renderers
{
renderer.drawExtras(context: context)
}
}
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
for renderer in _renderers
{
renderer.drawHighlighted(context: context, indices: indices)
}
}
public override func calcXBounds(chart chart: BarLineChartViewBase, xAxisModulus: Int)
{
for renderer in _renderers
{
renderer.calcXBounds(chart: chart, xAxisModulus: xAxisModulus)
}
}
/// - returns: the sub-renderer object at the specified index.
public func getSubRenderer(index index: Int) -> ChartDataRendererBase?
{
if (index >= _renderers.count || index < 0)
{
return nil
}
else
{
return _renderers[index]
}
}
/// Returns all sub-renderers.
public var subRenderers: [ChartDataRendererBase]
{
get { return _renderers }
set { _renderers = newValue }
}
// MARK: Accessors
/// - returns: true if drawing the highlighting arrow is enabled, false if not
public var isDrawHighlightArrowEnabled: Bool { return drawHighlightArrowEnabled; }
/// - returns: true if drawing values above bars is enabled, false if not
public var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled; }
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
public var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled; }
/// the order in which the provided data objects should be drawn.
/// The earlier you place them in the provided array, the further they will be in the background.
/// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
public var drawOrder: [CombinedChartView.CombinedChartDrawOrder]
{
get
{
return _drawOrder
}
set
{
if (newValue.count > 0)
{
_drawOrder = newValue
}
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/HorizontalBarChartRenderer.swift
================================================
//
// HorizontalBarChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class HorizontalBarChartRenderer: BarChartRenderer
{
public override init(dataProvider: BarChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(dataProvider: dataProvider, animator: animator, viewPortHandler: viewPortHandler)
}
public override func drawDataSet(context context: CGContext, dataSet: IBarChartDataSet, index: Int)
{
guard let
dataProvider = dataProvider,
barData = dataProvider.barData,
animator = animator
else { return }
CGContextSaveGState(context)
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let drawBarShadowEnabled: Bool = dataProvider.isDrawBarShadowEnabled
let dataSetOffset = (barData.dataSetCount - 1)
let groupSpace = barData.groupSpace
let groupSpaceHalf = groupSpace / 2.0
let barSpace = dataSet.barSpace
let barSpaceHalf = barSpace / 2.0
let containsStacks = dataSet.isStacked
let isInverted = dataProvider.isInverted(dataSet.axisDependency)
let barWidth: CGFloat = 0.5
let phaseY = animator.phaseY
var barRect = CGRect()
var barShadow = CGRect()
var y: Double
// do the drawing
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
// calculate the x-position, depending on datasetcount
let x = CGFloat(e.xIndex + e.xIndex * dataSetOffset) + CGFloat(index)
+ groupSpace * CGFloat(e.xIndex) + groupSpaceHalf
let values = e.values
if (!containsStacks || values == nil)
{
y = e.value
let bottom = x - barWidth + barSpaceHalf
let top = x + barWidth - barSpaceHalf
var right = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
var left = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
// multiply the height of the rect with the phase
if (right > 0)
{
right *= phaseY
}
else
{
left *= phaseY
}
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
{
continue
}
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
{
break
}
// if drawing the bar shadow is enabled
if (drawBarShadowEnabled)
{
barShadow.origin.x = viewPortHandler.contentLeft
barShadow.origin.y = barRect.origin.y
barShadow.size.width = viewPortHandler.contentWidth
barShadow.size.height = barRect.size.height
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
CGContextFillRect(context, barShadow)
}
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
CGContextFillRect(context, barRect)
}
else
{
let vals = values!
var posY = 0.0
var negY = -e.negativeSum
var yStart = 0.0
// if drawing the bar shadow is enabled
if (drawBarShadowEnabled)
{
y = e.value
let bottom = x - barWidth + barSpaceHalf
let top = x + barWidth - barSpaceHalf
var right = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
var left = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
// multiply the height of the rect with the phase
if (right > 0)
{
right *= phaseY
}
else
{
left *= phaseY
}
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
barShadow.origin.x = viewPortHandler.contentLeft
barShadow.origin.y = barRect.origin.y
barShadow.size.width = viewPortHandler.contentWidth
barShadow.size.height = barRect.size.height
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
CGContextFillRect(context, barShadow)
}
// fill the stack
for k in 0 ..< vals.count
{
let value = vals[k]
if value >= 0.0
{
y = posY
yStart = posY + value
posY = yStart
}
else
{
y = negY
yStart = negY + abs(value)
negY += abs(value)
}
let bottom = x - barWidth + barSpaceHalf
let top = x + barWidth - barSpaceHalf
var right: CGFloat, left: CGFloat
if isInverted
{
left = y >= yStart ? CGFloat(y) : CGFloat(yStart)
right = y <= yStart ? CGFloat(y) : CGFloat(yStart)
}
else
{
right = y >= yStart ? CGFloat(y) : CGFloat(yStart)
left = y <= yStart ? CGFloat(y) : CGFloat(yStart)
}
// multiply the height of the rect with the phase
right *= phaseY
left *= phaseY
barRect.origin.x = left
barRect.size.width = right - left
barRect.origin.y = top
barRect.size.height = bottom - top
trans.rectValueToPixel(&barRect)
if (k == 0 && !viewPortHandler.isInBoundsTop(barRect.origin.y + barRect.size.height))
{
// Skip to next bar
break
}
// avoid drawing outofbounds values
if (!viewPortHandler.isInBoundsBottom(barRect.origin.y))
{
break
}
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
CGContextSetFillColorWithColor(context, dataSet.colorAt(k).CGColor)
CGContextFillRect(context, barRect)
}
}
}
CGContextRestoreGState(context)
}
public override func prepareBarHighlight(x x: CGFloat, y1: Double, y2: Double, barspacehalf: CGFloat, trans: ChartTransformer, inout rect: CGRect)
{
let barWidth: CGFloat = 0.5
let top = x - barWidth + barspacehalf
let bottom = x + barWidth - barspacehalf
let left = CGFloat(y1)
let right = CGFloat(y2)
rect.origin.x = left
rect.origin.y = top
rect.size.width = right - left
rect.size.height = bottom - top
trans.rectValueToPixelHorizontal(&rect, phaseY: animator?.phaseY ?? 1.0)
}
public override func drawValues(context context: CGContext)
{
// if values are drawn
if (passesCheck())
{
guard let
dataProvider = dataProvider,
barData = dataProvider.barData,
animator = animator
else { return }
var dataSets = barData.dataSets
let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled
let textAlign = NSTextAlignment.Left
let valueOffsetPlus: CGFloat = 5.0
var posOffset: CGFloat
var negOffset: CGFloat
for dataSetIndex in 0 ..< barData.dataSetCount
{
guard let dataSet = dataSets[dataSetIndex] as? IBarChartDataSet else { continue }
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let isInverted = dataProvider.isInverted(dataSet.axisDependency)
let valueFont = dataSet.valueFont
let yOffset = -valueFont.lineHeight / 2.0
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let phaseY = animator.phaseY
let dataSetCount = barData.dataSetCount
let groupSpace = barData.groupSpace
// if only single values are drawn (sum)
if (!dataSet.isStacked)
{
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
let valuePoint = trans.getTransformedValueHorizontalBarChart(entry: e, xIndex: e.xIndex, dataSetIndex: dataSetIndex, phaseY: phaseY, dataSetCount: dataSetCount, groupSpace: groupSpace)
if (!viewPortHandler.isInBoundsTop(valuePoint.y))
{
break
}
if (!viewPortHandler.isInBoundsX(valuePoint.x))
{
continue
}
if (!viewPortHandler.isInBoundsBottom(valuePoint.y))
{
continue
}
let val = e.value
let valueText = formatter.stringFromNumber(val)!
// calculate the correct offset depending on the draw position of the value
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
if (isInverted)
{
posOffset = -posOffset - valueTextWidth
negOffset = -negOffset - valueTextWidth
}
drawValue(
context: context,
value: valueText,
xPos: valuePoint.x + (val >= 0.0 ? posOffset : negOffset),
yPos: valuePoint.y + yOffset,
font: valueFont,
align: textAlign,
color: dataSet.valueTextColorAt(j))
}
}
else
{
// if each value of a potential stack should be drawn
for j in 0 ..< Int(ceil(CGFloat(dataSet.entryCount) * animator.phaseX))
{
guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
let valuePoint = trans.getTransformedValueHorizontalBarChart(entry: e, xIndex: e.xIndex, dataSetIndex: dataSetIndex, phaseY: phaseY, dataSetCount: dataSetCount, groupSpace: groupSpace)
let values = e.values
// we still draw stacked bars, but there is one non-stacked in between
if (values == nil)
{
if (!viewPortHandler.isInBoundsTop(valuePoint.y))
{
break
}
if (!viewPortHandler.isInBoundsX(valuePoint.x))
{
continue
}
if (!viewPortHandler.isInBoundsBottom(valuePoint.y))
{
continue
}
let val = e.value
let valueText = formatter.stringFromNumber(val)!
// calculate the correct offset depending on the draw position of the value
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
if (isInverted)
{
posOffset = -posOffset - valueTextWidth
negOffset = -negOffset - valueTextWidth
}
drawValue(
context: context,
value: valueText,
xPos: valuePoint.x + (val >= 0.0 ? posOffset : negOffset),
yPos: valuePoint.y + yOffset,
font: valueFont,
align: textAlign,
color: dataSet.valueTextColorAt(j))
}
else
{
let vals = values!
var transformed = [CGPoint]()
var posY = 0.0
var negY = -e.negativeSum
for k in 0 ..< vals.count
{
let value = vals[k]
var y: Double
if value >= 0.0
{
posY += value
y = posY
}
else
{
y = negY
negY -= value
}
transformed.append(CGPoint(x: CGFloat(y) * animator.phaseY, y: 0.0))
}
trans.pointValuesToPixel(&transformed)
for k in 0 ..< transformed.count
{
let val = vals[k]
let valueText = formatter.stringFromNumber(val)!
// calculate the correct offset depending on the draw position of the value
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
if (isInverted)
{
posOffset = -posOffset - valueTextWidth
negOffset = -negOffset - valueTextWidth
}
let x = transformed[k].x + (val >= 0 ? posOffset : negOffset)
let y = valuePoint.y
if (!viewPortHandler.isInBoundsTop(y))
{
break
}
if (!viewPortHandler.isInBoundsX(x))
{
continue
}
if (!viewPortHandler.isInBoundsBottom(y))
{
continue
}
drawValue(context: context,
value: valueText,
xPos: x,
yPos: y + yOffset,
font: valueFont,
align: textAlign,
color: dataSet.valueTextColorAt(j))
}
}
}
}
}
}
}
internal override func passesCheck() -> Bool
{
guard let dataProvider = dataProvider, barData = dataProvider.barData else { return false }
return CGFloat(barData.yValCount) < CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleY
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/LineChartRenderer.swift
================================================
//
// LineChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class LineChartRenderer: LineRadarChartRenderer
{
public weak var dataProvider: LineChartDataProvider?
public init(dataProvider: LineChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.dataProvider = dataProvider
}
public override func drawData(context context: CGContext)
{
guard let lineData = dataProvider?.lineData else { return }
for i in 0 ..< lineData.dataSetCount
{
guard let set = lineData.getDataSetByIndex(i) else { continue }
if set.isVisible
{
if !(set is ILineChartDataSet)
{
fatalError("Datasets for LineChartRenderer must conform to ILineChartDataSet")
}
drawDataSet(context: context, dataSet: set as! ILineChartDataSet)
}
}
}
public func drawDataSet(context context: CGContext, dataSet: ILineChartDataSet)
{
let entryCount = dataSet.entryCount
if (entryCount < 1)
{
return
}
CGContextSaveGState(context)
CGContextSetLineWidth(context, dataSet.lineWidth)
if (dataSet.lineDashLengths != nil)
{
CGContextSetLineDash(context, dataSet.lineDashPhase, dataSet.lineDashLengths!, dataSet.lineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
// if drawing cubic lines is enabled
if (dataSet.isDrawCubicEnabled)
{
drawCubic(context: context, dataSet: dataSet)
}
else
{ // draw normal (straight) lines
drawLinear(context: context, dataSet: dataSet)
}
CGContextRestoreGState(context)
}
public func drawCubic(context context: CGContext, dataSet: ILineChartDataSet)
{
guard let
trans = dataProvider?.getTransformer(dataSet.axisDependency),
animator = animator
else { return }
let entryCount = dataSet.entryCount
guard let
entryFrom = dataSet.entryForXIndex(self.minX < 0 ? self.minX : 0, rounding: .Down),
entryTo = dataSet.entryForXIndex(self.maxX, rounding: .Up)
else { return }
let diff = (entryFrom == entryTo) ? 1 : 0
let minx = max(dataSet.entryIndex(entry: entryFrom) - diff - 1, 0)
let maxx = min(max(minx + 2, dataSet.entryIndex(entry: entryTo) + 1), entryCount)
let phaseX = animator.phaseX
let phaseY = animator.phaseY
// get the color that is specified for this position from the DataSet
let drawingColor = dataSet.colors.first!
let intensity = dataSet.cubicIntensity
// the path for the cubic-spline
let cubicPath = CGPathCreateMutable()
var valueToPixelMatrix = trans.valueToPixelMatrix
let size = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
if (size - minx >= 2)
{
var prevDx: CGFloat = 0.0
var prevDy: CGFloat = 0.0
var curDx: CGFloat = 0.0
var curDy: CGFloat = 0.0
var prevPrev: ChartDataEntry! = dataSet.entryForIndex(minx)
var prev: ChartDataEntry! = prevPrev
var cur: ChartDataEntry! = prev
var next: ChartDataEntry! = dataSet.entryForIndex(minx + 1)
if cur == nil || next == nil { return }
// let the spline start
CGPathMoveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
for j in minx + 1 ..< min(size, entryCount - 1)
{
prevPrev = prev
prev = cur
cur = next
next = dataSet.entryForIndex(j + 1)
if next == nil { break }
prevDx = CGFloat(cur.xIndex - prevPrev.xIndex) * intensity
prevDy = CGFloat(cur.value - prevPrev.value) * intensity
curDx = CGFloat(next.xIndex - prev.xIndex) * intensity
curDy = CGFloat(next.value - prev.value) * intensity
CGPathAddCurveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(prev.xIndex) + prevDx, (CGFloat(prev.value) + prevDy) * phaseY,
CGFloat(cur.xIndex) - curDx,
(CGFloat(cur.value) - curDy) * phaseY, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
}
if (size > entryCount - 1)
{
prevPrev = dataSet.entryForIndex(entryCount - (entryCount >= 3 ? 3 : 2))
prev = dataSet.entryForIndex(entryCount - 2)
cur = dataSet.entryForIndex(entryCount - 1)
next = cur
if prevPrev == nil || prev == nil || cur == nil { return }
prevDx = CGFloat(cur.xIndex - prevPrev.xIndex) * intensity
prevDy = CGFloat(cur.value - prevPrev.value) * intensity
curDx = CGFloat(next.xIndex - prev.xIndex) * intensity
curDy = CGFloat(next.value - prev.value) * intensity
// the last cubic
CGPathAddCurveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(prev.xIndex) + prevDx, (CGFloat(prev.value) + prevDy) * phaseY,
CGFloat(cur.xIndex) - curDx,
(CGFloat(cur.value) - curDy) * phaseY, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
}
}
CGContextSaveGState(context)
if (dataSet.isDrawFilledEnabled)
{
// Copy this path because we make changes to it
let fillPath = CGPathCreateMutableCopy(cubicPath)
drawCubicFill(context: context, dataSet: dataSet, spline: fillPath!, matrix: valueToPixelMatrix, from: minx, to: size)
}
CGContextBeginPath(context)
CGContextAddPath(context, cubicPath)
CGContextSetStrokeColorWithColor(context, drawingColor.CGColor)
CGContextStrokePath(context)
CGContextRestoreGState(context)
}
public func drawCubicFill(context context: CGContext, dataSet: ILineChartDataSet, spline: CGMutablePath, matrix: CGAffineTransform, from: Int, to: Int)
{
guard let dataProvider = dataProvider else { return }
if to - from <= 1
{
return
}
let fillMin = dataSet.fillFormatter?.getFillLinePosition(dataSet: dataSet, dataProvider: dataProvider) ?? 0.0
// Take the from/to xIndex from the entries themselves,
// so missing entries won't screw up the filling.
// What we need to draw is line from points of the xIndexes - not arbitrary entry indexes!
let xTo = dataSet.entryForIndex(to - 1)?.xIndex ?? 0
let xFrom = dataSet.entryForIndex(from)?.xIndex ?? 0
var pt1 = CGPoint(x: CGFloat(xTo), y: fillMin)
var pt2 = CGPoint(x: CGFloat(xFrom), y: fillMin)
pt1 = CGPointApplyAffineTransform(pt1, matrix)
pt2 = CGPointApplyAffineTransform(pt2, matrix)
CGPathAddLineToPoint(spline, nil, pt1.x, pt1.y)
CGPathAddLineToPoint(spline, nil, pt2.x, pt2.y)
CGPathCloseSubpath(spline)
if dataSet.fill != nil
{
drawFilledPath(context: context, path: spline, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha)
}
else
{
drawFilledPath(context: context, path: spline, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha)
}
}
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
public func drawLinear(context context: CGContext, dataSet: ILineChartDataSet)
{
guard let
trans = dataProvider?.getTransformer(dataSet.axisDependency),
animator = animator
else { return }
let valueToPixelMatrix = trans.valueToPixelMatrix
let entryCount = dataSet.entryCount
let isDrawSteppedEnabled = dataSet.isDrawSteppedEnabled
let pointsPerEntryPair = isDrawSteppedEnabled ? 4 : 2
let phaseX = animator.phaseX
let phaseY = animator.phaseY
guard let
entryFrom = dataSet.entryForXIndex(self.minX < 0 ? self.minX : 0, rounding: .Down),
entryTo = dataSet.entryForXIndex(self.maxX, rounding: .Up)
else { return }
let diff = (entryFrom == entryTo) ? 1 : 0
let minx = max(dataSet.entryIndex(entry: entryFrom) - diff, 0)
let maxx = min(max(minx + 2, dataSet.entryIndex(entry: entryTo) + 1), entryCount)
CGContextSaveGState(context)
CGContextSetLineCap(context, dataSet.lineCapType)
// more than 1 color
if (dataSet.colors.count > 1)
{
if (_lineSegments.count != pointsPerEntryPair)
{
_lineSegments = [CGPoint](count: pointsPerEntryPair, repeatedValue: CGPoint())
}
let count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
for j in minx ..< count
{
if (count > 1 && j == count - 1)
{ // Last point, we have already drawn a line to this point
break
}
var e: ChartDataEntry! = dataSet.entryForIndex(j)
if e == nil { continue }
_lineSegments[0].x = CGFloat(e.xIndex)
_lineSegments[0].y = CGFloat(e.value) * phaseY
if (j + 1 < count)
{
e = dataSet.entryForIndex(j + 1)
if e == nil { break }
if isDrawSteppedEnabled
{
_lineSegments[1] = CGPoint(x: CGFloat(e.xIndex), y: _lineSegments[0].y)
_lineSegments[2] = _lineSegments[1]
_lineSegments[3] = CGPoint(x: CGFloat(e.xIndex), y: CGFloat(e.value) * phaseY)
}
else
{
_lineSegments[1] = CGPoint(x: CGFloat(e.xIndex), y: CGFloat(e.value) * phaseY)
}
}
else
{
_lineSegments[1] = _lineSegments[0]
}
for i in 0..<_lineSegments.count
{
_lineSegments[i] = CGPointApplyAffineTransform(_lineSegments[i], valueToPixelMatrix)
}
if (!viewPortHandler.isInBoundsRight(_lineSegments[0].x))
{
break
}
// make sure the lines don't do shitty things outside bounds
if (!viewPortHandler.isInBoundsLeft(_lineSegments[1].x)
|| (!viewPortHandler.isInBoundsTop(_lineSegments[0].y) && !viewPortHandler.isInBoundsBottom(_lineSegments[1].y))
|| (!viewPortHandler.isInBoundsTop(_lineSegments[0].y) && !viewPortHandler.isInBoundsBottom(_lineSegments[1].y)))
{
continue
}
// get the color that is set for this line-segment
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
CGContextStrokeLineSegments(context, _lineSegments, pointsPerEntryPair)
}
}
else
{ // only one color per dataset
var e1: ChartDataEntry!
var e2: ChartDataEntry!
if (_lineSegments.count != max((entryCount - 1) * pointsPerEntryPair, pointsPerEntryPair))
{
_lineSegments = [CGPoint](count: max((entryCount - 1) * pointsPerEntryPair, pointsPerEntryPair), repeatedValue: CGPoint())
}
e1 = dataSet.entryForIndex(minx)
if e1 != nil
{
let count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
var j = 0
for x in (count > 1 ? minx + 1 : minx) ..< count
{
e1 = dataSet.entryForIndex(x == 0 ? 0 : (x - 1))
e2 = dataSet.entryForIndex(x)
if e1 == nil || e2 == nil { continue }
_lineSegments[j] = CGPointApplyAffineTransform(
CGPoint(
x: CGFloat(e1.xIndex),
y: CGFloat(e1.value) * phaseY
), valueToPixelMatrix)
j += 1
if isDrawSteppedEnabled
{
_lineSegments[j] = CGPointApplyAffineTransform(
CGPoint(
x: CGFloat(e2.xIndex),
y: CGFloat(e1.value) * phaseY
), valueToPixelMatrix)
j += 1
_lineSegments[j] = CGPointApplyAffineTransform(
CGPoint(
x: CGFloat(e2.xIndex),
y: CGFloat(e1.value) * phaseY
), valueToPixelMatrix)
j += 1
}
_lineSegments[j] = CGPointApplyAffineTransform(
CGPoint(
x: CGFloat(e2.xIndex),
y: CGFloat(e2.value) * phaseY
), valueToPixelMatrix)
j += 1
}
let size = max((count - minx - 1) * pointsPerEntryPair, pointsPerEntryPair)
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(0).CGColor)
CGContextStrokeLineSegments(context, _lineSegments, size)
}
}
CGContextRestoreGState(context)
// if drawing filled is enabled
if (dataSet.isDrawFilledEnabled && entryCount > 0)
{
drawLinearFill(context: context, dataSet: dataSet, minx: minx, maxx: maxx, trans: trans)
}
}
public func drawLinearFill(context context: CGContext, dataSet: ILineChartDataSet, minx: Int, maxx: Int, trans: ChartTransformer)
{
guard let dataProvider = dataProvider else { return }
let filled = generateFilledPath(
dataSet: dataSet,
fillMin: dataSet.fillFormatter?.getFillLinePosition(dataSet: dataSet, dataProvider: dataProvider) ?? 0.0,
from: minx,
to: maxx,
matrix: trans.valueToPixelMatrix)
if dataSet.fill != nil
{
drawFilledPath(context: context, path: filled, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha)
}
else
{
drawFilledPath(context: context, path: filled, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha)
}
}
/// Generates the path that is used for filled drawing.
private func generateFilledPath(dataSet dataSet: ILineChartDataSet, fillMin: CGFloat, from: Int, to: Int, matrix: CGAffineTransform) -> CGPath
{
let phaseX = animator?.phaseX ?? 1.0
let phaseY = animator?.phaseY ?? 1.0
let isDrawSteppedEnabled = dataSet.isDrawSteppedEnabled
var matrix = matrix
var e: ChartDataEntry!
let filled = CGPathCreateMutable()
e = dataSet.entryForIndex(from)
if e != nil
{
CGPathMoveToPoint(filled, &matrix, CGFloat(e.xIndex), fillMin)
CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(e.value) * phaseY)
}
// create a new path
for x in (from + 1).stride(to: Int(ceil(CGFloat(to - from) * phaseX + CGFloat(from))), by: 1)
{
guard let e = dataSet.entryForIndex(x) else { continue }
if isDrawSteppedEnabled
{
guard let ePrev = dataSet.entryForIndex(x-1) else { continue }
CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(ePrev.value) * phaseY)
}
CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(e.value) * phaseY)
}
// close up
e = dataSet.entryForIndex(max(min(Int(ceil(CGFloat(to - from) * phaseX + CGFloat(from))) - 1, dataSet.entryCount - 1), 0))
if e != nil
{
CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), fillMin)
}
CGPathCloseSubpath(filled)
return filled
}
public override func drawValues(context context: CGContext)
{
guard let
dataProvider = dataProvider,
lineData = dataProvider.lineData,
animator = animator
else { return }
if (CGFloat(lineData.yValCount) < CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleX)
{
var dataSets = lineData.dataSets
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< dataSets.count
{
guard let dataSet = dataSets[i] as? ILineChartDataSet else { continue }
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
// make sure the values do not interfear with the circles
var valOffset = Int(dataSet.circleRadius * 1.75)
if (!dataSet.isDrawCirclesEnabled)
{
valOffset = valOffset / 2
}
let entryCount = dataSet.entryCount
guard let
entryFrom = dataSet.entryForXIndex(self.minX < 0 ? self.minX : 0, rounding: .Down),
entryTo = dataSet.entryForXIndex(self.maxX, rounding: .Up)
else { continue }
let diff = (entryFrom == entryTo) ? 1 : 0
let minx = max(dataSet.entryIndex(entry: entryFrom) - diff, 0)
let maxx = min(max(minx + 2, dataSet.entryIndex(entry: entryTo) + 1), entryCount)
for j in minx ..< Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
{
guard let e = dataSet.entryForIndex(j) else { break }
pt.x = CGFloat(e.xIndex)
pt.y = CGFloat(e.value) * phaseY
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
ChartUtils.drawText(context: context,
text: formatter.stringFromNumber(e.value)!,
point: CGPoint(
x: pt.x,
y: pt.y - CGFloat(valOffset) - valueFont.lineHeight),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)])
}
}
}
}
public override func drawExtras(context context: CGContext)
{
drawCircles(context: context)
}
private func drawCircles(context context: CGContext)
{
guard let
dataProvider = dataProvider,
lineData = dataProvider.lineData,
animator = animator
else { return }
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let dataSets = lineData.dataSets
var pt = CGPoint()
var rect = CGRect()
CGContextSaveGState(context)
for i in 0 ..< dataSets.count
{
guard let dataSet = lineData.getDataSetByIndex(i) as? ILineChartDataSet else { continue }
if !dataSet.isVisible || !dataSet.isDrawCirclesEnabled || dataSet.entryCount == 0
{
continue
}
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let entryCount = dataSet.entryCount
let circleRadius = dataSet.circleRadius
let circleDiameter = circleRadius * 2.0
let circleHoleDiameter = circleRadius
let circleHoleRadius = circleHoleDiameter / 2.0
let isDrawCircleHoleEnabled = dataSet.isDrawCircleHoleEnabled
guard let
entryFrom = dataSet.entryForXIndex(self.minX < 0 ? self.minX : 0, rounding: .Down),
entryTo = dataSet.entryForXIndex(self.maxX, rounding: .Up)
else { continue }
let diff = (entryFrom == entryTo) ? 1 : 0
let minx = max(dataSet.entryIndex(entry: entryFrom) - diff, 0)
let maxx = min(max(minx + 2, dataSet.entryIndex(entry: entryTo) + 1), entryCount)
for j in minx ..< Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
{
guard let e = dataSet.entryForIndex(j) else { break }
pt.x = CGFloat(e.xIndex)
pt.y = CGFloat(e.value) * phaseY
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
// make sure the circles don't do shitty things outside bounds
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
CGContextSetFillColorWithColor(context, dataSet.getCircleColor(j)!.CGColor)
rect.origin.x = pt.x - circleRadius
rect.origin.y = pt.y - circleRadius
rect.size.width = circleDiameter
rect.size.height = circleDiameter
CGContextFillEllipseInRect(context, rect)
if (isDrawCircleHoleEnabled)
{
CGContextSetFillColorWithColor(context, dataSet.circleHoleColor.CGColor)
rect.origin.x = pt.x - circleHoleRadius
rect.origin.y = pt.y - circleHoleRadius
rect.size.width = circleHoleDiameter
rect.size.height = circleHoleDiameter
CGContextFillEllipseInRect(context, rect)
}
}
}
CGContextRestoreGState(context)
}
private var _highlightPointBuffer = CGPoint()
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
lineData = dataProvider?.lineData,
chartXMax = dataProvider?.chartXMax,
animator = animator
else { return }
CGContextSaveGState(context)
for i in 0 ..< indices.count
{
guard let set = lineData.getDataSetByIndex(indices[i].dataSetIndex) as? ILineChartDataSet else { continue }
if !set.isHighlightEnabled
{
continue
}
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
CGContextSetLineWidth(context, set.highlightLineWidth)
if (set.highlightLineDashLengths != nil)
{
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let xIndex = indices[i].xIndex; // get the x-position
if (CGFloat(xIndex) > CGFloat(chartXMax) * animator.phaseX)
{
continue
}
let yValue = set.yValForXIndex(xIndex)
if (yValue.isNaN)
{
continue
}
let y = CGFloat(yValue) * animator.phaseY; // get the y-position
_highlightPointBuffer.x = CGFloat(xIndex)
_highlightPointBuffer.y = y
let trans = dataProvider?.getTransformer(set.axisDependency)
trans?.pointValueToPixel(&_highlightPointBuffer)
// draw the lines
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/LineRadarChartRenderer.swift
================================================
//
// LineRadarChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/01/2016.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class LineRadarChartRenderer: LineScatterCandleRadarChartRenderer
{
public override init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
}
/// Draws the provided path in filled mode with the provided drawable.
public func drawFilledPath(context context: CGContext, path: CGPath, fill: ChartFill, fillAlpha: CGFloat)
{
CGContextSaveGState(context)
CGContextBeginPath(context)
CGContextAddPath(context, path)
// filled is usually drawn with less alpha
CGContextSetAlpha(context, fillAlpha)
fill.fillPath(context: context, rect: viewPortHandler.contentRect)
CGContextRestoreGState(context)
}
/// Draws the provided path in filled mode with the provided color and alpha.
public func drawFilledPath(context context: CGContext, path: CGPath, fillColor: NSUIColor, fillAlpha: CGFloat)
{
CGContextSaveGState(context)
CGContextBeginPath(context)
CGContextAddPath(context, path)
// filled is usually drawn with less alpha
CGContextSetAlpha(context, fillAlpha)
CGContextSetFillColorWithColor(context, fillColor.CGColor)
CGContextFillPath(context)
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/LineScatterCandleRadarChartRenderer.swift
================================================
//
// LineScatterCandleRadarChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 29/7/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class LineScatterCandleRadarChartRenderer: ChartDataRendererBase
{
public override init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
}
/// Draws vertical & horizontal highlight-lines if enabled.
/// :param: context
/// :param: points
/// :param: horizontal
/// :param: vertical
public func drawHighlightLines(context context: CGContext, point: CGPoint, set: ILineScatterCandleRadarChartDataSet)
{
// draw vertical highlight lines
if set.isVerticalHighlightIndicatorEnabled
{
CGContextBeginPath(context)
CGContextMoveToPoint(context, point.x, viewPortHandler.contentTop)
CGContextAddLineToPoint(context, point.x, viewPortHandler.contentBottom)
CGContextStrokePath(context)
}
// draw horizontal highlight lines
if set.isHorizontalHighlightIndicatorEnabled
{
CGContextBeginPath(context)
CGContextMoveToPoint(context, viewPortHandler.contentLeft, point.y)
CGContextAddLineToPoint(context, viewPortHandler.contentRight, point.y)
CGContextStrokePath(context)
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/PieChartRenderer.swift
================================================
//
// PieChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class PieChartRenderer: ChartDataRendererBase
{
public weak var chart: PieChartView?
public init(chart: PieChartView, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.chart = chart
}
public override func drawData(context context: CGContext)
{
guard let chart = chart else { return }
let pieData = chart.data
if (pieData != nil)
{
for set in pieData!.dataSets as! [IPieChartDataSet]
{
if set.isVisible && set.entryCount > 0
{
drawDataSet(context: context, dataSet: set)
}
}
}
}
public func calculateMinimumRadiusForSpacedSlice(
center center: CGPoint,
radius: CGFloat,
angle: CGFloat,
arcStartPointX: CGFloat,
arcStartPointY: CGFloat,
startAngle: CGFloat,
sweepAngle: CGFloat) -> CGFloat
{
let angleMiddle = startAngle + sweepAngle / 2.0
// Other point of the arc
let arcEndPointX = center.x + radius * cos((startAngle + sweepAngle) * ChartUtils.Math.FDEG2RAD)
let arcEndPointY = center.y + radius * sin((startAngle + sweepAngle) * ChartUtils.Math.FDEG2RAD)
// Middle point on the arc
let arcMidPointX = center.x + radius * cos(angleMiddle * ChartUtils.Math.FDEG2RAD)
let arcMidPointY = center.y + radius * sin(angleMiddle * ChartUtils.Math.FDEG2RAD)
// This is the base of the contained triangle
let basePointsDistance = sqrt(
pow(arcEndPointX - arcStartPointX, 2) +
pow(arcEndPointY - arcStartPointY, 2))
// After reducing space from both sides of the "slice",
// the angle of the contained triangle should stay the same.
// So let's find out the height of that triangle.
let containedTriangleHeight = (basePointsDistance / 2.0 *
tan((180.0 - angle) / 2.0 * ChartUtils.Math.FDEG2RAD))
// Now we subtract that from the radius
var spacedRadius = radius - containedTriangleHeight
// And now subtract the height of the arc that's between the triangle and the outer circle
spacedRadius -= sqrt(
pow(arcMidPointX - (arcEndPointX + arcStartPointX) / 2.0, 2) +
pow(arcMidPointY - (arcEndPointY + arcStartPointY) / 2.0, 2))
return spacedRadius
}
public func drawDataSet(context context: CGContext, dataSet: IPieChartDataSet)
{
guard let
chart = chart,
data = chart.data,
animator = animator
else {return }
var angle: CGFloat = 0.0
let rotationAngle = chart.rotationAngle
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let entryCount = dataSet.entryCount
var drawAngles = chart.drawAngles
let center = chart.centerCircleBox
let radius = chart.radius
let drawInnerArc = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled
let userInnerRadius = drawInnerArc ? radius * chart.holeRadiusPercent : 0.0
var visibleAngleCount = 0
for j in 0 ..< entryCount
{
guard let e = dataSet.entryForIndex(j) else { continue }
if ((abs(e.value) > 0.000001))
{
visibleAngleCount += 1
}
}
let sliceSpace = visibleAngleCount <= 1 ? 0.0 : dataSet.sliceSpace
CGContextSaveGState(context)
for j in 0 ..< entryCount
{
let sliceAngle = drawAngles[j]
var innerRadius = userInnerRadius
guard let e = dataSet.entryForIndex(j) else { continue }
// draw only if the value is greater than zero
if ((abs(e.value) > 0.000001))
{
if (!chart.needsHighlight(xIndex: e.xIndex,
dataSetIndex: data.indexOfDataSet(dataSet)))
{
let accountForSliceSpacing = sliceSpace > 0.0 && sliceAngle <= 180.0
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
let sliceSpaceAngleOuter = visibleAngleCount == 1 ?
0.0 :
sliceSpace / (ChartUtils.Math.FDEG2RAD * radius)
let startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.0) * phaseY
var sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY
if (sweepAngleOuter < 0.0)
{
sweepAngleOuter = 0.0
}
let arcStartPointX = center.x + radius * cos(startAngleOuter * ChartUtils.Math.FDEG2RAD)
let arcStartPointY = center.y + radius * sin(startAngleOuter * ChartUtils.Math.FDEG2RAD)
let path = CGPathCreateMutable()
CGPathMoveToPoint(
path,
nil,
arcStartPointX,
arcStartPointY)
CGPathAddRelativeArc(
path,
nil,
center.x,
center.y,
radius,
startAngleOuter * ChartUtils.Math.FDEG2RAD,
sweepAngleOuter * ChartUtils.Math.FDEG2RAD)
if drawInnerArc &&
(innerRadius > 0.0 || accountForSliceSpacing)
{
if accountForSliceSpacing
{
var minSpacedRadius = calculateMinimumRadiusForSpacedSlice(
center: center,
radius: radius,
angle: sliceAngle * phaseY,
arcStartPointX: arcStartPointX,
arcStartPointY: arcStartPointY,
startAngle: startAngleOuter,
sweepAngle: sweepAngleOuter)
if minSpacedRadius < 0.0
{
minSpacedRadius = -minSpacedRadius
}
innerRadius = min(max(innerRadius, minSpacedRadius), radius)
}
let sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.0 ?
0.0 :
sliceSpace / (ChartUtils.Math.FDEG2RAD * innerRadius)
let startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.0) * phaseY
var sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY
if (sweepAngleInner < 0.0)
{
sweepAngleInner = 0.0
}
let endAngleInner = startAngleInner + sweepAngleInner
CGPathAddLineToPoint(
path,
nil,
center.x + innerRadius * cos(endAngleInner * ChartUtils.Math.FDEG2RAD),
center.y + innerRadius * sin(endAngleInner * ChartUtils.Math.FDEG2RAD))
CGPathAddRelativeArc(
path,
nil,
center.x,
center.y,
innerRadius,
endAngleInner * ChartUtils.Math.FDEG2RAD,
-sweepAngleInner * ChartUtils.Math.FDEG2RAD)
}
else
{
if accountForSliceSpacing
{
let angleMiddle = startAngleOuter + sweepAngleOuter / 2.0
let sliceSpaceOffset =
calculateMinimumRadiusForSpacedSlice(
center: center,
radius: radius,
angle: sliceAngle * phaseY,
arcStartPointX: arcStartPointX,
arcStartPointY: arcStartPointY,
startAngle: startAngleOuter,
sweepAngle: sweepAngleOuter)
let arcEndPointX = center.x + sliceSpaceOffset * cos(angleMiddle * ChartUtils.Math.FDEG2RAD)
let arcEndPointY = center.y + sliceSpaceOffset * sin(angleMiddle * ChartUtils.Math.FDEG2RAD)
CGPathAddLineToPoint(
path,
nil,
arcEndPointX,
arcEndPointY)
}
else
{
CGPathAddLineToPoint(
path,
nil,
center.x,
center.y)
}
}
CGPathCloseSubpath(path)
CGContextBeginPath(context)
CGContextAddPath(context, path)
CGContextEOFillPath(context)
}
}
angle += sliceAngle * phaseX
}
CGContextRestoreGState(context)
}
public override func drawValues(context context: CGContext)
{
guard let
chart = chart,
data = chart.data,
animator = animator
else { return }
let center = chart.centerCircleBox
// get whole the radius
var r = chart.radius
let rotationAngle = chart.rotationAngle
var drawAngles = chart.drawAngles
var absoluteAngles = chart.absoluteAngles
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var off = r / 10.0 * 3.0
if chart.drawHoleEnabled
{
off = (r - (r * chart.holeRadiusPercent)) / 2.0
}
r -= off; // offset to keep things inside the chart
var dataSets = data.dataSets
let yValueSum = (data as! PieChartData).yValueSum
let drawXVals = chart.isDrawSliceTextEnabled
let usePercentValuesEnabled = chart.usePercentValuesEnabled
var angle: CGFloat = 0.0
var xIndex = 0
for i in 0 ..< dataSets.count
{
guard let dataSet = dataSets[i] as? IPieChartDataSet else { continue }
let drawYVals = dataSet.isDrawValuesEnabled
if (!drawYVals && !drawXVals)
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
for j in 0 ..< dataSet.entryCount
{
if (drawXVals && !drawYVals && (j >= data.xValCount || data.xVals[j] == nil))
{
continue
}
guard let e = dataSet.entryForIndex(j) else { continue }
if (xIndex == 0)
{
angle = 0.0
}
else
{
angle = absoluteAngles[xIndex - 1] * phaseX
}
let sliceAngle = drawAngles[xIndex]
let sliceSpace = dataSet.sliceSpace
let sliceSpaceMiddleAngle = sliceSpace / (ChartUtils.Math.FDEG2RAD * r)
// offset needed to center the drawn text in the slice
let offset = (sliceAngle - sliceSpaceMiddleAngle / 2.0) / 2.0
angle = angle + offset
// calculate the text position
let x = r
* cos((rotationAngle + angle * phaseY) * ChartUtils.Math.FDEG2RAD)
+ center.x
var y = r
* sin((rotationAngle + angle * phaseY) * ChartUtils.Math.FDEG2RAD)
+ center.y
let value = usePercentValuesEnabled ? e.value / yValueSum * 100.0 : e.value
let val = formatter.stringFromNumber(value)!
let lineHeight = valueFont.lineHeight
y -= lineHeight
// draw everything, depending on settings
if (drawXVals && drawYVals)
{
ChartUtils.drawText(
context: context,
text: val,
point: CGPoint(x: x, y: y),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
if (j < data.xValCount && data.xVals[j] != nil)
{
ChartUtils.drawText(
context: context,
text: data.xVals[j]!,
point: CGPoint(x: x, y: y + lineHeight),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
}
}
else if (drawXVals)
{
ChartUtils.drawText(
context: context,
text: data.xVals[j]!,
point: CGPoint(x: x, y: y + lineHeight / 2.0),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
}
else if (drawYVals)
{
ChartUtils.drawText(
context: context,
text: val,
point: CGPoint(x: x, y: y + lineHeight / 2.0),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
}
xIndex += 1
}
}
}
public override func drawExtras(context context: CGContext)
{
drawHole(context: context)
drawCenterText(context: context)
}
/// draws the hole in the center of the chart and the transparent circle / hole
private func drawHole(context context: CGContext)
{
guard let
chart = chart,
animator = animator
else { return }
if (chart.drawHoleEnabled)
{
CGContextSaveGState(context)
let radius = chart.radius
let holeRadius = radius * chart.holeRadiusPercent
let center = chart.centerCircleBox
if let holeColor = chart.holeColor
{
if holeColor != NSUIColor.clearColor()
{
// draw the hole-circle
CGContextSetFillColorWithColor(context, chart.holeColor!.CGColor)
CGContextFillEllipseInRect(context, CGRect(x: center.x - holeRadius, y: center.y - holeRadius, width: holeRadius * 2.0, height: holeRadius * 2.0))
}
}
// only draw the circle if it can be seen (not covered by the hole)
if let transparentCircleColor = chart.transparentCircleColor
{
if transparentCircleColor != NSUIColor.clearColor() &&
chart.transparentCircleRadiusPercent > chart.holeRadiusPercent
{
let alpha = animator.phaseX * animator.phaseY
let secondHoleRadius = radius * chart.transparentCircleRadiusPercent
// make transparent
CGContextSetAlpha(context, alpha);
CGContextSetFillColorWithColor(context, transparentCircleColor.CGColor)
// draw the transparent-circle
CGContextBeginPath(context)
CGContextAddEllipseInRect(context, CGRect(
x: center.x - secondHoleRadius,
y: center.y - secondHoleRadius,
width: secondHoleRadius * 2.0,
height: secondHoleRadius * 2.0))
CGContextAddEllipseInRect(context, CGRect(
x: center.x - holeRadius,
y: center.y - holeRadius,
width: holeRadius * 2.0,
height: holeRadius * 2.0))
CGContextEOFillPath(context)
}
}
CGContextRestoreGState(context)
}
}
/// draws the description text in the center of the pie chart makes most sense when center-hole is enabled
private func drawCenterText(context context: CGContext)
{
guard let
chart = chart,
centerAttributedText = chart.centerAttributedText
else { return }
if chart.drawCenterTextEnabled && centerAttributedText.length > 0
{
let center = chart.centerCircleBox
let innerRadius = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled ? chart.radius * chart.holeRadiusPercent : chart.radius
let holeRect = CGRect(x: center.x - innerRadius, y: center.y - innerRadius, width: innerRadius * 2.0, height: innerRadius * 2.0)
var boundingRect = holeRect
if (chart.centerTextRadiusPercent > 0.0)
{
boundingRect = CGRectInset(boundingRect, (boundingRect.width - boundingRect.width * chart.centerTextRadiusPercent) / 2.0, (boundingRect.height - boundingRect.height * chart.centerTextRadiusPercent) / 2.0)
}
let textBounds = centerAttributedText.boundingRectWithSize(boundingRect.size, options: [.UsesLineFragmentOrigin, .UsesFontLeading, .TruncatesLastVisibleLine], context: nil)
var drawingRect = boundingRect
drawingRect.origin.x += (boundingRect.size.width - textBounds.size.width) / 2.0
drawingRect.origin.y += (boundingRect.size.height - textBounds.size.height) / 2.0
drawingRect.size = textBounds.size
CGContextSaveGState(context)
let clippingPath = CGPathCreateWithEllipseInRect(holeRect, nil)
CGContextBeginPath(context)
CGContextAddPath(context, clippingPath)
CGContextClip(context)
centerAttributedText.drawWithRect(drawingRect, options: [.UsesLineFragmentOrigin, .UsesFontLeading, .TruncatesLastVisibleLine], context: nil)
CGContextRestoreGState(context)
}
}
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
chart = chart,
data = chart.data,
animator = animator
else { return }
CGContextSaveGState(context)
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var angle: CGFloat = 0.0
let rotationAngle = chart.rotationAngle
var drawAngles = chart.drawAngles
var absoluteAngles = chart.absoluteAngles
let center = chart.centerCircleBox
let radius = chart.radius
let drawInnerArc = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled
let userInnerRadius = drawInnerArc ? radius * chart.holeRadiusPercent : 0.0
for i in 0 ..< indices.count
{
// get the index to highlight
let xIndex = indices[i].xIndex
if (xIndex >= drawAngles.count)
{
continue
}
guard let set = data.getDataSetByIndex(indices[i].dataSetIndex) as? IPieChartDataSet else { continue }
if !set.isHighlightEnabled
{
continue
}
let entryCount = set.entryCount
var visibleAngleCount = 0
for j in 0 ..< entryCount
{
guard let e = set.entryForIndex(j) else { continue }
if ((abs(e.value) > 0.000001))
{
visibleAngleCount += 1
}
}
if (xIndex == 0)
{
angle = 0.0
}
else
{
angle = absoluteAngles[xIndex - 1] * phaseX
}
let sliceSpace = visibleAngleCount <= 1 ? 0.0 : set.sliceSpace
let sliceAngle = drawAngles[xIndex]
var innerRadius = userInnerRadius
let shift = set.selectionShift
let highlightedRadius = radius + shift
let accountForSliceSpacing = sliceSpace > 0.0 && sliceAngle <= 180.0
CGContextSetFillColorWithColor(context, set.colorAt(xIndex).CGColor)
let sliceSpaceAngleOuter = visibleAngleCount == 1 ?
0.0 :
sliceSpace / (ChartUtils.Math.FDEG2RAD * radius)
let sliceSpaceAngleShifted = visibleAngleCount == 1 ?
0.0 :
sliceSpace / (ChartUtils.Math.FDEG2RAD * highlightedRadius)
let startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.0) * phaseY
var sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY
if (sweepAngleOuter < 0.0)
{
sweepAngleOuter = 0.0
}
let startAngleShifted = rotationAngle + (angle + sliceSpaceAngleShifted / 2.0) * phaseY
var sweepAngleShifted = (sliceAngle - sliceSpaceAngleShifted) * phaseY
if (sweepAngleShifted < 0.0)
{
sweepAngleShifted = 0.0
}
let path = CGPathCreateMutable()
CGPathMoveToPoint(
path,
nil,
center.x + highlightedRadius * cos(startAngleShifted * ChartUtils.Math.FDEG2RAD),
center.y + highlightedRadius * sin(startAngleShifted * ChartUtils.Math.FDEG2RAD))
CGPathAddRelativeArc(
path,
nil,
center.x,
center.y,
highlightedRadius,
startAngleShifted * ChartUtils.Math.FDEG2RAD,
sweepAngleShifted * ChartUtils.Math.FDEG2RAD)
var sliceSpaceRadius: CGFloat = 0.0
if accountForSliceSpacing
{
sliceSpaceRadius = calculateMinimumRadiusForSpacedSlice(
center: center,
radius: radius,
angle: sliceAngle * phaseY,
arcStartPointX: center.x + radius * cos(startAngleOuter * ChartUtils.Math.FDEG2RAD),
arcStartPointY: center.y + radius * sin(startAngleOuter * ChartUtils.Math.FDEG2RAD),
startAngle: startAngleOuter,
sweepAngle: sweepAngleOuter)
}
if drawInnerArc &&
(innerRadius > 0.0 || accountForSliceSpacing)
{
if accountForSliceSpacing
{
var minSpacedRadius = sliceSpaceRadius
if minSpacedRadius < 0.0
{
minSpacedRadius = -minSpacedRadius
}
innerRadius = min(max(innerRadius, minSpacedRadius), radius)
}
let sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.0 ?
0.0 :
sliceSpace / (ChartUtils.Math.FDEG2RAD * innerRadius)
let startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.0) * phaseY
var sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY
if (sweepAngleInner < 0.0)
{
sweepAngleInner = 0.0
}
let endAngleInner = startAngleInner + sweepAngleInner
CGPathAddLineToPoint(
path,
nil,
center.x + innerRadius * cos(endAngleInner * ChartUtils.Math.FDEG2RAD),
center.y + innerRadius * sin(endAngleInner * ChartUtils.Math.FDEG2RAD))
CGPathAddRelativeArc(
path,
nil,
center.x,
center.y,
innerRadius,
endAngleInner * ChartUtils.Math.FDEG2RAD,
-sweepAngleInner * ChartUtils.Math.FDEG2RAD)
}
else
{
if accountForSliceSpacing
{
let angleMiddle = startAngleOuter + sweepAngleOuter / 2.0
let arcEndPointX = center.x + sliceSpaceRadius * cos(angleMiddle * ChartUtils.Math.FDEG2RAD)
let arcEndPointY = center.y + sliceSpaceRadius * sin(angleMiddle * ChartUtils.Math.FDEG2RAD)
CGPathAddLineToPoint(
path,
nil,
arcEndPointX,
arcEndPointY)
}
else
{
CGPathAddLineToPoint(
path,
nil,
center.x,
center.y)
}
}
CGPathCloseSubpath(path)
CGContextBeginPath(context)
CGContextAddPath(context, path)
CGContextEOFillPath(context)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/RadarChartRenderer.swift
================================================
//
// RadarChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class RadarChartRenderer: LineRadarChartRenderer
{
public weak var chart: RadarChartView?
public init(chart: RadarChartView, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.chart = chart
}
public override func drawData(context context: CGContext)
{
guard let chart = chart else { return }
let radarData = chart.data
if (radarData != nil)
{
var mostEntries = 0
for set in radarData!.dataSets
{
if set.entryCount > mostEntries
{
mostEntries = set.entryCount
}
}
for set in radarData!.dataSets as! [IRadarChartDataSet]
{
if set.isVisible && set.entryCount > 0
{
drawDataSet(context: context, dataSet: set, mostEntries: mostEntries)
}
}
}
}
/// Draws the RadarDataSet
///
/// - parameter context:
/// - parameter dataSet:
/// - parameter mostEntries: the entry count of the dataset with the most entries
internal func drawDataSet(context context: CGContext, dataSet: IRadarChartDataSet, mostEntries: Int)
{
guard let
chart = chart,
animator = animator
else { return }
CGContextSaveGState(context)
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let sliceangle = chart.sliceAngle
// calculate the factor that is needed for transforming the value to pixels
let factor = chart.factor
let center = chart.centerOffsets
let entryCount = dataSet.entryCount
let path = CGPathCreateMutable()
var hasMovedToPoint = false
for j in 0 ..< entryCount
{
guard let e = dataSet.entryForIndex(j) else { continue }
let p = ChartUtils.getPosition(
center: center,
dist: CGFloat(e.value - chart.chartYMin) * factor * phaseY,
angle: sliceangle * CGFloat(j) * phaseX + chart.rotationAngle)
if p.x.isNaN
{
continue
}
if !hasMovedToPoint
{
CGPathMoveToPoint(path, nil, p.x, p.y)
hasMovedToPoint = true
}
else
{
CGPathAddLineToPoint(path, nil, p.x, p.y)
}
}
// if this is the largest set, close it
if dataSet.entryCount < mostEntries
{
// if this is not the largest set, draw a line to the center before closing
CGPathAddLineToPoint(path, nil, center.x, center.y)
}
CGPathCloseSubpath(path)
// draw filled
if dataSet.isDrawFilledEnabled
{
if dataSet.fill != nil
{
drawFilledPath(context: context, path: path, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha)
}
else
{
drawFilledPath(context: context, path: path, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha)
}
}
// draw the line (only if filled is disabled or alpha is below 255)
if !dataSet.isDrawFilledEnabled || dataSet.fillAlpha < 1.0
{
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(0).CGColor)
CGContextSetLineWidth(context, dataSet.lineWidth)
CGContextSetAlpha(context, 1.0)
CGContextBeginPath(context)
CGContextAddPath(context, path)
CGContextStrokePath(context)
}
CGContextRestoreGState(context)
}
public override func drawValues(context context: CGContext)
{
guard let
chart = chart,
data = chart.data,
animator = animator
else { return }
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let sliceangle = chart.sliceAngle
// calculate the factor that is needed for transforming the value to pixels
let factor = chart.factor
let center = chart.centerOffsets
let yoffset = CGFloat(5.0)
for i in 0 ..< data.dataSetCount
{
let dataSet = data.getDataSetByIndex(i) as! IRadarChartDataSet
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let entryCount = dataSet.entryCount
for j in 0 ..< entryCount
{
guard let e = dataSet.entryForIndex(j) else { continue }
let p = ChartUtils.getPosition(
center: center,
dist: CGFloat(e.value) * factor * phaseY,
angle: sliceangle * CGFloat(j) * phaseX + chart.rotationAngle)
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
ChartUtils.drawText(
context: context,
text: formatter.stringFromNumber(e.value)!,
point: CGPoint(x: p.x, y: p.y - yoffset - valueFont.lineHeight),
align: .Center,
attributes: [NSFontAttributeName: valueFont,
NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
}
}
}
public override func drawExtras(context context: CGContext)
{
drawWeb(context: context)
}
private var _webLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
public func drawWeb(context context: CGContext)
{
guard let
chart = chart,
data = chart.data
else { return }
let sliceangle = chart.sliceAngle
CGContextSaveGState(context)
// calculate the factor that is needed for transforming the value to
// pixels
let factor = chart.factor
let rotationangle = chart.rotationAngle
let center = chart.centerOffsets
// draw the web lines that come from the center
CGContextSetLineWidth(context, chart.webLineWidth)
CGContextSetStrokeColorWithColor(context, chart.webColor.CGColor)
CGContextSetAlpha(context, chart.webAlpha)
let xIncrements = 1 + chart.skipWebLineCount
for i in 0.stride(to: data.xValCount, by: xIncrements)
{
let p = ChartUtils.getPosition(
center: center,
dist: CGFloat(chart.yRange) * factor,
angle: sliceangle * CGFloat(i) + rotationangle)
_webLineSegmentsBuffer[0].x = center.x
_webLineSegmentsBuffer[0].y = center.y
_webLineSegmentsBuffer[1].x = p.x
_webLineSegmentsBuffer[1].y = p.y
CGContextStrokeLineSegments(context, _webLineSegmentsBuffer, 2)
}
// draw the inner-web
CGContextSetLineWidth(context, chart.innerWebLineWidth)
CGContextSetStrokeColorWithColor(context, chart.innerWebColor.CGColor)
CGContextSetAlpha(context, chart.webAlpha)
let labelCount = chart.yAxis.entryCount
for j in 0 ..< labelCount
{
for i in 0 ..< data.xValCount
{
let r = CGFloat(chart.yAxis.entries[j] - chart.chartYMin) * factor
let p1 = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(i) + rotationangle)
let p2 = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(i + 1) + rotationangle)
_webLineSegmentsBuffer[0].x = p1.x
_webLineSegmentsBuffer[0].y = p1.y
_webLineSegmentsBuffer[1].x = p2.x
_webLineSegmentsBuffer[1].y = p2.y
CGContextStrokeLineSegments(context, _webLineSegmentsBuffer, 2)
}
}
CGContextRestoreGState(context)
}
private var _highlightPointBuffer = CGPoint()
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
chart = chart,
data = chart.data as? RadarChartData,
animator = animator
else { return }
CGContextSaveGState(context)
CGContextSetLineWidth(context, data.highlightLineWidth)
if (data.highlightLineDashLengths != nil)
{
CGContextSetLineDash(context, data.highlightLineDashPhase, data.highlightLineDashLengths!, data.highlightLineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let phaseX = animator.phaseX
let phaseY = animator.phaseY
let sliceangle = chart.sliceAngle
let factor = chart.factor
let center = chart.centerOffsets
for i in 0 ..< indices.count
{
guard let set = chart.data?.getDataSetByIndex(indices[i].dataSetIndex) as? IRadarChartDataSet else { continue }
if !set.isHighlightEnabled
{
continue
}
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
// get the index to highlight
let xIndex = indices[i].xIndex
let e = set.entryForXIndex(xIndex)
if e?.xIndex != xIndex
{
continue
}
let j = set.entryIndex(entry: e!)
let y = (e!.value - chart.chartYMin)
if (y.isNaN)
{
continue
}
_highlightPointBuffer = ChartUtils.getPosition(
center: center,
dist: CGFloat(y) * factor * phaseY,
angle: sliceangle * CGFloat(j) * phaseX + chart.rotationAngle)
// draw the lines
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
if (set.isDrawHighlightCircleEnabled)
{
if (!_highlightPointBuffer.x.isNaN && !_highlightPointBuffer.y.isNaN)
{
var strokeColor = set.highlightCircleStrokeColor
if strokeColor == nil
{
strokeColor = set.colorAt(0)
}
if set.highlightCircleStrokeAlpha < 1.0
{
strokeColor = strokeColor?.colorWithAlphaComponent(set.highlightCircleStrokeAlpha)
}
drawHighlightCircle(
context: context,
atPoint: _highlightPointBuffer,
innerRadius: set.highlightCircleInnerRadius,
outerRadius: set.highlightCircleOuterRadius,
fillColor: set.highlightCircleFillColor,
strokeColor: strokeColor,
strokeWidth: set.highlightCircleStrokeWidth)
}
}
}
CGContextRestoreGState(context)
}
internal func drawHighlightCircle(
context context: CGContext,
atPoint point: CGPoint,
innerRadius: CGFloat,
outerRadius: CGFloat,
fillColor: NSUIColor?,
strokeColor: NSUIColor?,
strokeWidth: CGFloat)
{
CGContextSaveGState(context)
if let fillColor = fillColor
{
CGContextBeginPath(context)
CGContextAddEllipseInRect(context, CGRectMake(point.x - outerRadius, point.y - outerRadius, outerRadius * 2.0, outerRadius * 2.0))
if innerRadius > 0.0
{
CGContextAddEllipseInRect(context, CGRectMake(point.x - innerRadius, point.y - innerRadius, innerRadius * 2.0, innerRadius * 2.0))
}
CGContextSetFillColorWithColor(context, fillColor.CGColor)
CGContextEOFillPath(context)
}
if let strokeColor = strokeColor
{
CGContextBeginPath(context)
CGContextAddEllipseInRect(context, CGRectMake(point.x - outerRadius, point.y - outerRadius, outerRadius * 2.0, outerRadius * 2.0))
CGContextSetStrokeColorWithColor(context, strokeColor.CGColor)
CGContextSetLineWidth(context, strokeWidth)
CGContextStrokePath(context)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Renderers/ScatterChartRenderer.swift
================================================
//
// ScatterChartRenderer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 4/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ScatterChartRenderer: LineScatterCandleRadarChartRenderer
{
public weak var dataProvider: ScatterChartDataProvider?
public init(dataProvider: ScatterChartDataProvider?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
{
super.init(animator: animator, viewPortHandler: viewPortHandler)
self.dataProvider = dataProvider
}
public override func drawData(context context: CGContext)
{
guard let scatterData = dataProvider?.scatterData else { return }
for i in 0 ..< scatterData.dataSetCount
{
guard let set = scatterData.getDataSetByIndex(i) else { continue }
if set.isVisible
{
if !(set is IScatterChartDataSet)
{
fatalError("Datasets for ScatterChartRenderer must conform to IScatterChartDataSet")
}
drawDataSet(context: context, dataSet: set as! IScatterChartDataSet)
}
}
}
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
public func drawDataSet(context context: CGContext, dataSet: IScatterChartDataSet)
{
guard let
dataProvider = dataProvider,
animator = animator
else { return }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let phaseY = animator.phaseY
let entryCount = dataSet.entryCount
let shapeSize = dataSet.scatterShapeSize
let shapeHalf = shapeSize / 2.0
let shapeHoleSizeHalf = dataSet.scatterShapeHoleRadius
let shapeHoleSize = shapeHoleSizeHalf * 2.0
let shapeHoleColor = dataSet.scatterShapeHoleColor
let shapeStrokeSize = (shapeSize - shapeHoleSize) / 2.0
let shapeStrokeSizeHalf = shapeStrokeSize / 2.0
var point = CGPoint()
let valueToPixelMatrix = trans.valueToPixelMatrix
let shape = dataSet.scatterShape
CGContextSaveGState(context)
for j in 0 ..< Int(min(ceil(CGFloat(entryCount) * animator.phaseX), CGFloat(entryCount)))
{
guard let e = dataSet.entryForIndex(j) else { continue }
point.x = CGFloat(e.xIndex)
point.y = CGFloat(e.value) * phaseY
point = CGPointApplyAffineTransform(point, valueToPixelMatrix);
if (!viewPortHandler.isInBoundsRight(point.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(point.x) || !viewPortHandler.isInBoundsY(point.y))
{
continue
}
if (shape == .Square)
{
if shapeHoleSize > 0.0
{
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
CGContextSetLineWidth(context, shapeStrokeSize)
var rect = CGRect()
rect.origin.x = point.x - shapeHoleSizeHalf - shapeStrokeSizeHalf
rect.origin.y = point.y - shapeHoleSizeHalf - shapeStrokeSizeHalf
rect.size.width = shapeHoleSize + shapeStrokeSize
rect.size.height = shapeHoleSize + shapeStrokeSize
CGContextStrokeRect(context, rect)
if let shapeHoleColor = shapeHoleColor
{
CGContextSetFillColorWithColor(context, shapeHoleColor.CGColor)
rect.origin.x = point.x - shapeHoleSizeHalf
rect.origin.y = point.y - shapeHoleSizeHalf
rect.size.width = shapeHoleSize
rect.size.height = shapeHoleSize
CGContextFillRect(context, rect)
}
}
else
{
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
var rect = CGRect()
rect.origin.x = point.x - shapeHalf
rect.origin.y = point.y - shapeHalf
rect.size.width = shapeSize
rect.size.height = shapeSize
CGContextFillRect(context, rect)
}
}
else if (shape == .Circle)
{
if shapeHoleSize > 0.0
{
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
CGContextSetLineWidth(context, shapeStrokeSize)
var rect = CGRect()
rect.origin.x = point.x - shapeHoleSizeHalf - shapeStrokeSizeHalf
rect.origin.y = point.y - shapeHoleSizeHalf - shapeStrokeSizeHalf
rect.size.width = shapeHoleSize + shapeStrokeSize
rect.size.height = shapeHoleSize + shapeStrokeSize
CGContextStrokeEllipseInRect(context, rect)
if let shapeHoleColor = shapeHoleColor
{
CGContextSetFillColorWithColor(context, shapeHoleColor.CGColor)
rect.origin.x = point.x - shapeHoleSizeHalf
rect.origin.y = point.y - shapeHoleSizeHalf
rect.size.width = shapeHoleSize
rect.size.height = shapeHoleSize
CGContextFillEllipseInRect(context, rect)
}
}
else
{
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
var rect = CGRect()
rect.origin.x = point.x - shapeHalf
rect.origin.y = point.y - shapeHalf
rect.size.width = shapeSize
rect.size.height = shapeSize
CGContextFillEllipseInRect(context, rect)
}
}
else if (shape == .Triangle)
{
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
// create a triangle path
CGContextBeginPath(context)
CGContextMoveToPoint(context, point.x, point.y - shapeHalf)
CGContextAddLineToPoint(context, point.x + shapeHalf, point.y + shapeHalf)
CGContextAddLineToPoint(context, point.x - shapeHalf, point.y + shapeHalf)
if shapeHoleSize > 0.0
{
CGContextAddLineToPoint(context, point.x, point.y - shapeHalf)
CGContextMoveToPoint(context, point.x - shapeHalf + shapeStrokeSize, point.y + shapeHalf - shapeStrokeSize)
CGContextAddLineToPoint(context, point.x + shapeHalf - shapeStrokeSize, point.y + shapeHalf - shapeStrokeSize)
CGContextAddLineToPoint(context, point.x, point.y - shapeHalf + shapeStrokeSize)
CGContextAddLineToPoint(context, point.x - shapeHalf + shapeStrokeSize, point.y + shapeHalf - shapeStrokeSize)
}
CGContextClosePath(context)
CGContextFillPath(context)
if shapeHoleSize > 0.0 && shapeHoleColor != nil
{
CGContextSetFillColorWithColor(context, shapeHoleColor!.CGColor)
// create a triangle path
CGContextBeginPath(context)
CGContextMoveToPoint(context, point.x, point.y - shapeHalf + shapeStrokeSize)
CGContextAddLineToPoint(context, point.x + shapeHalf - shapeStrokeSize, point.y + shapeHalf - shapeStrokeSize)
CGContextAddLineToPoint(context, point.x - shapeHalf + shapeStrokeSize, point.y + shapeHalf - shapeStrokeSize)
CGContextClosePath(context)
CGContextFillPath(context)
}
}
else if (shape == .Cross)
{
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
_lineSegments[0].x = point.x - shapeHalf
_lineSegments[0].y = point.y
_lineSegments[1].x = point.x + shapeHalf
_lineSegments[1].y = point.y
CGContextStrokeLineSegments(context, _lineSegments, 2)
_lineSegments[0].x = point.x
_lineSegments[0].y = point.y - shapeHalf
_lineSegments[1].x = point.x
_lineSegments[1].y = point.y + shapeHalf
CGContextStrokeLineSegments(context, _lineSegments, 2)
}
else if (shape == .X)
{
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
_lineSegments[0].x = point.x - shapeHalf
_lineSegments[0].y = point.y - shapeHalf
_lineSegments[1].x = point.x + shapeHalf
_lineSegments[1].y = point.y + shapeHalf
CGContextStrokeLineSegments(context, _lineSegments, 2)
_lineSegments[0].x = point.x + shapeHalf
_lineSegments[0].y = point.y - shapeHalf
_lineSegments[1].x = point.x - shapeHalf
_lineSegments[1].y = point.y + shapeHalf
CGContextStrokeLineSegments(context, _lineSegments, 2)
}
else if (shape == .Custom)
{
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
let customShape = dataSet.customScatterShape
if customShape == nil
{
return
}
// transform the provided custom path
CGContextSaveGState(context)
CGContextTranslateCTM(context, point.x, point.y)
CGContextBeginPath(context)
CGContextAddPath(context, customShape)
CGContextFillPath(context)
CGContextRestoreGState(context)
}
}
CGContextRestoreGState(context)
}
public override func drawValues(context context: CGContext)
{
guard let
dataProvider = dataProvider,
scatterData = dataProvider.scatterData,
animator = animator
else { return }
// if values are drawn
if (scatterData.yValCount < Int(ceil(CGFloat(dataProvider.maxVisibleValueCount) * viewPortHandler.scaleX)))
{
guard let dataSets = scatterData.dataSets as? [IScatterChartDataSet] else { return }
let phaseX = animator.phaseX
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< scatterData.dataSetCount
{
let dataSet = dataSets[i]
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let entryCount = dataSet.entryCount
let shapeSize = dataSet.scatterShapeSize
let lineHeight = valueFont.lineHeight
for j in 0 ..< Int(ceil(CGFloat(entryCount) * phaseX))
{
guard let e = dataSet.entryForIndex(j) else { break }
pt.x = CGFloat(e.xIndex)
pt.y = CGFloat(e.value) * phaseY
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
// make sure the lines don't do shitty things outside bounds
if ((!viewPortHandler.isInBoundsLeft(pt.x)
|| !viewPortHandler.isInBoundsY(pt.y)))
{
continue
}
let text = formatter.stringFromNumber(e.value)
ChartUtils.drawText(
context: context,
text: text!,
point: CGPoint(
x: pt.x,
y: pt.y - shapeSize - lineHeight),
align: .Center,
attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: dataSet.valueTextColorAt(j)]
)
}
}
}
}
public override func drawExtras(context context: CGContext)
{
}
private var _highlightPointBuffer = CGPoint()
public override func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
{
guard let
dataProvider = dataProvider,
scatterData = dataProvider.scatterData,
animator = animator
else { return }
let chartXMax = dataProvider.chartXMax
CGContextSaveGState(context)
for i in 0 ..< indices.count
{
guard let set = scatterData.getDataSetByIndex(indices[i].dataSetIndex) as? IScatterChartDataSet else { continue }
if !set.isHighlightEnabled
{
continue
}
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
CGContextSetLineWidth(context, set.highlightLineWidth)
if (set.highlightLineDashLengths != nil)
{
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
}
else
{
CGContextSetLineDash(context, 0.0, nil, 0)
}
let xIndex = indices[i].xIndex; // get the x-position
if (CGFloat(xIndex) > CGFloat(chartXMax) * animator.phaseX)
{
continue
}
let yVal = set.yValForXIndex(xIndex)
if (yVal.isNaN)
{
continue
}
let y = CGFloat(yVal) * animator.phaseY; // get the y-position
_highlightPointBuffer.x = CGFloat(xIndex)
_highlightPointBuffer.y = y
let trans = dataProvider.getTransformer(set.axisDependency)
trans.pointValueToPixel(&_highlightPointBuffer)
// draw the lines
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartColorTemplates.swift
================================================
//
// ChartColorTemplates.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartColorTemplates: NSObject
{
public class func liberty () -> [NSUIColor]
{
return [
NSUIColor(red: 207/255.0, green: 248/255.0, blue: 246/255.0, alpha: 1.0),
NSUIColor(red: 148/255.0, green: 212/255.0, blue: 212/255.0, alpha: 1.0),
NSUIColor(red: 136/255.0, green: 180/255.0, blue: 187/255.0, alpha: 1.0),
NSUIColor(red: 118/255.0, green: 174/255.0, blue: 175/255.0, alpha: 1.0),
NSUIColor(red: 42/255.0, green: 109/255.0, blue: 130/255.0, alpha: 1.0)
]
}
public class func joyful () -> [NSUIColor]
{
return [
NSUIColor(red: 217/255.0, green: 80/255.0, blue: 138/255.0, alpha: 1.0),
NSUIColor(red: 254/255.0, green: 149/255.0, blue: 7/255.0, alpha: 1.0),
NSUIColor(red: 254/255.0, green: 247/255.0, blue: 120/255.0, alpha: 1.0),
NSUIColor(red: 106/255.0, green: 167/255.0, blue: 134/255.0, alpha: 1.0),
NSUIColor(red: 53/255.0, green: 194/255.0, blue: 209/255.0, alpha: 1.0)
]
}
public class func pastel () -> [NSUIColor]
{
return [
NSUIColor(red: 64/255.0, green: 89/255.0, blue: 128/255.0, alpha: 1.0),
NSUIColor(red: 149/255.0, green: 165/255.0, blue: 124/255.0, alpha: 1.0),
NSUIColor(red: 217/255.0, green: 184/255.0, blue: 162/255.0, alpha: 1.0),
NSUIColor(red: 191/255.0, green: 134/255.0, blue: 134/255.0, alpha: 1.0),
NSUIColor(red: 179/255.0, green: 48/255.0, blue: 80/255.0, alpha: 1.0)
]
}
public class func colorful () -> [NSUIColor]
{
return [
NSUIColor(red: 193/255.0, green: 37/255.0, blue: 82/255.0, alpha: 1.0),
NSUIColor(red: 255/255.0, green: 102/255.0, blue: 0/255.0, alpha: 1.0),
NSUIColor(red: 245/255.0, green: 199/255.0, blue: 0/255.0, alpha: 1.0),
NSUIColor(red: 106/255.0, green: 150/255.0, blue: 31/255.0, alpha: 1.0),
NSUIColor(red: 179/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0)
]
}
public class func vordiplom () -> [NSUIColor]
{
return [
NSUIColor(red: 192/255.0, green: 255/255.0, blue: 140/255.0, alpha: 1.0),
NSUIColor(red: 255/255.0, green: 247/255.0, blue: 140/255.0, alpha: 1.0),
NSUIColor(red: 255/255.0, green: 208/255.0, blue: 140/255.0, alpha: 1.0),
NSUIColor(red: 140/255.0, green: 234/255.0, blue: 255/255.0, alpha: 1.0),
NSUIColor(red: 255/255.0, green: 140/255.0, blue: 157/255.0, alpha: 1.0)
]
}
public class func colorFromString(colorString: String) -> NSUIColor
{
let leftParenCharset: NSCharacterSet = NSCharacterSet(charactersInString: "( ")
let commaCharset: NSCharacterSet = NSCharacterSet(charactersInString: ", ")
let colorString = colorString.lowercaseString
if colorString.hasPrefix("#")
{
var argb: [UInt] = [255, 0, 0, 0]
let colorString = colorString.unicodeScalars
var length = colorString.count
var index = colorString.startIndex
let endIndex = colorString.endIndex
index = index.advancedBy(1)
length = length - 1
if length == 3 || length == 6 || length == 8
{
var i = length == 8 ? 0 : 1
while index < endIndex
{
var c = colorString[index]
index = index.advancedBy(1)
var val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
argb[i] = UInt(val) * 16
if length == 3
{
argb[i] = argb[i] + UInt(val)
}
else
{
c = colorString[index]
index = index.advancedBy(1)
val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
argb[i] = argb[i] + UInt(val)
}
i += 1
}
}
return NSUIColor(red: CGFloat(argb[1]) / 255.0, green: CGFloat(argb[2]) / 255.0, blue: CGFloat(argb[3]) / 255.0, alpha: CGFloat(argb[0]) / 255.0)
}
else if colorString.hasPrefix("rgba")
{
var a: Float = 1.0
var r: Int32 = 0
var g: Int32 = 0
var b: Int32 = 0
let scanner: NSScanner = NSScanner(string: colorString)
scanner.scanString("rgba", intoString: nil)
scanner.scanCharactersFromSet(leftParenCharset, intoString: nil)
scanner.scanInt(&r)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&g)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&b)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanFloat(&a)
return NSUIColor(
red: CGFloat(r) / 255.0,
green: CGFloat(g) / 255.0,
blue: CGFloat(b) / 255.0,
alpha: CGFloat(a)
)
}
else if colorString.hasPrefix("argb")
{
var a: Float = 1.0
var r: Int32 = 0
var g: Int32 = 0
var b: Int32 = 0
let scanner: NSScanner = NSScanner(string: colorString)
scanner.scanString("argb", intoString: nil)
scanner.scanCharactersFromSet(leftParenCharset, intoString: nil)
scanner.scanFloat(&a)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&r)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&g)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&b)
return NSUIColor(
red: CGFloat(r) / 255.0,
green: CGFloat(g) / 255.0,
blue: CGFloat(b) / 255.0,
alpha: CGFloat(a)
)
}
else if colorString.hasPrefix("rgb")
{
var r: Int32 = 0
var g: Int32 = 0
var b: Int32 = 0
let scanner: NSScanner = NSScanner(string: colorString)
scanner.scanString("rgb", intoString: nil)
scanner.scanCharactersFromSet(leftParenCharset, intoString: nil)
scanner.scanInt(&r)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&g)
scanner.scanCharactersFromSet(commaCharset, intoString: nil)
scanner.scanInt(&b)
return NSUIColor(
red: CGFloat(r) / 255.0,
green: CGFloat(g) / 255.0,
blue: CGFloat(b) / 255.0,
alpha: 1.0
)
}
return NSUIColor.clearColor()
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartFill.swift
================================================
//
// ChartFill.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/01/2016.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartFill: NSObject
{
@objc
public enum ChartFillType: Int
{
case Empty
case Color
case LinearGradient
case RadialGradient
case Image
case TiledImage
case Layer
}
private var _type: ChartFillType = ChartFillType.Empty
private var _color: CGColorRef?
private var _gradient: CGGradientRef?
private var _gradientAngle: CGFloat = 0.0
private var _gradientStartOffsetPercent: CGPoint = CGPoint()
private var _gradientStartRadiusPercent: CGFloat = 0.0
private var _gradientEndOffsetPercent: CGPoint = CGPoint()
private var _gradientEndRadiusPercent: CGFloat = 0.0
private var _image: CGImageRef?
private var _layer: CGLayerRef?
// MARK: Properties
public var type: ChartFillType
{
return _type
}
public var color: CGColorRef?
{
return _color
}
public var gradient: CGGradientRef?
{
return _gradient
}
public var gradientAngle: CGFloat
{
return _gradientAngle
}
public var gradientStartOffsetPercent: CGPoint
{
return _gradientStartOffsetPercent
}
public var gradientStartRadiusPercent: CGFloat
{
return _gradientStartRadiusPercent
}
public var gradientEndOffsetPercent: CGPoint
{
return _gradientEndOffsetPercent
}
public var gradientEndRadiusPercent: CGFloat
{
return _gradientEndRadiusPercent
}
public var image: CGImageRef?
{
return _image
}
public var layer: CGLayerRef?
{
return _layer
}
// MARK: Constructors
public override init()
{
}
public init(CGColor: CGColorRef)
{
_type = .Color
_color = CGColor
}
public convenience init(color: NSUIColor)
{
self.init(CGColor: color.CGColor)
}
public init(linearGradient: CGGradientRef, angle: CGFloat)
{
_type = .LinearGradient
_gradient = linearGradient
_gradientAngle = angle
}
public init(
radialGradient: CGGradientRef,
startOffsetPercent: CGPoint,
startRadiusPercent: CGFloat,
endOffsetPercent: CGPoint,
endRadiusPercent: CGFloat
)
{
_type = .RadialGradient
_gradient = radialGradient
_gradientStartOffsetPercent = startOffsetPercent
_gradientStartRadiusPercent = startRadiusPercent
_gradientEndOffsetPercent = endOffsetPercent
_gradientEndRadiusPercent = endRadiusPercent
}
public convenience init(radialGradient: CGGradientRef)
{
self.init(
radialGradient: radialGradient,
startOffsetPercent: CGPointMake(0.0, 0.0),
startRadiusPercent: 0.0,
endOffsetPercent: CGPointMake(0.0, 0.0),
endRadiusPercent: 1.0
)
}
public init(CGImage: CGImageRef, tiled: Bool)
{
_type = tiled ? .TiledImage : .Image
_image = CGImage
}
public convenience init(image: NSUIImage, tiled: Bool)
{
if image.CGImage == nil
{
self.init()
}
else
{
self.init(CGImage: image.CGImage!, tiled: tiled)
}
}
public convenience init(CGImage: CGImageRef)
{
self.init(CGImage: CGImage, tiled: false)
}
public convenience init(image: NSUIImage)
{
self.init(image: image, tiled: false)
}
public init(CGLayer: CGLayerRef)
{
_type = .Layer
_layer = CGLayer
}
// MARK: Constructors
public class func fillWithCGColor(CGColor: CGColorRef) -> ChartFill
{
return ChartFill(CGColor: CGColor)
}
public class func fillWithColor(color: NSUIColor) -> ChartFill
{
return ChartFill(color: color)
}
public class func fillWithLinearGradient(linearGradient: CGGradientRef, angle: CGFloat) -> ChartFill
{
return ChartFill(linearGradient: linearGradient, angle: angle)
}
public class func fillWithRadialGradient(
radialGradient: CGGradientRef,
startOffsetPercent: CGPoint,
startRadiusPercent: CGFloat,
endOffsetPercent: CGPoint,
endRadiusPercent: CGFloat
) -> ChartFill
{
return ChartFill(
radialGradient: radialGradient,
startOffsetPercent: startOffsetPercent,
startRadiusPercent: startRadiusPercent,
endOffsetPercent: endOffsetPercent,
endRadiusPercent: endRadiusPercent
)
}
public class func fillWithRadialGradient(radialGradient: CGGradientRef) -> ChartFill
{
return ChartFill(radialGradient: radialGradient)
}
public class func fillWithCGImage(CGImage: CGImageRef, tiled: Bool) -> ChartFill
{
return ChartFill(CGImage: CGImage, tiled: tiled)
}
public class func fillWithImage(image: NSUIImage, tiled: Bool) -> ChartFill
{
return ChartFill(image: image, tiled: tiled)
}
public class func fillWithCGImage(CGImage: CGImageRef) -> ChartFill
{
return ChartFill(CGImage: CGImage)
}
public class func fillWithImage(image: NSUIImage) -> ChartFill
{
return ChartFill(image: image)
}
public class func fillWithCGLayer(CGLayer: CGLayerRef) -> ChartFill
{
return ChartFill(CGLayer: CGLayer)
}
// MARK: Drawing code
/// Draws the provided path in filled mode with the provided area
public func fillPath(
context context: CGContext,
rect: CGRect)
{
let fillType = _type
if fillType == .Empty
{
return
}
CGContextSaveGState(context)
switch fillType
{
case .Color:
CGContextSetFillColorWithColor(context, _color)
CGContextFillPath(context)
case .Image:
CGContextClip(context)
CGContextDrawImage(context, rect, _image)
case .TiledImage:
CGContextClip(context)
CGContextDrawTiledImage(context, rect, _image)
case .Layer:
CGContextClip(context)
CGContextDrawLayerInRect(context, rect, _layer)
case .LinearGradient:
let radians = ChartUtils.Math.FDEG2RAD * (360.0 - _gradientAngle)
let centerPoint = CGPointMake(rect.midX, rect.midY)
let xAngleDelta = cos(radians) * rect.width / 2.0
let yAngleDelta = sin(radians) * rect.height / 2.0
let startPoint = CGPointMake(
centerPoint.x - xAngleDelta,
centerPoint.y - yAngleDelta
)
let endPoint = CGPointMake(
centerPoint.x + xAngleDelta,
centerPoint.y + yAngleDelta
)
CGContextClip(context)
CGContextDrawLinearGradient(
context,
_gradient,
startPoint,
endPoint,
[.DrawsAfterEndLocation, .DrawsBeforeStartLocation]
)
case .RadialGradient:
let centerPoint = CGPointMake(rect.midX, rect.midY)
let radius = max(rect.width, rect.height) / 2.0
CGContextClip(context)
CGContextDrawRadialGradient(
context,
_gradient,
CGPointMake(
centerPoint.x + rect.width * _gradientStartOffsetPercent.x,
centerPoint.y + rect.height * _gradientStartOffsetPercent.y
),
radius * _gradientStartRadiusPercent,
CGPointMake(
centerPoint.x + rect.width * _gradientEndOffsetPercent.x,
centerPoint.y + rect.height * _gradientEndOffsetPercent.y
),
radius * _gradientEndRadiusPercent,
[.DrawsAfterEndLocation, .DrawsBeforeStartLocation]
)
case .Empty:
break;
}
CGContextRestoreGState(context)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartPlatform.swift
================================================
import Foundation
/** This file provides a thin abstraction layer atop of UIKit (iOS, tvOS) and Cocoa (OS X). The two APIs are very much
alike, and for the chart library's usage of the APIs it is often sufficient to typealias one to the other. The NSUI*
types are aliased to either their UI* implementation (on iOS) or their NS* implementation (on OS X). */
#if os(iOS) || os(tvOS)
import UIKit
public typealias NSUIFont = UIFont
public typealias NSUIColor = UIColor
public typealias NSUIEvent = UIEvent
public typealias NSUITouch = UITouch
public typealias NSUIImage = UIImage
public typealias NSUIScrollView = UIScrollView
public typealias NSUIGestureRecognizer = UIGestureRecognizer
public typealias NSUIGestureRecognizerState = UIGestureRecognizerState
public typealias NSUIGestureRecognizerDelegate = UIGestureRecognizerDelegate
public typealias NSUITapGestureRecognizer = UITapGestureRecognizer
public typealias NSUIPanGestureRecognizer = UIPanGestureRecognizer
#if !os(tvOS)
public typealias NSUIPinchGestureRecognizer = UIPinchGestureRecognizer
public typealias NSUIRotationGestureRecognizer = UIRotationGestureRecognizer
#endif
public typealias NSUIScreen = UIScreen
public typealias NSUIDisplayLink = CADisplayLink
extension NSUITapGestureRecognizer
{
final func nsuiNumberOfTouches() -> Int
{
return numberOfTouches()
}
final var nsuiNumberOfTapsRequired: Int
{
get
{
return self.numberOfTapsRequired
}
set
{
self.numberOfTapsRequired = newValue
}
}
}
extension NSUIPanGestureRecognizer
{
final func nsuiNumberOfTouches() -> Int
{
return numberOfTouches()
}
final func nsuiLocationOfTouch(touch: Int, inView: UIView?) -> CGPoint
{
return super.locationOfTouch(touch, inView: inView)
}
}
#if !os(tvOS)
extension NSUIRotationGestureRecognizer
{
final var nsuiRotation: CGFloat
{
get { return rotation }
set { rotation = newValue }
}
}
#endif
#if !os(tvOS)
extension NSUIPinchGestureRecognizer
{
final var nsuiScale: CGFloat
{
get
{
return scale
}
set
{
scale = newValue
}
}
final func nsuiLocationOfTouch(touch: Int, inView: UIView?) -> CGPoint
{
return super.locationOfTouch(touch, inView: inView)
}
}
#endif
public class NSUIView: UIView
{
public final override func touchesBegan(touches: Set, withEvent event: NSUIEvent?)
{
self.nsuiTouchesBegan(touches, withEvent: event)
}
public final override func touchesMoved(touches: Set, withEvent event: NSUIEvent?)
{
self.nsuiTouchesMoved(touches, withEvent: event)
}
public final override func touchesEnded(touches: Set, withEvent event: NSUIEvent?)
{
self.nsuiTouchesEnded(touches, withEvent: event)
}
public final override func touchesCancelled(touches: Set?, withEvent event: NSUIEvent?)
{
self.nsuiTouchesCancelled(touches, withEvent: event)
}
public func nsuiTouchesBegan(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesBegan(touches, withEvent: event!)
}
public func nsuiTouchesMoved(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesMoved(touches, withEvent: event!)
}
public func nsuiTouchesEnded(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesEnded(touches, withEvent: event!)
}
public func nsuiTouchesCancelled(touches: Set?, withEvent event: NSUIEvent?)
{
super.touchesCancelled(touches, withEvent: event!)
}
var nsuiLayer: CALayer?
{
return self.layer
}
}
extension UIView
{
final var nsuiGestureRecognizers: [NSUIGestureRecognizer]?
{
return self.gestureRecognizers
}
}
extension UIScreen
{
final var nsuiScale: CGFloat
{
return self.scale
}
}
func NSUIGraphicsGetCurrentContext() -> CGContextRef?
{
return UIGraphicsGetCurrentContext()
}
func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage!
{
return UIGraphicsGetImageFromCurrentImageContext()
}
func NSUIGraphicsPushContext(context: CGContextRef)
{
UIGraphicsPushContext(context)
}
func NSUIGraphicsPopContext()
{
UIGraphicsPopContext()
}
func NSUIGraphicsEndImageContext()
{
UIGraphicsEndImageContext()
}
func NSUIImagePNGRepresentation(image: NSUIImage) -> NSData?
{
return UIImagePNGRepresentation(image)
}
func NSUIImageJPEGRepresentation(image: NSUIImage, _ quality: CGFloat = 0.8) -> NSData?
{
return UIImageJPEGRepresentation(image, quality)
}
func NSUIMainScreen() -> NSUIScreen?
{
return NSUIScreen.mainScreen()
}
func NSUIGraphicsBeginImageContextWithOptions(size: CGSize, _ opaque: Bool, _ scale: CGFloat)
{
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
}
#endif
#if os(OSX)
import Cocoa
import Quartz
public typealias NSUIFont = NSFont
public typealias NSUIColor = NSColor
public typealias NSUIEvent = NSEvent
public typealias NSUITouch = NSTouch
public typealias NSUIImage = NSImage
public typealias NSUIScrollView = NSScrollView
public typealias NSUIGestureRecognizer = NSGestureRecognizer
public typealias NSUIGestureRecognizerState = NSGestureRecognizerState
public typealias NSUIGestureRecognizerDelegate = NSGestureRecognizerDelegate
public typealias NSUITapGestureRecognizer = NSClickGestureRecognizer
public typealias NSUIPanGestureRecognizer = NSPanGestureRecognizer
public typealias NSUIPinchGestureRecognizer = NSMagnificationGestureRecognizer
public typealias NSUIRotationGestureRecognizer = NSRotationGestureRecognizer
public typealias NSUIScreen = NSScreen
/** On OS X there is no CADisplayLink. Use a 60 fps timer to render the animations. */
public class NSUIDisplayLink
{
private var timer: NSTimer?
private var displayLink: CVDisplayLink?
private var _timestamp: CFTimeInterval = 0.0
private weak var _target: AnyObject?
private var _selector: Selector
public var timestamp: CFTimeInterval
{
return _timestamp
}
init(target: AnyObject, selector: Selector)
{
_target = target
_selector = selector
if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess
{
CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in
let _self = unsafeBitCast(userData, NSUIDisplayLink.self)
_self._timestamp = CFAbsoluteTimeGetCurrent()
_self._target?.performSelectorOnMainThread(_self._selector, withObject: _self, waitUntilDone: false)
return kCVReturnSuccess
}, UnsafeMutablePointer(unsafeAddressOf(self)))
}
else
{
timer = NSTimer(timeInterval: 1.0 / 60.0, target: target, selector: selector, userInfo: nil, repeats: true)
}
}
deinit
{
stop()
}
public func addToRunLoop(runloop: NSRunLoop, forMode: String)
{
if displayLink != nil
{
CVDisplayLinkStart(displayLink!)
}
else if timer != nil
{
runloop.addTimer(timer!, forMode: forMode)
}
}
public func removeFromRunLoop(runloop: NSRunLoop, forMode: String)
{
stop()
}
private func stop()
{
if displayLink != nil
{
CVDisplayLinkStop(displayLink!)
}
if timer != nil
{
timer?.invalidate()
}
}
}
/** The 'tap' gesture is mapped to clicks. */
extension NSUITapGestureRecognizer
{
final func nsuiNumberOfTouches() -> Int
{
return 1
}
final var nsuiNumberOfTapsRequired: Int
{
get
{
return self.numberOfClicksRequired
}
set
{
self.numberOfClicksRequired = newValue
}
}
}
extension NSUIPanGestureRecognizer
{
final func nsuiNumberOfTouches() -> Int
{
return 1
}
/// FIXME: Currently there are no more than 1 touch in OSX gestures, and not way to create custom touch gestures.
final func nsuiLocationOfTouch(touch: Int, inView: NSView?) -> NSPoint
{
return super.locationInView(inView)
}
}
extension NSUIRotationGestureRecognizer
{
/// FIXME: Currently there are no velocities in OSX gestures, and not way to create custom touch gestures.
final var velocity: CGFloat
{
return 0.1
}
final var nsuiRotation: CGFloat
{
get { return -rotation }
set { rotation = -newValue }
}
}
extension NSUIPinchGestureRecognizer
{
final var nsuiScale: CGFloat
{
get
{
return magnification + 1.0
}
set
{
magnification = newValue - 1.0
}
}
/// FIXME: Currently there are no more than 1 touch in OSX gestures, and not way to create custom touch gestures.
final func nsuiLocationOfTouch(touch: Int, inView: NSView?) -> NSPoint
{
return super.locationInView(inView)
}
}
extension NSView
{
final var nsuiGestureRecognizers: [NSGestureRecognizer]?
{
return self.gestureRecognizers
}
}
public class NSUIView: NSView
{
public final override var flipped: Bool
{
return true
}
func setNeedsDisplay()
{
self.setNeedsDisplayInRect(self.bounds)
}
public final override func touchesBeganWithEvent(event: NSEvent)
{
self.nsuiTouchesBegan(event.touchesMatchingPhase(.Any, inView: self), withEvent: event)
}
public final override func touchesEndedWithEvent(event: NSEvent)
{
self.nsuiTouchesEnded(event.touchesMatchingPhase(.Any, inView: self), withEvent: event)
}
public final override func touchesMovedWithEvent(event: NSEvent)
{
self.nsuiTouchesMoved(event.touchesMatchingPhase(.Any, inView: self), withEvent: event)
}
public override func touchesCancelledWithEvent(event: NSEvent)
{
self.nsuiTouchesCancelled(event.touchesMatchingPhase(.Any, inView: self), withEvent: event)
}
public func nsuiTouchesBegan(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesBeganWithEvent(event!)
}
public func nsuiTouchesMoved(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesMovedWithEvent(event!)
}
public func nsuiTouchesEnded(touches: Set, withEvent event: NSUIEvent?)
{
super.touchesEndedWithEvent(event!)
}
public func nsuiTouchesCancelled(touches: Set?, withEvent event: NSUIEvent?)
{
super.touchesCancelledWithEvent(event!)
}
var backgroundColor: NSUIColor?
{
get
{
return self.layer?.backgroundColor == nil
? nil
: NSColor(CGColor: self.layer!.backgroundColor!)
}
set
{
self.layer?.backgroundColor = newValue == nil ? nil : newValue!.CGColor
}
}
final var nsuiLayer: CALayer?
{
return self.layer
}
}
extension NSFont
{
var lineHeight: CGFloat
{
// Not sure if this is right, but it looks okay
return self.boundingRectForFont.size.height
}
}
extension NSScreen
{
final var nsuiScale: CGFloat
{
return self.backingScaleFactor
}
}
extension NSImage
{
var CGImage: CGImageRef?
{
return self.CGImageForProposedRect(nil, context: nil, hints: nil)
}
}
extension NSTouch
{
/** Touch locations on OS X are relative to the trackpad, whereas on iOS they are actually *on* the view. */
func locationInView(view: NSView) -> NSPoint
{
let n = self.normalizedPosition
let b = view.bounds
return NSPoint(x: b.origin.x + b.size.width * n.x, y: b.origin.y + b.size.height * n.y)
}
}
extension NSScrollView
{
var scrollEnabled: Bool
{
get
{
return true
}
set
{
// FIXME: We can't disable scrolling it on OSX
}
}
}
func NSUIGraphicsGetCurrentContext() -> CGContextRef?
{
return NSGraphicsContext.currentContext()?.CGContext
}
func NSUIGraphicsPushContext(context: CGContextRef)
{
let address = unsafeAddressOf(context)
let ptr: UnsafeMutablePointer = UnsafeMutablePointer(UnsafePointer(address))
let cx = NSGraphicsContext(graphicsPort: ptr, flipped: true)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.setCurrentContext(cx)
}
func NSUIGraphicsPopContext()
{
NSGraphicsContext.restoreGraphicsState()
}
func NSUIImagePNGRepresentation(image: NSUIImage) -> NSData?
{
image.lockFocus()
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
image.unlockFocus()
return rep?.representationUsingType(.NSPNGFileType, properties: [:])
}
func NSUIImageJPEGRepresentation(image: NSUIImage, _ quality: CGFloat = 0.9) -> NSData?
{
image.lockFocus()
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
image.unlockFocus()
return rep?.representationUsingType(.NSJPEGFileType, properties: [NSImageCompressionFactor: quality])
}
private var imageContextStack: [CGFloat] = []
func NSUIGraphicsBeginImageContextWithOptions(size: CGSize, _ opaque: Bool, _ scale: CGFloat)
{
var scale = scale
if scale == 0.0
{
scale = NSScreen.mainScreen()?.backingScaleFactor ?? 1.0
}
let width = Int(size.width * scale)
let height = Int(size.height * scale)
if width > 0 && height > 0
{
imageContextStack.append(scale)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let ctx = CGBitmapContextCreate(nil, width, height, 8, 4*width, colorSpace, (opaque ? CGImageAlphaInfo.NoneSkipFirst.rawValue : CGImageAlphaInfo.PremultipliedFirst.rawValue))
CGContextConcatCTM(ctx, CGAffineTransformMake(1, 0, 0, -1, 0, CGFloat(height)))
CGContextScaleCTM(ctx, scale, scale)
NSUIGraphicsPushContext(ctx!)
}
}
func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage?
{
if !imageContextStack.isEmpty
{
let ctx = NSUIGraphicsGetCurrentContext()
let scale = imageContextStack.last!
if let theCGImage = CGBitmapContextCreateImage(ctx)
{
let size = CGSizeMake(CGFloat(CGBitmapContextGetWidth(ctx)) / scale, CGFloat(CGBitmapContextGetHeight(ctx)) / scale)
let image = NSImage(CGImage: theCGImage, size: size)
return image
}
}
return nil
}
func NSUIGraphicsEndImageContext()
{
if imageContextStack.last != nil
{
imageContextStack.removeLast()
NSUIGraphicsPopContext()
}
}
func NSUIMainScreen() -> NSUIScreen?
{
return NSUIScreen.mainScreen()
}
#endif
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartSelectionDetail.swift
================================================
//
// ChartSelectionDetail.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
public class ChartSelectionDetail: NSObject
{
private var _value = Double(0)
private var _dataSetIndex = Int(0)
private var _dataSet: IChartDataSet!
public override init()
{
super.init()
}
public init(value: Double, dataSetIndex: Int, dataSet: IChartDataSet)
{
super.init()
_value = value
_dataSetIndex = dataSetIndex
_dataSet = dataSet
}
public var value: Double
{
return _value
}
public var dataSetIndex: Int
{
return _dataSetIndex
}
public var dataSet: IChartDataSet?
{
return _dataSet
}
// MARK: NSObject
public override func isEqual(object: AnyObject?) -> Bool
{
if (object === nil)
{
return false
}
if (!object!.isKindOfClass(self.dynamicType))
{
return false
}
if (object!.value != _value)
{
return false
}
if (object!.dataSetIndex != _dataSetIndex)
{
return false
}
if (object!.dataSet !== _dataSet)
{
return false
}
return true
}
}
public func ==(lhs: ChartSelectionDetail, rhs: ChartSelectionDetail) -> Bool
{
if (lhs === rhs)
{
return true
}
if (!lhs.isKindOfClass(rhs.dynamicType))
{
return false
}
if (lhs.value != rhs.value)
{
return false
}
if (lhs.dataSetIndex != rhs.dataSetIndex)
{
return false
}
if (lhs.dataSet !== rhs.dataSet)
{
return false
}
return true
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartTransformer.swift
================================================
//
// ChartTransformer.swift
// Charts
//
// Created by Daniel Cohen Gindi on 6/3/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Transformer class that contains all matrices and is responsible for transforming values into pixels on the screen and backwards.
public class ChartTransformer: NSObject
{
/// matrix to map the values to the screen pixels
internal var _matrixValueToPx = CGAffineTransformIdentity
/// matrix for handling the different offsets of the chart
internal var _matrixOffset = CGAffineTransformIdentity
internal var _viewPortHandler: ChartViewPortHandler
public init(viewPortHandler: ChartViewPortHandler)
{
_viewPortHandler = viewPortHandler
}
/// Prepares the matrix that transforms values to pixels. Calculates the scale factors from the charts size and offsets.
public func prepareMatrixValuePx(chartXMin chartXMin: Double, deltaX: CGFloat, deltaY: CGFloat, chartYMin: Double)
{
var scaleX = (_viewPortHandler.contentWidth / deltaX)
var scaleY = (_viewPortHandler.contentHeight / deltaY)
if CGFloat.infinity == scaleX
{
scaleX = 0.0
}
if CGFloat.infinity == scaleY
{
scaleY = 0.0
}
// setup all matrices
_matrixValueToPx = CGAffineTransformIdentity
_matrixValueToPx = CGAffineTransformScale(_matrixValueToPx, scaleX, -scaleY)
_matrixValueToPx = CGAffineTransformTranslate(_matrixValueToPx, CGFloat(-chartXMin), CGFloat(-chartYMin))
}
/// Prepares the matrix that contains all offsets.
public func prepareMatrixOffset(inverted: Bool)
{
if (!inverted)
{
_matrixOffset = CGAffineTransformMakeTranslation(_viewPortHandler.offsetLeft, _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom)
}
else
{
_matrixOffset = CGAffineTransformMakeScale(1.0, -1.0)
_matrixOffset = CGAffineTransformTranslate(_matrixOffset, _viewPortHandler.offsetLeft, -_viewPortHandler.offsetTop)
}
}
/// Transforms an Entry into a transformed point for bar chart
public func getTransformedValueBarChart(entry entry: ChartDataEntry, xIndex: Int, dataSetIndex: Int, phaseY: CGFloat, dataSetCount: Int, groupSpace: CGFloat) -> CGPoint
{
// calculate the x-position, depending on datasetcount
let x = CGFloat(xIndex + (xIndex * (dataSetCount - 1)) + dataSetIndex) + groupSpace * CGFloat(xIndex) + groupSpace / 2.0
let y = entry.value
var valuePoint = CGPoint(
x: x,
y: CGFloat(y) * phaseY
)
pointValueToPixel(&valuePoint)
return valuePoint
}
/// Transforms an Entry into a transformed point for horizontal bar chart
public func getTransformedValueHorizontalBarChart(entry entry: ChartDataEntry, xIndex: Int, dataSetIndex: Int, phaseY: CGFloat, dataSetCount: Int, groupSpace: CGFloat) -> CGPoint
{
// calculate the x-position, depending on datasetcount
let x = CGFloat(xIndex + (xIndex * (dataSetCount - 1)) + dataSetIndex) + groupSpace * CGFloat(xIndex) + groupSpace / 2.0
let y = entry.value
var valuePoint = CGPoint(
x: CGFloat(y) * phaseY,
y: x
)
pointValueToPixel(&valuePoint)
return valuePoint
}
/// Transform an array of points with all matrices.
// VERY IMPORTANT: Keep matrix order "value-touch-offset" when transforming.
public func pointValuesToPixel(inout pts: [CGPoint])
{
let trans = valueToPixelMatrix
for i in 0 ..< pts.count
{
pts[i] = CGPointApplyAffineTransform(pts[i], trans)
}
}
public func pointValueToPixel(inout point: CGPoint)
{
point = CGPointApplyAffineTransform(point, valueToPixelMatrix)
}
/// Transform a rectangle with all matrices.
public func rectValueToPixel(inout r: CGRect)
{
r = CGRectApplyAffineTransform(r, valueToPixelMatrix)
}
/// Transform a rectangle with all matrices with potential animation phases.
public func rectValueToPixel(inout r: CGRect, phaseY: CGFloat)
{
// multiply the height of the rect with the phase
var bottom = r.origin.y + r.size.height
bottom *= phaseY
let top = r.origin.y * phaseY
r.size.height = bottom - top
r.origin.y = top
r = CGRectApplyAffineTransform(r, valueToPixelMatrix)
}
/// Transform a rectangle with all matrices.
public func rectValueToPixelHorizontal(inout r: CGRect)
{
r = CGRectApplyAffineTransform(r, valueToPixelMatrix)
}
/// Transform a rectangle with all matrices with potential animation phases.
public func rectValueToPixelHorizontal(inout r: CGRect, phaseY: CGFloat)
{
// multiply the height of the rect with the phase
var right = r.origin.x + r.size.width
right *= phaseY
let left = r.origin.x * phaseY
r.size.width = right - left
r.origin.x = left
r = CGRectApplyAffineTransform(r, valueToPixelMatrix)
}
/// transforms multiple rects with all matrices
public func rectValuesToPixel(inout rects: [CGRect])
{
let trans = valueToPixelMatrix
for i in 0 ..< rects.count
{
rects[i] = CGRectApplyAffineTransform(rects[i], trans)
}
}
/// Transforms the given array of touch points (pixels) into values on the chart.
public func pixelsToValue(inout pixels: [CGPoint])
{
let trans = pixelToValueMatrix
for i in 0 ..< pixels.count
{
pixels[i] = CGPointApplyAffineTransform(pixels[i], trans)
}
}
/// Transforms the given touch point (pixels) into a value on the chart.
public func pixelToValue(inout pixel: CGPoint)
{
pixel = CGPointApplyAffineTransform(pixel, pixelToValueMatrix)
}
/// - returns: the x and y values in the chart at the given touch point
/// (encapsulated in a PointD). This method transforms pixel coordinates to
/// coordinates / values in the chart.
public func getValueByTouchPoint(point: CGPoint) -> CGPoint
{
return CGPointApplyAffineTransform(point, pixelToValueMatrix)
}
public var valueToPixelMatrix: CGAffineTransform
{
return
CGAffineTransformConcat(
CGAffineTransformConcat(
_matrixValueToPx,
_viewPortHandler.touchMatrix
),
_matrixOffset
)
}
public var pixelToValueMatrix: CGAffineTransform
{
return CGAffineTransformInvert(valueToPixelMatrix)
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartTransformerHorizontalBarChart.swift
================================================
//
// ChartTransformerHorizontalBarChart.swift
// Charts
//
// Created by Daniel Cohen Gindi on 1/4/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
public class ChartTransformerHorizontalBarChart: ChartTransformer
{
/// Prepares the matrix that contains all offsets.
public override func prepareMatrixOffset(inverted: Bool)
{
if (!inverted)
{
_matrixOffset = CGAffineTransformMakeTranslation(_viewPortHandler.offsetLeft, _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom)
}
else
{
_matrixOffset = CGAffineTransformMakeScale(-1.0, 1.0)
_matrixOffset = CGAffineTransformTranslate(_matrixOffset,
-(_viewPortHandler.chartWidth - _viewPortHandler.offsetRight),
_viewPortHandler.chartHeight - _viewPortHandler.offsetBottom)
}
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartUtils.swift
================================================
//
// Utils.swift
// Charts
//
// Created by Daniel Cohen Gindi on 23/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
#if !os(OSX)
import UIKit
#endif
public class ChartUtils
{
private static var _defaultValueFormatter: NSNumberFormatter = ChartUtils.generateDefaultValueFormatter()
internal struct Math
{
internal static let FDEG2RAD = CGFloat(M_PI / 180.0)
internal static let FRAD2DEG = CGFloat(180.0 / M_PI)
internal static let DEG2RAD = M_PI / 180.0
internal static let RAD2DEG = 180.0 / M_PI
}
internal class func roundToNextSignificant(number number: Double) -> Double
{
if (isinf(number) || isnan(number) || number == 0)
{
return number
}
let d = ceil(log10(number < 0.0 ? -number : number))
let pw = 1 - Int(d)
let magnitude = pow(Double(10.0), Double(pw))
let shifted = round(number * magnitude)
return shifted / magnitude
}
internal class func decimals(number: Double) -> Int
{
if (number == 0.0)
{
return 0
}
let i = roundToNextSignificant(number: Double(number))
return Int(ceil(-log10(i))) + 2
}
internal class func nextUp(number: Double) -> Double
{
if (isinf(number) || isnan(number))
{
return number
}
else
{
return number + DBL_EPSILON
}
}
/// - returns: the index of the DataSet that contains the closest value on the y-axis. This will return -Integer.MAX_VALUE if failure.
internal class func closestDataSetIndex(valsAtIndex: [ChartSelectionDetail], value: Double, axis: ChartYAxis.AxisDependency?) -> Int
{
var index = -Int.max
var distance = DBL_MAX
for i in 0 ..< valsAtIndex.count
{
let sel = valsAtIndex[i]
if (axis == nil || sel.dataSet?.axisDependency == axis)
{
let cdistance = abs(sel.value - value)
if (cdistance < distance)
{
index = valsAtIndex[i].dataSetIndex
distance = cdistance
}
}
}
return index
}
/// - returns: the minimum distance from a touch-y-value (in pixels) to the closest y-value (in pixels) that is displayed in the chart.
internal class func getMinimumDistance(valsAtIndex: [ChartSelectionDetail], val: Double, axis: ChartYAxis.AxisDependency) -> Double
{
var distance = DBL_MAX
for i in 0 ..< valsAtIndex.count
{
let sel = valsAtIndex[i]
if (sel.dataSet!.axisDependency == axis)
{
let cdistance = abs(sel.value - val)
if (cdistance < distance)
{
distance = cdistance
}
}
}
return distance
}
/// Calculates the position around a center point, depending on the distance from the center, and the angle of the position around the center.
internal class func getPosition(center center: CGPoint, dist: CGFloat, angle: CGFloat) -> CGPoint
{
return CGPoint(
x: center.x + dist * cos(angle * Math.FDEG2RAD),
y: center.y + dist * sin(angle * Math.FDEG2RAD)
)
}
public class func drawText(context context: CGContext, text: String, point: CGPoint, align: NSTextAlignment, attributes: [String : AnyObject]?)
{
var point = point
if (align == .Center)
{
point.x -= text.sizeWithAttributes(attributes).width / 2.0
}
else if (align == .Right)
{
point.x -= text.sizeWithAttributes(attributes).width
}
NSUIGraphicsPushContext(context)
(text as NSString).drawAtPoint(point, withAttributes: attributes)
NSUIGraphicsPopContext()
}
public class func drawText(context context: CGContext, text: String, point: CGPoint, attributes: [String : AnyObject]?, anchor: CGPoint, angleRadians: CGFloat)
{
var drawOffset = CGPoint()
NSUIGraphicsPushContext(context)
if angleRadians != 0.0
{
let size = text.sizeWithAttributes(attributes)
// Move the text drawing rect in a way that it always rotates around its center
drawOffset.x = -size.width * 0.5
drawOffset.y = -size.height * 0.5
var translate = point
// Move the "outer" rect relative to the anchor, assuming its centered
if anchor.x != 0.5 || anchor.y != 0.5
{
let rotatedSize = sizeOfRotatedRectangle(size, radians: angleRadians)
translate.x -= rotatedSize.width * (anchor.x - 0.5)
translate.y -= rotatedSize.height * (anchor.y - 0.5)
}
CGContextSaveGState(context)
CGContextTranslateCTM(context, translate.x, translate.y)
CGContextRotateCTM(context, angleRadians)
(text as NSString).drawAtPoint(drawOffset, withAttributes: attributes)
CGContextRestoreGState(context)
}
else
{
if anchor.x != 0.0 || anchor.y != 0.0
{
let size = text.sizeWithAttributes(attributes)
drawOffset.x = -size.width * anchor.x
drawOffset.y = -size.height * anchor.y
}
drawOffset.x += point.x
drawOffset.y += point.y
(text as NSString).drawAtPoint(drawOffset, withAttributes: attributes)
}
NSUIGraphicsPopContext()
}
internal class func drawMultilineText(context context: CGContext, text: String, knownTextSize: CGSize, point: CGPoint, attributes: [String : AnyObject]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat)
{
var rect = CGRect(origin: CGPoint(), size: knownTextSize)
NSUIGraphicsPushContext(context)
if angleRadians != 0.0
{
// Move the text drawing rect in a way that it always rotates around its center
rect.origin.x = -knownTextSize.width * 0.5
rect.origin.y = -knownTextSize.height * 0.5
var translate = point
// Move the "outer" rect relative to the anchor, assuming its centered
if anchor.x != 0.5 || anchor.y != 0.5
{
let rotatedSize = sizeOfRotatedRectangle(knownTextSize, radians: angleRadians)
translate.x -= rotatedSize.width * (anchor.x - 0.5)
translate.y -= rotatedSize.height * (anchor.y - 0.5)
}
CGContextSaveGState(context)
CGContextTranslateCTM(context, translate.x, translate.y)
CGContextRotateCTM(context, angleRadians)
(text as NSString).drawWithRect(rect, options: .UsesLineFragmentOrigin, attributes: attributes, context: nil)
CGContextRestoreGState(context)
}
else
{
if anchor.x != 0.0 || anchor.y != 0.0
{
rect.origin.x = -knownTextSize.width * anchor.x
rect.origin.y = -knownTextSize.height * anchor.y
}
rect.origin.x += point.x
rect.origin.y += point.y
(text as NSString).drawWithRect(rect, options: .UsesLineFragmentOrigin, attributes: attributes, context: nil)
}
NSUIGraphicsPopContext()
}
internal class func drawMultilineText(context context: CGContext, text: String, point: CGPoint, attributes: [String : AnyObject]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat)
{
let rect = text.boundingRectWithSize(constrainedToSize, options: .UsesLineFragmentOrigin, attributes: attributes, context: nil)
drawMultilineText(context: context, text: text, knownTextSize: rect.size, point: point, attributes: attributes, constrainedToSize: constrainedToSize, anchor: anchor, angleRadians: angleRadians)
}
/// - returns: an angle between 0.0 < 360.0 (not less than zero, less than 360)
internal class func normalizedAngleFromAngle(angle: CGFloat) -> CGFloat
{
var angle = angle
while (angle < 0.0)
{
angle += 360.0
}
return angle % 360.0
}
private class func generateDefaultValueFormatter() -> NSNumberFormatter
{
let formatter = NSNumberFormatter()
formatter.minimumIntegerDigits = 1
formatter.maximumFractionDigits = 1
formatter.minimumFractionDigits = 1
formatter.usesGroupingSeparator = true
return formatter
}
/// - returns: the default value formatter used for all chart components that needs a default
internal class func defaultValueFormatter() -> NSNumberFormatter
{
return _defaultValueFormatter
}
internal class func sizeOfRotatedRectangle(rectangleSize: CGSize, degrees: CGFloat) -> CGSize
{
let radians = degrees * Math.FDEG2RAD
return sizeOfRotatedRectangle(rectangleWidth: rectangleSize.width, rectangleHeight: rectangleSize.height, radians: radians)
}
internal class func sizeOfRotatedRectangle(rectangleSize: CGSize, radians: CGFloat) -> CGSize
{
return sizeOfRotatedRectangle(rectangleWidth: rectangleSize.width, rectangleHeight: rectangleSize.height, radians: radians)
}
internal class func sizeOfRotatedRectangle(rectangleWidth rectangleWidth: CGFloat, rectangleHeight: CGFloat, degrees: CGFloat) -> CGSize
{
let radians = degrees * Math.FDEG2RAD
return sizeOfRotatedRectangle(rectangleWidth: rectangleWidth, rectangleHeight: rectangleHeight, radians: radians)
}
internal class func sizeOfRotatedRectangle(rectangleWidth rectangleWidth: CGFloat, rectangleHeight: CGFloat, radians: CGFloat) -> CGSize
{
return CGSize(
width: abs(rectangleWidth * cos(radians)) + abs(rectangleHeight * sin(radians)),
height: abs(rectangleWidth * sin(radians)) + abs(rectangleHeight * cos(radians))
)
}
/// MARK: - Bridging functions
internal class func bridgedObjCGetNSUIColorArray (swift array: [NSUIColor?]) -> [NSObject]
{
var newArray = [NSObject]()
for val in array
{
if (val == nil)
{
newArray.append(NSNull())
}
else
{
newArray.append(val!)
}
}
return newArray
}
internal class func bridgedObjCGetNSUIColorArray (objc array: [NSObject]) -> [NSUIColor?]
{
var newArray = [NSUIColor?]()
for object in array
{
newArray.append(object as? NSUIColor)
}
return newArray
}
internal class func bridgedObjCGetStringArray (swift array: [String?]) -> [NSObject]
{
var newArray = [NSObject]()
for val in array
{
if (val == nil)
{
newArray.append(NSNull())
}
else
{
newArray.append(val!)
}
}
return newArray
}
internal class func bridgedObjCGetStringArray (objc array: [NSObject]) -> [String?]
{
var newArray = [String?]()
for object in array
{
newArray.append(object as? String)
}
return newArray
}
}
================================================
FILE: Sublime/Pods/Charts/Charts/Classes/Utils/ChartViewPortHandler.swift
================================================
//
// ChartViewPortHandler.swift
// Charts
//
// Created by Daniel Cohen Gindi on 27/2/15.
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/ios-charts
//
import Foundation
import CoreGraphics
/// Class that contains information about the charts current viewport settings, including offsets, scale & translation levels, ...
public class ChartViewPortHandler: NSObject
{
/// matrix used for touch events
private var _touchMatrix = CGAffineTransformIdentity
/// this rectangle defines the area in which graph values can be drawn
private var _contentRect = CGRect()
private var _chartWidth = CGFloat(0.0)
private var _chartHeight = CGFloat(0.0)
/// minimum scale value on the y-axis
private var _minScaleY = CGFloat(1.0)
/// maximum scale value on the y-axis
private var _maxScaleY = CGFloat.max
/// minimum scale value on the x-axis
private var _minScaleX = CGFloat(1.0)
/// maximum scale value on the x-axis
private var _maxScaleX = CGFloat.max
/// contains the current scale factor of the x-axis
private var _scaleX = CGFloat(1.0)
/// contains the current scale factor of the y-axis
private var _scaleY = CGFloat(1.0)
/// current translation (drag distance) on the x-axis
private var _transX = CGFloat(0.0)
/// current translation (drag distance) on the y-axis
private var _transY = CGFloat(0.0)
/// offset that allows the chart to be dragged over its bounds on the x-axis
private var _transOffsetX = CGFloat(0.0)
/// offset that allows the chart to be dragged over its bounds on the x-axis
private var _transOffsetY = CGFloat(0.0)
public override init()
{
}
/// Constructor - don't forget calling setChartDimens(...)
public init(width: CGFloat, height: CGFloat)
{
super.init()
setChartDimens(width: width, height: height)
}
public func setChartDimens(width width: CGFloat, height: CGFloat)
{
let offsetLeft = self.offsetLeft
let offsetTop = self.offsetTop
let offsetRight = self.offsetRight
let offsetBottom = self.offsetBottom
_chartHeight = height
_chartWidth = width
restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom)
}
public var hasChartDimens: Bool
{
if (_chartHeight > 0.0 && _chartWidth > 0.0)
{
return true
}
else
{
return false
}
}
public func restrainViewPort(offsetLeft offsetLeft: CGFloat, offsetTop: CGFloat, offsetRight: CGFloat, offsetBottom: CGFloat)
{
_contentRect.origin.x = offsetLeft
_contentRect.origin.y = offsetTop
_contentRect.size.width = _chartWidth - offsetLeft - offsetRight
_contentRect.size.height = _chartHeight - offsetBottom - offsetTop
}
public var offsetLeft: CGFloat
{
return _contentRect.origin.x
}
public var offsetRight: CGFloat
{
return _chartWidth - _contentRect.size.width - _contentRect.origin.x
}
public var offsetTop: CGFloat
{
return _contentRect.origin.y
}
public var offsetBottom: CGFloat
{
return _chartHeight - _contentRect.size.height - _contentRect.origin.y
}
public var contentTop: CGFloat
{
return _contentRect.origin.y
}
public var contentLeft: CGFloat
{
return _contentRect.origin.x
}
public var contentRight: CGFloat
{
return _contentRect.origin.x + _contentRect.size.width
}
public var contentBottom: CGFloat
{
return _contentRect.origin.y + _contentRect.size.height
}
public var contentWidth: CGFloat
{
return _contentRect.size.width
}
public var contentHeight: CGFloat
{
return _contentRect.size.height
}
public var contentRect: CGRect
{
return _contentRect
}
public var contentCenter: CGPoint
{
return CGPoint(x: _contentRect.origin.x + _contentRect.size.width / 2.0, y: _contentRect.origin.y + _contentRect.size.height / 2.0)
}
public var chartHeight: CGFloat
{
return _chartHeight
}
public var chartWidth: CGFloat
{
return _chartWidth
}
// MARK: - Scaling/Panning etc.
/// Zooms by the specified zoom factors.
public func zoom(scaleX scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform
{
return CGAffineTransformScale(_touchMatrix, scaleX, scaleY)
}
/// Zooms around the specified center
public func zoom(scaleX scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform
{
var matrix = CGAffineTransformTranslate(_touchMatrix, x, y)
matrix = CGAffineTransformScale(matrix, scaleX, scaleY)
matrix = CGAffineTransformTranslate(matrix, -x, -y)
return matrix
}
/// Zooms in by 1.4, x and y are the coordinates (in pixels) of the zoom center.
public func zoomIn(x x: CGFloat, y: CGFloat) -> CGAffineTransform
{
return zoom(scaleX: 1.4, scaleY: 1.4, x: x, y: y)
}
/// Zooms out by 0.7, x and y are the coordinates (in pixels) of the zoom center.
public func zoomOut(x x: CGFloat, y: CGFloat) -> CGAffineTransform
{
return zoom(scaleX: 0.7, scaleY: 0.7, x: x, y: y)
}
/// Sets the scale factor to the specified values.
public func setZoom(scaleX scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform
{
var matrix = _touchMatrix
matrix.a = scaleX
matrix.d = scaleY
return matrix
}
/// Sets the scale factor to the specified values. x and y is pivot.
public func setZoom(scaleX scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform
{
var matrix = _touchMatrix
matrix.a = 1.0
matrix.d = 1.0
matrix = CGAffineTransformTranslate(matrix, x, y)
matrix = CGAffineTransformScale(matrix, scaleX, scaleY)
matrix = CGAffineTransformTranslate(matrix, -x, -y)
return matrix
}
/// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
public func fitScreen() -> CGAffineTransform
{
_minScaleX = 1.0
_minScaleY = 1.0
return CGAffineTransformIdentity
}
/// Translates to the specified point.
public func translate(pt pt: CGPoint) -> CGAffineTransform
{
let translateX = pt.x - offsetLeft
let translateY = pt.y - offsetTop
let matrix = CGAffineTransformConcat(_touchMatrix, CGAffineTransformMakeTranslation(-translateX, -translateY))
return matrix
}
/// Centers the viewport around the specified position (x-index and y-value) in the chart.
/// Centering the viewport outside the bounds of the chart is not possible.
/// Makes most sense in combination with the setScaleMinima(...) method.
public func centerViewPort(pt pt: CGPoint, chart: ChartViewBase)
{
let translateX = pt.x - offsetLeft
let translateY = pt.y - offsetTop
let matrix = CGAffineTransformConcat(_touchMatrix, CGAffineTransformMakeTranslation(-translateX, -translateY))
refresh(newMatrix: matrix, chart: chart, invalidate: true)
}
/// call this method to refresh the graph with a given matrix
public func refresh(newMatrix newMatrix: CGAffineTransform, chart: ChartViewBase, invalidate: Bool) -> CGAffineTransform
{
_touchMatrix = newMatrix
// make sure scale and translation are within their bounds
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
chart.setNeedsDisplay()
return _touchMatrix
}
/// limits the maximum scale and X translation of the given matrix
private func limitTransAndScale(inout matrix matrix: CGAffineTransform, content: CGRect?)
{
// min scale-x is 1
_scaleX = min(max(_minScaleX, matrix.a), _maxScaleX)
// min scale-y is 1
_scaleY = min(max(_minScaleY, matrix.d), _maxScaleY)
var width: CGFloat = 0.0
var height: CGFloat = 0.0
if (content != nil)
{
width = content!.width
height = content!.height
}
let maxTransX = -width * (_scaleX - 1.0)
_transX = min(max(matrix.tx, maxTransX - _transOffsetX), _transOffsetX)
let maxTransY = height * (_scaleY - 1.0)
_transY = max(min(matrix.ty, maxTransY + _transOffsetY), -_transOffsetY)
matrix.tx = _transX
matrix.a = _scaleX
matrix.ty = _transY
matrix.d = _scaleY
}
/// Sets the minimum scale factor for the x-axis
public func setMinimumScaleX(xScale: CGFloat)
{
var newValue = xScale
if (newValue < 1.0)
{
newValue = 1.0
}
_minScaleX = newValue
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
}
/// Sets the maximum scale factor for the x-axis
public func setMaximumScaleX(xScale: CGFloat)
{
_maxScaleX = xScale
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
}
/// Sets the minimum and maximum scale factors for the x-axis
public func setMinMaxScaleX(minScaleX minScaleX: CGFloat, maxScaleX: CGFloat)
{
var newMin = minScaleX
if (newMin < 1.0)
{
newMin = 1.0
}
_minScaleX = newMin
_maxScaleX = maxScaleX
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
}
/// Sets the minimum scale factor for the y-axis
public func setMinimumScaleY(yScale: CGFloat)
{
var newValue = yScale
if (newValue < 1.0)
{
newValue = 1.0
}
_minScaleY = newValue
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
}
/// Sets the maximum scale factor for the y-axis
public func setMaximumScaleY(yScale: CGFloat)
{
_maxScaleY = yScale
limitTransAndScale(matrix: &_touchMatrix, content: _contentRect)
}
public var touchMatrix: CGAffineTransform
{
return _touchMatrix
}
// MARK: - Boundaries Check
public func isInBoundsX(x: CGFloat) -> Bool
{
if (isInBoundsLeft(x) && isInBoundsRight(x))
{
return true
}
else
{
return false
}
}
public func isInBoundsY(y: CGFloat) -> Bool
{
if (isInBoundsTop(y) && isInBoundsBottom(y))
{
return true
}
else
{
return false
}
}
public func isInBounds(x x: CGFloat, y: CGFloat) -> Bool
{
if (isInBoundsX(x) && isInBoundsY(y))
{
return true
}
else
{
return false
}
}
public func isInBoundsLeft(x: CGFloat) -> Bool
{
return _contentRect.origin.x <= x ? true : false
}
public func isInBoundsRight(x: CGFloat) -> Bool
{
let normalizedX = CGFloat(Int(x * 100.0)) / 100.0
return (_contentRect.origin.x + _contentRect.size.width) >= normalizedX ? true : false
}
public func isInBoundsTop(y: CGFloat) -> Bool
{
return _contentRect.origin.y <= y ? true : false
}
public func isInBoundsBottom(y: CGFloat) -> Bool
{
let normalizedY = CGFloat(Int(y * 100.0)) / 100.0
return (_contentRect.origin.y + _contentRect.size.height) >= normalizedY ? true : false
}
/// - returns: the current x-scale factor
public var scaleX: CGFloat
{
return _scaleX
}
/// - returns: the current y-scale factor
public var scaleY: CGFloat
{
return _scaleY
}
/// - returns: the minimum x-scale factor
public var minScaleX: CGFloat
{
return _minScaleX
}
/// - returns: the minimum y-scale factor
public var minScaleY: CGFloat
{
return _minScaleY
}
/// - returns: the minimum x-scale factor
public var maxScaleX: CGFloat
{
return _maxScaleX
}
/// - returns: the minimum y-scale factor
public var maxScaleY: CGFloat
{
return _maxScaleY
}
/// - returns: the translation (drag / pan) distance on the x-axis
public var transX: CGFloat
{
return _transX
}
/// - returns: the translation (drag / pan) distance on the y-axis
public var transY: CGFloat
{
return _transY
}
/// if the chart is fully zoomed out, return true
public var isFullyZoomedOut: Bool
{
if (isFullyZoomedOutX && isFullyZoomedOutY)
{
return true
}
else
{
return false
}
}
/// - returns: true if the chart is fully zoomed out on it's y-axis (vertical).
public var isFullyZoomedOutY: Bool
{
if (_scaleY > _minScaleY || _minScaleY > 1.0)
{
return false
}
else
{
return true
}
}
/// - returns: true if the chart is fully zoomed out on it's x-axis (horizontal).
public var isFullyZoomedOutX: Bool
{
if (_scaleX > _minScaleX || _minScaleX > 1.0)
{
return false
}
else
{
return true
}
}
/// Set an offset in pixels that allows the user to drag the chart over it's bounds on the x-axis.
public func setDragOffsetX(offset: CGFloat)
{
_transOffsetX = offset
}
/// Set an offset in pixels that allows the user to drag the chart over it's bounds on the y-axis.
public func setDragOffsetY(offset: CGFloat)
{
_transOffsetY = offset
}
/// - returns: true if both drag offsets (x and y) are zero or smaller.
public var hasNoDragOffset: Bool
{
return _transOffsetX <= 0.0 && _transOffsetY <= 0.0 ? true : false
}
/// - returns: true if the chart is not yet fully zoomed out on the x-axis
public var canZoomOutMoreX: Bool
{
return (_scaleX > _minScaleX)
}
/// - returns: true if the chart is not yet fully zoomed in on the x-axis
public var canZoomInMoreX: Bool
{
return (_scaleX < _maxScaleX)
}
/// - returns: true if the chart is not yet fully zoomed out on the y-axis
public var canZoomOutMoreY: Bool
{
return (_scaleY > _minScaleY)
}
/// - returns: true if the chart is not yet fully zoomed in on the y-axis
public var canZoomInMoreY: Bool
{
return (_scaleY < _maxScaleY)
}
}
================================================
FILE: Sublime/Pods/Charts/LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Sublime/Pods/Charts/README.md
================================================
**Version 2.2.4**, synced to [MPAndroidChart #2e41714](https://github.com/PhilJay/MPAndroidChart/commit/2e41714)

 [](https://github.com/danielgindi/Charts/releases) [](http://cocoapods.org/pods/charts) [](https://github.com/Carthage/Carthage) [](https://travis-ci.org/danielgindi/Charts)
[](https://gitter.im/danielgindi/Charts?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Just a heads up: We've renamed from *ios-charts* to **Charts**.
* Xcode 7.3 / Swift 2.2 / 3.0
* iOS 7.0 (Drag .swift files to your project)
* iOS 8.0 / 9.0 (Use as an **Embedded** Framework)
* tvOS 9.0
* OSX 10.11
Okay so there's this beautiful library called [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) by [Philipp Jahoda](https://www.linkedin.com/in/philippjahoda) which has become very popular amongst Android developers, and in the meanwhile there's no decent charting solution for iOS.
I've chosen to write it in `Swift` as it can be highly optimized by the compiler, and can be used in both `Swift` and `ObjC` project. The demo project is written in `ObjC` to demonstrate how it works.
**An amazing feature** of this library now, for Android, iOS, tvOS and OSX, is the time it saves you when developing for both platforms, as the learning curve is singleton- it happens only once, and the code stays very similar so developers don't have to go around and re-invent the app to produce the same output with a different library. (And that's not even considering the fact that there's not really another good choice out there currently...)
## Usage
In order to correctly compile:
1. Drag the `Charts.xcodeproj` to your project
2. Go to your target's settings, hit the "+" under the "Embedded Binaries" section, and select the Charts.framework
3. **Temporary workaround**: Xcode 6.3.1 has a bug, where you have to build your project once before actually writing the `@import` line. So hit "Build" now!
4. `@import Charts`
5. When using Swift in an ObjC project:
- You need to import your Bridging Header. Usually it is "*YourProject-Swift.h*", so in ChartsDemo it's "*ChartsDemo-Swift.h*". Do not try to actually include "*ChartsDemo-Swift.h*" in your project :-)
- Under "Build Options", mark "Embedded Content Contains Swift Code"
6. When using [Realm.io](https://realm.io/):
- Note that the Realm framework is not linked with Charts - it is only there for *optional* bindings. Which means that you need to have the framework in your project, and in a compatible version to whatever is compiled with Charts. We will do our best to always compile against the latest version.
If you want to compile for iOS 7:
1. Drag the code itself (.swift files) to your project. As sadly, Swift currently does not support compiling Frameworks for iOS 7.
2. Make sure that the files are added to the Target membership.
## Troubleshooting
#### Can't compile?
* Please note the difference between installing a compiled framework from CocoaPods or Carthage, and copying the source code.
* If you are using [Realm](https://realm.io/), please also `#import `
* If you are compiling the source code and want to use Realm, please make sure to include the code from `ChartsRealm` project.
* Please read the **Usage** section again.
* Search in the issues
* Try to politely ask in the issues section
#### Other problems / feature requests
* Search in the issues
* Try to politely ask in the issues section
## CocoaPods Install
Add `pod 'Charts'` to your Podfile. "Charts" is the name of the library.
For [Realm](https://realm.io/) support you can specify the subspec in your Podfile as follows:
```
pod 'Charts/Realm'
```
**Note:** ~~`pod 'ios-charts'`~~ is not the correct library, and refers to a different project by someone else.
## Carthage Install
Charts now include Carthage prebuilt binaries.
```carthage
github "danielgindi/Charts" == 2.2.4
github "danielgindi/Charts" ~> 2.2.4
```
In order to build the binaries for a new release, use `carthage build --no-skip-current && carthage archive Charts && carthage archive ChartsRealm`.
## Help
If you like what you see here, and want to support the work being done in this repository, you could:
* Contribute code, issues and pull requests
* Let people know this library exists (:fire: spread the word :fire:)
* [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=68UL6Y8KUPS96) (You can buy me a beer, or you can buy me dinner :-)
**Note:** The author of [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) is the reason that this library exists, and is accepting [donations](https://github.com/PhilJay/MPAndroidChart#donations) on his page. He deserves them!
Questions & Issues
-----
If you are having questions or problems, you should:
- Make sure you are using the latest version of the library. Check the [**release-section**](https://github.com/danielgindi/Charts/releases).
- Study the Android version's [**Documentation-Wiki**](https://github.com/PhilJay/MPAndroidChart/wiki)
- Study the (Still incomplete [](http://cocoadocs.org/docsets/Charts/)) [**Pod-Documentation**](http://cocoadocs.org/docsets/Charts/)
- Search or open questions on [**stackoverflow**](http://stackoverflow.com/questions/tagged/ios-charts) with the `ios-charts` tag
- Search [**known issues**](https://github.com/danielgindi/Charts/issues) for your problem (open and closed)
- Create new issues (please :fire: **search known issues before** :fire:, do not create duplicate issues)
Features
=======
**Core features:**
- 8 different chart types
- Scaling on both axes (with touch-gesture, axes separately or pinch-zoom)
- Dragging / Panning (with touch-gesture)
- Combined-Charts (line-, bar-, scatter-, candle-stick-, bubble-)
- Dual (separate) Axes
- Customizable Axes (both x- and y-axis)
- Highlighting values (with customizable popup-views)
- Save chart to camera-roll / export to PNG/JPEG
- Predefined color templates
- Legends (generated automatically, customizable)
- Animations (build up animations, on both x- and y-axis)
- Limit lines (providing additional information, maximums, ...)
- Fully customizable (paints, typefaces, legends, colors, background, gestures, dashed lines, ...)
- Plotting data directly from [**Realm.io**](https://realm.io) mobile database
**Chart types:**
*Screenshots are currently taken from the original repository, as they render exactly the same :-)*
- **LineChart (with legend, simple design)**

- **LineChart (with legend, simple design)**

- **LineChart (cubic lines)**

- **LineChart (gradient fill)**

- **Combined-Chart (bar- and linechart in this case)**

- **BarChart (with legend, simple design)**

- **BarChart (grouped DataSets)**

- **Horizontal-BarChart**

- **PieChart (with selection, ...)**

- **ScatterChart** (with squares, triangles, circles, ... and more)

- **CandleStickChart** (for financial data)

- **BubbleChart** (area covered by bubbles indicates the value)

- **RadarChart** (spider web chart)

Documentation
=======
Currently there's no need for documentation for the iOS/tvOS/OSX version, as the API is **95% the same** as on Android.
You can read the official [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) documentation here: [**Wiki**](https://github.com/PhilJay/MPAndroidChart/wiki)
Or you can see the [**ChartsDemo**](https://github.com/danielgindi/Charts/tree/master/ChartsDemo) project and learn the how-tos from it.
Special Thanks
=======
Goes to [@liuxuan30](https://github.com/liuxuan30), [@petester42](https://github.com/petester42) and [@AlBirdie](https://github.com/AlBirdie) for new features, bugfixes, and lots and lots of involvement in our open-sourced community! You guys are a huge help to all of those coming here with questions and issues, and I couldn't respond to all of those without you.
License
=======
Copyright 2016 Daniel Cohen Gindi & Philipp Jahoda
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/DGElasticPullToRefresh/DGElasticPullToRefreshConstants.swift
================================================
/*
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import CoreGraphics
public struct DGElasticPullToRefreshConstants {
struct KeyPaths {
static let ContentOffset = "contentOffset"
static let ContentInset = "contentInset"
static let Frame = "frame"
static let PanGestureRecognizerState = "panGestureRecognizer.state"
}
static let WaveMaxHeight: CGFloat = 70.0
static let MinOffsetToPull: CGFloat = 95.0
static let LoadingContentInset: CGFloat = 50.0
static let LoadingViewSize: CGFloat = 30.0
}
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/DGElasticPullToRefresh/DGElasticPullToRefreshExtensions.swift
================================================
/*
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import UIKit
import ObjectiveC
// MARK: -
// MARK: (NSObject) Extension
public extension NSObject {
// MARK: -
// MARK: Vars
private struct dg_associatedKeys {
static var observersArray = "observers"
}
private var dg_observers: [[String : NSObject]] {
get {
if let observers = objc_getAssociatedObject(self, &dg_associatedKeys.observersArray) as? [[String : NSObject]] {
return observers
} else {
let observers = [[String : NSObject]]()
self.dg_observers = observers
return observers
}
} set {
objc_setAssociatedObject(self, &dg_associatedKeys.observersArray, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
// MARK: -
// MARK: Methods
public func dg_addObserver(observer: NSObject, forKeyPath keyPath: String) {
let observerInfo = [keyPath : observer]
if dg_observers.indexOf({ $0 == observerInfo }) == nil {
dg_observers.append(observerInfo)
addObserver(observer, forKeyPath: keyPath, options: .New, context: nil)
}
}
public func dg_removeObserver(observer: NSObject, forKeyPath keyPath: String) {
let observerInfo = [keyPath : observer]
if let index = dg_observers.indexOf({ $0 == observerInfo}) {
dg_observers.removeAtIndex(index)
removeObserver(observer, forKeyPath: keyPath)
}
}
}
// MARK: -
// MARK: (UIScrollView) Extension
public extension UIScrollView {
// MARK: -
// MARK: Vars
private struct dg_associatedKeys {
static var pullToRefreshView = "pullToRefreshView"
}
private var _pullToRefreshView: DGElasticPullToRefreshView? {
get {
if let pullToRefreshView = objc_getAssociatedObject(self, &dg_associatedKeys.pullToRefreshView) as? DGElasticPullToRefreshView {
return pullToRefreshView
}
return nil
}
set {
objc_setAssociatedObject(self, &dg_associatedKeys.pullToRefreshView, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
private var pullToRefreshView: DGElasticPullToRefreshView! {
get {
if let pullToRefreshView = _pullToRefreshView {
return pullToRefreshView
} else {
let pullToRefreshView = DGElasticPullToRefreshView()
_pullToRefreshView = pullToRefreshView
return pullToRefreshView
}
}
}
// MARK: -
// MARK: Methods (Public)
public func dg_addPullToRefreshWithActionHandler(actionHandler: () -> Void) {
dg_addPullToRefreshWithActionHandler(actionHandler, loadingView: nil)
}
public func dg_addPullToRefreshWithActionHandler(actionHandler: () -> Void, loadingView: DGElasticPullToRefreshLoadingView?) {
multipleTouchEnabled = false
panGestureRecognizer.maximumNumberOfTouches = 1
pullToRefreshView.actionHandler = actionHandler
pullToRefreshView.loadingView = loadingView
addSubview(pullToRefreshView)
pullToRefreshView.observing = true
}
public func dg_removePullToRefresh() {
pullToRefreshView.observing = false
pullToRefreshView.removeFromSuperview()
}
public func dg_setPullToRefreshBackgroundColor(color: UIColor) {
pullToRefreshView.backgroundColor = color
}
public func dg_setPullToRefreshFillColor(color: UIColor) {
pullToRefreshView.fillColor = color
}
public func dg_stopLoading() {
pullToRefreshView.stopLoading()
}
func dg_stopScrollingAnimation() {
if let superview = self.superview, let index = superview.subviews.indexOf({ $0 == self }) as Int! {
removeFromSuperview()
superview.insertSubview(self, atIndex: index)
}
}
}
// MARK: -
// MARK: (UIView) Extension
public extension UIView {
func dg_center(usePresentationLayerIfPossible: Bool) -> CGPoint {
if usePresentationLayerIfPossible, let presentationLayer = layer.presentationLayer() as? CALayer {
// Position can be used as a center, because anchorPoint is (0.5, 0.5)
return presentationLayer.position
}
return center
}
}
// MARK: -
// MARK: (UIPanGestureRecognizer) Extension
public extension UIPanGestureRecognizer {
func dg_resign() {
enabled = false
enabled = true
}
}
// MARK: -
// MARK: (UIGestureRecognizerState) Extension
public extension UIGestureRecognizerState {
func dg_isAnyOf(values: [UIGestureRecognizerState]) -> Bool {
return values.contains({ $0 == self })
}
}
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/DGElasticPullToRefresh/DGElasticPullToRefreshLoadingView.swift
================================================
/*
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import UIKit
public class DGElasticPullToRefreshLoadingView: UIView {
// MARK: -
// MARK: Vars
lazy var maskLayer: CAShapeLayer = {
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.clearColor().CGColor
maskLayer.fillColor = UIColor.blackColor().CGColor
maskLayer.actions = ["path" : NSNull(), "position" : NSNull(), "bounds" : NSNull()]
self.layer.mask = maskLayer
return maskLayer
}()
// MARK: -
// MARK: Constructors
public init() {
super.init(frame: .zero)
}
public override init(frame: CGRect) {
super.init(frame: .zero)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: -
// MARK: Methods
public func setPullProgress(progress: CGFloat) {
}
public func startAnimating() {
}
public func stopLoading() {
}
}
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/DGElasticPullToRefresh/DGElasticPullToRefreshLoadingViewCircle.swift
================================================
/*
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import UIKit
// MARK: -
// MARK: (CGFloat) Extension
public extension CGFloat {
public func toRadians() -> CGFloat {
return (self * CGFloat(M_PI)) / 180.0
}
public func toDegrees() -> CGFloat {
return self * 180.0 / CGFloat(M_PI)
}
}
// MARK: -
// MARK: DGElasticPullToRefreshLoadingViewCircle
public class DGElasticPullToRefreshLoadingViewCircle: DGElasticPullToRefreshLoadingView {
// MARK: -
// MARK: Vars
private let kRotationAnimation = "kRotationAnimation"
private let shapeLayer = CAShapeLayer()
private lazy var identityTransform: CATransform3D = {
var transform = CATransform3DIdentity
transform.m34 = CGFloat(1.0 / -500.0)
transform = CATransform3DRotate(transform, CGFloat(-90.0).toRadians(), 0.0, 0.0, 1.0)
return transform
}()
// MARK: -
// MARK: Constructors
public override init() {
super.init(frame: .zero)
shapeLayer.lineWidth = 1.0
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = tintColor.CGColor
shapeLayer.actions = ["strokeEnd" : NSNull(), "transform" : NSNull()]
shapeLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.addSublayer(shapeLayer)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: -
// MARK: Methods
override public func setPullProgress(progress: CGFloat) {
super.setPullProgress(progress)
shapeLayer.strokeEnd = min(0.9 * progress, 0.9)
if progress > 1.0 {
let degrees = ((progress - 1.0) * 200.0)
shapeLayer.transform = CATransform3DRotate(identityTransform, degrees.toRadians(), 0.0, 0.0, 1.0)
} else {
shapeLayer.transform = identityTransform
}
}
override public func startAnimating() {
super.startAnimating()
if shapeLayer.animationForKey(kRotationAnimation) != nil { return }
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.toValue = CGFloat(2 * M_PI) + currentDegree()
rotationAnimation.duration = 1.0
rotationAnimation.repeatCount = Float.infinity
rotationAnimation.removedOnCompletion = false
rotationAnimation.fillMode = kCAFillModeForwards
shapeLayer.addAnimation(rotationAnimation, forKey: kRotationAnimation)
}
override public func stopLoading() {
super.stopLoading()
shapeLayer.removeAnimationForKey(kRotationAnimation)
}
private func currentDegree() -> CGFloat {
return shapeLayer.valueForKeyPath("transform.rotation.z") as! CGFloat
}
override public func tintColorDidChange() {
super.tintColorDidChange()
shapeLayer.strokeColor = tintColor.CGColor
}
// MARK: -
// MARK: Layout
override public func layoutSubviews() {
super.layoutSubviews()
shapeLayer.frame = bounds
let inset = shapeLayer.lineWidth / 2.0
shapeLayer.path = UIBezierPath(ovalInRect: CGRectInset(shapeLayer.bounds, inset, inset)).CGPath
}
}
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/DGElasticPullToRefresh/DGElasticPullToRefreshView.swift
================================================
/*
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import UIKit
// MARK: -
// MARK: DGElasticPullToRefreshState
public
enum DGElasticPullToRefreshState: Int {
case Stopped
case Dragging
case AnimatingBounce
case Loading
case AnimatingToStopped
func isAnyOf(values: [DGElasticPullToRefreshState]) -> Bool {
return values.contains({ $0 == self })
}
}
// MARK: -
// MARK: DGElasticPullToRefreshView
public class DGElasticPullToRefreshView: UIView {
// MARK: -
// MARK: Vars
private var _state: DGElasticPullToRefreshState = .Stopped
private(set) var state: DGElasticPullToRefreshState {
get { return _state }
set {
let previousValue = state
_state = newValue
if previousValue == .Dragging && newValue == .AnimatingBounce {
loadingView?.startAnimating()
animateBounce()
} else if newValue == .Loading && actionHandler != nil {
actionHandler()
} else if newValue == .AnimatingToStopped {
resetScrollViewContentInset(shouldAddObserverWhenFinished: true, animated: true, completion: { [weak self] () -> () in self?.state = .Stopped })
} else if newValue == .Stopped {
loadingView?.stopLoading()
}
}
}
private var originalContentInsetTop: CGFloat = 0.0 { didSet { layoutSubviews() } }
private let shapeLayer = CAShapeLayer()
private var displayLink: CADisplayLink!
var actionHandler: (() -> Void)!
var loadingView: DGElasticPullToRefreshLoadingView? {
willSet {
loadingView?.removeFromSuperview()
if let newValue = newValue {
addSubview(newValue)
}
}
}
var observing: Bool = false {
didSet {
guard let scrollView = scrollView() else { return }
if observing {
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentOffset)
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentInset)
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.Frame)
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.PanGestureRecognizerState)
} else {
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentOffset)
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentInset)
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.Frame)
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.PanGestureRecognizerState)
}
}
}
var fillColor: UIColor = .clearColor() { didSet { shapeLayer.fillColor = fillColor.CGColor } }
// MARK: Views
private let bounceAnimationHelperView = UIView()
private let cControlPointView = UIView()
private let l1ControlPointView = UIView()
private let l2ControlPointView = UIView()
private let l3ControlPointView = UIView()
private let r1ControlPointView = UIView()
private let r2ControlPointView = UIView()
private let r3ControlPointView = UIView()
// MARK: -
// MARK: Constructors
init() {
super.init(frame: CGRect.zero)
displayLink = CADisplayLink(target: self, selector: Selector("displayLinkTick"))
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
displayLink.paused = true
shapeLayer.backgroundColor = UIColor.clearColor().CGColor
shapeLayer.fillColor = UIColor.blackColor().CGColor
shapeLayer.actions = ["path" : NSNull(), "position" : NSNull(), "bounds" : NSNull()]
layer.addSublayer(shapeLayer)
addSubview(bounceAnimationHelperView)
addSubview(cControlPointView)
addSubview(l1ControlPointView)
addSubview(l2ControlPointView)
addSubview(l3ControlPointView)
addSubview(r1ControlPointView)
addSubview(r2ControlPointView)
addSubview(r3ControlPointView)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("applicationWillEnterForeground"), name: UIApplicationWillEnterForegroundNotification, object: nil)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: -
deinit {
observing = false
NSNotificationCenter.defaultCenter().removeObserver(self)
}
// MARK: -
// MARK: Observer
override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) {
if keyPath == DGElasticPullToRefreshConstants.KeyPaths.ContentOffset {
if let newContentOffsetY = change?[NSKeyValueChangeNewKey]?.CGPointValue.y, let scrollView = scrollView() {
if state.isAnyOf([.Loading, .AnimatingToStopped]) && newContentOffsetY < -scrollView.contentInset.top {
scrollView.dg_stopScrollingAnimation()
scrollView.contentOffset.y = -scrollView.contentInset.top
} else {
scrollViewDidChangeContentOffset(dragging: scrollView.dragging)
}
layoutSubviews()
}
} else if keyPath == DGElasticPullToRefreshConstants.KeyPaths.ContentInset {
if let newContentInsetTop = change?[NSKeyValueChangeNewKey]?.UIEdgeInsetsValue().top {
originalContentInsetTop = newContentInsetTop
}
} else if keyPath == DGElasticPullToRefreshConstants.KeyPaths.Frame {
layoutSubviews()
} else if keyPath == DGElasticPullToRefreshConstants.KeyPaths.PanGestureRecognizerState {
if let gestureState = scrollView()?.panGestureRecognizer.state where gestureState.dg_isAnyOf([.Ended, .Cancelled, .Failed]) {
scrollViewDidChangeContentOffset(dragging: false)
}
}
}
// MARK: -
// MARK: Notifications
func applicationWillEnterForeground() {
if state == .Loading {
layoutSubviews()
}
}
// MARK: -
// MARK: Methods (Public)
private func scrollView() -> UIScrollView? {
return superview as? UIScrollView
}
func stopLoading() {
// Prevent stop close animation
if state == .AnimatingToStopped {
return
}
state = .AnimatingToStopped
}
// MARK: Methods (Private)
private func isAnimating() -> Bool {
return state.isAnyOf([.AnimatingBounce, .AnimatingToStopped])
}
private func actualContentOffsetY() -> CGFloat {
guard let scrollView = scrollView() else { return 0.0 }
return max(-scrollView.contentInset.top - scrollView.contentOffset.y, 0)
}
private func currentHeight() -> CGFloat {
guard let scrollView = scrollView() else { return 0.0 }
return max(-originalContentInsetTop - scrollView.contentOffset.y, 0)
}
private func currentWaveHeight() -> CGFloat {
return min(bounds.height / 3.0 * 1.6, DGElasticPullToRefreshConstants.WaveMaxHeight)
}
private func currentPath() -> CGPath {
let width: CGFloat = scrollView()?.bounds.width ?? 0.0
let bezierPath = UIBezierPath()
let animating = isAnimating()
bezierPath.moveToPoint(CGPoint(x: 0.0, y: 0.0))
bezierPath.addLineToPoint(CGPoint(x: 0.0, y: l3ControlPointView.dg_center(animating).y))
bezierPath.addCurveToPoint(l1ControlPointView.dg_center(animating), controlPoint1: l3ControlPointView.dg_center(animating), controlPoint2: l2ControlPointView.dg_center(animating))
bezierPath.addCurveToPoint(r1ControlPointView.dg_center(animating), controlPoint1: cControlPointView.dg_center(animating), controlPoint2: r1ControlPointView.dg_center(animating))
bezierPath.addCurveToPoint(r3ControlPointView.dg_center(animating), controlPoint1: r1ControlPointView.dg_center(animating), controlPoint2: r2ControlPointView.dg_center(animating))
bezierPath.addLineToPoint(CGPoint(x: width, y: 0.0))
bezierPath.closePath()
return bezierPath.CGPath
}
private func scrollViewDidChangeContentOffset(dragging dragging: Bool) {
let offsetY = actualContentOffsetY()
if state == .Stopped && dragging {
state = .Dragging
} else if state == .Dragging && dragging == false {
if offsetY >= DGElasticPullToRefreshConstants.MinOffsetToPull {
state = .AnimatingBounce
scrollView()?.dg_stopScrollingAnimation()
} else {
state = .Stopped
}
} else if state.isAnyOf([.Dragging, .Stopped]) {
let pullProgress: CGFloat = offsetY / DGElasticPullToRefreshConstants.MinOffsetToPull
loadingView?.setPullProgress(pullProgress)
}
}
private func resetScrollViewContentInset(shouldAddObserverWhenFinished shouldAddObserverWhenFinished: Bool, animated: Bool, completion: (() -> ())?) {
guard let scrollView = scrollView() else { return }
var contentInset = scrollView.contentInset
contentInset.top = originalContentInsetTop
if state == .AnimatingBounce {
contentInset.top += currentHeight()
} else if state == .Loading {
contentInset.top += DGElasticPullToRefreshConstants.LoadingContentInset
}
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentInset)
let animationBlock = { scrollView.contentInset = contentInset }
let completionBlock = { () -> Void in
if shouldAddObserverWhenFinished {
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentInset)
}
completion?()
}
if animated {
startDisplayLink()
UIView.animateWithDuration(0.4, animations: animationBlock, completion: { _ in
self.stopDisplayLink()
completionBlock()
})
} else {
animationBlock()
completionBlock()
}
}
private func animateBounce() {
guard let scrollView = scrollView() else { return }
resetScrollViewContentInset(shouldAddObserverWhenFinished: false, animated: false, completion: nil)
let centerY = DGElasticPullToRefreshConstants.LoadingContentInset
let duration = 0.9
scrollView.scrollEnabled = false
startDisplayLink()
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentOffset)
scrollView.dg_removeObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentInset)
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.43, initialSpringVelocity: 0.0, options: [], animations: { () -> Void in
self.cControlPointView.center.y = centerY
self.l1ControlPointView.center.y = centerY
self.l2ControlPointView.center.y = centerY
self.l3ControlPointView.center.y = centerY
self.r1ControlPointView.center.y = centerY
self.r2ControlPointView.center.y = centerY
self.r3ControlPointView.center.y = centerY
}, completion: { _ in
self.stopDisplayLink()
self.resetScrollViewContentInset(shouldAddObserverWhenFinished: true, animated: false, completion: nil)
scrollView.dg_addObserver(self, forKeyPath: DGElasticPullToRefreshConstants.KeyPaths.ContentOffset)
scrollView.scrollEnabled = true
self.state = .Loading
})
bounceAnimationHelperView.center = CGPoint(x: 0.0, y: originalContentInsetTop + currentHeight())
UIView.animateWithDuration(duration * 0.4, animations: { () -> Void in
self.bounceAnimationHelperView.center = CGPoint(x: 0.0, y: self.originalContentInsetTop + DGElasticPullToRefreshConstants.LoadingContentInset)
}, completion: nil)
}
// MARK: -
// MARK: CADisplayLink
private func startDisplayLink() {
displayLink.paused = false
}
private func stopDisplayLink() {
displayLink.paused = true
}
func displayLinkTick() {
let width = bounds.width
var height: CGFloat = 0.0
if state == .AnimatingBounce {
guard let scrollView = scrollView() else { return }
scrollView.contentInset.top = bounceAnimationHelperView.dg_center(isAnimating()).y
scrollView.contentOffset.y = -scrollView.contentInset.top
height = scrollView.contentInset.top - originalContentInsetTop
frame = CGRect(x: 0.0, y: -height - 1.0, width: width, height: height)
} else if state == .AnimatingToStopped {
height = actualContentOffsetY()
}
shapeLayer.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
shapeLayer.path = currentPath()
layoutLoadingView()
}
// MARK: -
// MARK: Layout
private func layoutLoadingView() {
let width = bounds.width
let height: CGFloat = bounds.height
let loadingViewSize: CGFloat = DGElasticPullToRefreshConstants.LoadingViewSize
let minOriginY = (DGElasticPullToRefreshConstants.LoadingContentInset - loadingViewSize) / 2.0
let originY: CGFloat = max(min((height - loadingViewSize) / 2.0, minOriginY), 0.0)
loadingView?.frame = CGRect(x: (width - loadingViewSize) / 2.0, y: originY, width: loadingViewSize, height: loadingViewSize)
loadingView?.maskLayer.frame = convertRect(shapeLayer.frame, toView: loadingView)
loadingView?.maskLayer.path = shapeLayer.path
}
override public func layoutSubviews() {
super.layoutSubviews()
if let scrollView = scrollView() where state != .AnimatingBounce {
let width = scrollView.bounds.width
let height = currentHeight()
frame = CGRect(x: 0.0, y: -height, width: width, height: height)
if state.isAnyOf([.Loading, .AnimatingToStopped]) {
cControlPointView.center = CGPoint(x: width / 2.0, y: height)
l1ControlPointView.center = CGPoint(x: 0.0, y: height)
l2ControlPointView.center = CGPoint(x: 0.0, y: height)
l3ControlPointView.center = CGPoint(x: 0.0, y: height)
r1ControlPointView.center = CGPoint(x: width, y: height)
r2ControlPointView.center = CGPoint(x: width, y: height)
r3ControlPointView.center = CGPoint(x: width, y: height)
} else {
let locationX = scrollView.panGestureRecognizer.locationInView(scrollView).x
let waveHeight = currentWaveHeight()
let baseHeight = bounds.height - waveHeight
let minLeftX = min((locationX - width / 2.0) * 0.28, 0.0)
let maxRightX = max(width + (locationX - width / 2.0) * 0.28, width)
let leftPartWidth = locationX - minLeftX
let rightPartWidth = maxRightX - locationX
cControlPointView.center = CGPoint(x: locationX , y: baseHeight + waveHeight * 1.36)
l1ControlPointView.center = CGPoint(x: minLeftX + leftPartWidth * 0.71, y: baseHeight + waveHeight * 0.64)
l2ControlPointView.center = CGPoint(x: minLeftX + leftPartWidth * 0.44, y: baseHeight)
l3ControlPointView.center = CGPoint(x: minLeftX, y: baseHeight)
r1ControlPointView.center = CGPoint(x: maxRightX - rightPartWidth * 0.71, y: baseHeight + waveHeight * 0.64)
r2ControlPointView.center = CGPoint(x: maxRightX - (rightPartWidth * 0.44), y: baseHeight)
r3ControlPointView.center = CGPoint(x: maxRightX, y: baseHeight)
}
shapeLayer.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
shapeLayer.path = currentPath()
layoutLoadingView()
}
}
}
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Sublime/Pods/DGElasticPullToRefresh/README.md
================================================
# DGElasticPullToRefresh
Elastic pull to refresh compontent developed in Swift
Inspired by this Dribbble post: [Pull Down to Refresh](https://dribbble.com/shots/2232385-Pull-Down-to-Refresh) by [Hoang Nguyen](https://dribbble.com/Hoanguyen)
Tutorial on how this bounce effect was achieved can be found [here](http://iostuts.io/2015/10/17/elastic-bounce-using-uibezierpath-and-pan-gesture/).


## Requirements
* Xcode 7 or higher
* iOS 8.0 or higher (may work on previous versions, just did not test it)
* ARC
* Swift 2.0
## Demo
Open and run the DGElasticPullToRefreshExample project in Xcode to see DGElasticPullToRefresh in action.
## Installation
### Cocoapods
``` ruby
pod "DGElasticPullToRefresh"
```
### Manual
Add DGElasticPullToRefresh folder into your project.
## Example usage
``` swift
// Initialize tableView
let loadingView = DGElasticPullToRefreshLoadingViewCircle()
loadingView.tintColor = UIColor(red: 78/255.0, green: 221/255.0, blue: 200/255.0, alpha: 1.0)
tableView.dg_addPullToRefreshWithActionHandler({ [weak self] () -> Void in
// Add your logic here
// Do not forget to call dg_stopLoading() at the end
self?.tableView.dg_stopLoading()
}, loadingView: loadingView)
tableView.dg_setPullToRefreshFillColor(UIColor(red: 57/255.0, green: 67/255.0, blue: 89/255.0, alpha: 1.0))
tableView.dg_setPullToRefreshBackgroundColor(tableView.backgroundColor!)
```
### Description
Add pull to refresh without loading view:
``` swift
func dg_addPullToRefreshWithActionHandler(actionHandler: () -> Void)
```
Add pull to refresh with loading view:
``` swift
func dg_addPullToRefreshWithActionHandler(actionHandler: () -> Void, loadingView: DGElasticPullToRefreshLoadingView?)
```
You can use built-in *DGElasticPullToRefreshLoadingViewCircle* or create your own by subclassing **DGElasticPullToRefreshLoadingView** and implementing these methods:
``` swift
func setPullProgress(progress: CGFloat) { }
func startAnimating() { }
func stopLoading() { }
```
Remove pull to refresh:
``` swift
func dg_removePullToRefresh()
```
Change pull to refresh background color:
``` swift
func dg_setPullToRefreshBackgroundColor(color: UIColor)
```
Change pull to refresh fill color:
``` swift
func dg_setPullToRefreshFillColor(color: UIColor)
```
## Contribution
Please feel free to submit pull requests. Cannot wait to see your custom loading views for this pull to refresh.
## Contact
Danil Gontovnik
- https://github.com/gontovnik
- https://twitter.com/gontovnik
- http://gontovnik.com/
- danil@gontovnik.com
- http://iostuts.io/author/danil-gontovnik/
## License
The MIT License (MIT)
Copyright (c) 2015 Danil Gontovnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/AEFloatConverter.h
================================================
//
// AEFloatConverter.h
// The Amazing Audio Engine
//
// Created by Michael Tyson on 25/10/2012.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#ifdef __cplusplus
extern "C" {
#endif
#import
#import
/*!
* Universal converter to float format
*
* Use this class to easily convert arbitrary audio formats to floating point
* for use with utilities like the Accelerate framework.
*/
@interface AEFloatConverter : NSObject
/*!
* Initialize
*
* @param sourceFormat The audio format to use
*/
- (id)initWithSourceFormat:(AudioStreamBasicDescription)sourceFormat;
/*!
* Convert audio to floating-point
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a noninterleaved float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffers An array of floating-point arrays to store the converted float audio into.
* Note that you must provide the correct number of arrays, to match the number of channels.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL AEFloatConverterToFloat(AEFloatConverter* converter, AudioBufferList *sourceBuffer, float * const * targetBuffers, UInt32 frames);
/*!
* Convert audio to floating-point, in a buffer list
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a noninterleaved float format.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffer An audio buffer list to store the converted floating-point audio.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL AEFloatConverterToFloatBufferList(AEFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* Convert audio from floating-point
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffers An array of floating-point arrays containing the floating-point audio to convert.
* Note that you must provide the correct number of arrays, to match the number of channels.
* @param targetBuffer An audio buffer list to store the converted audio into.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL AEFloatConverterFromFloat(AEFloatConverter* converter, float * const * sourceBuffers, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* Convert audio from floating-point, in a buffer list
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffer An audio buffer list to store the converted audio into.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL AEFloatConverterFromFloatBufferList(AEFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* The AudioStreamBasicDescription representing the converted floating-point format
*/
@property (nonatomic, readonly) AudioStreamBasicDescription floatingPointAudioDescription;
/*!
* The source audio format set at initialization
*/
@property (nonatomic, readonly) AudioStreamBasicDescription sourceFormat;
@end
#ifdef __cplusplus
}
#endif
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/AEFloatConverter.m
================================================
//
// AEFloatConverter.m
// The Amazing Audio Engine
//
// Created by Michael Tyson on 25/10/2012.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import "AEFloatConverter.h"
#define checkResult(result,operation) (_checkResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
static inline BOOL _checkResult(OSStatus result, const char *operation, const char* file, int line) {
if ( result != noErr ) {
NSLog(@"%s:%d: %s result %d %08X %4.4s", file, line, operation, (int)result, (int)result, (char*)&result);
return NO;
}
return YES;
}
#define kNoMoreDataErr -2222
struct complexInputDataProc_t {
AudioBufferList *sourceBuffer;
};
@interface AEFloatConverter () {
AudioStreamBasicDescription _sourceAudioDescription;
AudioStreamBasicDescription _floatAudioDescription;
AudioConverterRef _toFloatConverter;
AudioConverterRef _fromFloatConverter;
AudioBufferList *_scratchFloatBufferList;
}
static OSStatus complexInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData);
@end
@implementation AEFloatConverter
@synthesize sourceFormat = _sourceAudioDescription;
-(id)initWithSourceFormat:(AudioStreamBasicDescription)sourceFormat {
if ( !(self = [super init]) ) return nil;
_floatAudioDescription.mFormatID = kAudioFormatLinearPCM;
_floatAudioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
_floatAudioDescription.mChannelsPerFrame = sourceFormat.mChannelsPerFrame;
_floatAudioDescription.mBytesPerPacket = sizeof(float);
_floatAudioDescription.mFramesPerPacket = 1;
_floatAudioDescription.mBytesPerFrame = sizeof(float);
_floatAudioDescription.mBitsPerChannel = 8 * sizeof(float);
_floatAudioDescription.mSampleRate = sourceFormat.mSampleRate;
_sourceAudioDescription = sourceFormat;
if ( memcmp(&sourceFormat, &_floatAudioDescription, sizeof(AudioStreamBasicDescription)) != 0 ) {
checkResult(AudioConverterNew(&sourceFormat, &_floatAudioDescription, &_toFloatConverter), "AudioConverterNew");
checkResult(AudioConverterNew(&_floatAudioDescription, &sourceFormat, &_fromFloatConverter), "AudioConverterNew");
_scratchFloatBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + (_floatAudioDescription.mChannelsPerFrame-1)*sizeof(AudioBuffer));
_scratchFloatBufferList->mNumberBuffers = _floatAudioDescription.mChannelsPerFrame;
for ( int i=0; i<_scratchFloatBufferList->mNumberBuffers; i++ ) {
_scratchFloatBufferList->mBuffers[i].mNumberChannels = 1;
}
}
return self;
}
-(void)dealloc {
if ( _toFloatConverter ) AudioConverterDispose(_toFloatConverter);
if ( _fromFloatConverter ) AudioConverterDispose(_fromFloatConverter);
if ( _scratchFloatBufferList ) free(_scratchFloatBufferList);
// [super dealloc];
}
BOOL AEFloatConverterToFloat(AEFloatConverter* THIS, AudioBufferList *sourceBuffer, float * const * targetBuffers, UInt32 frames) {
if ( frames == 0 ) return YES;
if ( THIS->_toFloatConverter ) {
UInt32 priorDataByteSize = sourceBuffer->mBuffers[0].mDataByteSize;
for ( int i=0; imNumberBuffers; i++ ) {
sourceBuffer->mBuffers[i].mDataByteSize = frames * THIS->_sourceAudioDescription.mBytesPerFrame;
}
for ( int i=0; i_scratchFloatBufferList->mNumberBuffers; i++ ) {
THIS->_scratchFloatBufferList->mBuffers[i].mData = targetBuffers[i];
THIS->_scratchFloatBufferList->mBuffers[i].mDataByteSize = frames * sizeof(float);
}
OSStatus result = AudioConverterFillComplexBuffer(THIS->_toFloatConverter,
complexInputDataProc,
&(struct complexInputDataProc_t) { .sourceBuffer = sourceBuffer },
&frames,
THIS->_scratchFloatBufferList,
NULL);
for ( int i=0; imNumberBuffers; i++ ) {
sourceBuffer->mBuffers[i].mDataByteSize = priorDataByteSize;
}
if ( !checkResult(result, "AudioConverterConvertComplexBuffer") ) {
return NO;
}
} else {
for ( int i=0; imNumberBuffers; i++ ) {
memcpy(targetBuffers[i], sourceBuffer->mBuffers[i].mData, frames * sizeof(float));
}
}
return YES;
}
BOOL AEFloatConverterToFloatBufferList(AEFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames) {
assert(targetBuffer->mNumberBuffers == converter->_floatAudioDescription.mChannelsPerFrame);
float *targetBuffers[targetBuffer->mNumberBuffers];
for ( int i=0; imNumberBuffers; i++ ) {
targetBuffers[i] = (float*)targetBuffer->mBuffers[i].mData;
}
return AEFloatConverterToFloat(converter, sourceBuffer, targetBuffers, frames);
}
BOOL AEFloatConverterFromFloat(AEFloatConverter* THIS, float * const * sourceBuffers, AudioBufferList *targetBuffer, UInt32 frames) {
if ( frames == 0 ) return YES;
if ( THIS->_fromFloatConverter ) {
for ( int i=0; i_scratchFloatBufferList->mNumberBuffers; i++ ) {
THIS->_scratchFloatBufferList->mBuffers[i].mData = sourceBuffers[i];
THIS->_scratchFloatBufferList->mBuffers[i].mDataByteSize = frames * sizeof(float);
}
UInt32 priorDataByteSize = targetBuffer->mBuffers[0].mDataByteSize;
for ( int i=0; imNumberBuffers; i++ ) {
targetBuffer->mBuffers[i].mDataByteSize = frames * THIS->_sourceAudioDescription.mBytesPerFrame;
}
OSStatus result = AudioConverterFillComplexBuffer(THIS->_fromFloatConverter,
complexInputDataProc,
&(struct complexInputDataProc_t) { .sourceBuffer = THIS->_scratchFloatBufferList },
&frames,
targetBuffer,
NULL);
for ( int i=0; imNumberBuffers; i++ ) {
targetBuffer->mBuffers[i].mDataByteSize = priorDataByteSize;
}
if ( !checkResult(result, "AudioConverterConvertComplexBuffer") ) {
return NO;
}
} else {
for ( int i=0; imNumberBuffers; i++ ) {
memcpy(targetBuffer->mBuffers[i].mData, sourceBuffers[i], frames * sizeof(float));
}
}
return YES;
}
BOOL AEFloatConverterFromFloatBufferList(AEFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames) {
assert(sourceBuffer->mNumberBuffers == converter->_floatAudioDescription.mChannelsPerFrame);
float *sourceBuffers[sourceBuffer->mNumberBuffers];
for ( int i=0; imNumberBuffers; i++ ) {
sourceBuffers[i] = (float*)sourceBuffer->mBuffers[i].mData;
}
return AEFloatConverterFromFloat(converter, sourceBuffers, targetBuffer, frames);
}
static OSStatus complexInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData) {
struct complexInputDataProc_t *arg = (struct complexInputDataProc_t*)inUserData;
if ( !arg->sourceBuffer ) {
return kNoMoreDataErr;
}
memcpy(ioData, arg->sourceBuffer, sizeof(AudioBufferList) + (arg->sourceBuffer->mNumberBuffers-1)*sizeof(AudioBuffer));
arg->sourceBuffer = NULL;
return noErr;
}
-(AudioStreamBasicDescription)floatingPointAudioDescription {
return _floatAudioDescription;
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudio.h
================================================
//
// EZAudio.h
// EZAudio
//
// Created by Syed Haris Ali on 11/21/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#pragma mark - 3rd Party Utilties
#import "AEFloatConverter.h"
#import "TPCircularBuffer.h"
#pragma mark - Core Components
#import "EZAudioFile.h"
#import "EZMicrophone.h"
#import "EZOutput.h"
#import "EZRecorder.h"
#pragma mark - Extended Components
#import "EZAudioPlayer.h"
#pragma mark - Interface Components
#import "EZPlot.h"
#import "EZAudioPlot.h"
#import "EZAudioPlotGL.h"
#import "EZAudioPlotGLKViewController.h"
/**
EZAudio is a simple, intuitive framework for iOS and OSX. The goal of EZAudio was to provide a modular, cross-platform framework to simplify performing everyday audio operations like getting microphone input, creating audio waveforms, recording/playing audio files, etc. The visualization tools like the EZAudioPlot and EZAudioPlotGL were created to plug right into the framework's various components and provide highly optimized drawing routines that work in harmony with audio callback loops. All components retain the same namespace whether you're on an iOS device or a Mac computer so an EZAudioPlot understands it will subclass an UIView on an iOS device or an NSView on a Mac.
Class methods for EZAudio are provided as utility methods used throughout the other modules within the framework. For instance, these methods help make sense of error codes (checkResult:operation:), map values betwen coordinate systems (MAP:leftMin:leftMax:rightMin:rightMax:), calculate root mean squared values for buffers (RMS:length:), etc.
*/
@interface EZAudio : NSObject
#pragma mark - AudioBufferList Utility
///-----------------------------------------------------------
/// @name AudioBufferList Utility
///-----------------------------------------------------------
/**
Allocates an AudioBufferList structure. Make sure to call freeBufferList when done using AudioBufferList or it will leak.
@param frames The number of frames that will be stored within each audio buffer
@param channels The number of channels (e.g. 2 for stereo, 1 for mono, etc.)
@param interleaved Whether the samples will be interleaved (if not it will be assumed to be non-interleaved and each channel will have an AudioBuffer allocated)
@return An AudioBufferList struct that has been allocated in memory
*/
+(AudioBufferList *)audioBufferListWithNumberOfFrames:(UInt32)frames
numberOfChannels:(UInt32)channels
interleaved:(BOOL)interleaved;
/**
Deallocates an AudioBufferList structure from memory.
@param bufferList A pointer to the buffer list you would like to free
*/
+(void)freeBufferList:(AudioBufferList*)bufferList;
#pragma mark - AudioStreamBasicDescription Utilties
///-----------------------------------------------------------
/// @name Creating An AudioStreamBasicDescription
///-----------------------------------------------------------
/**
@param channels The desired number of channels
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)AIFFFormatWithNumberOfChannels:(UInt32)channels
sampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)iLBCFormatWithSampleRate:(float)sampleRate;
/**
@param channels The desired number of channels
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)M4AFormatWithNumberOfChannels:(UInt32)channels
sampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)monoFloatFormatWithSampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)monoCanonicalFormatWithSampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)stereoCanonicalNonInterleavedFormatWithSampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)stereoFloatInterleavedFormatWithSampleRate:(float)sampleRate;
/**
@param sampleRate The desired sample rate
@return A new AudioStreamBasicDescription with the specified format.
*/
+(AudioStreamBasicDescription)stereoFloatNonInterleavedFormatWithSampleRate:(float)sameRate;
///-----------------------------------------------------------
/// @name AudioStreamBasicDescription Utilities
///-----------------------------------------------------------
/**
Nicely logs out the contents of an AudioStreamBasicDescription struct
@param asbd The AudioStreamBasicDescription struct with content to print out
*/
+(void)printASBD:(AudioStreamBasicDescription)asbd;
/**
Just a wrapper around the setCanonical function provided in the Core Audio Utility C++ class.
@param asbd The AudioStreamBasicDescription structure to modify
@param nChannels The number of expected channels on the description
@param interleaved A flag indicating whether the stereo samples should be interleaved in the buffer
*/
+(void)setCanonicalAudioStreamBasicDescription:(AudioStreamBasicDescription*)asbd
numberOfChannels:(UInt32)nChannels
interleaved:(BOOL)interleaved;
#pragma mark - Math Utilities
///-----------------------------------------------------------
/// @name Math Utilities
///-----------------------------------------------------------
/**
Appends an array of values to a history buffer and performs an internal shift to add the values to the tail and removes the same number of values from the head.
@param buffer A float array of values to append to the tail of the history buffer
@param bufferLength The length of the float array being appended to the history buffer
@param scrollHistory The target history buffer in which to append the values
@param scrollHistoryLength The length of the target history buffer
*/
+(void)appendBufferAndShift:(float*)buffer
withBufferSize:(int)bufferLength
toScrollHistory:(float*)scrollHistory
withScrollHistorySize:(int)scrollHistoryLength;
/**
Appends a value to a history buffer and performs an internal shift to add the value to the tail and remove the 0th value.
@param value The float value to append to the history array
@param scrollHistory The target history buffer in which to append the values
@param scrollHistoryLength The length of the target history buffer
*/
+(void) appendValue:(float)value
toScrollHistory:(float*)scrollHistory
withScrollHistorySize:(int)scrollHistoryLength;
/**
Maps a value from one coordinate system into another one. Takes in the current value to map, the minimum and maximum values of the first coordinate system, and the minimum and maximum values of the second coordinate system and calculates the mapped value in the second coordinate system's constraints.
@param value The value expressed in the first coordinate system
@param leftMin The minimum of the first coordinate system
@param leftMax The maximum of the first coordinate system
@param rightMin The minimum of the second coordindate system
@param rightMax The maximum of the second coordinate system
@return The mapped value in terms of the second coordinate system
*/
+(float)MAP:(float)value
leftMin:(float)leftMin
leftMax:(float)leftMax
rightMin:(float)rightMin
rightMax:(float)rightMax;
/**
Calculates the root mean squared for a buffer.
@param buffer A float buffer array of values whose root mean squared to calculate
@param bufferSize The size of the float buffer
@return The root mean squared of the buffer
*/
+(float)RMS:(float*)buffer
length:(int)bufferSize;
/**
Calculate the sign function sgn(x) =
{ -1 , x < 0,
{ 0 , x = 0,
{ 1 , x > 0
@param value The float value for which to use as x
@return The float sign value
*/
+(float)SGN:(float)value;
#pragma mark - OSStatus Utility
///-----------------------------------------------------------
/// @name OSStatus Utility
///-----------------------------------------------------------
/**
Basic check result function useful for checking each step of the audio setup process
@param result The OSStatus representing the result of an operation
@param operation A string (const char, not NSString) describing the operation taking place (will print if fails)
*/
+(void)checkResult:(OSStatus)result
operation:(const char*)operation;
#pragma mark - Plot Utility
///-----------------------------------------------------------
/// @name Plot Utility
///-----------------------------------------------------------
+(void)updateScrollHistory:(float**)scrollHistory
withLength:(int)scrollHistoryLength
atIndex:(int*)index
withBuffer:(float*)buffer
withBufferSize:(int)bufferSize
isResolutionChanging:(BOOL*)isChanging;
#pragma mark - TPCircularBuffer Utility
///-----------------------------------------------------------
/// @name TPCircularBuffer Utility
///-----------------------------------------------------------
/**
Appends the data from the audio buffer list to the circular buffer
@param circularBuffer Pointer to the instance of the TPCircularBuffer to add the audio data to
@param audioBufferList Pointer to the instance of the AudioBufferList with the audio data
*/
+(void)appendDataToCircularBuffer:(TPCircularBuffer*)circularBuffer
fromAudioBufferList:(AudioBufferList*)audioBufferList;
/**
Initializes the circular buffer (just a wrapper around the C method)
* @param circularBuffer Pointer to an instance of the TPCircularBuffer
* @param size The length of the TPCircularBuffer (usually 1024)
*/
+(void)circularBuffer:(TPCircularBuffer*)circularBuffer
withSize:(int)size;
/**
Frees a circular buffer
@param circularBuffer Pointer to the circular buffer to clear
*/
+(void)freeCircularBuffer:(TPCircularBuffer*)circularBuffer;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudio.m
================================================
//
// EZAudio.m
// EZAudio
//
// Created by Syed Haris Ali on 11/21/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZAudio.h"
@implementation EZAudio
#pragma mark - AudioBufferList Utility
+(AudioBufferList *)audioBufferListWithNumberOfFrames:(UInt32)frames
numberOfChannels:(UInt32)channels
interleaved:(BOOL)interleaved
{
AudioBufferList *audioBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList));
UInt32 outputBufferSize = 32 * frames; // 32 KB
audioBufferList->mNumberBuffers = interleaved ? 1 : channels;
for( int i = 0; i < audioBufferList->mNumberBuffers; i++ )
{
audioBufferList->mBuffers[i].mNumberChannels = channels;
audioBufferList->mBuffers[i].mDataByteSize = channels * outputBufferSize;
audioBufferList->mBuffers[i].mData = (float*)malloc(channels * sizeof(float) *outputBufferSize);
}
return audioBufferList;
}
+(void)freeBufferList:(AudioBufferList *)bufferList
{
if( bufferList )
{
if( bufferList->mNumberBuffers )
{
for( int i = 0; i < bufferList->mNumberBuffers; i++ )
{
if( bufferList->mBuffers[i].mData )
{
free(bufferList->mBuffers[i].mData);
}
}
}
free(bufferList);
}
bufferList = NULL;
}
#pragma mark - AudioStreamBasicDescription Utility
+(AudioStreamBasicDescription)AIFFFormatWithNumberOfChannels:(UInt32)channels
sampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
memset(&asbd, 0, sizeof(asbd));
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFormatFlags = kAudioFormatFlagIsBigEndian|kAudioFormatFlagIsPacked|kAudioFormatFlagIsSignedInteger;
asbd.mSampleRate = sampleRate;
asbd.mChannelsPerFrame = channels;
asbd.mBitsPerChannel = 32;
asbd.mBytesPerPacket = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame;
asbd.mFramesPerPacket = 1;
asbd.mBytesPerFrame = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame;
return asbd;
}
+(AudioStreamBasicDescription)iLBCFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
memset(&asbd, 0, sizeof(asbd));
asbd.mFormatID = kAudioFormatiLBC;
asbd.mChannelsPerFrame = 1;
asbd.mSampleRate = sampleRate;
// Fill in the rest of the descriptions using the Audio Format API
UInt32 propSize = sizeof(asbd);
[EZAudio checkResult:AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&asbd)
operation:"Failed to fill out the rest of the m4a AudioStreamBasicDescription"];
return asbd;
}
+(AudioStreamBasicDescription)M4AFormatWithNumberOfChannels:(UInt32)channels
sampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
memset(&asbd, 0, sizeof(asbd));
asbd.mFormatID = kAudioFormatMPEG4AAC;
asbd.mChannelsPerFrame = channels;
asbd.mSampleRate = sampleRate;
// Fill in the rest of the descriptions using the Audio Format API
UInt32 propSize = sizeof(asbd);
[EZAudio checkResult:AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&asbd)
operation:"Failed to fill out the rest of the m4a AudioStreamBasicDescription"];
return asbd;
}
+(AudioStreamBasicDescription)monoFloatFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
UInt32 byteSize = sizeof(float);
asbd.mBitsPerChannel = 8 * byteSize;
asbd.mBytesPerFrame = byteSize;
asbd.mBytesPerPacket = byteSize;
asbd.mChannelsPerFrame = 1;
asbd.mFormatFlags = kAudioFormatFlagIsPacked|kAudioFormatFlagIsFloat;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFramesPerPacket = 1;
asbd.mSampleRate = sampleRate;
return asbd;
}
+(AudioStreamBasicDescription)monoCanonicalFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
UInt32 byteSize = sizeof(float);
asbd.mBitsPerChannel = 8 * byteSize;
asbd.mBytesPerFrame = byteSize;
asbd.mBytesPerPacket = byteSize;
asbd.mChannelsPerFrame = 1;
asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFramesPerPacket = 1;
asbd.mSampleRate = sampleRate;
return asbd;
}
+(AudioStreamBasicDescription)stereoCanonicalNonInterleavedFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
UInt32 byteSize = sizeof(float);
asbd.mBitsPerChannel = 8 * byteSize;
asbd.mBytesPerFrame = byteSize;
asbd.mBytesPerPacket = byteSize;
asbd.mChannelsPerFrame = 2;
asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFramesPerPacket = 1;
asbd.mSampleRate = sampleRate;
return asbd;
}
+(AudioStreamBasicDescription)stereoFloatInterleavedFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
UInt32 floatByteSize = sizeof(float);
asbd.mChannelsPerFrame = 2;
asbd.mBitsPerChannel = 8 * floatByteSize;
asbd.mBytesPerFrame = asbd.mChannelsPerFrame * floatByteSize;
asbd.mBytesPerPacket = asbd.mChannelsPerFrame * floatByteSize;
asbd.mFormatFlags = kAudioFormatFlagIsPacked|kAudioFormatFlagIsFloat;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFramesPerPacket = 1;
asbd.mSampleRate = sampleRate;
return asbd;
}
+(AudioStreamBasicDescription)stereoFloatNonInterleavedFormatWithSampleRate:(float)sampleRate
{
AudioStreamBasicDescription asbd;
UInt32 floatByteSize = sizeof(float);
asbd.mBitsPerChannel = 8 * floatByteSize;
asbd.mBytesPerFrame = floatByteSize;
asbd.mBytesPerPacket = floatByteSize;
asbd.mChannelsPerFrame = 2;
asbd.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsNonInterleaved;
asbd.mFormatID = kAudioFormatLinearPCM;
asbd.mFramesPerPacket = 1;
asbd.mSampleRate = sampleRate;
return asbd;
}
+(void)printASBD:(AudioStreamBasicDescription)asbd {
char formatIDString[5];
UInt32 formatID = CFSwapInt32HostToBig(asbd.mFormatID);
bcopy (&formatID, formatIDString, 4);
formatIDString[4] = '\0';
NSLog (@" Sample Rate: %10.0f", asbd.mSampleRate);
NSLog (@" Format ID: %10s", formatIDString);
NSLog (@" Format Flags: %10X", (unsigned int)asbd.mFormatFlags);
NSLog (@" Bytes per Packet: %10d", (unsigned int)asbd.mBytesPerPacket);
NSLog (@" Frames per Packet: %10d", (unsigned int)asbd.mFramesPerPacket);
NSLog (@" Bytes per Frame: %10d", (unsigned int)asbd.mBytesPerFrame);
NSLog (@" Channels per Frame: %10d", (unsigned int)asbd.mChannelsPerFrame);
NSLog (@" Bits per Channel: %10d", (unsigned int)asbd.mBitsPerChannel);
}
+(void)setCanonicalAudioStreamBasicDescription:(AudioStreamBasicDescription*)asbd
numberOfChannels:(UInt32)nChannels
interleaved:(BOOL)interleaved {
asbd->mFormatID = kAudioFormatLinearPCM;
#if TARGET_OS_IPHONE
int sampleSize = sizeof(float);
asbd->mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
#elif TARGET_OS_MAC
int sampleSize = sizeof(Float32);
asbd->mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
#endif
asbd->mBitsPerChannel = 8 * sampleSize;
asbd->mChannelsPerFrame = nChannels;
asbd->mFramesPerPacket = 1;
if (interleaved)
asbd->mBytesPerPacket = asbd->mBytesPerFrame = nChannels * sampleSize;
else {
asbd->mBytesPerPacket = asbd->mBytesPerFrame = sampleSize;
asbd->mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
}
}
#pragma mark - OSStatus Utility
+(void)checkResult:(OSStatus)result
operation:(const char *)operation {
if (result == noErr) return;
char errorString[20];
// see if it appears to be a 4-char-code
*(UInt32 *)(errorString + 1) = CFSwapInt32HostToBig(result);
if (isprint(errorString[1]) && isprint(errorString[2]) && isprint(errorString[3]) && isprint(errorString[4])) {
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
} else
// no, format it as an integer
sprintf(errorString, "%d", (int)result);
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
exit(1);
}
#pragma mark - Math Utility
+(void)appendBufferAndShift:(float*)buffer
withBufferSize:(int)bufferLength
toScrollHistory:(float*)scrollHistory
withScrollHistorySize:(int)scrollHistoryLength {
NSAssert(scrollHistoryLength>=bufferLength,@"Scroll history array length must be greater buffer length");
NSAssert(scrollHistoryLength>0,@"Scroll history array length must be greater than 0");
NSAssert(bufferLength>0,@"Buffer array length must be greater than 0");
int shiftLength = scrollHistoryLength - bufferLength;
size_t floatByteSize = sizeof(float);
size_t shiftByteSize = shiftLength * floatByteSize;
size_t bufferByteSize = bufferLength * floatByteSize;
memmove(&scrollHistory[0],
&scrollHistory[bufferLength],
shiftByteSize);
memmove(&scrollHistory[shiftLength],
&buffer[0],
bufferByteSize);
}
+(void) appendValue:(float)value
toScrollHistory:(float*)scrollHistory
withScrollHistorySize:(int)scrollHistoryLength {
float val[1]; val[0] = value;
[self appendBufferAndShift:val
withBufferSize:1
toScrollHistory:scrollHistory
withScrollHistorySize:scrollHistoryLength];
}
+(float)MAP:(float)value
leftMin:(float)leftMin
leftMax:(float)leftMax
rightMin:(float)rightMin
rightMax:(float)rightMax {
float leftSpan = leftMax - leftMin;
float rightSpan = rightMax - rightMin;
float valueScaled = ( value - leftMin ) / leftSpan;
return rightMin + (valueScaled * rightSpan);
}
+(float)RMS:(float *)buffer
length:(int)bufferSize {
float sum = 0.0;
for(int i = 0; i < bufferSize; i++)
sum += buffer[i] * buffer[i];
return sqrtf( sum / bufferSize );
}
+(float)SGN:(float)value
{
return value < 0 ? -1.0f : ( value > 0 ? 1.0f : 0.0f );
}
#pragma mark - Plot Utility
+(void)updateScrollHistory:(float **)scrollHistory
withLength:(int)scrollHistoryLength
atIndex:(int*)index
withBuffer:(float *)buffer
withBufferSize:(int)bufferSize
isResolutionChanging:(BOOL*)isChanging {
//
size_t floatByteSize = sizeof(float);
//
if( *scrollHistory == NULL ){
// Create the history buffer
*scrollHistory = (float*)calloc(kEZAudioPlotMaxHistoryBufferLength,floatByteSize);
}
//
if( !*isChanging ){
float rms = [EZAudio RMS:buffer length:bufferSize];
if( *index < scrollHistoryLength ){
float *hist = *scrollHistory;
hist[*index] = rms;
(*index)++;
}
else {
[EZAudio appendValue:rms
toScrollHistory:*scrollHistory
withScrollHistorySize:scrollHistoryLength];
}
}
}
#pragma mark - TPCircularBuffer Utility
+(void)circularBuffer:(TPCircularBuffer *)circularBuffer withSize:(int)size {
TPCircularBufferInit(circularBuffer,size);
}
+(void)appendDataToCircularBuffer:(TPCircularBuffer*)circularBuffer
fromAudioBufferList:(AudioBufferList*)audioBufferList {
TPCircularBufferProduceBytes(circularBuffer,
audioBufferList->mBuffers[0].mData,
audioBufferList->mBuffers[0].mDataByteSize);
}
+(void)freeCircularBuffer:(TPCircularBuffer *)circularBuffer {
TPCircularBufferClear(circularBuffer);
TPCircularBufferCleanup(circularBuffer);
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioFile.h
================================================
//
// EZAudioFile.h
// EZAudio
//
// Created by Syed Haris Ali on 12/1/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#import
@class EZAudio;
@class EZAudioFile;
/**
The EZAudioFileDelegate provides event callbacks for the EZAudioFile object. These type of events are triggered by reads and seeks on the file and gives feedback such as the audio data read as a float array for visualizations and the new seek position for UI updating.
*/
@protocol EZAudioFileDelegate
@optional
/**
Triggered from the EZAudioFile function `readFrames:audioBufferList:bufferSize:eof:` to notify the delegate of the read audio data as a float array instead of a buffer list. Common use case of this would be to visualize the float data using an audio plot or audio data dependent OpenGL sketch.
@param audioFile The instance of the EZAudioFile that triggered the event.
@param buffer A float array of float arrays holding the audio data. buffer[0] would be the left channel's float array while buffer[1] would be the right channel's float array in a stereo file.
@param bufferSize The length of the buffers float arrays
@param numberOfChannels The number of channels. 2 for stereo, 1 for mono.
*/
-(void) audioFile:(EZAudioFile*)audioFile
readAudio:(float**)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels;
/**
Occurs when the audio file's internal seek position has been updated by the EZAudioFile functions `readFrames:audioBufferList:bufferSize:eof:` or `audioFile:updatedPosition:`.
@param audioFile The instance of the EZAudio in which the change occured
@param framePosition The new frame index as a 64-bit signed integer
*/
-(void)audioFile:(EZAudioFile*)audioFile
updatedPosition:(SInt64)framePosition;
@end
/**
The EZAudioFile provides a lightweight and intuitive way to asynchronously interact with audio files. These interactions included reading audio data, seeking within an audio file, getting information about the file, and pulling the waveform data for visualizing the contents of the audio file. The EZAudioFileDelegate provides event callbacks for when reads, seeks, and various updates happen within the audio file to allow the caller to interact with the action in meaningful ways. Common use cases here could be to read the audio file's data as AudioBufferList structures for output (see EZOutput) and visualizing the audio file's data as a float array using an audio plot (see EZAudioPlot).
*/
@interface EZAudioFile : NSObject
#pragma mark - Blocks
/**
A block used when returning back the waveform data. The waveform data itself will be an array of float values and the length indicates the total length of the float array.
@param waveformData An array of float values representing the amplitude data from the audio waveform
@param length The length of the waveform data's float array
*/
typedef void (^WaveformDataCompletionBlock)(float *waveformData, UInt32 length);
#pragma mark - Properties
/**
A EZAudioFileDelegate for the audio file that is used to return events such as new seek positions within the file and the read audio data as a float array.
*/
@property (nonatomic,assign) id audioFileDelegate;
/**
The resolution of the waveform data. This value specifies how the recommendedDrawingFrameRate chooses itself. A low value like 128 will render a waveform containing 128 points representing a low resolution waveform while a high value like 4096 will render a high quality waveform. Higher resolutions provide more detail, but take more work to render in the audio waveform plots (EZAudioPlot or EZAudioPlotGL) while lower resolutions providel less detail, but work better for displaying many at a time (like in a UITableView)
*/
@property (nonatomic,assign) UInt32 waveformResolution;
#pragma mark - Initializers
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
/**
Creates a new instance of the EZAudioFile using a file path URL.
@param url The file path reference of the audio file as an NSURL.
@return The newly created EZAudioFile instance.
*/
-(EZAudioFile*)initWithURL:(NSURL*)url;
/**
Creates a new instance of the EZAudioFile using a file path URL and allows specifying an EZAudioFileDelegate.
@param url The file path reference of the audio file as an NSURL.
@param delegate The audio file delegate that receives events specified by the EZAudioFileDelegate protocol
@return The newly created EZAudioFile instance.
*/
-(EZAudioFile*)initWithURL:(NSURL*)url
andDelegate:(id)delegate;
#pragma mark - Class Initializers
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Class method that creates a new instance of the EZAudioFile using a file path URL.
@param url The file path reference of the audio file as an NSURL.
@return The newly created EZAudioFile instance.
*/
+(EZAudioFile*)audioFileWithURL:(NSURL*)url;
/**
Class method that creates a new instance of the EZAudioFile using a file path URL and allows specifying an EZAudioFileDelegate.
@param url The file path reference of the audio file as an NSURL.
@param delegate The audio file delegate that receives events specified by the EZAudioFileDelegate protocol
@return The newly created EZAudioFile instance.
*/
+(EZAudioFile*)audioFileWithURL:(NSURL*)url
andDelegate:(id)delegate;
#pragma mark - Class Methods
///-----------------------------------------------------------
/// @name Class Methods
///-----------------------------------------------------------
/**
Provides an array of the supported audio files types. Each audio file type is provided as a string, i.e. @"caf". Useful for filtering lists of files in an open panel to only the types allowed.
@return An array of NSString objects representing the represented file types.
*/
+(NSArray*)supportedAudioFileTypes;
#pragma mark - Events
///-----------------------------------------------------------
/// @name Reading The Audio File
///-----------------------------------------------------------
/**
Reads a specified number of frames from the audio file. In addition, this will notify the EZAudioFileDelegate (if specified) of the read data as a float array with the audioFile:readAudio:withBufferSize:withNumberOfChannels: event and the new seek position within the file with the audioFile:updatedPosition: event.
@param frames The number of frames to read from the file.
@param audioBufferList An allocated AudioBufferList structure in which to store the read audio data
@param bufferSize A pointer to a UInt32 in which to store the read buffersize
@param eof A pointer to a BOOL in which to store whether the read operation reached the end of the audio file.
*/
-(void)readFrames:(UInt32)frames
audioBufferList:(AudioBufferList*)audioBufferList
bufferSize:(UInt32*)bufferSize
eof:(BOOL*)eof;
///-----------------------------------------------------------
/// @name Seeking Through The Audio File
///-----------------------------------------------------------
/**
Seeks through an audio file to a specified frame. This will notify the EZAudioFileDelegate (if specified) with the audioFile:updatedPosition: function.
@param frame The new frame position to seek to as a SInt64.
*/
-(void)seekToFrame:(SInt64)frame;
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting Information About The Audio File
///-----------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure used within the app. The file's format will be converted to this format and then sent back as either a float array or a `AudioBufferList` pointer. Use this when communicating with other EZAudio components.
@return An AudioStreamBasicDescription structure describing the format of the audio file.
*/
-(AudioStreamBasicDescription)clientFormat;
/**
Provides the AudioStreamBasicDescription structure containing the format of the file.
@return An AudioStreamBasicDescription structure describing the format of the audio file.
*/
-(AudioStreamBasicDescription)fileFormat;
/**
Provides the frame index (a.k.a the seek positon) within the audio file as an integer. This can be helpful when seeking through the audio file.
@return The current frame index within the audio file as a SInt64.
*/
-(SInt64)frameIndex;
/**
Provides a dictionary containing the metadata (ID3) tags that are included in the header for the audio file. Typically this contains stuff like artist, title, release year, etc.
@return An NSDictionary containing the metadata for the audio file.
*/
-(NSDictionary *)metadata;
/**
Provides the total duration of the audio file in seconds.
@return The total duration of the audio file as a Float32.
*/
-(Float32)totalDuration;
/**
Provides the total frame count of the audio file.
@return The total number of frames in the audio file as a SInt64.
*/
-(SInt64)totalFrames;
/**
Provides the NSURL for the audio file.
@return An NSURL representing the path of the EZAudioFile instance.
*/
-(NSURL*)url;
#pragma mark - Helpers
///-----------------------------------------------------------
/// @name Manipulating The Audio Data
///-----------------------------------------------------------
/**
Tells the caller whether the EZAudioFile has cached waveform data that was loaded via the getWaveformDataWithCompletionBlock: function.
* @return A BOOL indicating whether there is cached waveform data
*/
-(BOOL)hasLoadedAudioData;
/**
Asynchronously pulls the waveform amplitude data into a float array for the receiver.
@param waveformDataCompletionBlock A WaveformDataCompletionBlock that executes when the waveform data has been extracted. Provides the waveform data as a float array and the length of the array.
*/
-(void)getWaveformDataWithCompletionBlock:(WaveformDataCompletionBlock)waveformDataCompletionBlock;
/**
Provides the minimum number of buffers that would be required with the constant frames read rate provided.
@param frameRate A constant frame rate to use when calculating the number of buffers needed as a UInt32.
@return The minimum number of buffers required for the constant frames read rate provided as a UInt32.
*/
-(UInt32)minBuffersWithFrameRate:(UInt32)frameRate;
/**
Provides a frame rate to use when drawing and averaging a bin of values to create each point in a graph. The ideal amount of end buffers seems to be between 1000-3000 so we determine a frame rate per audio file that can achieve a high degree of detail for the entire waveform.
@return A frame rate value as a UInt32 to use when reading frames in a file.
*/
-(UInt32)recommendedDrawingFrameRate;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioFile.m
================================================
//
// EZAudioFile.m
// EZAudio
//
// Created by Syed Haris Ali on 12/1/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZAudioFile.h"
#import "EZAudio.h"
#define kEZAudioFileWaveformDefaultResolution (1024)
@interface EZAudioFile (){
// Reading from the audio file
ExtAudioFileRef _audioFile;
AudioStreamBasicDescription _clientFormat;
AudioStreamBasicDescription _fileFormat;
float **_floatBuffers;
AEFloatConverter *_floatConverter;
SInt64 _frameIndex;
CFURLRef _sourceURL;
Float32 _totalDuration;
SInt64 _totalFrames;
// Waveform Data
float *_waveformData;
UInt32 _waveformFrameRate;
UInt32 _waveformTotalBuffers;
}
@end
@implementation EZAudioFile
@synthesize audioFileDelegate = _audioFileDelegate;
@synthesize waveformResolution = _waveformResolution;
#pragma mark - Initializers
-(EZAudioFile*)initWithURL:(NSURL*)url {
self = [super init];
if(self){
_sourceURL = (__bridge CFURLRef)url;
[self _configureAudioFile];
}
return self;
}
-(EZAudioFile *)initWithURL:(NSURL *)url andDelegate:(id)delegate {
self = [self initWithURL:url];
if(self){
self.audioFileDelegate = delegate;
}
return self;
}
#pragma mark - Class Initializers
+(EZAudioFile*)audioFileWithURL:(NSURL*)url {
return [[EZAudioFile alloc] initWithURL:url];
}
+(EZAudioFile *)audioFileWithURL:(NSURL *)url andDelegate:(id)delegate {
return [[EZAudioFile alloc] initWithURL:url andDelegate:delegate];
}
#pragma mark - Class Methods
+(NSArray *)supportedAudioFileTypes {
return @[ @"aac",
@"caf",
@"aif",
@"aiff",
@"aifc",
@"mp3",
@"mp4",
@"m4a",
@"snd",
@"au",
@"sd2",
@"wav" ];
}
#pragma mark - Private Configuation
-(void)_configureAudioFile {
// Source URL should not be nil
NSAssert(_sourceURL,@"Source URL was not specified correctly.");
// Try to open the file for reading
[EZAudio checkResult:ExtAudioFileOpenURL(_sourceURL,&_audioFile)
operation:"Failed to open audio file for reading"];
// Try pulling the stream description
UInt32 size = sizeof(_fileFormat);
[EZAudio checkResult:ExtAudioFileGetProperty(_audioFile,kExtAudioFileProperty_FileDataFormat, &size, &_fileFormat)
operation:"Failed to get audio stream basic description of input file"];
// Try pulling the total frame size
size = sizeof(_totalFrames);
[EZAudio checkResult:ExtAudioFileGetProperty(_audioFile,kExtAudioFileProperty_FileLengthFrames, &size, &_totalFrames)
operation:"Failed to get total frames of input file"];
_totalFrames = MAX(1, _totalFrames);
// Total duration
_totalDuration = _totalFrames / _fileFormat.mSampleRate;
// Set the client format on the stream
switch (_fileFormat.mChannelsPerFrame) {
case 1:
_clientFormat = [EZAudio monoFloatFormatWithSampleRate:_fileFormat.mSampleRate];
break;
case 2:
_clientFormat = [EZAudio stereoFloatInterleavedFormatWithSampleRate:_fileFormat.mSampleRate];
break;
default:
break;
}
[EZAudio checkResult:ExtAudioFileSetProperty(_audioFile,
kExtAudioFileProperty_ClientDataFormat,
sizeof (AudioStreamBasicDescription),
&_clientFormat)
operation:"Couldn't set client data format on input ext file"];
// Allocate the float buffers
_floatConverter = [[AEFloatConverter alloc] initWithSourceFormat:_clientFormat];
size_t sizeToAllocate = sizeof(float*) * _clientFormat.mChannelsPerFrame;
sizeToAllocate = MAX(8, sizeToAllocate);
_floatBuffers = (float**)malloc( sizeToAllocate );
UInt32 outputBufferSize = 32 * 1024; // 32 KB
for ( int i=0; i< _clientFormat.mChannelsPerFrame; i++ ) {
_floatBuffers[i] = (float*)malloc(outputBufferSize);
}
[EZAudio printASBD:_fileFormat];
// There's no waveform data yet
_waveformData = NULL;
// Set the default resolution for the waveform data
_waveformResolution = kEZAudioFileWaveformDefaultResolution;
}
#pragma mark - Events
-(void)readFrames:(UInt32)frames
audioBufferList:(AudioBufferList *)audioBufferList
bufferSize:(UInt32 *)bufferSize
eof:(BOOL *)eof {
[EZAudio checkResult:ExtAudioFileRead(_audioFile,
&frames,
audioBufferList)
operation:"Failed to read audio data from audio file"];
*bufferSize = audioBufferList->mBuffers[0].mDataByteSize/sizeof(float);
*eof = frames == 0;
_frameIndex += frames;
if( self.audioFileDelegate ){
if( [self.audioFileDelegate respondsToSelector:@selector(audioFile:updatedPosition:)] ){
[self.audioFileDelegate audioFile:self
updatedPosition:_frameIndex];
}
if( [self.audioFileDelegate respondsToSelector:@selector(audioFile:readAudio:withBufferSize:withNumberOfChannels:)] ){
AEFloatConverterToFloat(_floatConverter,audioBufferList,_floatBuffers,frames);
[self.audioFileDelegate audioFile:self
readAudio:_floatBuffers
withBufferSize:frames
withNumberOfChannels:_clientFormat.mChannelsPerFrame];
}
}
}
-(void)seekToFrame:(SInt64)frame {
[EZAudio checkResult:ExtAudioFileSeek(_audioFile,frame)
operation:"Failed to seek frame position within audio file"];
_frameIndex = frame;
if( self.audioFileDelegate ){
if( [self.audioFileDelegate respondsToSelector:@selector(audioFile:updatedPosition:)] ){
[self.audioFileDelegate audioFile:self updatedPosition:_frameIndex];
}
}
}
#pragma mark - Getters
-(BOOL)hasLoadedAudioData {
return _waveformData != NULL;
}
-(void)getWaveformDataWithCompletionBlock:(WaveformDataCompletionBlock)waveformDataCompletionBlock {
SInt64 currentFramePosition = _frameIndex;
if( _waveformData != NULL ){
waveformDataCompletionBlock( _waveformData, _waveformTotalBuffers );
return;
}
_waveformFrameRate = [self recommendedDrawingFrameRate];
_waveformTotalBuffers = [self minBuffersWithFrameRate:_waveformFrameRate];
_waveformData = (float*)malloc(sizeof(float)*_waveformTotalBuffers);
if( self.totalFrames == 0 ){
waveformDataCompletionBlock( _waveformData, _waveformTotalBuffers );
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0ul), ^{
for( int i = 0; i < _waveformTotalBuffers; i++ ){
// Take a snapshot of each buffer through the audio file to form the waveform
AudioBufferList *bufferList = [EZAudio audioBufferListWithNumberOfFrames:_waveformFrameRate
numberOfChannels:_clientFormat.mChannelsPerFrame
interleaved:YES];
UInt32 bufferSize;
BOOL eof;
// Read in the specified number of frames
[EZAudio checkResult:ExtAudioFileRead(_audioFile,
&_waveformFrameRate,
bufferList)
operation:"Failed to read audio data from audio file"];
bufferSize = bufferList->mBuffers[0].mDataByteSize/sizeof(float);
bufferSize = MAX(1, bufferSize);
eof = _waveformFrameRate == 0;
_frameIndex += _waveformFrameRate;
// Calculate RMS of each buffer
float rms = [EZAudio RMS:bufferList->mBuffers[0].mData
length:bufferSize];
_waveformData[i] = rms;
// Since we malloc'ed, we should cleanup
[EZAudio freeBufferList:bufferList];
}
// Seek the audio file back to the beginning
[EZAudio checkResult:ExtAudioFileSeek(_audioFile,currentFramePosition)
operation:"Failed to seek frame position within audio file"];
_frameIndex = currentFramePosition;
// Once we're done send off the waveform data
dispatch_async(dispatch_get_main_queue(), ^{
waveformDataCompletionBlock( _waveformData, _waveformTotalBuffers );
});
});
}
-(AudioStreamBasicDescription)clientFormat {
return _clientFormat;
}
-(AudioStreamBasicDescription)fileFormat {
return _fileFormat;
}
-(SInt64)frameIndex {
return _frameIndex;
}
-(NSDictionary *)metadata
{
AudioFileID audioFileID;
UInt32 propSize = sizeof(audioFileID);
[EZAudio checkResult:ExtAudioFileGetProperty(_audioFile,
kExtAudioFileProperty_AudioFile,
&propSize,
&audioFileID)
operation:"Failed to get audio file id"];
CFDictionaryRef metadata;
UInt32 isWritable;
[EZAudio checkResult:AudioFileGetPropertyInfo(audioFileID,
kAudioFilePropertyInfoDictionary,
&propSize,
&isWritable)
operation:"Failed to get the size of the metadata dictionary"];
[EZAudio checkResult:AudioFileGetProperty(audioFileID,
kAudioFilePropertyInfoDictionary,
&propSize,
&metadata)
operation:"Failed to get metadata dictionary"];
return (__bridge NSDictionary *)metadata;
}
-(Float32)totalDuration {
return _totalDuration;
}
-(SInt64)totalFrames {
return _totalFrames;
}
-(NSURL *)url {
return (__bridge NSURL*)_sourceURL;
}
#pragma mark - Setters
-(void)setWaveformResolution:(UInt32)waveformResolution {
if( _waveformResolution != waveformResolution ){
_waveformResolution = waveformResolution;
if( _waveformData ){
free(_waveformData);
_waveformData = NULL;
}
}
}
#pragma mark - Helpers
-(UInt32)minBuffersWithFrameRate:(UInt32)frameRate {
frameRate = frameRate > 0 ? frameRate : 1;
UInt32 val = (UInt32) _totalFrames / frameRate + 1;
return MAX(1, val);
}
-(UInt32)recommendedDrawingFrameRate {
UInt32 val = 1;
if(_waveformResolution > 0){
val = (UInt32) _totalFrames / _waveformResolution;
if(val > 1)
--val;
}
return MAX(1, val);
}
#pragma mark - Cleanup
-(void)dealloc {
if( _waveformData ){
free(_waveformData);
_waveformData = NULL;
}
// if( _floatBuffers ){
// free(_floatBuffers);
// _floatBuffers = NULL;
// }
_frameIndex = 0;
_waveformFrameRate = 0;
_waveformTotalBuffers = 0;
if( _audioFile ){
[EZAudio checkResult:ExtAudioFileDispose(_audioFile)
operation:"Failed to dispose of audio file"];
}
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlayer.h
================================================
//
// EZAudioPlayer.h
// EZAudio
//
// Created by Syed Haris Ali on 1/16/14.
// Copyright (c) 2014 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#import "TargetConditionals.h"
#import "EZAudio.h"
#if TARGET_OS_IPHONE
#import
#elif TARGET_OS_MAC
#endif
@class EZAudioPlayer;
/**
The EZAudioPlayerDelegate provides event callbacks for the EZAudioPlayer. These type of events are triggered by changes in the EZAudioPlayer's state and allow someone implementing the EZAudioPlayer to more easily update their user interface. Events are triggered anytime the EZAudioPlayer resumes/pauses playback, reaches the end of the file, reads audio data and converts it to float data visualizations (using the EZAudioFile), and updates its cursor position within the audio file during playback (use this for the play position on a slider on the user interface).
@warning These callbacks don't necessarily occur on the main thread so make sure you wrap any UI code in a GCD block like: dispatch_async(dispatch_get_main_queue(), ^{ // Update UI });
*/
@protocol EZAudioPlayerDelegate
@optional
/**
Triggered by the EZAudioPlayer when the playback has been resumed or started.
@param audioPlayer The instance of the EZAudioPlayer that triggered the event
@param audioFile The instance of the EZAudioFile that the event was triggered from
*/
-(void)audioPlayer:(EZAudioPlayer*)audioPlayer didResumePlaybackOnAudioFile:(EZAudioFile*)audioFile;
/**
Triggered by the EZAudioPlayer when the playback has been paused.
@param audioPlayer The instance of the EZAudioPlayer that triggered the event
@param audioFile The instance of the EZAudioFile that the event was triggered from
*/
-(void)audioPlayer:(EZAudioPlayer*)audioPlayer didPausePlaybackOnAudioFile:(EZAudioFile*)audioFile;
/**
Triggered by the EZAudioPlayer when the output has reached the end of the EZAudioFile it's playing. If the EZAudioPlayer has its `shouldLoop` property set to true this will trigger, but playback will continue to loop once its hit the end of the audio file.
@param audioPlayer The instance of the EZAudioPlayer that triggered the event
@param audioFile The instance of the EZAudioFile that the event was triggered from
*/
-(void)audioPlayer:(EZAudioPlayer*)audioPlayer reachedEndOfAudioFile:(EZAudioFile*)audioFile;
/**
Triggered by the EZAudioPlayer's internal EZAudioFile's EZAudioFileDelegate callback and notifies the delegate of the read audio data as a float array instead of a buffer list. Common use case of this would be to visualize the float data using an audio plot or audio data dependent OpenGL sketch.
@param audioPlayer The instance of the EZAudioPlayer that triggered the event
@param buffer A float array of float arrays holding the audio data. buffer[0] would be the left channel's float array while buffer[1] would be the right channel's float array in a stereo file.
@param bufferSize The length of the buffers float arrays
@param numberOfChannels The number of channels. 2 for stereo, 1 for mono.
@param audioFile The instance of the EZAudioFile that the event was triggered from
*/
-(void) audioPlayer:(EZAudioPlayer*)audioPlayer
readAudio:(float**)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
inAudioFile:(EZAudioFile*)audioFile;;
/**
Triggered by EZAudioPlayer's internal EZAudioFile's EZAudioFileDelegate callback and notifies the delegate of the current playback position. The framePosition provides the current frame position and can be calculated against the EZAudioPlayer's total frames using the `totalFrames` function from the EZAudioPlayer.
@param audioPlayer The instance of the EZAudioPlayer that triggered the event
@param framePosition The new frame index as a 64-bit signed integer
@param audioFile The instance of the EZAudioFile that the event was triggered from
*/
-(void)audioPlayer:(EZAudioPlayer*)audioPlayer
updatedPosition:(SInt64)framePosition
inAudioFile:(EZAudioFile*)audioFile;
@end
/**
The EZAudioPlayer acts as the master delegate (the EZAudioFileDelegate) over whatever EZAudioFile it is using for playback. Classes that want to get the EZAudioFileDelegate callbacks should implement the EZAudioPlayer's EZAudioPlayerDelegate on the EZAudioPlayer instance.
*/
@interface EZAudioPlayer : NSObject
#pragma mark - Properties
///-----------------------------------------------------------
/// @name Properties
///-----------------------------------------------------------
/**
The EZAudioPlayerDelegate that will handle the audio player callbacks
*/
@property (nonatomic,assign) id audioPlayerDelegate;
/**
A BOOL indicating whether the player should loop the file
*/
@property (nonatomic,assign) BOOL shouldLoop;
#pragma mark - Initializers
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
/**
Initializes the EZAudioPlayer with an EZAudioFile instance. This does not use the EZAudioFile by reference, but instead creates a separate EZAudioFile instance with the same file at the given file path provided by the internal NSURL to use for internal seeking so it doesn't cause any locking between the caller's instance of the EZAudioFile.
@param audioFile The instance of the EZAudioFile to use for initializing the EZAudioPlayer
@return The newly created instance of the EZAudioPlayer
*/
-(EZAudioPlayer*)initWithEZAudioFile:(EZAudioFile*)audioFile;
/**
Initializes the EZAudioPlayer with an EZAudioFile instance and provides a way to assign the EZAudioPlayerDelegate on instantiation. This does not use the EZAudioFile by reference, but instead creates a separate EZAudioFile instance with the same file at the given file path provided by the internal NSURL to use for internal seeking so it doesn't cause any locking between the caller's instance of the EZAudioFile.
@param audioFile The instance of the EZAudioFile to use for initializing the EZAudioPlayer
@param audioPlayerDelegate The receiver that will act as the EZAudioPlayerDelegate. Set to nil if it should have no delegate or use the initWithEZAudioFile: function instead.
@return The newly created instance of the EZAudioPlayer
*/
-(EZAudioPlayer*)initWithEZAudioFile:(EZAudioFile*)audioFile
withDelegate:(id)audioPlayerDelegate;
/**
Initializes the EZAudioPlayer with an NSURL instance representing the file path of the audio file.
@param url The NSURL instance representing the file path of the audio file.
@return The newly created instance of the EZAudioPlayer
*/
-(EZAudioPlayer*)initWithURL:(NSURL*)url;
/**
Initializes the EZAudioPlayer with an NSURL instance representing the file path of the audio file and a caller to assign as the EZAudioPlayerDelegate on instantiation.
@param url The NSURL instance representing the file path of the audio file.
@param audioPlayerDelegate The receiver that will act as the EZAudioPlayerDelegate. Set to nil if it should have no delegate or use the initWithEZAudioFile: function instead.
@return The newly created instance of the EZAudioPlayer
*/
-(EZAudioPlayer*)initWithURL:(NSURL*)url
withDelegate:(id)audioPlayerDelegate;
#pragma mark - Class Initializers
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Class initializer that initializes the EZAudioPlayer with an EZAudioFile instance. This does not use the EZAudioFile by reference, but instead creates a separate EZAudioFile instance with the same file at the given file path provided by the internal NSURL to use for internal seeking so it doesn't cause any locking between the caller's instance of the EZAudioFile.
@param audioFile The instance of the EZAudioFile to use for initializing the EZAudioPlayer
@return The newly created instance of the EZAudioPlayer
*/
+(EZAudioPlayer*)audioPlayerWithEZAudioFile:(EZAudioFile*)audioFile;
/**
Class initializer that initializes the EZAudioPlayer with an EZAudioFile instance and provides a way to assign the EZAudioPlayerDelegate on instantiation. This does not use the EZAudioFile by reference, but instead creates a separate EZAudioFile instance with the same file at the given file path provided by the internal NSURL to use for internal seeking so it doesn't cause any locking between the caller's instance of the EZAudioFile.
@param audioFile The instance of the EZAudioFile to use for initializing the EZAudioPlayer
@param audioPlayerDelegate The receiver that will act as the EZAudioPlayerDelegate. Set to nil if it should have no delegate or use the audioPlayerWithEZAudioFile: function instead.
@return The newly created instance of the EZAudioPlayer
*/
+(EZAudioPlayer*)audioPlayerWithEZAudioFile:(EZAudioFile*)audioFile
withDelegate:(id)audioPlayerDelegate;
/**
Class initializer that initializes the EZAudioPlayer with an NSURL instance representing the file path of the audio file.
@param url The NSURL instance representing the file path of the audio file.
@return The newly created instance of the EZAudioPlayer
*/
+(EZAudioPlayer*)audioPlayerWithURL:(NSURL*)url;
/**
Class initializer that initializes the EZAudioPlayer with an NSURL instance representing the file path of the audio file and a caller to assign as the EZAudioPlayerDelegate on instantiation.
@param url The NSURL instance representing the file path of the audio file.
@param audioPlayerDelegate The receiver that will act as the EZAudioPlayerDelegate. Set to nil if it should have no delegate or use the audioPlayerWithURL: function instead.
@return The newly created instance of the EZAudioPlayer
*/
+(EZAudioPlayer*)audioPlayerWithURL:(NSURL*)url
withDelegate:(id)audioPlayerDelegate;
#pragma mark - Singleton
///-----------------------------------------------------------
/// @name Shared Instance
///-----------------------------------------------------------
/**
The shared instance (singleton) of the audio player. Most applications will only have one instance of the EZAudioPlayer that can be reused with multiple different audio files.
* @return The shared instance of the EZAudioPlayer.
*/
+(EZAudioPlayer*)sharedAudioPlayer;
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting The Audio Player's Properties
///-----------------------------------------------------------
/**
Provides the EZAudioFile instance that is being used as the datasource for playback.
@return The EZAudioFile instance that is currently being used for playback.
*/
-(EZAudioFile*)audioFile;
/**
Provides the current time (a.k.a. the seek position) in seconds within the audio file that's being used for playback. This can be helpful when displaying the audio player's current time over duration.
@return A float representing the current time within the audio file used for playback.
*/
-(float)currentTime;
/**
Provides a flag indicating whether the EZAudioPlayer has reached the end of the audio file used for playback.
@return A BOOL indicating whether or not the EZAudioPlayer has reached the end of the file it is using for playback.
*/
-(BOOL)endOfFile;
/**
Provides the frame index (a.k.a the seek positon) within the audio file being used for playback. This can be helpful when seeking through the audio file.
@return An SInt64 representing the current frame index within the audio file used for playback.
*/
-(SInt64)frameIndex;
/**
Provides a flag indicating whether the EZAudioPlayer is currently playing back any audio.
@return A BOOL indicating whether or not the EZAudioPlayer is performing playback,
*/
-(BOOL)isPlaying;
/**
Provides the EZOutput instance that is being used to provide playback to the system output.
@return The EZOutput instance that is currently being used for output playback.
*/
-(EZOutput*)output;
/**
Provides the total duration of the current audio file being used for playback (in seconds).
@return A float representing the total duration of the current audio file being used for playback in seconds.
*/
-(float)totalDuration;
/**
Provides the total amount of frames in the current audio file being used for playback.
@return A SInt64 representing the total amount of frames in the current audio file being used for playback.
*/
-(SInt64)totalFrames;
/**
Provides the file path that's currently being used by the player for playback.
@return The NSURL representing the file path of the audio file being used for playback.
*/
-(NSURL*)url;
#pragma mark - Setters
///-----------------------------------------------------------
/// @name Setting The File/Output
///-----------------------------------------------------------
/**
Sets the EZAudioFile to use for playback. This does not use the EZAudioFile by reference, but instead creates a separate EZAudioFile instance with the same file at the given file path provided by the internal NSURL to use for internal seeking so it doesn't cause any locking between the caller's instance of the EZAudioFile.
@param audioFile The new EZAudioFile instance that should be used for playback
*/
-(void)setAudioFile:(EZAudioFile*)audioFile;
/**
Sets the EZOutput to route playback. By default this uses the [EZOutput sharedOutput] singleton.
@param output The new EZOutput instance that should be used for playback
*/
-(void)setOutput:(EZOutput*)output;
#pragma mark - Methods
///-----------------------------------------------------------
/// @name Play/Pause/Seeking the Player
///-----------------------------------------------------------
/**
Starts or resumes playback.
*/
-(void)play;
/**
Pauses playback.
*/
-(void)pause;
/**
Stops playback.
*/
-(void)stop;
/**
Seeks playback to a specified frame within the internal EZAudioFile. This will notify the EZAudioFileDelegate (if specified) with the audioPlayer:updatedPosition:inAudioFile: function.
@param frame The new frame position to seek to as a SInt64.
*/
-(void)seekToFrame:(SInt64)frame;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlayer.m
================================================
//
// EZAudioPlayer.m
// EZAudio
//
// Created by Syed Haris Ali on 1/16/14.
// Copyright (c) 2014 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZAudioPlayer.h"
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
#endif
@interface EZAudioPlayer ()
{
BOOL _eof;
}
@property (nonatomic,strong,setter=setAudioFile:) EZAudioFile *audioFile;
@property (nonatomic,strong,setter=setOutput:) EZOutput *output;
@end
@implementation EZAudioPlayer
@synthesize audioFile = _audioFile;
@synthesize audioPlayerDelegate = _audioPlayerDelegate;
@synthesize output = _output;
@synthesize shouldLoop = _shouldLoop;
#pragma mark - Initializers
-(id)init {
self = [super init];
if(self){
[self _configureAudioPlayer];
}
return self;
}
-(EZAudioPlayer*)initWithEZAudioFile:(EZAudioFile *)audioFile {
return [self initWithEZAudioFile:audioFile withDelegate:nil];
}
-(EZAudioPlayer *)initWithEZAudioFile:(EZAudioFile *)audioFile
withDelegate:(id)audioPlayerDelegate {
self = [super init];
if(self){
// This should make a separate reference to the audio file
[self _configureAudioPlayer];
self.audioFile = audioFile;
self.audioPlayerDelegate = audioPlayerDelegate;
}
return self;
}
-(EZAudioPlayer *)initWithURL:(NSURL *)url {
return [self initWithURL:url withDelegate:nil];
}
-(EZAudioPlayer *)initWithURL:(NSURL *)url
withDelegate:(id)audioPlayerDelegate {
self = [super init];
if(self){
[self _configureAudioPlayer];
self.audioFile = [EZAudioFile audioFileWithURL:url andDelegate:self];
self.audioPlayerDelegate = audioPlayerDelegate;
}
return self;
}
#pragma mark - Class Initializers
+(EZAudioPlayer *)audioPlayerWithEZAudioFile:(EZAudioFile *)audioFile {
return [[EZAudioPlayer alloc] initWithEZAudioFile:audioFile];
}
+(EZAudioPlayer *)audioPlayerWithEZAudioFile:(EZAudioFile *)audioFile
withDelegate:(id)audioPlayerDelegate {
return [[EZAudioPlayer alloc] initWithEZAudioFile:audioFile
withDelegate:audioPlayerDelegate];
}
+(EZAudioPlayer *)audioPlayerWithURL:(NSURL *)url {
return [[EZAudioPlayer alloc] initWithURL:url];
}
+(EZAudioPlayer *)audioPlayerWithURL:(NSURL *)url
withDelegate:(id)audioPlayerDelegate {
return [[EZAudioPlayer alloc] initWithURL:url
withDelegate:audioPlayerDelegate];
}
#pragma mark - Singleton
+(EZAudioPlayer *)sharedAudioPlayer {
static EZAudioPlayer *_sharedAudioPlayer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedAudioPlayer = [[EZAudioPlayer alloc] init];
});
return _sharedAudioPlayer;
}
#pragma mark - Private Configuration
-(void)_configureAudioPlayer {
// Defaults
self.output = [EZOutput sharedOutput];
#if TARGET_OS_IPHONE
// Configure the AVSession
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = NULL;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];
if( err ){
NSLog(@"There was an error creating the audio session");
}
// [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:NULL];
// if( err ){
// NSLog(@"There was an error sending the audio to the speakers");
// }
#elif TARGET_OS_MAC
#endif
}
#pragma mark - Getters
-(EZAudioFile*)audioFile {
return _audioFile;
}
-(float)currentTime {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
return [EZAudio MAP:self.audioFile.frameIndex
leftMin:0
leftMax:self.audioFile.totalFrames
rightMin:0
rightMax:self.audioFile.totalDuration];
}
-(BOOL)endOfFile {
return _eof;
}
-(SInt64)frameIndex {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
return _audioFile.frameIndex;
}
-(BOOL)isPlaying {
return self.output.isPlaying;
}
-(EZOutput*)output {
NSAssert(_output,@"No output was found, this should by default be the EZOutput shared instance");
return _output;
}
-(float)totalDuration {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
return _audioFile.totalDuration;
}
-(SInt64)totalFrames {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
return _audioFile.totalFrames;
}
-(NSURL *)url {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
return _audioFile.url;
}
#pragma mark - Setters
-(void)setAudioFile:(EZAudioFile *)audioFile {
if( _audioFile ){
_audioFile.audioFileDelegate = nil;
}
_eof = NO;
_audioFile = [EZAudioFile audioFileWithURL:audioFile.url andDelegate:self];
NSAssert(_output,@"No output was found, this should by default be the EZOutput shared instance");
[_output setAudioStreamBasicDescription:self.audioFile.clientFormat];
}
-(void)setOutput:(EZOutput*)output {
_output = output;
_output.outputDataSource = self;
}
#pragma mark - Methods
-(void)play {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
if( _audioFile ){
[_output startPlayback];
if( self.frameIndex != self.totalFrames ){
_eof = NO;
}
if( self.audioPlayerDelegate ){
if( [self.audioPlayerDelegate respondsToSelector:@selector(audioPlayer:didResumePlaybackOnAudioFile:)] ){
// Notify the delegate we're starting playback
[self.audioPlayerDelegate audioPlayer:self didResumePlaybackOnAudioFile:_audioFile];
}
}
}
}
-(void)pause {
NSAssert(self.audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
if( _audioFile ){
[_output stopPlayback];
if( self.audioPlayerDelegate ){
if( [self.audioPlayerDelegate respondsToSelector:@selector(audioPlayer:didPausePlaybackOnAudioFile:)] ){
// Notify the delegate we're pausing playback
[self.audioPlayerDelegate audioPlayer:self didPausePlaybackOnAudioFile:_audioFile];
}
}
}
}
-(void)seekToFrame:(SInt64)frame {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
if( _audioFile ){
[_audioFile seekToFrame:frame];
}
if( self.frameIndex != self.totalFrames ){
_eof = NO;
}
}
-(void)stop {
NSAssert(_audioFile,@"No audio file to perform the seek on, check that EZAudioFile is not nil");
if( _audioFile ){
[_output stopPlayback];
[_audioFile seekToFrame:0];
_eof = NO;
}
}
#pragma mark - EZAudioFileDelegate
-(void)audioFile:(EZAudioFile *)audioFile
readAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
if( self.audioPlayerDelegate ){
if( [self.audioPlayerDelegate respondsToSelector:@selector(audioPlayer:readAudio:withBufferSize:withNumberOfChannels:inAudioFile:)] ){
[self.audioPlayerDelegate audioPlayer:self
readAudio:buffer
withBufferSize:bufferSize
withNumberOfChannels:numberOfChannels
inAudioFile:audioFile];
}
}
}
-(void)audioFile:(EZAudioFile *)audioFile updatedPosition:(SInt64)framePosition {
if( self.audioPlayerDelegate ){
if( [self.audioPlayerDelegate respondsToSelector:@selector(audioPlayer:updatedPosition:inAudioFile:)] ){
[self.audioPlayerDelegate audioPlayer:self
updatedPosition:framePosition
inAudioFile:audioFile];
}
}
}
#pragma mark - EZOutputDataSource
-(void) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
{
if( self.audioFile )
{
UInt32 bufferSize;
[self.audioFile readFrames:frames
audioBufferList:audioBufferList
bufferSize:&bufferSize
eof:&_eof];
if( _eof && self.shouldLoop )
{
[self seekToFrame:0];
}
}
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlot.h
================================================
//
// EZAudioPlot.h
// EZAudio
//
// Created by Syed Haris Ali on 9/2/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "TargetConditionals.h"
#import "EZPlot.h"
@class EZAudio;
#define kEZAudioPlotMaxHistoryBufferLength (8192)
#define kEZAudioPlotDefaultHistoryBufferLength (1024)
/**
`EZAudioPlot`, a subclass of `EZPlot`, is a cross-platform (iOS and OSX) class that plots an audio waveform using Core Graphics.
The caller provides updates a constant stream of updated audio data in the `updateBuffer:withBufferSize:` function, which in turn will be plotted in one of the plot types:
* Buffer (`EZPlotTypeBuffer`) - A plot that only consists of the current buffer and buffer size from the last call to `updateBuffer:withBufferSize:`. This looks similar to the default openFrameworks input audio example.
* Rolling (`EZPlotTypeRolling`) - A plot that consists of a rolling history of values averaged from each buffer. This is the traditional waveform look.
#Parent Methods and Properties#
See EZPlot for full API methods and properties (colors, plot type, update function)
*/
@interface EZAudioPlot : EZPlot
{
CGPoint *plotData;
UInt32 plotLength;
}
#pragma mark - Adjust Resolution
///-----------------------------------------------------------
/// @name Adjusting The Resolution
///-----------------------------------------------------------
/**
Sets the length of the rolling history display. Can grow or shrink the display up to the maximum size specified by the kEZAudioPlotMaxHistoryBufferLength macro. Will return the actual set value, which will be either the given value if smaller than the kEZAudioPlotMaxHistoryBufferLength or kEZAudioPlotMaxHistoryBufferLength if a larger value is attempted to be set.
@param historyLength The new length of the rolling history buffer.
@return The new value equal to the historyLength or the kEZAudioPlotMaxHistoryBufferLength.
*/
-(int)setRollingHistoryLength:(int)historyLength;
/**
Provides the length of the rolling history buffer
* @return An int representing the length of the rolling history buffer
*/
-(int)rollingHistoryLength;
#pragma mark - Subclass Methods
/**
<#Description#>
@param data <#theplotData description#>
@param length <#length description#>
*/
-(void)setSampleData:(float *)data
length:(int)length;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlot.m
================================================
//
// EZAudioPlot.m
// EZAudio
//
// Created by Syed Haris Ali on 9/2/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZAudioPlot.h"
#import "EZAudio.h"
@interface EZAudioPlot () {
// BOOL _hasData;
// TPCircularBuffer _historyBuffer;
// Rolling History
BOOL _setMaxLength;
float *_scrollHistory;
int _scrollHistoryIndex;
UInt32 _scrollHistoryLength;
BOOL _changingHistorySize;
}
@end
@implementation EZAudioPlot
@synthesize backgroundColor = _backgroundColor;
@synthesize color = _color;
@synthesize gain = _gain;
@synthesize plotType = _plotType;
@synthesize shouldFill = _shouldFill;
@synthesize shouldMirror = _shouldMirror;
#pragma mark - Initialization
-(id)init {
self = [super init];
if(self){
[self initPlot];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self){
[self initPlot];
}
return self;
}
#if TARGET_OS_IPHONE
-(id)initWithFrame:(CGRect)frameRect {
#elif TARGET_OS_MAC
-(id)initWithFrame:(NSRect)frameRect {
#endif
self = [super initWithFrame:frameRect];
if(self){
[self initPlot];
}
return self;
}
-(void)initPlot {
#if TARGET_OS_IPHONE
self.backgroundColor = [UIColor blackColor];
self.color = [UIColor colorWithHue:0 saturation:1.0 brightness:1.0 alpha:1.0];
#elif TARGET_OS_MAC
self.backgroundColor = [NSColor blackColor];
self.color = [NSColor colorWithCalibratedHue:0 saturation:1.0 brightness:1.0 alpha:1.0];
#endif
self.gain = 1.0;
self.plotType = EZPlotTypeRolling;
self.shouldMirror = NO;
self.shouldFill = NO;
plotData = NULL;
_scrollHistory = NULL;
_scrollHistoryLength = kEZAudioPlotDefaultHistoryBufferLength;
}
#pragma mark - Setters
-(void)setBackgroundColor:(id)backgroundColor {
_backgroundColor = backgroundColor;
[self _refreshDisplay];
}
-(void)setColor:(id)color {
_color = color;
[self _refreshDisplay];
}
-(void)setGain:(float)gain {
_gain = gain;
[self _refreshDisplay];
}
-(void)setPlotType:(EZPlotType)plotType {
_plotType = plotType;
[self _refreshDisplay];
}
-(void)setShouldFill:(BOOL)shouldFill {
_shouldFill = shouldFill;
[self _refreshDisplay];
}
-(void)setShouldMirror:(BOOL)shouldMirror {
_shouldMirror = shouldMirror;
[self _refreshDisplay];
}
-(void)_refreshDisplay {
#if TARGET_OS_IPHONE
[self setNeedsDisplay];
#elif TARGET_OS_MAC
[self setNeedsDisplay:YES];
#endif
}
#pragma mark - Get Data
-(void)setSampleData:(float *)data
length:(int)length {
if( plotData != nil ){
free(plotData);
}
plotData = (CGPoint *)calloc(sizeof(CGPoint),length);
plotLength = length;
for(int i = 0; i < length; i++) {
data[i] = i == 0 ? 0 : data[i];
plotData[i] = CGPointMake(i,data[i] * _gain);
}
[self _refreshDisplay];
}
#pragma mark - Update
-(void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize {
if( _plotType == EZPlotTypeRolling ){
// Update the scroll history datasource
[EZAudio updateScrollHistory:&_scrollHistory
withLength:_scrollHistoryLength
atIndex:&_scrollHistoryIndex
withBuffer:buffer
withBufferSize:bufferSize
isResolutionChanging:&_changingHistorySize];
//
[self setSampleData:_scrollHistory
length:(!_setMaxLength?kEZAudioPlotMaxHistoryBufferLength:_scrollHistoryLength)];
_setMaxLength = YES;
}
else if( _plotType == EZPlotTypeBuffer ){
[self setSampleData:buffer
length:bufferSize];
}
else {
// Unknown plot type
}
}
#if TARGET_OS_IPHONE
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGRect frame = self.bounds;
#elif TARGET_OS_MAC
- (void)drawRect:(NSRect)dirtyRect
{
[[NSGraphicsContext currentContext] saveGraphicsState];
NSGraphicsContext * nsGraphicsContext = [NSGraphicsContext currentContext];
CGContextRef ctx = (CGContextRef) [nsGraphicsContext graphicsPort];
NSRect frame = self.bounds;
#endif
#if TARGET_OS_IPHONE
// Set the background color
[(UIColor*)self.backgroundColor set];
UIRectFill(frame);
// Set the waveform line color
[(UIColor*)self.color set];
#elif TARGET_OS_MAC
[(NSColor*)self.backgroundColor set];
NSRectFill(frame);
[(NSColor*)self.color set];
#endif
if(plotLength > 0) {
plotData[plotLength-1] = CGPointMake(plotLength-1,0.0f);
CGMutablePathRef halfPath = CGPathCreateMutable();
CGPathAddLines(halfPath,
NULL,
plotData,
plotLength);
CGMutablePathRef path = CGPathCreateMutable();
double xscale = (frame.size.width) / (float)plotLength;
double halfHeight = floor( frame.size.height / 2.0 );
// iOS drawing origin is flipped by default so make sure we account for that
int deviceOriginFlipped = 1;
#if TARGET_OS_IPHONE
deviceOriginFlipped = -1;
#elif TARGET_OS_MAC
deviceOriginFlipped = 1;
#endif
CGAffineTransform xf = CGAffineTransformIdentity;
xf = CGAffineTransformTranslate( xf, frame.origin.x , halfHeight + frame.origin.y );
xf = CGAffineTransformScale( xf, xscale, deviceOriginFlipped*halfHeight );
CGPathAddPath( path, &xf, halfPath );
if( self.shouldMirror ){
xf = CGAffineTransformIdentity;
xf = CGAffineTransformTranslate( xf, frame.origin.x , halfHeight + frame.origin.y);
xf = CGAffineTransformScale( xf, xscale, -deviceOriginFlipped*(halfHeight));
CGPathAddPath( path, &xf, halfPath );
}
CGPathRelease( halfPath );
// Now, path contains the full waveform path.
CGContextAddPath(ctx, path);
// Make this color customizable
if( self.shouldFill ){
CGContextFillPath(ctx);
}
else {
CGContextStrokePath(ctx);
}
CGPathRelease(path);
}
#if TARGET_OS_IPHONE
CGContextRestoreGState(ctx);
#elif TARGET_OS_MAC
[[NSGraphicsContext currentContext] restoreGraphicsState];
#endif
}
#pragma mark - Adjust Resolution
-(int)setRollingHistoryLength:(int)historyLength {
historyLength = MIN(historyLength,kEZAudioPlotMaxHistoryBufferLength);
size_t floatByteSize = sizeof(float);
_changingHistorySize = YES;
if( _scrollHistoryLength != historyLength ){
_scrollHistoryLength = historyLength;
}
_scrollHistory = realloc(_scrollHistory,_scrollHistoryLength*floatByteSize);
if( _scrollHistoryIndex < _scrollHistoryLength ){
memset(&_scrollHistory[_scrollHistoryIndex],
0,
(_scrollHistoryLength-_scrollHistoryIndex)*floatByteSize);
}
else {
_scrollHistoryIndex = _scrollHistoryLength;
}
_changingHistorySize = NO;
return historyLength;
}
-(int)rollingHistoryLength {
return _scrollHistoryLength;
}
-(void)dealloc {
if( plotData ){
free(plotData);
}
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlotGL.h
================================================
//
// EZAudioPlotGL.h
// EZAudio
//
// Created by Syed Haris Ali on 11/22/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "TargetConditionals.h"
#import "EZPlot.h"
#if TARGET_OS_IPHONE
#import
@class EZAudioPlotGLKViewController;
#elif TARGET_OS_MAC
#import
#import
#import
#import
#endif
#pragma mark - Enumerations
/**
Constant drawing types wrapping around the OpenGL equivalents. In the audio drawings the line strip will be the stroked graph while the triangle will provide the filled equivalent.
*/
typedef NS_ENUM(NSUInteger,EZAudioPlotGLDrawType){
/**
* Maps to the OpenGL constant for a line strip, which for the audio graph will correspond to a stroked drawing (no fill).
*/
EZAudioPlotGLDrawTypeLineStrip = GL_LINE_STRIP,
/**
* Maps to the OpenGL constant for a triangle strip, which for the audio graph will correspond to a filled drawing.
*/
EZAudioPlotGLDrawTypeTriangleStrip = GL_TRIANGLE_STRIP
};
#pragma mark - Structures
/**
A structure describing a 2D point (x,y) in space for an audio plot.
*/
typedef struct {
GLfloat x;
GLfloat y;
} EZAudioPlotGLPoint;
/**
EZAudioPlotGL is a subclass of either the EZPlot on iOS or an NSOpenGLView on OSX. I apologize ahead of time for the weirdness in the docs for this class, but I had to do a bit of hackery to get a universal namespace for something works on both iOS and OSX without any additional components. The EZAudioPlotGL provides an the same utilities and interface as the EZAudioPlot with the added benefit of being GPU-accelerated. This is the recommended plot to use on iOS devices to get super fast real-time drawings of audio streams. For the methods and properties below I've included notes on the bottom just indicating which OS they correspond to. In most (if not all) use cases you can just refer to the EZPlot documentation to see which custom properties can be setup. There update function is the same as the EZPlot as well: `updateBuffer:withBufferSize:`
*/
#if TARGET_OS_IPHONE
@interface EZAudioPlotGL : EZPlot
#elif TARGET_OS_MAC
@interface EZAudioPlotGL : NSOpenGLView
#endif
#if TARGET_OS_IPHONE
// Inherited from EZPlot
#elif TARGET_OS_MAC
#pragma mark - Properties
///-----------------------------------------------------------
/// @name Customizing The Plot's Appearance
///-----------------------------------------------------------
/**
The default background color of the plot. For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is black.
*/
@property (nonatomic,strong) id backgroundColor;
/**
The default color of the plot's data (i.e. waveform, y-axis values). For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is red.
*/
@property (nonatomic,strong) id color;
/**
The plot's gain value, which controls the scale of the y-axis values. The default value of the gain is 1.0f and should always be greater than 0.0f.
*/
@property (nonatomic,assign,setter=setGain:) float gain;
/**
The type of plot as specified by the `EZPlotType` enumeration (i.e. a buffer or rolling plot type).
*/
@property (nonatomic,assign,setter=setPlotType:) EZPlotType plotType;
/**
A BOOL indicating whether or not to fill in the graph. A value of YES will make a filled graph (filling in the space between the x-axis and the y-value), while a value of NO will create a stroked graph (connecting the points along the y-axis).
*/
@property (nonatomic,assign,setter=setShouldFill:) BOOL shouldFill;
/**
A boolean indicating whether the graph should be rotated along the x-axis to give a mirrored reflection. This is typical for audio plots to produce the classic waveform look. A value of YES will produce a mirrored reflection of the y-values about the x-axis, while a value of NO will only plot the y-values.
*/
@property (nonatomic,assign,setter=setShouldMirror:) BOOL shouldMirror;
#pragma mark - Get Samples
///-----------------------------------------------------------
/// @name Updating The Plot
///-----------------------------------------------------------
/**
Updates the plot with the new buffer data and tells the view to redraw itself. Caller will provide a float array with the values they expect to see on the y-axis. The plot will internally handle mapping the x-axis and y-axis to the current view port, any interpolation for fills effects, and mirroring.
@param buffer A float array of values to map to the y-axis.
@param bufferSize The size of the float array that will be mapped to the y-axis.
@warning The bufferSize is expected to be the same, constant value once initial triggered. For plots using OpenGL a vertex buffer object will be allocated with a maximum buffersize of (2 * the initial given buffer size) to account for any interpolation necessary for filling in the graph. Updates use the glBufferSubData(...) function, which will crash if the buffersize exceeds the initial maximum allocated size.
*/
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize;
#endif
#pragma mark - Adjust Resolution
///-----------------------------------------------------------
/// @name Adjusting The Resolution
///-----------------------------------------------------------
/**
Sets the length of the rolling history display. Can grow or shrink the display up to the maximum size specified by the kEZAudioPlotMaxHistoryBufferLength macro. Will return the actual set value, which will be either the given value if smaller than the kEZAudioPlotMaxHistoryBufferLength or kEZAudioPlotMaxHistoryBufferLength if a larger value is attempted to be set.
@param historyLength The new length of the rolling history buffer.
@return The new value equal to the historyLength or the kEZAudioPlotMaxHistoryBufferLength.
*/
-(int)setRollingHistoryLength:(int)historyLength;
/**
Provides the length of the rolling history buffer
* @return An int representing the length of the rolling history buffer
*/
-(int)rollingHistoryLength;
#pragma mark - Shared Methods
///-----------------------------------------------------------
/// @name Clearing The Plot
///-----------------------------------------------------------
/**
Clears all data from the audio plot (includes both EZPlotTypeBuffer and EZPlotTypeRolling)
*/
-(void)clear;
///-----------------------------------------------------------
/// @name Shared OpenGL Methods
///-----------------------------------------------------------
/**
Converts a float array to an array of EZAudioPlotGLPoint structures that hold the (x,y) values the OpenGL buffer needs to properly plot its points.
@param graph A pointer to the array that should hold the EZAudioPlotGLPoint structures.
@param graphSize The size (or length) of the array with the EZAudioPlotGLPoint structures.
@param drawingType The EZAudioPlotGLDrawType constant defining whether the plot should interpolate between points for a triangle strip (filled waveform) or not for a line strip (stroked waveform)
@param buffer The float array holding the audio data
@param bufferSize The size of the float array holding the audio data
@param gain The gain (always greater than 0.0) to apply to the amplitudes (y-values) of the graph. Y-values can only range from -1.0 to 1.0 so any value that's greater will be rounded to -1.0 or 1.0.
*/
+(void)fillGraph:(EZAudioPlotGLPoint*)graph
withGraphSize:(UInt32)graphSize
forDrawingType:(EZAudioPlotGLDrawType)drawingType
withBuffer:(float*)buffer
withBufferSize:(UInt32)bufferSize
withGain:(float)gain;
/**
Determines the proper size of a graph given a EZAudioPlotGLDrawType (line strip or triangle strip) and the size of the incoming buffer. Triangle strips require interpolating between points so the buffer becomes 2*bufferSize
@param drawingType The EZAudioPlotGLDraw type (line strip or triangle strip)
@param bufferSize The size of the float array holding the audio data coming in.
@return A Int32 representing the proper graph size that should be used to account for any necessary interpolating between points.
*/
+(UInt32)graphSizeForDrawingType:(EZAudioPlotGLDrawType)drawingType
withBufferSize:(UInt32)bufferSize;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlotGL.m
================================================
//
// EZAudioPlotGL.m
// EZAudio
//
// Created by Syed Haris Ali on 11/22/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZAudioPlotGL.h"
#import "EZAudio.h"
#if TARGET_OS_IPHONE
#import "EZAudioPlotGLKViewController.h"
@interface EZAudioPlotGL ()
@property (nonatomic,strong,readonly) EZAudioPlotGLKViewController *glViewController;
@end
#elif TARGET_OS_MAC
@interface EZAudioPlotGL (){
// Flags indicating whether the plots have been instantiated
BOOL _hasBufferPlotData;
BOOL _hasRollingPlotData;
// Vertex Array Buffers
GLuint _bufferPlotVAB;
GLuint _rollingPlotVAB;
// Vertex Buffer Objects
GLuint _bufferPlotVBO;
GLuint _rollingPlotVBO;
// Display Link
CVDisplayLinkRef _displayLink;
// Buffers size
UInt32 _bufferPlotGraphSize;
UInt32 _rollingPlotGraphSize;
// Rolling History
BOOL _setMaxLength;
float *_scrollHistory;
int _scrollHistoryIndex;
UInt32 _scrollHistoryLength;
BOOL _changingHistorySize;
// Copied buffer data
float *_copiedBuffer;
UInt32 _copiedBufferSize;
}
@property (nonatomic,assign,readonly) EZAudioPlotGLDrawType drawingType;
@property (nonatomic,strong) GLKBaseEffect *baseEffect;
@end
#endif
@implementation EZAudioPlotGL
#if TARGET_OS_IPHONE
@synthesize glViewController = _glViewController;
#elif TARGET_OS_MAC
@synthesize baseEffect = _baseEffect;
#endif
@synthesize backgroundColor = _backgroundColor;
@synthesize color = _color;
@synthesize gain = _gain;
@synthesize plotType = _plotType;
@synthesize shouldFill = _shouldFill;
@synthesize shouldMirror = _shouldMirror;
#pragma mark - Initialization
-(id)init
{
self = [super init];
if (self) {
[self initializeView];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self){
[self initializeView];
}
return self;
}
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initializeView];
}
return self;
}
#pragma mark - Initialize Properties Here
-(void)initializeView {
#if TARGET_OS_IPHONE
// Initialize the subview controller
_glViewController = [[EZAudioPlotGLKViewController alloc] init];
_glViewController.view.frame = self.bounds;
[self insertSubview:self.glViewController.view atIndex:0];
#elif TARGET_OS_MAC
_copiedBuffer = NULL;
#endif
// Set the default properties
self.gain = 1.0;
self.plotType = EZPlotTypeBuffer;
#if TARGET_OS_IPHONE
self.backgroundColor = [UIColor colorWithRed:0.796 green:0.749 blue:0.663 alpha:1];
self.color = [UIColor colorWithRed:0.481 green:0.548 blue:0.637 alpha:1];
#elif TARGET_OS_MAC
_scrollHistory = NULL;
_scrollHistoryLength = kEZAudioPlotDefaultHistoryBufferLength;
#endif
self.shouldFill = NO;
self.shouldMirror = NO;
}
#pragma mark - Setters
-(void)setBackgroundColor:(id)backgroundColor {
_backgroundColor = backgroundColor;
#if TARGET_OS_IPHONE
self.glViewController.backgroundColor = backgroundColor;
#elif TARGET_OS_MAC
[self _refreshWithBackgroundColor:backgroundColor];
#endif
}
-(void)setColor:(id)color {
_color = color;
#if TARGET_OS_IPHONE
self.glViewController.color = color;
#elif TARGET_OS_MAC
[self _refreshWithColor:color];
#endif
}
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
-(void)setDrawingType:(EZAudioPlotGLDrawType)drawingType {
CGLLockContext([[self openGLContext] CGLContextObj]);
_drawingType = drawingType;
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
#endif
#if TARGET_OS_IPHONE
-(void)setGain:(float)gain {
_gain = gain;
self.glViewController.gain = gain;
}
#elif TARGET_OS_MAC
// Gain changed mac
#endif
#if TARGET_OS_IPHONE
-(void)setPlotType:(EZPlotType)plotType {
_plotType = plotType;
self.glViewController.plotType = plotType;
}
#elif TARGET_OS_MAC
// Plot type changed mac
#endif
-(void)setShouldFill:(BOOL)shouldFill {
_shouldFill = shouldFill;
#if TARGET_OS_IPHONE
self.glViewController.drawingType = shouldFill ? EZAudioPlotGLDrawTypeTriangleStrip : EZAudioPlotGLDrawTypeLineStrip;
#elif TARGET_OS_MAC
// Fill flag changed mac
self.drawingType = shouldFill ? EZAudioPlotGLDrawTypeTriangleStrip : EZAudioPlotGLDrawTypeLineStrip;
#endif
}
#if TARGET_OS_IPHONE
-(void)setShouldMirror:(BOOL)shouldMirror {
_shouldMirror = shouldMirror;
self.glViewController.shouldMirror = shouldMirror;
}
#elif TARGET_OS_MAC
// Mirror flag changed mac
#endif
#pragma mark - Get Samples
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize {
#if TARGET_OS_IPHONE
[self.glViewController updateBuffer:buffer
withBufferSize:bufferSize];
#elif TARGET_OS_MAC
if( _copiedBuffer == NULL ){
_copiedBuffer = (float*)malloc(bufferSize*sizeof(float));
}
_copiedBufferSize = bufferSize;
// Copy the buffer
memcpy(_copiedBuffer,
buffer,
bufferSize*sizeof(float));
// Draw based on plot type
switch(_plotType) {
case EZPlotTypeBuffer:
[self _updateBufferPlotBufferWithAudioReceived:_copiedBuffer
withBufferSize:_copiedBufferSize];
break;
case EZPlotTypeRolling:
[self _updateRollingPlotBufferWithAudioReceived:_copiedBuffer
withBufferSize:_copiedBufferSize];
break;
default:
break;
}
#endif
}
#pragma mark - OSX Specific GL Implementation
#if TARGET_OS_IPHONE
// Handled by the embedded GLKViewController
#elif TARGET_OS_MAC
#pragma mark - Awake
-(void)awakeFromNib {
// Setup the base effect
[self _setupBaseEffect];
// Setup the OpenGL Pixel Format and Context
[self _setupProfile];
// Setup view
[self _setupView];
}
-(void)_setupBaseEffect {
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.useConstantColor = GL_TRUE;
self.baseEffect.constantColor = GLKVector4Make(0.489, 0.34, 0.185, 1.0);
}
-(void)_setupProfile {
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAMultisample,
NSOpenGLPFASampleBuffers, 1,
NSOpenGLPFASamples, 4,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAOpenGLProfile,
NSOpenGLProfileVersion3_2Core, 0
};
NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if (!pf)
{
NSLog(@"No OpenGL pixel format");
}
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
// Debug only
CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
self.pixelFormat = pf;
self.openGLContext = context;
}
-(void)_setupView {
self.backgroundColor = [NSColor colorWithCalibratedRed: 0.796 green: 0.749 blue: 0.663 alpha: 1];
self.color = [NSColor colorWithCalibratedRed: 0.481 green: 0.548 blue: 0.637 alpha: 1];
}
#pragma mark - Prepare
-(void)prepareOpenGL {
[super prepareOpenGL];
GLint swapInt = 1;
[self.openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
////////////////////////////////////////////////////////////////////////////
// Setup VABs and VBOs //
////////////////////////////////////////////////////////////////////////////
// Buffer
glGenVertexArrays(1,&_bufferPlotVAB);
glBindVertexArray(_bufferPlotVAB);
glGenBuffers(1,&_bufferPlotVBO);
glBindBuffer(GL_ARRAY_BUFFER,_bufferPlotVBO);
// Rolling
glGenVertexArrays(1,&_rollingPlotVAB);
glBindVertexArray(_rollingPlotVAB);
glGenBuffers(1,&_rollingPlotVBO);
glBindBuffer(GL_ARRAY_BUFFER,_rollingPlotVBO);
if( self.shouldFill ){
glBindVertexArray(_rollingPlotVAB);
glBindBuffer(GL_ARRAY_BUFFER,_rollingPlotVBO);
}
// Enable anti-aliasing
glEnable(GL_MULTISAMPLE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 0);
self.layer = nil;
// Set the background color
[self _refreshWithBackgroundColor:self.backgroundColor];
[self _refreshWithColor:self.color];
// Setup the display link (rendering loop)
[self _setupDisplayLink];
}
-(void)_setupDisplayLink {
// Create a display link capable of being used with all active displays
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
// Set the renderer output callback function
CVDisplayLinkSetOutputCallback(_displayLink, &DisplayLinkCallback, (__bridge void *)(self));
// Set the display link for the current renderer
CGLContextObj cglContext = self.openGLContext.CGLContextObj;
CGLPixelFormatObj cglPixelFormat = self.pixelFormat.CGLPixelFormatObj;
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
// Activate the display link
CVDisplayLinkStart(_displayLink);
// Register to be notified when the window closes so we can stop the displaylink
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:[self window]];
}
- (void) windowWillClose:(NSNotification*)notification
{
// Stop the display link when the window is closing because default
// OpenGL render buffers will be destroyed. If display link continues to
// fire without renderbuffers, OpenGL draw calls will set errors.
CVDisplayLinkStop(_displayLink);
}
#pragma mark - Display Link Callback
// This is the renderer output callback function
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp* now,
const CVTimeStamp* outputTime,
CVOptionFlags flagsIn,
CVOptionFlags* flagsOut,
void* displayLinkContext)
{
CVReturn result = [(__bridge EZAudioPlotGL*)displayLinkContext getFrameForTime:outputTime];
return result;
}
- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime
{
@autoreleasepool {
[self drawFrame];
}
return kCVReturnSuccess;
}
#pragma mark - Buffer Updating By Type
-(void)_updateBufferPlotBufferWithAudioReceived:(float*)buffer
withBufferSize:(UInt32)bufferSize {
// Lock
CGLLockContext([[self openGLContext] CGLContextObj]);
// Bind to buffer VBO
glBindVertexArray(_bufferPlotVAB);
glBindBuffer(GL_ARRAY_BUFFER,_bufferPlotVBO);
// If starting with a VBO of half of our max size make sure we initialize it to anticipate
// a filled graph (which needs 2 * bufferSize) to allocate its resources properly
if( !_hasBufferPlotData && _drawingType == EZAudioPlotGLDrawTypeLineStrip ){
EZAudioPlotGLPoint maxGraph[2*bufferSize];
glBufferData(GL_ARRAY_BUFFER, sizeof(maxGraph), maxGraph, GL_STREAM_DRAW );
_hasBufferPlotData = YES;
}
// Setup the buffer plot's graph size
_bufferPlotGraphSize = [EZAudioPlotGL graphSizeForDrawingType:_drawingType
withBufferSize:bufferSize];
// Setup the graph
EZAudioPlotGLPoint graph[_bufferPlotGraphSize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_bufferPlotGraphSize
forDrawingType:_drawingType
withBuffer:buffer
withBufferSize:bufferSize
withGain:self.gain];
// Update the drawing
if( !_hasBufferPlotData ){
glBufferData(GL_ARRAY_BUFFER, sizeof(graph) , graph, GL_STREAM_DRAW);
_hasBufferPlotData = YES;
}
else {
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
// Unlock
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
-(void)_updateRollingPlotBufferWithAudioReceived:(float*)buffer
withBufferSize:(UInt32)bufferSize {
// Lock
CGLLockContext([[self openGLContext] CGLContextObj]);
// Bind to rolling VBO
glBindVertexArray(_rollingPlotVAB);
glBindBuffer(GL_ARRAY_BUFFER,_rollingPlotVBO);
// If starting with a VBO of half of our max size make sure we initialize it to anticipate
// a filled graph (which needs 2 * bufferSize) to allocate its resources properly
if( !_hasRollingPlotData ){
EZAudioPlotGLPoint maxGraph[2*kEZAudioPlotMaxHistoryBufferLength];
glBufferData(GL_ARRAY_BUFFER, sizeof(maxGraph), maxGraph, GL_STREAM_DRAW );
_hasRollingPlotData = YES;
}
// Setup the plot
_rollingPlotGraphSize = [EZAudioPlotGL graphSizeForDrawingType:_drawingType
withBufferSize:_scrollHistoryLength];
// Fill the graph with data
EZAudioPlotGLPoint graph[_rollingPlotGraphSize];
// Update the scroll history datasource
[EZAudio updateScrollHistory:&_scrollHistory
withLength:_scrollHistoryLength
atIndex:&_scrollHistoryIndex
withBuffer:buffer
withBufferSize:bufferSize
isResolutionChanging:&_changingHistorySize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_rollingPlotGraphSize
forDrawingType:_drawingType
withBuffer:_scrollHistory
withBufferSize:_scrollHistoryLength
withGain:self.gain];
// Update the drawing
if( !_hasRollingPlotData ){
glBufferData(GL_ARRAY_BUFFER, sizeof(graph), graph, GL_STREAM_DRAW);
_hasRollingPlotData = YES;
}
else {
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
// Unlock
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
//#pragma mark - Render
-(void)drawFrame {
// Avoid flickering during resize by drawing
[[self openGLContext] makeCurrentContext];
// Lock
CGLLockContext([[self openGLContext] CGLContextObj]);
// Draw frame
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
if( _hasBufferPlotData || _hasRollingPlotData ){
// Plot either a buffer plot or a rolling plot
switch(_plotType) {
case EZPlotTypeBuffer:
[self _drawBufferPlot];
break;
case EZPlotTypeRolling:
[self _drawRollingPlot];
break;
default:
break;
}
}
// Flush and unlock
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
-(void)_drawBufferPlot {
glBindVertexArray(_bufferPlotVAB);
glBindBuffer(GL_ARRAY_BUFFER,_bufferPlotVBO);
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(0);
// Enable the vertex data
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Define the vertex data size & layout
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Draw the triangle
glDrawArrays(_drawingType,0,_bufferPlotGraphSize);
// Mirrored
if( self.shouldMirror ){
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(M_PI);
// Enable the vertex data
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Define the vertex data size & layout
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Draw the triangle
glDrawArrays(_drawingType, 0, _bufferPlotGraphSize);
}
}
-(void)_drawRollingPlot {
glBindVertexArray(_rollingPlotVAB);
glBindBuffer(GL_ARRAY_BUFFER,_rollingPlotVBO);
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(0);
// Enable the vertex data
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Define the vertex data size & layout
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Draw the triangle
glDrawArrays(_drawingType, 0,_rollingPlotGraphSize);
// Mirrored
if( self.shouldMirror ){
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(M_PI);
// Enable the vertex data
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Define the vertex data size & layout
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Draw the triangle
glDrawArrays(_drawingType, 0,_rollingPlotGraphSize);
}
}
-(void)drawRect:(NSRect)dirtyRect {
[self drawFrame];
}
#pragma mark - Reshape
-(void)reshape {
[super reshape];
// We draw on a secondary thread through the display link. However, when
// resizing the view, -drawRect is called on the main thread.
// Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing.
CGLLockContext([[self openGLContext] CGLContextObj]);
// Get the view size in Points
NSRect viewRectPoints = [self bounds];
NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints];
// Set the new dimensions in our renderer
glViewport(0, 0, viewRectPixels.size.width, viewRectPixels.size.height);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
#pragma mark - Private Setters
-(void)_refreshWithBackgroundColor:(NSColor*)backgroundColor {
CGLLockContext([[self openGLContext] CGLContextObj]);
// Extract colors
CGFloat red; CGFloat green; CGFloat blue; CGFloat alpha;
[backgroundColor getRed:&red
green:&green
blue:&blue
alpha:&alpha];
// Set them on the context
glClearColor((GLclampf)red,(GLclampf)green,(GLclampf)blue,(GLclampf)alpha);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
-(void)_refreshWithColor:(NSColor*)color {
CGLLockContext([[self openGLContext] CGLContextObj]);
// Extract colors
CGFloat red; CGFloat green; CGFloat blue; CGFloat alpha;
[color getRed:&red
green:&green
blue:&blue
alpha:&alpha];
// Set them on the base shader
self.baseEffect.constantColor = GLKVector4Make((GLclampf)red,(GLclampf)green,(GLclampf)blue,(GLclampf)alpha);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
#pragma mark - Cleanup
- (void) dealloc
{
// Stop the display link BEFORE releasing anything in the view
// otherwise the display link thread may call into the view and crash
// when it encounters something that has been release
CVDisplayLinkStop(_displayLink);
CVDisplayLinkRelease(_displayLink);
if( _copiedBuffer != NULL ){
free( _copiedBuffer );
}
}
#endif
#pragma mark - Adjust Resolution
-(int)setRollingHistoryLength:(int)historyLength {
#if TARGET_OS_IPHONE
int result = [self.glViewController setRollingHistoryLength:historyLength];
return result;
#elif TARGET_OS_MAC
historyLength = MIN(historyLength,kEZAudioPlotMaxHistoryBufferLength);
size_t floatByteSize = sizeof(float);
_changingHistorySize = YES;
if( _scrollHistoryLength != historyLength ){
_scrollHistoryLength = historyLength;
}
_scrollHistory = realloc(_scrollHistory,_scrollHistoryLength*floatByteSize);
if( _scrollHistoryIndex < _scrollHistoryLength ){
memset(&_scrollHistory[_scrollHistoryIndex],
0,
(_scrollHistoryLength-_scrollHistoryIndex)*floatByteSize);
}
else {
_scrollHistoryIndex = _scrollHistoryLength;
}
_changingHistorySize = NO;
return historyLength;
#endif
return kEZAudioPlotDefaultHistoryBufferLength;
}
-(int)rollingHistoryLength {
#if TARGET_OS_IPHONE
return self.glViewController.rollingHistoryLength;
#elif TARGET_OS_MAC
return _scrollHistoryLength;
#endif
}
#pragma mark - Clearing
-(void)clear {
#if TARGET_OS_IPHONE
[self.glViewController clear];
#elif TARGET_OS_MAC
#endif
}
#pragma mark - Graph Methods
+(void)fillGraph:(EZAudioPlotGLPoint*)graph
withGraphSize:(UInt32)graphSize
forDrawingType:(EZAudioPlotGLDrawType)drawingType
withBuffer:(float*)buffer
withBufferSize:(UInt32)bufferSize
withGain:(float)gain {
if( drawingType == EZAudioPlotGLDrawTypeLineStrip ){
// graph size = buffer size to stroke waveform
for(int i = 0; i < graphSize; i++){
float x = [EZAudio MAP:i
leftMin:0
leftMax:bufferSize
rightMin:-1.0
rightMax:1.0];
graph[i].x = x;
graph[i].y = gain*buffer[i];
}
}
else if( drawingType == EZAudioPlotGLDrawTypeTriangleStrip ) {
// graph size = 2 * buffer size to draw triangles and fill regions properly
for(int i = 0; i < graphSize; i+=2){
int bufferIndex = (int)[EZAudio MAP:i
leftMin:0
leftMax:graphSize
rightMin:0
rightMax:bufferSize];
float x = [EZAudio MAP:bufferIndex
leftMin:0
leftMax:bufferSize
rightMin:-1.0
rightMax:1.0];
graph[i].x = x;
graph[i].y = 0.0f;
}
for(int i = 0; i < graphSize; i+=2){
int bufferIndex = (int)[EZAudio
MAP:i
leftMin:0
leftMax:graphSize
rightMin:0
rightMax:bufferSize];
float x = [EZAudio MAP:bufferIndex
leftMin:0
leftMax:bufferSize
rightMin:-1.0
rightMax:1.0];
graph[i+1].x = x;
graph[i+1].y = gain*buffer[bufferIndex];
}
}
}
+(UInt32)graphSizeForDrawingType:(EZAudioPlotGLDrawType)drawingType
withBufferSize:(UInt32)bufferSize {
UInt32 graphSize = bufferSize;
switch(drawingType) {
case EZAudioPlotGLDrawTypeLineStrip:
graphSize = bufferSize;
break;
case EZAudioPlotGLDrawTypeTriangleStrip:
graphSize = 2*bufferSize;
break;
default:
break;
}
return graphSize;
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlotGLKViewController.h
================================================
//
// EZAudioPlotGLKViewController.h
// EZAudio
//
// Created by Syed Haris Ali on 11/22/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "TargetConditionals.h"
#if TARGET_OS_IPHONE
#import "EZAudioPlotGL.h"
@class EZAudio;
/**
EZAudioPlotGLKViewController is a subclass of the GLKViewController and handles the OpenGL drawing routine for iOS OpenGL ES views. This class has not been used outside the scope of the EZAudioPlotGL, but should be safe to use by itself if the intended use case is to have a view controller take up the whole screen.
*/
@interface EZAudioPlotGLKViewController : GLKViewController
#pragma mark - Properties
///-----------------------------------------------------------
/// @name Customizing The Plot's Appearance
///-----------------------------------------------------------
/**
The default background color of the plot. For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is black.
*/
@property (nonatomic,strong) UIColor *backgroundColor;
/**
The default shader to use to fill the graph.
*/
@property (nonatomic,strong) GLKBaseEffect *baseEffect;
/**
The default color of the plot's data (i.e. waveform, y-axis values). For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is red.
*/
@property (nonatomic,strong) UIColor *color;
/**
The OpenGL ES context (EAGLContext) in which to perform the drawing
*/
@property (nonatomic,strong) EAGLContext *context;
/**
The EZAudioPlotGLDrawType specifying which OpenGL primitive to use for drawing (either line strip for stroke and no fill or triangle strip for fill)
*/
@property (nonatomic,assign) EZAudioPlotGLDrawType drawingType;
/**
The plot's gain value, which controls the scale of the y-axis values. The default value of the gain is 1.0f and should always be greater than 0.0f.
*/
@property (nonatomic,assign,setter=setGain:) float gain;
/**
The type of plot as specified by the `EZPlotType` enumeration (i.e. a buffer or rolling plot type).
*/
@property (nonatomic,assign,setter=setPlotType:) EZPlotType plotType;
/**
A boolean indicating whether the graph should be rotated along the x-axis to give a mirrored reflection. This is typical for audio plots to produce the classic waveform look. A value of YES will produce a mirrored reflection of the y-values about the x-axis, while a value of NO will only plot the y-values.
*/
@property (nonatomic,assign,setter=setShouldMirror:) BOOL shouldMirror;
#pragma mark - Adjust Resolution
///-----------------------------------------------------------
/// @name Adjusting The Resolution
///-----------------------------------------------------------
/**
Sets the length of the rolling history display. Can grow or shrink the display up to the maximum size specified by the kEZAudioPlotMaxHistoryBufferLength macro. Will return the actual set value, which will be either the given value if smaller than the kEZAudioPlotMaxHistoryBufferLength or kEZAudioPlotMaxHistoryBufferLength if a larger value is attempted to be set.
@param historyLength The new length of the rolling history buffer.
@return The new value equal to the historyLength or the kEZAudioPlotMaxHistoryBufferLength.
*/
-(int)setRollingHistoryLength:(int)historyLength;
/**
Provides the length of the rolling history buffer
* @return An int representing the length of the rolling history buffer
*/
-(int)rollingHistoryLength;
#pragma mark - Clearing
///-----------------------------------------------------------
/// @name Clearing The Plot
///-----------------------------------------------------------
/**
Clears all data from the audio plot (includes both EZPlotTypeBuffer and EZPlotTypeRolling)
*/
-(void)clear;
#pragma mark - Get Samples
///-----------------------------------------------------------
/// @name Updating The Plot
///-----------------------------------------------------------
/**
Updates the plot with the new buffer data and tells the view to redraw itself. Caller will provide a float array with the values they expect to see on the y-axis. The plot will internally handle mapping the x-axis and y-axis to the current view port, any interpolation for fills effects, and mirroring.
@param buffer A float array of values to map to the y-axis.
@param bufferSize The size of the float array that will be mapped to the y-axis.
@warning The bufferSize is expected to be the same, constant value once initial triggered. For plots using OpenGL a vertex buffer object will be allocated with a maximum buffersize of (2 * the initial given buffer size) to account for any interpolation necessary for filling in the graph. Updates use the glBufferSubData(...) function, which will crash if the buffersize exceeds the initial maximum allocated size.
*/
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize;
@end
#elif TARGET_OS_MAC
#endif
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZAudioPlotGLKViewController.m
================================================
//
// EZAudioPlotGLKViewController.m
// EZAudio
//
// Created by Syed Haris Ali on 11/22/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if TARGET_OS_IPHONE
#import "EZAudioPlotGLKViewController.h"
#import "EZAudio.h"
@interface EZAudioPlotGLKViewController () {
// Flags indicating whether the plots have been instantiated
BOOL _hasBufferPlotData;
BOOL _hasRollingPlotData;
// The buffers
GLuint _bufferPlotVBO;
GLuint _rollingPlotVBO;
// Buffers size
UInt32 _bufferPlotGraphSize;
UInt32 _rollingPlotGraphSize;
// Rolling History
BOOL _setMaxLength;
float *_scrollHistory;
int _scrollHistoryIndex;
UInt32 _scrollHistoryLength;
BOOL _changingHistorySize;
}
@end
@implementation EZAudioPlotGLKViewController
@synthesize baseEffect = _baseEffect;
@synthesize context = _context;
@synthesize drawingType = _drawingType;
@synthesize plotType = _plotType;
@synthesize shouldMirror = _shouldMirror;
#pragma mark - Initialization
-(id)init
{
self = [super init];
if (self) {
[self initializeView];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self){
[self initializeView];
}
return self;
}
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self){
[self initializeView];
}
return self;
}
#pragma mark - Initialize Properties Here
-(void)initializeView {
// Setup the base effect
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.useConstantColor = GL_TRUE;
self.preferredFramesPerSecond = 60;
_scrollHistory = NULL;
_scrollHistoryLength = kEZAudioPlotDefaultHistoryBufferLength;
}
#pragma mark - View Did Load
-(void)viewDidLoad {
[super viewDidLoad];
// Setup the context
if( ![EAGLContext currentContext] )
{
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}
else
{
self.context = [EAGLContext currentContext];
}
if (!self.context) {
NSLog(@"Failed to create ES context");
}
else {
EAGLContext.currentContext = self.context;
}
// Set the view's context
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableMultisample = GLKViewDrawableMultisample4X;
// Generate both the buffer id references
glGenBuffers(1, &_bufferPlotVBO);
glGenBuffers(1, &_rollingPlotVBO);
// Refresh color values
[self _refreshWithBackgroundColor: self.backgroundColor];
[self _refreshWithColor: self.color];
// Set the line width for the context
glLineWidth(2.0);
}
#pragma mark - Adjust Resolution
-(int)setRollingHistoryLength:(int)historyLength {
_changingHistorySize = YES;
historyLength = MIN(historyLength,kEZAudioPlotMaxHistoryBufferLength);
size_t floatByteSize = sizeof(float);
if( _scrollHistoryLength != historyLength ){
_scrollHistoryLength = historyLength;
}
_scrollHistory = realloc(_scrollHistory,_scrollHistoryLength*floatByteSize);
if( _scrollHistoryIndex < _scrollHistoryLength ){
memset(&_scrollHistory[_scrollHistoryIndex],
0,
(_scrollHistoryLength-_scrollHistoryIndex)*floatByteSize);
}
else {
_scrollHistoryIndex = _scrollHistoryLength;
}
[self _updateRollingPlotDisplay];
_changingHistorySize = NO;
return historyLength;
}
-(int)rollingHistoryLength {
return _scrollHistoryLength;
}
#pragma mark - Clearing
-(void)clear
{
_scrollHistoryIndex = 0;
[self _clearBufferPlot];
[self _clearRollingPlot];
}
-(void)_clearBufferPlot
{
if( _hasBufferPlotData )
{
float empty[_bufferPlotGraphSize];
memset( empty, 0.0f, sizeof(float) );
[self _updateBufferPlotBufferWithAudioReceived:empty
withBufferSize:_bufferPlotGraphSize];
}
}
-(void)_clearRollingPlot
{
if( _hasRollingPlotData )
{
float empty[_rollingPlotGraphSize];
EZAudioPlotGLPoint graph[_rollingPlotGraphSize];
// Figure out better way to do this
for(int i = 0; i < _rollingPlotGraphSize; i++ )
{
empty[i] = 0.0f;
}
for(int i = 0; i < _scrollHistoryLength; i++)
{
_scrollHistory[i] = 0.0f;
}
// Update the scroll history datasource
[EZAudio updateScrollHistory:&_scrollHistory
withLength:_scrollHistoryLength
atIndex:&_scrollHistoryIndex
withBuffer:empty
withBufferSize:_rollingPlotGraphSize
isResolutionChanging:&_changingHistorySize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_rollingPlotGraphSize
forDrawingType:_drawingType
withBuffer:_scrollHistory
withBufferSize:_scrollHistoryLength
withGain:self.gain];
// Update the drawing
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
}
#pragma mark - Get Samples
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize {
// Make sure the update render loop is active
if( self.paused ) self.paused = NO;
// Make sure we are updating the buffers on the correct gl context.
EAGLContext.currentContext = self.context;
// Draw based on plot type
switch(_plotType) {
case EZPlotTypeBuffer:
[self _updateBufferPlotBufferWithAudioReceived:buffer
withBufferSize:bufferSize];
break;
case EZPlotTypeRolling:
[self _updateRollingPlotBufferWithAudioReceived:buffer
withBufferSize:bufferSize];
break;
default:
break;
}
}
#pragma mark - Buffer Updating By Type
-(void)_updateBufferPlotBufferWithAudioReceived:(float*)buffer
withBufferSize:(UInt32)bufferSize {
glBindBuffer(GL_ARRAY_BUFFER, _bufferPlotVBO);
// If starting with a VBO of half of our max size make sure we initialize it to anticipate
// a filled graph (which needs 2 * bufferSize) to allocate its resources properly
if( !_hasBufferPlotData && _drawingType == EZAudioPlotGLDrawTypeLineStrip ){
EZAudioPlotGLPoint maxGraph[2*bufferSize];
glBufferData(GL_ARRAY_BUFFER, sizeof(maxGraph), maxGraph, GL_STREAM_DRAW );
_hasBufferPlotData = YES;
}
// Setup the buffer plot's graph size
_bufferPlotGraphSize = [EZAudioPlotGL graphSizeForDrawingType:_drawingType
withBufferSize:bufferSize];
// Setup the graph
EZAudioPlotGLPoint graph[_bufferPlotGraphSize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_bufferPlotGraphSize
forDrawingType:_drawingType
withBuffer:buffer
withBufferSize:bufferSize
withGain:self.gain];
if( !_hasBufferPlotData ){
glBufferData( GL_ARRAY_BUFFER, sizeof(graph), graph, GL_STREAM_DRAW );
_hasBufferPlotData = YES;
}
else {
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
-(void)_updateRollingPlotBufferWithAudioReceived:(float*)buffer
withBufferSize:(UInt32)bufferSize {
glBindBuffer(GL_ARRAY_BUFFER, _rollingPlotVBO);
// If starting with a VBO of half of our max size make sure we initialize it to anticipate
// a filled graph (which needs 2 * bufferSize) to allocate its resources properly
if( !_hasRollingPlotData ){
EZAudioPlotGLPoint maxGraph[2*kEZAudioPlotMaxHistoryBufferLength];
glBufferData( GL_ARRAY_BUFFER, sizeof(maxGraph), maxGraph, GL_STREAM_DRAW );
_hasRollingPlotData = YES;
}
// Setup the plot
_rollingPlotGraphSize = [EZAudioPlotGL graphSizeForDrawingType:_drawingType
withBufferSize:_scrollHistoryLength];
// Fill the graph with data
EZAudioPlotGLPoint graph[_rollingPlotGraphSize];
// Update the scroll history datasource
[EZAudio updateScrollHistory:&_scrollHistory
withLength:_scrollHistoryLength
atIndex:&_scrollHistoryIndex
withBuffer:buffer
withBufferSize:bufferSize
isResolutionChanging:&_changingHistorySize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_rollingPlotGraphSize
forDrawingType:_drawingType
withBuffer:_scrollHistory
withBufferSize:_scrollHistoryLength
withGain:self.gain];
// Update the drawing
if( !_hasRollingPlotData ){
glBufferData( GL_ARRAY_BUFFER, sizeof(graph) , graph, GL_STREAM_DRAW );
_hasRollingPlotData = YES;
}
else {
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
-(void)_updateRollingPlotDisplay {
// Setup the plot
_rollingPlotGraphSize = [EZAudioPlotGL graphSizeForDrawingType:_drawingType
withBufferSize:_scrollHistoryLength];
// Fill the graph with data
EZAudioPlotGLPoint graph[_rollingPlotGraphSize];
// Fill in graph data
[EZAudioPlotGL fillGraph:graph
withGraphSize:_rollingPlotGraphSize
forDrawingType:_drawingType
withBuffer:_scrollHistory
withBufferSize:_scrollHistoryLength
withGain:self.gain];
// Update the drawing
if( _hasRollingPlotData ){
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(graph), graph);
}
}
#pragma mark - Drawing
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
EAGLContext.currentContext = self.context;
// Clear the context
glClear(GL_COLOR_BUFFER_BIT);
if( _hasBufferPlotData || _hasRollingPlotData ){
// Prepare the effect for drawing
[self.baseEffect prepareToDraw];
// Plot either a buffer plot or a rolling plot
switch(_plotType) {
case EZPlotTypeBuffer:
[self _drawBufferPlotWithView:view
drawInRect:rect];
break;
case EZPlotTypeRolling:
[self _drawRollingPlotWithView:view
drawInRect:rect];
break;
default:
break;
}
}
}
#pragma mark - Private Drawing
-(void)_drawBufferPlotWithView:(GLKView*)view drawInRect:(CGRect)rect {
if( _hasBufferPlotData ){
glBindBuffer(GL_ARRAY_BUFFER, _bufferPlotVBO);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Normal plot
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(0);
glDrawArrays(_drawingType, 0, _bufferPlotGraphSize);
if( self.shouldMirror ){
// Mirrored plot
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(M_PI);
glDrawArrays(_drawingType, 0, _bufferPlotGraphSize);
}
glBindBuffer(GL_ARRAY_BUFFER,0);
}
}
-(void)_drawRollingPlotWithView:(GLKView*)view drawInRect:(CGRect)rect {
if( _hasRollingPlotData ){
// Normal plot
glBindBuffer(GL_ARRAY_BUFFER, _rollingPlotVBO);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(EZAudioPlotGLPoint), NULL);
// Normal plot
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(0);
glDrawArrays(_drawingType, 0, _rollingPlotGraphSize);
if( self.shouldMirror ){
// Mirrored plot
[self.baseEffect prepareToDraw];
self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeXRotation(3.14159265359);
glDrawArrays(_drawingType, 0, _rollingPlotGraphSize);
}
glBindBuffer(GL_ARRAY_BUFFER,0);
}
}
#pragma mark - Setters
-(void)setBackgroundColor:(UIColor *)backgroundColor {
// Set the background color
_backgroundColor = backgroundColor;
// Refresh background color (map to GL vector)
[self _refreshWithBackgroundColor:backgroundColor];
}
-(void)setColor:(UIColor *)color {
// Set the color
_color = color;
// Refresh the color (map to GL vector)
[self _refreshWithColor:color];
}
#pragma mark - Private Setters
-(void)_refreshWithBackgroundColor:(UIColor*)backgroundColor {
// Extract colors
CGFloat red; CGFloat green; CGFloat blue; CGFloat alpha;
[backgroundColor getRed:&red
green:&green
blue:&blue
alpha:&alpha];
// Set them on the context
glClearColor((GLclampf)red,(GLclampf)green,(GLclampf)blue,(GLclampf)alpha);
}
-(void)_refreshWithColor:(UIColor*)color {
// Extract colors
CGFloat red; CGFloat green; CGFloat blue; CGFloat alpha;
[color getRed:&red
green:&green
blue:&blue
alpha:&alpha];
// Set them on the base shader
self.baseEffect.constantColor = GLKVector4Make((GLclampf)red,(GLclampf)green,(GLclampf)blue,(GLclampf)alpha);
}
@end
#elif TARGET_OS_MAC
#endif
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZMicrophone.h
================================================
//
// EZMicrophone.h
// EZAudio
//
// Created by Syed Haris Ali on 9/2/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#import
#import "AEFloatConverter.h"
#import "TargetConditionals.h"
@class EZAudio;
@class EZMicrophone;
#pragma mark - EZMicrophoneDelegate
/**
The delegate for the EZMicrophone provides a receiver for the incoming audio data events. When the microphone has been successfully internally configured it will try to send its delegate an AudioStreamBasicDescription describing the format of the incoming audio data.
The audio data itself is sent back to the delegate in various forms:
-`microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:`
Provides float arrays instead of the AudioBufferList structure to hold the audio data. There could be a number of float arrays depending on the number of channels (see the function description below). These are useful for doing any visualizations that would like to make use of the raw audio data.
-`microphone:hasBufferList:withBufferSize:withNumberOfChannels:`
Provides the AudioBufferList structures holding the audio data. These are the native structures Core Audio uses to hold the buffer information and useful for piping out directly to an output (see EZOutput).
*/
@protocol EZMicrophoneDelegate
@optional
///-----------------------------------------------------------
/// @name Audio Data Description
///-----------------------------------------------------------
/**
Returns back the audio stream basic description as soon as it has been initialized. This is guaranteed to occur before the stream callbacks, `microphone:hasBufferList:withBufferSize:withNumberOfChannels:` or `microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:`
@param microphone The instance of the EZMicrophone that triggered the event.
@param audioStreamBasicDescription The AudioStreamBasicDescription that was created for the microphone instance.
*/
-(void) microphone:(EZMicrophone *)microphone
hasAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
///-----------------------------------------------------------
/// @name Audio Data Callbacks
///-----------------------------------------------------------
/**
Returns back a float array of the audio received. This occurs on the background thread so any drawing code must explicity perform its functions on the main thread.
@param microphone The instance of the EZMicrophone that triggered the event.
@param buffer The audio data as an array of float arrays. In a stereo signal buffer[0] represents the left channel while buffer[1] would represent the right channel.
@param bufferSize The size of each of the buffers (the length of each float array).
@param numberOfChannels The number of channels for the incoming audio.
@warning This function executes on a background thread to avoid blocking any audio operations. If operations should be performed on any other thread (like the main thread) it should be performed within a dispatch block like so: dispatch_async(dispatch_get_main_queue(), ^{ ...Your Code... })
*/
-(void) microphone:(EZMicrophone*)microphone
hasAudioReceived:(float**)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels;
/**
Returns back the buffer list containing the audio received. This occurs on the background thread so any drawing code must explicity perform its functions on the main thread.
@param microphone The instance of the EZMicrophone that triggered the event.
@param bufferList The AudioBufferList holding the audio data.
@param bufferSize The size of each of the buffers of the AudioBufferList.
@param numberOfChannels The number of channels for the incoming audio.
@warning This function executes on a background thread to avoid blocking any audio operations. If operations should be performed on any other thread (like the main thread) it should be performed within a dispatch block like so: dispatch_async(dispatch_get_main_queue(), ^{ ...Your Code... })
*/
-(void) microphone:(EZMicrophone*)microphone
hasBufferList:(AudioBufferList*)bufferList
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels;
@end
#pragma mark - EZMicrophone
/**
The EZMicrophone provides a component to get audio data from the default device microphone. On OSX this is the default selected input device in the system preferences while on iOS this defaults to use the default RemoteIO audio unit. The microphone data is converted to a float buffer array and returned back to the caller via the EZMicrophoneDelegate protocol.
*/
@interface EZMicrophone : NSObject
/**
The EZMicrophoneDelegate for which to handle the microphone callbacks
*/
@property (nonatomic,assign) id microphoneDelegate;
/**
A bool describing whether the microphone is on and passing back audio data to its delegate.
*/
@property (nonatomic,assign) BOOL microphoneOn;
#pragma mark - Initializers
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback. This will not start fetching the audio until startFetchingAudio has been called. Use initWithMicrophoneDelegate:startsImmediately: to instantiate this class and immediately start fetching audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
-(EZMicrophone*)initWithMicrophoneDelegate:(id)microphoneDelegate;
/**
Creates an instance of the EZMicrophone with a custom AudioStreamBasicDescription and provides the caller to specify a delegate to respond to the audioReceived callback. This will not start fetching the audio until startFetchingAudio has been called. Use initWithMicrophoneDelegate:startsImmediately: to instantiate this class and immediately start fetching audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param audioStreamBasicDescription A custom AudioStreamBasicFormat for the microphone input.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
-(EZMicrophone*)initWithMicrophoneDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback and allows the caller to specify whether they'd immediately like to start fetching the audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param startsImmediately A boolean indicating whether to start fetching the data immediately. IF YES, the delegate's audioReceived callback will immediately start getting called.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
-(EZMicrophone*)initWithMicrophoneDelegate:(id)microphoneDelegate
startsImmediately:(BOOL)startsImmediately;
/**
Creates an instance of the EZMicrophone with a custom AudioStreamBasicDescription and provides the caller with a delegate to respond to the audioReceived callback and allows the caller to specify whether they'd immediately like to start fetching the audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param audioStreamBasicDescription A custom AudioStreamBasicFormat for the microphone input.
@param startsImmediately A boolean indicating whether to start fetching the data immediately. IF YES, the delegate's audioReceived callback will immediately start getting called.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
-(EZMicrophone*)initWithMicrophoneDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription
startsImmediately:(BOOL)startsImmediately;
#pragma mark - Class Initializers
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback. This will not start fetching the audio until startFetchingAudio has been called. Use microphoneWithDelegate:startsImmediately: to instantiate this class and immediately start fetching audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@return An instance of the EZMicrophone class. This should be declared as a strong property!
*/
+(EZMicrophone*)microphoneWithDelegate:(id)microphoneDelegate;
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback. This will not start fetching the audio until startFetchingAudio has been called. Use microphoneWithDelegate:startsImmediately: to instantiate this class and immediately start fetching audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param audioStreamBasicDescription A custom AudioStreamBasicFormat for the microphone input.
@return An instance of the EZMicrophone class. This should be declared as a strong property!
*/
+(EZMicrophone*)microphoneWithDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback and allows the caller to specify whether they'd immediately like to start fetching the audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param startsImmediately A boolean indicating whether to start fetching the data immediately. IF YES, the delegate's audioReceived callback will immediately start getting called.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
+(EZMicrophone*)microphoneWithDelegate:(id)microphoneDelegate
startsImmediately:(BOOL)startsImmediately;
/**
Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback and allows the caller to specify whether they'd immediately like to start fetching the audio data.
@param microphoneDelegate A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
@param audioStreamBasicDescription A custom AudioStreamBasicFormat for the microphone input.
@param startsImmediately A boolean indicating whether to start fetching the data immediately. IF YES, the delegate's audioReceived callback will immediately start getting called.
@return An instance of the EZMicrophone class. This should be strongly retained.
*/
+(EZMicrophone*)microphoneWithDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription
startsImmediately:(BOOL)startsImmediately;
#pragma mark - Singleton
///-----------------------------------------------------------
/// @name Shared Instance
///-----------------------------------------------------------
/**
A shared instance of the microphone component. Most applications will only need to use one instance of the microphone component across multiple views. Make sure to call the `startFetchingAudio` method to receive the audio data in the microphone delegate.
@return A shared instance of the `EZAudioMicrophone` component.
*/
+(EZMicrophone*)sharedMicrophone;
#pragma mark - Events
///-----------------------------------------------------------
/// @name Starting/Stopping The Microphone
///-----------------------------------------------------------
/**
Starts fetching audio from the default microphone. Will notify delegate with audioReceived callback.
*/
-(void)startFetchingAudio;
/**
Stops fetching audio. Will stop notifying the delegate's audioReceived callback.
*/
-(void)stopFetchingAudio;
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting The Microphone's Audio Format
///-----------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure containing the format of the microphone's audio.
@return An AudioStreamBasicDescription structure describing the format of the microphone's audio.
*/
-(AudioStreamBasicDescription)audioStreamBasicDescription;
#pragma mark - Setters
///-----------------------------------------------------------
/// @name Customizing The Microphone Input Format
///-----------------------------------------------------------
/**
Sets the AudioStreamBasicDescription on the microphone input.
@warning Do not set this while fetching audio (startFetchingAudio)
@param asbd The new AudioStreamBasicDescription to use in place of the current audio format description.
*/
-(void)setAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZMicrophone.m
================================================
//
// EZMicrophone.m
// EZAudio
//
// Created by Syed Haris Ali on 9/2/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZMicrophone.h"
#ifndef MAC_OS_X_VERSION_10_7
// CoreServices defines eofErr, replaced in 10.7 by kAudioFileEndOfFileError
#include
#endif
#import "EZAudio.h"
/// Buses
static const AudioUnitScope kEZAudioMicrophoneInputBus = 1;
static const AudioUnitScope kEZAudioMicrophoneOutputBus = 0;
/// Flags
#if TARGET_OS_IPHONE
static const UInt32 kEZAudioMicrophoneDisableFlag = 1;
#elif TARGET_OS_MAC
static const UInt32 kEZAudioMicrophoneDisableFlag = 0;
#endif
static const UInt32 kEZAudioMicrophoneEnableFlag = 1;
@interface EZMicrophone (){
/// Internal
BOOL _customASBD;
BOOL _isConfigured;
BOOL _isFetching;
/// Stream Description
AEFloatConverter *converter;
AudioStreamBasicDescription streamFormat;
/// Audio Graph and Input/Output Units
AudioUnit microphoneInput;
/// Audio Buffers
float **floatBuffers;
AudioBufferList *microphoneInputBuffer;
/// Device Parameters
Float64 _deviceSampleRate;
Float32 _deviceBufferDuration;
UInt32 _deviceBufferFrameSize;
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
Float64 inputScopeSampleRate;
#endif
}
@end
@implementation EZMicrophone
@synthesize microphoneDelegate = _microphoneDelegate;
@synthesize microphoneOn = _microphoneOn;
#pragma mark - Callbacks
static OSStatus inputCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData ) {
EZMicrophone *microphone = (__bridge EZMicrophone*)inRefCon;
OSStatus result = noErr;
// Render audio into buffer
result = AudioUnitRender(microphone->microphoneInput,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
microphone->microphoneInputBuffer);
if( !result ){
// ----- Notify delegate (OF-style) -----
// Audio Received (float array)
if( microphone.microphoneDelegate ){
// THIS IS NOT OCCURING ON THE MAIN THREAD
if( [microphone.microphoneDelegate respondsToSelector:@selector(microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:)] ){
AEFloatConverterToFloat(microphone->converter,
microphone->microphoneInputBuffer,
microphone->floatBuffers,
inNumberFrames);
[microphone.microphoneDelegate microphone:microphone
hasAudioReceived:microphone->floatBuffers
withBufferSize:inNumberFrames
withNumberOfChannels:microphone->streamFormat.mChannelsPerFrame];
}
}
// Audio Received (buffer list)
if( microphone.microphoneDelegate ){
if( [microphone.microphoneDelegate respondsToSelector:@selector(microphone:hasBufferList:withBufferSize:withNumberOfChannels:)] ){
[microphone.microphoneDelegate microphone:microphone
hasBufferList:microphone->microphoneInputBuffer
withBufferSize:inNumberFrames
withNumberOfChannels:microphone->streamFormat.mChannelsPerFrame];
}
}
}
return result;
}
#pragma mark - Initialization
-(id)init {
self = [super init];
if(self){
// Clear the float buffer
floatBuffers = NULL;
// We're not fetching anything yet
_isConfigured = NO;
_isFetching = NO;
if( !_isConfigured ){
// Create the input audio graph
[self _createInputUnit];
// We're configured meow
_isConfigured = YES;
}
}
return self;
}
-(EZMicrophone *)initWithMicrophoneDelegate:(id)microphoneDelegate {
self = [super init];
if(self){
self.microphoneDelegate = microphoneDelegate;
// Clear the float buffer
floatBuffers = NULL;
// We're not fetching anything yet
_isConfigured = NO;
_isFetching = NO;
if( !_isConfigured ){
// Create the input audio graph
[self _createInputUnit];
// We're configured meow
_isConfigured = YES;
}
}
return self;
}
-(EZMicrophone *)initWithMicrophoneDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription {
self = [self initWithMicrophoneDelegate:microphoneDelegate];
if(self){
_customASBD = YES;
streamFormat = audioStreamBasicDescription;
}
return self;
}
-(EZMicrophone *)initWithMicrophoneDelegate:(id)microphoneDelegate
startsImmediately:(BOOL)startsImmediately {
self = [self initWithMicrophoneDelegate:microphoneDelegate];
if(self){
startsImmediately ? [self startFetchingAudio] : -1;
}
return self;
}
-(EZMicrophone *)initWithMicrophoneDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription
startsImmediately:(BOOL)startsImmediately {
self = [self initWithMicrophoneDelegate:microphoneDelegate withAudioStreamBasicDescription:audioStreamBasicDescription];
if(self){
startsImmediately ? [self startFetchingAudio] : -1;
}
return self;
}
#pragma mark - Class Initializers
+(EZMicrophone *)microphoneWithDelegate:(id)microphoneDelegate {
return [[EZMicrophone alloc] initWithMicrophoneDelegate:microphoneDelegate];
}
+(EZMicrophone *)microphoneWithDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription {
return [[EZMicrophone alloc] initWithMicrophoneDelegate:microphoneDelegate
withAudioStreamBasicDescription:audioStreamBasicDescription];
}
+(EZMicrophone *)microphoneWithDelegate:(id)microphoneDelegate
startsImmediately:(BOOL)startsImmediately {
return [[EZMicrophone alloc] initWithMicrophoneDelegate:microphoneDelegate
startsImmediately:startsImmediately];
}
+(EZMicrophone *)microphoneWithDelegate:(id)microphoneDelegate
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription
startsImmediately:(BOOL)startsImmediately {
return [[EZMicrophone alloc] initWithMicrophoneDelegate:microphoneDelegate
withAudioStreamBasicDescription:audioStreamBasicDescription
startsImmediately:startsImmediately];
}
#pragma mark - Singleton
+(EZMicrophone*)sharedMicrophone {
static EZMicrophone *_sharedMicrophone = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedMicrophone = [[EZMicrophone alloc] init];
});
return _sharedMicrophone;
}
#pragma mark - Events
-(void)startFetchingAudio {
if( !_isFetching ){
// Start fetching input
[EZAudio checkResult:AudioOutputUnitStart(self->microphoneInput)
operation:"Microphone failed to start fetching audio"];
_isFetching = YES;
self.microphoneOn = YES;
}
}
-(void)stopFetchingAudio {
// Stop fetching input data
if( _isConfigured ){
if( _isFetching ){
[EZAudio checkResult:AudioOutputUnitStop(self->microphoneInput)
operation:"Microphone failed to stop fetching audio"];
_isFetching = NO;
self.microphoneOn = NO;
}
}
}
#pragma mark - Getters
-(AudioStreamBasicDescription)audioStreamBasicDescription {
return streamFormat;
}
#pragma mark - Setter
-(void)setMicrophoneOn:(BOOL)microphoneOn {
_microphoneOn = microphoneOn;
if( microphoneOn ){
[self startFetchingAudio];
}
else {
[self stopFetchingAudio];
}
}
-(void)setAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd {
if( self.microphoneOn ){
NSAssert(self.microphoneOn,@"Cannot set the AudioStreamBasicDescription while microphone is fetching audio");
}
else {
_customASBD = YES;
streamFormat = asbd;
[self _configureStreamFormatWithSampleRate:_deviceSampleRate];
}
}
#pragma mark - Configure The Input Unit
-(void)_createInputUnit {
// Get component description for input
AudioComponentDescription inputComponentDescription = [self _getInputAudioComponentDescription];
// Get the input component
AudioComponent inputComponent = [self _getInputComponentWithAudioComponentDescription:inputComponentDescription];
// Create a new instance of the component and store it for internal use
[self _createNewInstanceForInputComponent:inputComponent];
// Enable Input Scope
[self _enableInputScope];
// Disable Output Scope
[self _disableOutputScope];
// Get the default device if we need to (OSX only, iOS uses RemoteIO)
#if TARGET_OS_IPHONE
// Do nothing (using RemoteIO)
#elif TARGET_OS_MAC
[self _configureDefaultDevice];
#endif
// Configure device and pull hardware specific sampling rate (default = 44.1 kHz)
_deviceSampleRate = [self _configureDeviceSampleRateWithDefault:44100.0];
// Configure device and pull hardware specific buffer duration (default = 0.0232)
_deviceBufferDuration = [self _configureDeviceBufferDurationWithDefault:0.0232];
// Configure the stream format with the hardware sample rate
[self _configureStreamFormatWithSampleRate:_deviceSampleRate];
// Notify delegate the audio stream basic description was successfully created
[self _notifyDelegateOfStreamFormat];
// Get buffer frame size
_deviceBufferFrameSize = [self _getBufferFrameSize];
// Create the audio buffer list and pre-malloc the buffers in the list
[self _configureAudioBufferListWithFrameSize:_deviceBufferFrameSize];
// Set the float converter's stream format
[self _configureFloatConverterWithFrameSize:_deviceBufferFrameSize];
// Setup input callback
[self _configureInputCallback];
// Disable buffer allocation (optional - do this if we want to pass in our own)
[self _disableCallbackBufferAllocation];
// Initialize the audio unit
[EZAudio checkResult:AudioUnitInitialize( microphoneInput )
operation:"Couldn't initialize the input unit"];
}
#pragma mark - Audio Component Initialization
-(AudioComponentDescription)_getInputAudioComponentDescription {
// Create an input component description for mic input
AudioComponentDescription inputComponentDescription;
inputComponentDescription.componentType = kAudioUnitType_Output;
inputComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
inputComponentDescription.componentFlags = 0;
inputComponentDescription.componentFlagsMask = 0;
#if TARGET_OS_IPHONE
inputComponentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
#elif TARGET_OS_MAC
inputComponentDescription.componentSubType = kAudioUnitSubType_HALOutput;
#endif
// Return the successfully created input component description
return inputComponentDescription;
}
-(AudioComponent)_getInputComponentWithAudioComponentDescription:(AudioComponentDescription)audioComponentDescription {
// Try and find the component
AudioComponent inputComponent = AudioComponentFindNext( NULL , &audioComponentDescription );
NSAssert(inputComponent,@"Couldn't get input component unit!");
return inputComponent;
}
-(void)_createNewInstanceForInputComponent:(AudioComponent)audioComponent {
[EZAudio checkResult:AudioComponentInstanceNew(audioComponent,
µphoneInput )
operation:"Couldn't open component for microphone input unit."];
}
#pragma mark - Input/Output Scope Initialization
-(void)_disableOutputScope {
[EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kEZAudioMicrophoneOutputBus,
&kEZAudioMicrophoneDisableFlag,
sizeof(kEZAudioMicrophoneDisableFlag))
operation:"Couldn't disable output on I/O unit."];
}
-(void)_enableInputScope {
[EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kEZAudioMicrophoneInputBus,
&kEZAudioMicrophoneEnableFlag,
sizeof(kEZAudioMicrophoneEnableFlag))
operation:"Couldn't enable input on I/O unit."];
}
#pragma mark - Pull Default Device (OSX)
#if TARGET_OS_IPHONE
// Not needed, using RemoteIO
#elif TARGET_OS_MAC
-(void)_configureDefaultDevice {
// Get the default audio input device (pulls an abstract type from system preferences)
AudioDeviceID defaultDevice = kAudioObjectUnknown;
UInt32 propSize = sizeof(defaultDevice);
AudioObjectPropertyAddress defaultDeviceProperty;
defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice;
defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster;
[EZAudio checkResult:AudioObjectGetPropertyData(kAudioObjectSystemObject,
&defaultDeviceProperty,
0,
NULL,
&propSize,
&defaultDevice)
operation:"Couldn't get default input device"];
// Set the default device on the microphone input unit
propSize = sizeof(defaultDevice);
[EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
kEZAudioMicrophoneOutputBus,
&defaultDevice,
propSize)
operation:"Couldn't set default device on I/O unit"];
// Get the stream format description from the newly created input unit and assign it to the output of the input unit
AudioStreamBasicDescription inputScopeFormat;
propSize = sizeof(AudioStreamBasicDescription);
[EZAudio checkResult:AudioUnitGetProperty(microphoneInput,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kEZAudioMicrophoneInputBus,
&inputScopeFormat,
&propSize)
operation:"Couldn't get ASBD from input unit (1)"];
// Assign the same stream format description from the output of the input unit and pull the sample rate
AudioStreamBasicDescription outputScopeFormat;
propSize = sizeof(AudioStreamBasicDescription);
[EZAudio checkResult:AudioUnitGetProperty(microphoneInput,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kEZAudioMicrophoneInputBus,
&outputScopeFormat,
&propSize)
operation:"Couldn't get ASBD from input unit (2)"];
// Store the input scope's sample rate
inputScopeSampleRate = inputScopeFormat.mSampleRate;
}
#endif
#pragma mark - Pull Sample Rate
-(Float64)_configureDeviceSampleRateWithDefault:(float)defaultSampleRate {
Float64 hardwareSampleRate = defaultSampleRate;
#if TARGET_OS_IPHONE
// Use approximations for simulator and pull from real device if connected
#if !(TARGET_IPHONE_SIMULATOR)
// Sample Rate
hardwareSampleRate = [[AVAudioSession sharedInstance] sampleRate];
#endif
#elif TARGET_OS_MAC
hardwareSampleRate = inputScopeSampleRate;
#endif
return hardwareSampleRate;
}
#pragma mark - Pull Buffer Duration
-(Float32)_configureDeviceBufferDurationWithDefault:(float)defaultBufferDuration {
Float32 bufferDuration = defaultBufferDuration; // Type 1/43 by default
#if TARGET_OS_IPHONE
// Use approximations for simulator and pull from real device if connected
#if !(TARGET_IPHONE_SIMULATOR)
NSError *err;
[[AVAudioSession sharedInstance] setPreferredIOBufferDuration:bufferDuration error:&err];
if (err) {
NSLog(@"Error setting preferredIOBufferDuration for audio session: %@", err.localizedDescription);
}
// Buffer Size
bufferDuration = [[AVAudioSession sharedInstance] IOBufferDuration];
#endif
#elif TARGET_OS_MAC
#endif
return bufferDuration;
}
#pragma mark - Pull Buffer Frame Size
-(UInt32)_getBufferFrameSize {
UInt32 bufferFrameSize;
UInt32 propSize = sizeof(bufferFrameSize);
[EZAudio checkResult:AudioUnitGetProperty(microphoneInput,
#if TARGET_OS_IPHONE
kAudioUnitProperty_MaximumFramesPerSlice,
#elif TARGET_OS_MAC
kAudioDevicePropertyBufferFrameSize,
#endif
kAudioUnitScope_Global,
kEZAudioMicrophoneOutputBus,
&bufferFrameSize,
&propSize)
operation:"Failed to get buffer frame size"];
return bufferFrameSize;
}
#pragma mark - Stream Format Initialization
-(void)_configureStreamFormatWithSampleRate:(Float64)sampleRate {
// Set the stream format
if( !_customASBD ){
streamFormat = [EZAudio stereoCanonicalNonInterleavedFormatWithSampleRate:sampleRate];
}
else {
streamFormat.mSampleRate = sampleRate;
}
UInt32 propSize = sizeof(streamFormat);
// Set the stream format for output on the microphone's input scope
[EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kEZAudioMicrophoneOutputBus,
&streamFormat,
propSize)
operation:"Could not set microphone's stream format bus 0"];
// Set the stream format for the input on the microphone's output scope
[EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kEZAudioMicrophoneInputBus,
&streamFormat,
propSize)
operation:"Could not set microphone's stream format bus 1"];
}
-(void)_notifyDelegateOfStreamFormat {
if( _microphoneDelegate ){
if( [_microphoneDelegate respondsToSelector:@selector(microphone:hasAudioStreamBasicDescription:) ] ){
[_microphoneDelegate microphone:self
hasAudioStreamBasicDescription:streamFormat];
}
}
}
#pragma mark - AudioBufferList Initialization
-(void)_configureAudioBufferListWithFrameSize:(UInt32)bufferFrameSize {
UInt32 bufferSizeBytes = bufferFrameSize * streamFormat.mBytesPerFrame;
UInt32 propSize = offsetof( AudioBufferList, mBuffers[0] ) + ( sizeof( AudioBuffer ) *streamFormat.mChannelsPerFrame );
microphoneInputBuffer = (AudioBufferList*)malloc(propSize);
microphoneInputBuffer->mNumberBuffers = streamFormat.mChannelsPerFrame;
for( UInt32 i = 0; i < microphoneInputBuffer->mNumberBuffers; i++ ){
microphoneInputBuffer->mBuffers[i].mNumberChannels = streamFormat.mChannelsPerFrame;
microphoneInputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes;
microphoneInputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes);
}
}
#pragma mark - Float Converter Initialization
-(void)_configureFloatConverterWithFrameSize:(UInt32)bufferFrameSize {
UInt32 bufferSizeBytes = bufferFrameSize * streamFormat.mBytesPerFrame;
converter = [[AEFloatConverter alloc] initWithSourceFormat:streamFormat];
floatBuffers = (float**)malloc(sizeof(float*)*streamFormat.mChannelsPerFrame);
assert(floatBuffers);
for ( int i=0; i
#import
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
#import
#endif
#import "TPCircularBuffer.h"
@class EZOutput;
/**
The EZOutputDataSource (required for the EZOutput) specifies a receiver to provide audio data when the EZOutput is started. Only ONE datasource method is expected to be implemented and priority is given as such:
1.) `output:callbackWithActionFlags:inTimeStamp:inBusNumber:inNumberFrames:ioData:`
2.) `outputShouldUseCircularBuffer:`
3.) `output:needsBufferListWithFrames:withBufferSize:`
*/
@protocol EZOutputDataSource
@optional
///-----------------------------------------------------------
/// @name Pulling The Audio Data
///-----------------------------------------------------------
/**
Provides complete override of the output callback function. The delegate is expected to
@param output The instance of the EZOutput that asked for the data
@param ioActionFlags AudioUnitRenderActionFlags provided by the output callback
@param inTimeStamp AudioTimeStamp reference provided by the output callback
@param inBusNumber UInt32 representing the bus number provided by the output callback
@param inNumberFrames UInt32 representing the number of frames provided by the output callback
@param ioData AudioBufferList pointer representing the audio data that will be used for output provided by the output callback (fill this!)
*/
-(void)output:(EZOutput*)output
callbackWithActionFlags:(AudioUnitRenderActionFlags*)ioActionFlags
inTimeStamp:(const AudioTimeStamp*)inTimeStamp
inBusNumber:(UInt32)inBusNumber
inNumberFrames:(UInt32)inNumberFrames
ioData:(AudioBufferList*)ioData;
/**
Provides output using a circular
@param output The instance of the EZOutput that asked for the data
@return The EZOutputDataSource's TPCircularBuffer structure holding the audio data in a circular buffer
*/
-(TPCircularBuffer*)outputShouldUseCircularBuffer:(EZOutput *)output;
/**
Provides a way to provide output with data anytime the EZOutput needs audio data to play. This function provides an already allocated AudioBufferList to use for providing audio data into the output buffer.
@param output The instance of the EZOutput that asked for the data.
@param audioBufferList The AudioBufferList structure pointer that needs to be filled with audio data
@param frames The amount of frames as a UInt32 that output will need to properly fill its output buffer.
@return A pointer to the AudioBufferList structure holding the audio data. If nil or NULL, will output silence.
*/
-(void) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList*)audioBufferList
withNumberOfFrames:(UInt32)frames;
@end
/**
The EZOutput component provides a generic output to glue all the other EZAudio components together and push whatever sound you've created to the default output device (think opposite of the microphone). The EZOutputDataSource provides the required AudioBufferList needed to populate the output buffer.
*/
@interface EZOutput : NSObject
#pragma mark - Properties
/**
The EZOutputDataSource that provides the required AudioBufferList to the output callback function
*/
@property (nonatomic,assign) idoutputDataSource;
#pragma mark - Initializers
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
/**
Creates a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@return A newly created instance of the EZOutput class.
*/
-(id)initWithDataSource:(id)dataSource;
/**
Creates a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@param audioStreamBasicDescription The AudioStreamBasicDescription of the EZOutput.
@warning AudioStreamBasicDescriptions that are invalid will cause the EZOutput to fail to initialize
@return A newly created instance of the EZOutput class.
*/
-(id) initWithDataSource:(id)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
#pragma mark - Class Initializers
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Class method to create a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@return A newly created instance of the EZOutput class.
*/
+(EZOutput*)outputWithDataSource:(id)dataSource;
/**
Class method to create a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@param audioStreamBasicDescription The AudioStreamBasicDescription of the EZOutput.
@warning AudioStreamBasicDescriptions that are invalid will cause the EZOutput to fail to initialize
@return A newly created instance of the EZOutput class.
*/
+(EZOutput*)outputWithDataSource:(id)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
#pragma mark - Singleton
///-----------------------------------------------------------
/// @name Shared Instance
///-----------------------------------------------------------
/**
Creates a shared instance of the EZOutput (one app will usually only need one output and share the role of the EZOutputDataSource).
@return The shared instance of the EZOutput class.
*/
+(EZOutput*)sharedOutput;
#pragma mark - Events
///-----------------------------------------------------------
/// @name Starting/Stopping The Output
///-----------------------------------------------------------
/**
Starts pulling audio data from the EZOutputDataSource to the default device output.
*/
-(void)startPlayback;
/**
Stops pulling audio data from the EZOutputDataSource to the default device output.
*/
-(void)stopPlayback;
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting The Output Audio Format
///-----------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure containing the format of the microphone's audio.
@return An AudioStreamBasicDescription structure describing the format of the microphone's audio.
*/
-(AudioStreamBasicDescription)audioStreamBasicDescription;
///-----------------------------------------------------------
/// @name Getting The State Of The Output
///-----------------------------------------------------------
/**
Provides a flag indicating whether the EZOutput is pulling audio data from the EZOutputDataSource for playback.
@return YES if the EZOutput is pulling audio data to the output device, NO if it is stopped
*/
-(BOOL)isPlaying;
#pragma mark - Setters
///-----------------------------------------------------------
/// @name Customizing The Output Format
///-----------------------------------------------------------
/**
Sets the AudioStreamBasicDescription on the output.
@warning Do not set this during playback.
@param asbd The new AudioStreamBasicDescription to use in place of the current audio format description.
*/
-(void)setAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZOutput.m
================================================
//
// EZOutput.m
// EZAudio
//
// Created by Syed Haris Ali on 12/2/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZOutput.h"
#import "EZAudio.h"
@interface EZOutput (){
BOOL _customASBD;
BOOL _isPlaying;
AudioStreamBasicDescription _outputASBD;
AudioUnit _outputUnit;
}
@end
@implementation EZOutput
@synthesize outputDataSource = _outputDataSource;
static OSStatus OutputRenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData){
// NSLog(@"output something");
EZOutput *output = (__bridge EZOutput*)inRefCon;
// Manual override
if( [output.outputDataSource respondsToSelector:@selector(output:callbackWithActionFlags:inTimeStamp:inBusNumber:inNumberFrames:ioData:)] ){
[output.outputDataSource output:output
callbackWithActionFlags:ioActionFlags
inTimeStamp:inTimeStamp
inBusNumber:inBusNumber
inNumberFrames:inNumberFrames
ioData:ioData];
}
else if( [output.outputDataSource respondsToSelector:@selector(outputShouldUseCircularBuffer:)] ){
TPCircularBuffer *circularBuffer = [output.outputDataSource outputShouldUseCircularBuffer:output];
if( !circularBuffer ){
float *left = (float*)ioData->mBuffers[0].mData;
float *right = (float*)ioData->mBuffers[1].mData;
for(int i = 0; i < inNumberFrames; i++ ){
left[ i ] = 0.0f;
right[ i ] = 0.0f;
}
return noErr;
};
/**
Thank you Michael Tyson (A Tasty Pixel) for writing the TPCircularBuffer, you are amazing!
*/
// Get the desired amount of bytes to copy
int32_t bytesToCopy = ioData->mBuffers[0].mDataByteSize;
float *left = (float*)ioData->mBuffers[0].mData;
float *right = (float*)ioData->mBuffers[1].mData;
// Get the available bytes in the circular buffer
int32_t availableBytes;
float *buffer = TPCircularBufferTail(circularBuffer,&availableBytes);
// Ideally we'd have all the bytes to be copied, but compare it against the available bytes (get min)
int32_t amount = MIN(bytesToCopy,availableBytes);
memcpy( left, buffer, amount );
memcpy( right, buffer, amount );
// Consume those bytes ( this will internally push the head of the circular buffer )
TPCircularBufferConsume(circularBuffer,amount);
}
// Provided an AudioBufferList (defaults to silence)
else if( [output.outputDataSource respondsToSelector:@selector(output:shouldFillAudioBufferList:withNumberOfFrames:)] ) {
[output.outputDataSource output:output
shouldFillAudioBufferList:ioData
withNumberOfFrames:inNumberFrames];
}
return noErr;
}
#pragma mark - Initialization
-(id)init {
self = [super init];
if(self){
[self _configureOutput];
}
return self;
}
-(id)initWithDataSource:(id)dataSource {
self = [super init];
if(self){
self.outputDataSource = dataSource;
[self _configureOutput];
}
return self;
}
-(id) initWithDataSource:(id)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription {
self = [super init];
if(self){
_customASBD = YES;
_outputASBD = audioStreamBasicDescription;
self.outputDataSource = dataSource;
[self _configureOutput];
}
return self;
}
#pragma mark - Class Initializers
+(EZOutput*)outputWithDataSource:(id)dataSource {
return [[EZOutput alloc] initWithDataSource:dataSource];
}
+(EZOutput *)outputWithDataSource:(id)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription {
return [[EZOutput alloc] initWithDataSource:dataSource withAudioStreamBasicDescription:audioStreamBasicDescription];
}
#pragma mark - Singleton
+(EZOutput*)sharedOutput {
static EZOutput *_sharedOutput = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedOutput = [[EZOutput alloc] init];
});
return _sharedOutput;
}
#pragma mark - Audio Component Initialization
-(AudioComponentDescription)_getOutputAudioComponentDescription {
// Create an output component description for default output device
AudioComponentDescription outputComponentDescription;
outputComponentDescription.componentFlags = 0;
outputComponentDescription.componentFlagsMask = 0;
outputComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
#if TARGET_OS_IPHONE
outputComponentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
#elif TARGET_OS_MAC
outputComponentDescription.componentSubType = kAudioUnitSubType_DefaultOutput;
#endif
outputComponentDescription.componentType = kAudioUnitType_Output;
return outputComponentDescription;
}
-(AudioComponent)_getOutputComponentWithAudioComponentDescription:(AudioComponentDescription)outputComponentDescription {
// Try and find the component
AudioComponent outputComponent = AudioComponentFindNext( NULL , &outputComponentDescription );
NSAssert(outputComponent,@"Couldn't get input component unit!");
return outputComponent;
}
-(void)_createNewInstanceForOutputComponent:(AudioComponent)outputComponent {
//
[EZAudio checkResult:AudioComponentInstanceNew( outputComponent, &_outputUnit )
operation:"Failed to open component for output unit"];
}
#pragma mark - Configure The Output Unit
//-(void)_configureOutput {
//
// // Get component description for output
// AudioComponentDescription outputComponentDescription = [self _getOutputAudioComponentDescription];
//
// // Get the output component
// AudioComponent outputComponent = [self _getOutputComponentWithAudioComponentDescription:outputComponentDescription];
//
// // Create a new instance of the component and store it for internal use
// [self _createNewInstanceForOutputComponent:outputComponent];
//
//}
#if TARGET_OS_IPHONE
-(void)_configureOutput {
//
AudioComponentDescription outputcd;
outputcd.componentFlags = 0;
outputcd.componentFlagsMask = 0;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
outputcd.componentType = kAudioUnitType_Output;
//
AudioComponent comp = AudioComponentFindNext(NULL,&outputcd);
[EZAudio checkResult:AudioComponentInstanceNew(comp,&_outputUnit)
operation:"Failed to get output unit"];
// Setup the output unit for playback
UInt32 oneFlag = 1;
AudioUnitElement bus0 = 0;
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
bus0,
&oneFlag,
sizeof(oneFlag))
operation:"Failed to enable output unit"];
// Get the hardware sample rate
Float64 hardwareSampleRate = 44100;
#if !(TARGET_IPHONE_SIMULATOR)
hardwareSampleRate = [[AVAudioSession sharedInstance] sampleRate];
#endif
// Setup an ASBD in canonical format by default
if( !_customASBD ){
_outputASBD = [EZAudio stereoCanonicalNonInterleavedFormatWithSampleRate:hardwareSampleRate];
}
// Set the format for output
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
bus0,
&_outputASBD,
sizeof(_outputASBD))
operation:"Couldn't set the ASBD for input scope/bos 0"];
//
AURenderCallbackStruct input;
input.inputProc = OutputRenderCallback;
input.inputProcRefCon = (__bridge void *)self;
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
bus0,
&input,
sizeof(input))
operation:"Failed to set the render callback on the output unit"];
//
[EZAudio checkResult:AudioUnitInitialize(_outputUnit)
operation:"Couldn't initialize output unit"];
}
#elif TARGET_OS_MAC
-(void)_configureOutput {
//
AudioComponentDescription outputcd;
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
//
AudioComponent comp = AudioComponentFindNext(NULL,&outputcd);
if( comp == NULL ){
NSLog(@"Failed to get output unit");
exit(-1);
}
[EZAudio checkResult:AudioComponentInstanceNew(comp,&_outputUnit)
operation:"Failed to open component for output unit"];
// Setup an ASBD in canonical format by default
if( !_customASBD ){
_outputASBD = [EZAudio stereoCanonicalNonInterleavedFormatWithSampleRate:44100];
}
// Set the format for output
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&_outputASBD,
sizeof(_outputASBD))
operation:"Couldn't set the ASBD for input scope/bos 0"];
//
AURenderCallbackStruct input;
input.inputProc = OutputRenderCallback;
input.inputProcRefCon = (__bridge void *)(self);
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input))
operation:"Failed to set the render callback on the output unit"];
//
[EZAudio checkResult:AudioUnitInitialize(_outputUnit)
operation:"Couldn't initialize output unit"];
}
#endif
#pragma mark - Events
-(void)startPlayback {
if( !_isPlaying ){
[EZAudio checkResult:AudioOutputUnitStart(_outputUnit)
operation:"Failed to start output unit"];
_isPlaying = YES;
}
}
-(void)stopPlayback {
if( _isPlaying ){
[EZAudio checkResult:AudioOutputUnitStop(_outputUnit)
operation:"Failed to stop output unit"];
_isPlaying = NO;
}
}
#pragma mark - Getters
-(AudioStreamBasicDescription)audioStreamBasicDescription {
return _outputASBD;
}
-(BOOL)isPlaying {
return _isPlaying;
}
#pragma mark - Setters
-(void)setAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd {
BOOL wasPlaying = NO;
if( self.isPlaying ){
[self stopPlayback];
wasPlaying = YES;
}
_customASBD = YES;
_outputASBD = asbd;
// Set the format for output
[EZAudio checkResult:AudioUnitSetProperty(_outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&_outputASBD,
sizeof(_outputASBD))
operation:"Couldn't set the ASBD for input scope/bos 0"];
if( wasPlaying )
{
[self startPlayback];
}
}
-(void)dealloc {
[EZAudio checkResult:AudioOutputUnitStop(_outputUnit)
operation:"Failed to uninitialize output unit"];
[EZAudio checkResult:AudioUnitUninitialize(_outputUnit)
operation:"Failed to uninitialize output unit"];
[EZAudio checkResult:AudioComponentInstanceDispose(_outputUnit)
operation:"Failed to uninitialize output unit"];
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZPlot.h
================================================
//
// EZPlot.h
// EZAudio
//
// Created by Syed Haris Ali on 11/24/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma mark - Enumerations
///-----------------------------------------------------------
/// @name Plot Types
///-----------------------------------------------------------
/**
The types of plots that can be displayed in the view using the data.
*/
typedef NS_ENUM(NSInteger,EZPlotType){
/**
Plot that displays only the samples of the current buffer
*/
EZPlotTypeBuffer,
/**
Plot that displays a rolling history of values using the RMS calculated for each incoming buffer
*/
EZPlotTypeRolling
};
/**
EZPlot is a cross-platform (iOS and OSX) class used to subclass the default view type (either UIView or NSView, respectively).
## Subclassing Notes
This class isn't meant to be directly used in practice, but instead establishes the default properties and behaviors subclasses should obey to provide consistent behavior accross multiple types of graphs (i.e. set background color, plot type, should fill in, etc.). Subclasses should make use of the inherited properties from this class to allow all child plots to benefit from the same
*/
#if TARGET_OS_IPHONE
#import
@interface EZPlot : UIView
#elif TARGET_OS_MAC
#import
@interface EZPlot : NSView
#endif
#pragma mark - Properties
///-----------------------------------------------------------
/// @name Customizing The Plot's Appearance
///-----------------------------------------------------------
/**
The default background color of the plot. For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is black.
*/
@property (nonatomic,strong) id backgroundColor;
/**
The default color of the plot's data (i.e. waveform, y-axis values). For iOS the color is specified as a UIColor while for OSX the color is an NSColor. The default value on both platforms is red.
*/
@property (nonatomic,strong) id color;
/**
The plot's gain value, which controls the scale of the y-axis values. The default value of the gain is 1.0f and should always be greater than 0.0f.
*/
@property (nonatomic,assign,setter=setGain:) float gain;
/**
The type of plot as specified by the `EZPlotType` enumeration (i.e. a buffer or rolling plot type).
*/
@property (nonatomic,assign,setter=setPlotType:) EZPlotType plotType;
/**
A boolean indicating whether or not to fill in the graph. A value of YES will make a filled graph (filling in the space between the x-axis and the y-value), while a value of NO will create a stroked graph (connecting the points along the y-axis).
*/
@property (nonatomic,assign,setter=setShouldFill:) BOOL shouldFill;
/**
A boolean indicating whether the graph should be rotated along the x-axis to give a mirrored reflection. This is typical for audio plots to produce the classic waveform look. A value of YES will produce a mirrored reflection of the y-values about the x-axis, while a value of NO will only plot the y-values.
*/
@property (nonatomic,assign,setter=setShouldMirror:) BOOL shouldMirror;
#pragma mark - Clearing
///-----------------------------------------------------------
/// @name Clearing The Plot
///-----------------------------------------------------------
/**
Clears all data from the audio plot (includes both EZPlotTypeBuffer and EZPlotTypeRolling)
*/
-(void)clear;
#pragma mark - Get Samples
///-----------------------------------------------------------
/// @name Updating The Plot
///-----------------------------------------------------------
/**
Updates the plot with the new buffer data and tells the view to redraw itself. Caller will provide a float array with the values they expect to see on the y-axis. The plot will internally handle mapping the x-axis and y-axis to the current view port, any interpolation for fills effects, and mirroring.
@param buffer A float array of values to map to the y-axis.
@param bufferSize The size of the float array that will be mapped to the y-axis.
@warning The bufferSize is expected to be the same, constant value once initial triggered. For plots using OpenGL a vertex buffer object will be allocated with a maximum buffersize of (2 * the initial given buffer size) to account for any interpolation necessary for filling in the graph. Updates use the glBufferSubData(...) function, which will crash if the buffersize exceeds the initial maximum allocated size.
*/
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZPlot.m
================================================
//
// EZPlot.m
// EZAudio
//
// Created by Syed Haris Ali on 11/24/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZPlot.h"
@interface EZPlot ()
@end
@implementation EZPlot
#pragma mark - Clearing
-(void)clear
{
// Override in subclass
}
#pragma mark - Get Samples
-(void)updateBuffer:(float *)buffer
withBufferSize:(UInt32)bufferSize
{
// Override in subclass
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZRecorder.h
================================================
//
// EZRecorder.h
// EZAudio
//
// Created by Syed Haris Ali on 12/1/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#import
/**
To ensure valid recording formats are used when recording to a file the EZRecorderFileType describes the most common file types that a file can be encoded in. Each of these types can be used to output recordings as such:
EZRecorderFileTypeAIFF - .aif, .aiff, .aifc, .aac
EZRecorderFileTypeM4A - .m4a, .mp4
EZRecorderFileTypeWAV - .wav
*/
typedef NS_ENUM(NSInteger, EZRecorderFileType)
{
/**
Recording format that describes AIFF file types. These are uncompressed, LPCM files that are completely lossless, but are large in file size.
*/
EZRecorderFileTypeAIFF,
/**
Recording format that describes M4A file types. These are compressed, but yield great results especially when file size is an issue.
*/
EZRecorderFileTypeM4A,
/**
Recording format that describes WAV file types. These are uncompressed, LPCM files that are completely lossless, but are large in file size.
*/
EZRecorderFileTypeWAV
};
/**
The EZRecorder provides a flexible way to create an audio file and append raw audio data to it. The EZRecorder will convert the incoming audio on the fly to the destination format so no conversion is needed between this and any other component. Right now the only supported output format is 'caf'. Each output file should have its own EZRecorder instance (think 1 EZRecorder = 1 audio file).
*/
@interface EZRecorder : NSObject
#pragma mark - Initializers
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
/**
Creates a new instance of an EZRecorder using a destination file path URL and the source format of the incoming audio.
@param url An NSURL specifying the file path location of where the audio file should be written to.
@param sourceFormat The AudioStreamBasicDescription for the incoming audio that will be written to the file.
@param destinationFileType A constant described by the EZRecorderFileType that corresponds to the type of destination file that should be written. For instance, an AAC file written using an '.m4a' extension would correspond to EZRecorderFileTypeM4A. See EZRecorderFileType for all the constants and mapping combinations.
@return The newly created EZRecorder instance.
*/
-(EZRecorder*)initWithDestinationURL:(NSURL*)url
sourceFormat:(AudioStreamBasicDescription)sourceFormat
destinationFileType:(EZRecorderFileType)destinationFileType;
#pragma mark - Class Initializers
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Class method to create a new instance of an EZRecorder using a destination file path URL and the source format of the incoming audio.
@param url An NSURL specifying the file path location of where the audio file should be written to.
@param sourceFormat The AudioStreamBasicDescription for the incoming audio that will be written to the file.
@param destinationFileType A constant described by the EZRecorderFileType that corresponds to the type of destination file that should be written. For instance, an AAC file written using an '.m4a' extension would correspond to EZRecorderFileTypeM4A. See EZRecorderFileType for all the constants and mapping combinations.
@return The newly created EZRecorder instance.
*/
+(EZRecorder*)recorderWithDestinationURL:(NSURL*)url
sourceFormat:(AudioStreamBasicDescription)sourceFormat
destinationFileType:(EZRecorderFileType)destinationFileType;
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting The Recorder's Properties
///-----------------------------------------------------------
/**
Provides the file path that's currently being used by the recorder.
@return The NSURL representing the file path of the audio file path being used for recording.
*/
-(NSURL*)url;
#pragma mark - Events
///-----------------------------------------------------------
/// @name Appending Data To The Audio File
///-----------------------------------------------------------
/**
Appends audio data to the tail of the output file from an AudioBufferList.
@param bufferList The AudioBufferList holding the audio data to append
@param bufferSize The size of each of the buffers in the buffer list.
*/
-(void)appendDataFromBufferList:(AudioBufferList*)bufferList
withBufferSize:(UInt32)bufferSize;
///-----------------------------------------------------------
/// @name Closing The Audio File
///-----------------------------------------------------------
/**
Finishes writes to the audio file and closes it.
*/
-(void)closeAudioFile;
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/EZRecorder.m
================================================
//
// EZRecorder.m
// EZAudio
//
// Created by Syed Haris Ali on 12/1/13.
// Copyright (c) 2013 Syed Haris Ali. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "EZRecorder.h"
#import "EZAudio.h"
@interface EZRecorder (){
ExtAudioFileRef _destinationFile;
AudioFileTypeID _destinationFileTypeID;
CFURLRef _destinationFileURL;
AudioStreamBasicDescription _destinationFormat;
AudioStreamBasicDescription _sourceFormat;
}
@end
@implementation EZRecorder
#pragma mark - Initializers
-(EZRecorder*)initWithDestinationURL:(NSURL*)url
sourceFormat:(AudioStreamBasicDescription)sourceFormat
destinationFileType:(EZRecorderFileType)destinationFileType
{
self = [super init];
if( self )
{
// Set defaults
_destinationFile = NULL;
_destinationFileURL = (__bridge CFURLRef)url;
_sourceFormat = sourceFormat;
_destinationFormat = [EZRecorder recorderFormatForFileType:destinationFileType
withSourceFormat:_sourceFormat];
_destinationFileTypeID = [EZRecorder recorderFileTypeIdForFileType:destinationFileType
withSourceFormat:_sourceFormat];
// Initializer the recorder instance
[self _initializeRecorder];
}
return self;
}
#pragma mark - Class Initializers
+(EZRecorder*)recorderWithDestinationURL:(NSURL*)url
sourceFormat:(AudioStreamBasicDescription)sourceFormat
destinationFileType:(EZRecorderFileType)destinationFileType
{
return [[EZRecorder alloc] initWithDestinationURL:url
sourceFormat:sourceFormat
destinationFileType:destinationFileType];
}
#pragma mark - Private Configuration
+(AudioStreamBasicDescription)recorderFormatForFileType:(EZRecorderFileType)fileType
withSourceFormat:(AudioStreamBasicDescription)sourceFormat
{
AudioStreamBasicDescription asbd;
switch ( fileType )
{
case EZRecorderFileTypeAIFF:
asbd = [EZAudio AIFFFormatWithNumberOfChannels:sourceFormat.mChannelsPerFrame
sampleRate:sourceFormat.mSampleRate];
break;
case EZRecorderFileTypeM4A:
asbd = [EZAudio M4AFormatWithNumberOfChannels:sourceFormat.mChannelsPerFrame
sampleRate:sourceFormat.mSampleRate];
break;
case EZRecorderFileTypeWAV:
asbd = [EZAudio stereoFloatInterleavedFormatWithSampleRate:sourceFormat.mSampleRate];
break;
default:
asbd = [EZAudio stereoCanonicalNonInterleavedFormatWithSampleRate:sourceFormat.mSampleRate];
break;
}
return asbd;
}
+(AudioFileTypeID)recorderFileTypeIdForFileType:(EZRecorderFileType)fileType
withSourceFormat:(AudioStreamBasicDescription)sourceFormat
{
AudioFileTypeID audioFileTypeID;
switch ( fileType )
{
case EZRecorderFileTypeAIFF:
audioFileTypeID = kAudioFileAIFFType;
break;
case EZRecorderFileTypeM4A:
audioFileTypeID = kAudioFileM4AType;
break;
case EZRecorderFileTypeWAV:
audioFileTypeID = kAudioFileWAVEType;
break;
default:
audioFileTypeID = kAudioFileWAVEType;
break;
}
return audioFileTypeID;
}
-(void)_initializeRecorder
{
// Finish filling out the destination format description
UInt32 propSize = sizeof(_destinationFormat);
[EZAudio checkResult:AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&_destinationFormat)
operation:"Failed to fill out rest of destination format"];
// Create the audio file
[EZAudio checkResult:ExtAudioFileCreateWithURL(_destinationFileURL,
_destinationFileTypeID,
&_destinationFormat,
NULL,
kAudioFileFlags_EraseFile,
&_destinationFile)
operation:"Failed to create audio file"];
// Set the client format (which should be equal to the source format)
[EZAudio checkResult:ExtAudioFileSetProperty(_destinationFile,
kExtAudioFileProperty_ClientDataFormat,
sizeof(_sourceFormat),
&_sourceFormat)
operation:"Failed to set client format on recorded audio file"];
}
#pragma mark - Events
-(void)appendDataFromBufferList:(AudioBufferList *)bufferList
withBufferSize:(UInt32)bufferSize
{
if( _destinationFile )
{
[EZAudio checkResult:ExtAudioFileWriteAsync(_destinationFile,
bufferSize,
bufferList)
operation:"Failed to write audio data to recorded audio file"];
}
}
-(void)closeAudioFile
{
if( _destinationFile )
{
// Dispose of the audio file reference
[EZAudio checkResult:ExtAudioFileDispose(_destinationFile)
operation:"Failed to close audio file"];
// Null out the file reference
_destinationFile = NULL;
}
}
-(NSURL *)url
{
return (__bridge NSURL*)_destinationFileURL;
}
#pragma mark - Dealloc
-(void)dealloc
{
[self closeAudioFile];
}
@end
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/TPCircularBuffer.c
================================================
//
// TPCircularBuffer.c
// Circular/Ring buffer implementation
//
// https://github.com/michaeltyson/TPCircularBuffer
//
// Created by Michael Tyson on 10/12/2011.
//
// Copyright (C) 2012-2013 A Tasty Pixel
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#include "TPCircularBuffer.h"
#include
#include
#define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
if ( result != ERR_SUCCESS ) {
printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
return false;
}
return true;
}
bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
// Keep trying until we get our buffer, needed to handle race conditions
int retries = 3;
while ( true ) {
buffer->length = (int32_t)round_page(length); // We need whole page sizes
// Temporarily allocate twice the length, so we have the contiguous address space to
// support a second instance of the buffer directly after
vm_address_t bufferAddress;
kern_return_t result = vm_allocate(mach_task_self(),
&bufferAddress,
buffer->length * 2,
VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit
if ( result != ERR_SUCCESS ) {
if ( retries-- == 0 ) {
reportResult(result, "Buffer allocation");
return false;
}
// Try again if we fail
continue;
}
// Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
result = vm_deallocate(mach_task_self(),
bufferAddress + buffer->length,
buffer->length);
if ( result != ERR_SUCCESS ) {
if ( retries-- == 0 ) {
reportResult(result, "Buffer deallocation");
return false;
}
// If this fails somehow, deallocate the whole region and try again
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
continue;
}
// Re-map the buffer to the address space immediately after the buffer
vm_address_t virtualAddress = bufferAddress + buffer->length;
vm_prot_t cur_prot, max_prot;
result = vm_remap(mach_task_self(),
&virtualAddress, // mirror target
buffer->length, // size of mirror
0, // auto alignment
0, // force remapping to virtualAddress
mach_task_self(), // same task
bufferAddress, // mirror source
0, // MAP READ-WRITE, NOT COPY
&cur_prot, // unused protection struct
&max_prot, // unused protection struct
VM_INHERIT_DEFAULT);
if ( result != ERR_SUCCESS ) {
if ( retries-- == 0 ) {
reportResult(result, "Remap buffer memory");
return false;
}
// If this remap failed, we hit a race condition, so deallocate and try again
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
continue;
}
if ( virtualAddress != bufferAddress+buffer->length ) {
// If the memory is not contiguous, clean up both allocated buffers and try again
if ( retries-- == 0 ) {
printf("Couldn't map buffer memory to end of buffer\n");
return false;
}
vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
continue;
}
buffer->buffer = (void*)bufferAddress;
buffer->fillCount = 0;
buffer->head = buffer->tail = 0;
return true;
}
return false;
}
void TPCircularBufferCleanup(TPCircularBuffer *buffer) {
vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2);
memset(buffer, 0, sizeof(TPCircularBuffer));
}
void TPCircularBufferClear(TPCircularBuffer *buffer) {
int32_t fillCount;
if ( TPCircularBufferTail(buffer, &fillCount) ) {
TPCircularBufferConsume(buffer, fillCount);
}
}
================================================
FILE: Sublime/Pods/EZAudio/EZAudio/TPCircularBuffer.h
================================================
//
// TPCircularBuffer.h
// Circular/Ring buffer implementation
//
// https://github.com/michaeltyson/TPCircularBuffer
//
// Created by Michael Tyson on 10/12/2011.
//
//
// This implementation makes use of a virtual memory mapping technique that inserts a virtual copy
// of the buffer memory directly after the buffer's end, negating the need for any buffer wrap-around
// logic. Clients can simply use the returned memory address as if it were contiguous space.
//
// The implementation is thread-safe in the case of a single producer and single consumer.
//
// Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and
// adapted to Darwin by Kurt Revis (http://www.snoize.com,
// http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz)
//
//
// Copyright (C) 2012-2013 A Tasty Pixel
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef TPCircularBuffer_h
#define TPCircularBuffer_h
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
void *buffer;
int32_t length;
int32_t tail;
int32_t head;
volatile int32_t fillCount;
} TPCircularBuffer;
/*!
* Initialise buffer
*
* Note that the length is advisory only: Because of the way the
* memory mirroring technique works, the true buffer length will
* be multiples of the device page size (e.g. 4096 bytes)
*
* @param buffer Circular buffer
* @param length Length of buffer
*/
bool TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length);
/*!
* Cleanup buffer
*
* Releases buffer resources.
*/
void TPCircularBufferCleanup(TPCircularBuffer *buffer);
/*!
* Clear buffer
*
* Resets buffer to original, empty state.
*
* This is safe for use by consumer while producer is accessing
* buffer.
*/
void TPCircularBufferClear(TPCircularBuffer *buffer);
// Reading (consuming)
/*!
* Access end of buffer
*
* This gives you a pointer to the end of the buffer, ready
* for reading, and the number of available bytes to read.
*
* @param buffer Circular buffer
* @param availableBytes On output, the number of bytes ready for reading
* @return Pointer to the first bytes ready for reading, or NULL if buffer is empty
*/
static __inline__ __attribute__((always_inline)) void* TPCircularBufferTail(TPCircularBuffer *buffer, int32_t* availableBytes) {
*availableBytes = buffer->fillCount;
if ( *availableBytes == 0 ) return NULL;
return (void*)((char*)buffer->buffer + buffer->tail);
}
/*!
* Consume bytes in buffer
*
* This frees up the just-read bytes, ready for writing again.
*
* @param buffer Circular buffer
* @param amount Number of bytes to consume
*/
static __inline__ __attribute__((always_inline)) void TPCircularBufferConsume(TPCircularBuffer *buffer, int32_t amount) {
buffer->tail = (buffer->tail + amount) % buffer->length;
OSAtomicAdd32Barrier(-amount, &buffer->fillCount);
assert(buffer->fillCount >= 0);
}
/*!
* Version of TPCircularBufferConsume without the memory barrier, for more optimal use in single-threaded contexts
*/
static __inline__ __attribute__((always_inline)) void TPCircularBufferConsumeNoBarrier(TPCircularBuffer *buffer, int32_t amount) {
buffer->tail = (buffer->tail + amount) % buffer->length;
buffer->fillCount -= amount;
assert(buffer->fillCount >= 0);
}
/*!
* Access front of buffer
*
* This gives you a pointer to the front of the buffer, ready
* for writing, and the number of available bytes to write.
*
* @param buffer Circular buffer
* @param availableBytes On output, the number of bytes ready for writing
* @return Pointer to the first bytes ready for writing, or NULL if buffer is full
*/
static __inline__ __attribute__((always_inline)) void* TPCircularBufferHead(TPCircularBuffer *buffer, int32_t* availableBytes) {
*availableBytes = (buffer->length - buffer->fillCount);
if ( *availableBytes == 0 ) return NULL;
return (void*)((char*)buffer->buffer + buffer->head);
}
// Writing (producing)
/*!
* Produce bytes in buffer
*
* This marks the given section of the buffer ready for reading.
*
* @param buffer Circular buffer
* @param amount Number of bytes to produce
*/
static __inline__ __attribute__((always_inline)) void TPCircularBufferProduce(TPCircularBuffer *buffer, int amount) {
buffer->head = (buffer->head + amount) % buffer->length;
OSAtomicAdd32Barrier(amount, &buffer->fillCount);
assert(buffer->fillCount <= buffer->length);
}
/*!
* Version of TPCircularBufferProduce without the memory barrier, for more optimal use in single-threaded contexts
*/
static __inline__ __attribute__((always_inline)) void TPCircularBufferProduceNoBarrier(TPCircularBuffer *buffer, int amount) {
buffer->head = (buffer->head + amount) % buffer->length;
buffer->fillCount += amount;
assert(buffer->fillCount <= buffer->length);
}
/*!
* Helper routine to copy bytes to buffer
*
* This copies the given bytes to the buffer, and marks them ready for writing.
*
* @param buffer Circular buffer
* @param src Source buffer
* @param len Number of bytes in source buffer
* @return true if bytes copied, false if there was insufficient space
*/
static __inline__ __attribute__((always_inline)) bool TPCircularBufferProduceBytes(TPCircularBuffer *buffer, const void* src, int32_t len) {
int32_t space;
void *ptr = TPCircularBufferHead(buffer, &space);
if ( space < len ) return false;
memcpy(ptr, src, len);
TPCircularBufferProduce(buffer, len);
return true;
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: Sublime/Pods/EZAudio/LICENSE
================================================
The MIT License (MIT)
EZAudio
Copyright (c) 2013 Syed Haris Ali
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Sublime/Pods/EZAudio/README.md
================================================

#EZAudio
A simple, intuitive audio framework for iOS and OSX.
*The Official EZAudio Page:*
http://syedharisali.com/projects/EZAudio/getting-started
## Update
Thank you everyone for using EZAudio! Just an update - I'm working on a 1.0.0 production version of EZAudio that will contain a bunch of improvements in the API, feature an EZAudioPlayer, and hooks for the DOUAudioStreamer for visualizing remote streaming audio. To make the next version of EZAudio even better I encourage you all to email me your feedback, feature requests, and experiences using the framework. Thanks!
##Features

**Awesome Components**
I've designed six core components to allow you to immediately get your hands dirty recording, playing, and visualizing audio data. These components simply plug into each other and build on top of the high-performance, low-latency AudioUnits API and give you an easy to use API written in Objective-C instead of pure C.
[EZMicrophone](#EZMicrophone)
A microphone class that provides its delegate audio data from the default device microphone with one line of code.
[EZRecorder](#EZRecorder)
A recorder class that provides a quick and easy way to write audio files from any datasource.
[EZAudioFile](#EZAudioFile)
An audio file class that reads/seeks through audio files and provides useful delegate callbacks.
[EZOutput](#EZOutput)
An output class that will playback any audio it is provided by its datasource.
[EZAudioPlot](#EZAudioPlot)
A CoreGraphics-based audio waveform plot capable of visualizing any float array as a buffer or rolling plot.
[EZAudioPlotGL](#EZAudioPlotGL)
An OpenGL-based, GPU-accelerated audio waveform plot capable of visualizing any float array as a buffer or rolling plot.
**Cross Platform**
`EZAudio` was designed to work transparently across all iOS and OSX devices. This means one universal API whether you're building for Mac or iOS. For instance, under the hood an `EZAudioPlot` knows that it will subclass a UIView for iOS or an NSView for OSX and the `EZMicrophone` knows to build on top of the RemoteIO AudioUnit for iOS, but defaults to the system defaults for input and output for OSX.
##Examples & Docs
Within this repo you'll find the examples for iOS and OSX to get you up to speed using each component and plugging them into each other. With just a few lines of code you'll be recording from the microphone, generating audio waveforms, and playing audio files like a boss. See the full Getting Started guide for an interactive look into each of components.
### Example Projects
**_EZAudioCoreGraphicsWaveformExample_**
Shows how to use the `EZMicrophone` and `EZAudioPlot` to visualize the audio data from the microphone in real-time. The waveform can be displayed as a buffer or a rolling waveform plot (traditional waveform look).
**_EZAudioOpenGLWaveformExample_**
Shows how to use the `EZMicrophone` and `EZAudioPlotGL` to visualize the audio data from the microphone in real-time. The drawing is using OpenGL so it is much faster and like the first example can display a buffer or rolling waveform.
**_EZAudioPlayFileExample_**
Shows how to use the `EZAudioFile`, `EZOutput`, and `EZAudioPlotGL` to playback, pause, and seek through an audio file while displaying its waveform as a buffer or a rolling waveform plot.
**_EZAudioRecordWaveformExample_**
Shows how to use the `EZMicrophone`, `EZRecorder`, and `EZAudioPlotGL` to record the audio from the microphone input to a file while displaying the audio waveform of the incoming data. You can then playback the newly recorded audio file using AVFoundation and keep adding more audio data to the tail of the file.
**_EZAudioWaveformFromFileExample_**
Shows how to use the `EZAudioFile` and `EZAudioPlot` to display the audio waveform an entire audio file.
**_EZAudioPassThroughExample_**
Shows how to use the `EZMicrophone`, `EZOutput`, and the `EZAudioPlotGL` to pass the microphone input to the output for playback while displaying the audio waveform (as a buffer or rolling plot) in real-time.
**_EZAudioFFTExample_**
Shows how to calculate the real-time FFT of the audio data coming from the `EZMicrophone` and the Accelerate framework. The audio data is plotted using the `EZAudioPlotGL` for the time domain plot and the `EZAudioPlot` for the frequency domain plot.

### Documentation
The official documentation for EZAudio can be found here: http://cocoadocs.org/docsets/EZAudio/0.0.5/
You can also generate the docset yourself using appledocs by running the appledocs on the EZAudio source folder.
##Getting Started
*To see the full project page, interactive Getting Started guide, and Documentation go here:*
http://syedharisali.com/projects/EZAudio/getting-started
To begin using `EZAudio` you must first make sure you have the proper build requirements and frameworks. Below you'll find explanations of each component and code snippets to show how to use each to perform common tasks like getting microphone data, updating audio waveform plots, reading/seeking through audio files, and performing playback.
###Build Requirements
**iOS**
- 6.0+
**OSX**
- 10.8+
###Frameworks
**iOS**
- AudioToolbox
- AVFoundation
- GLKit
**OSX**
- AudioToolbox
- AudioUnit
- CoreAudio
- QuartzCore
- OpenGL
- GLKit
###Adding To Project
You can add EZAudio to your project in a few ways:
1.) The easiest way to use EZAudio is via Cocoapods. Simply add EZAudio to your Podfile like so:
`
pod 'EZAudio', '~> 0.0.5'
`
2.) Alternatively, you could clone or fork this repo and just drag and drop the source into your project.
*For more information see main project page:*
http://syedharisali.com/projects/EZAudio/getting-started
##Core Components
`EZAudio` currently offers four components that encompass a wide range of audio functionality. In addition to the functional aspects of these components such as pulling audio data, reading/writing from files, and performing playback they also take special care to hook into the interface components to allow developers to display visual feedback (see the Interface Components below).
###EZAudioFile
Provides simple read/seek operations, pulls waveform amplitude data, and provides the `EZAudioFileDelegate` to notify of any read/seek action occuring on the `EZAudioFile`.
**_Relevant Example Projects_**
- EZAudioPlayFileExample (iOS)
- EZAudioPlayFileExample (OSX)
- EZAudioWaveformFromFileExample (iOS)
- EZAudioWaveformFromFileExample (OSX)
####Opening An Audio File
To open an audio file create a new instance of the `EZAudioFile` class.
```objectivec
// Declare the EZAudioFile as a strong property
@property (nonatomic,strong) EZAudioFile *audioFile;
...
// Initialize the EZAudioFile instance and assign it a delegate to receive the read/seek callbacks
self.audioFile = [EZAudioFile audioFileWithURL:[NSURL fileURLWithPath:@"/path/to/your/file"]
andDelegate:self];
```
####Getting Waveform Data
There is a `getWaveformDataWithCompletionBlock:` method to allow you to easily and asynchronously get the waveform amplitude data that will best represent the whole audio file (will calculate the best fit that's constrainted to ~2048 data points)
```objectivec
// Get the waveform data from the audio file asynchronously
[audioFile getWaveformDataWithCompletionBlock:^(float *waveformData, UInt32 length) {
// Update the audio plot with the waveform data (use the EZPlotTypeBuffer in this case)
self.audioPlot.plotType = EZPlotTypeBuffer;
[self.audioPlot updateBuffer:waveformData withBufferSize:length];
}];
```
####Reading From An Audio File
Reading audio data from a file requires you to create an AudioBufferList to hold the data. The `EZAudio` utility function, `audioBufferList`, provides a convenient way to get an allocated AudioBufferList to use. There is also a utility function, `freeBufferList:`, to use to free (or release) the AudioBufferList when you are done using that audio data.
**Note: You have to free the AudioBufferList, even in ARC.**
```objectivec
// Allocate a buffer list to hold the file's data
UInt32 frames = 512;
AudioBufferList *bufferList = [EZAudio audioBufferList];
UInt32 bufferSize; // Read function will populate this value
BOOL eof; // Read function will populate this value
// Reads 512 frames from the audio file
[audioFile readFrames:frames
audioBufferList:bufferList
bufferSize:&bufferSize
eof:&eof];
// Cleanup when done working with audio data (yes, even in ARC)
[EZAudio freeBufferList:bufferList];
```
When a read occurs the `EZAudioFileDelegate` receives two events.
An event notifying the delegate of the read audio data as float arrays:
```objectivec
// The EZAudioFile method `readFrames:audioBufferList:bufferSize:eof:` triggers an event notifying the delegate of the read audio data as float arrays
-(void) audioFile:(EZAudioFile *)audioFile
readAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
// The audio data from the read as a float buffer. You can feed this into an audio plot!
dispatch_async(dispatch_get_main_queue(), ^{
// Update that audio plot!
[self.audioPlot updateBuffer:buffer[0] withBufferSize:bufferSize];
});
}
```
and an event notifying the delegate of the new frame position within the `EZAudioFile`:
```objectivec
// The EZAudioFile method `readFrames:audioBufferList:bufferSize:eof:` triggers an event notifying the delegate of the new frame position within the file.
-(void)audioFile:(EZAudioFile *)audioFile updatedPosition:(SInt64)framePosition {
dispatch_async(dispatch_get_main_queue(), ^{
// Move that slider to this new position!
});
}
```
####Seeking Through An Audio File
You can seek very easily through an audio file using the `EZAudioFile`'s seekToFrame: method. The `EZAudioFile` provides a `totalFrames` method to provide you the total amount of frames in an audio file so you can calculate a proper offset.
```objectivec
// Get the total number of frames for the audio file
SInt64 totalFrames = [self.audioFile totalFrames];
// Seeks halfway through the audio file
[self.audioFile seekToFrame:(totalFrames/2)];
```
When a seek occurs the `EZAudioFileDelegate` receives the seek event:
```objectivec
// The EZAudioFile method `seekToFrame:` triggers an event notifying the delegate of the new frame position within the file.
-(void)audioFile:(EZAudioFile *)audioFile updatedPosition:(SInt64)framePosition {
dispatch_async(dispatch_get_main_queue(), ^{
// Move that slider to this new position!
});
}
```
###EZMicrophone
Provides access to the default device microphone in one line of code and provides delegate callbacks to receive the audio data as an AudioBufferList and float arrays.
**_Relevant Example Projects_**
- EZAudioCoreGraphicsWaveformExample (iOS)
- EZAudioCoreGraphicsWaveformExample (OSX)
- EZAudioOpenGLWaveformExample (iOS)
- EZAudioOpenGLWaveformExample (OSX)
- EZAudioRecordExample (iOS)
- EZAudioRecordExample (OSX)
####Creating A Microphone
Create an `EZMicrophone` instance by declaring a property and initializing it like so:
```objectivec
// Declare the EZMicrophone as a strong property
@property (nonatomic,strong) EZMicrophone *microphone;
...
// Initialize the microphone instance and assign it a delegate to receive the audio data callbacks
self.microphone = [EZMicrophone microphoneWithDelegate:self];
```
Alternatively, you could also use the shared `EZMicrophone` instance and just assign its `EZMicrophoneDelegate`.
```objectivec
// Assign a delegate to the shared instance of the microphone to receive the audio data callbacks
[EZMicrophone sharedMicrophone].microphoneDelegate = self;
```
####Getting Microphone Data
To tell the microphone to start fetching audio use the `startFetchingAudio` function.
```objectivec
// Starts fetching audio from the default device microphone and sends data to EZMicrophoneDelegate
[self.microphone startFetchingAudio];
```
Once the `EZMicrophone` has started it will send the `EZMicrophoneDelegate` the audio back in a few ways.
An array of float arrays:
```objectivec
/**
The microphone data represented as float arrays useful for:
- Creating real-time waveforms using EZAudioPlot or EZAudioPlotGL
- Creating any number of custom visualizations that utilize audio!
*/
-(void) microphone:(EZMicrophone *)microphone
hasAudioReceived:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
// Getting audio data as an array of float buffer arrays that can be fed into the EZAudioPlot, EZAudioPlotGL, or whatever visualization you would like to do with the microphone data.
dispatch_async(dispatch_get_main_queue(),^{
// Visualize this data brah, buffer[0] = left channel, buffer[1] = right channel
[self.audioPlot updateBuffer:buffer[0] withBufferSize:bufferSize];
});
}
```
or the AudioBufferList representation:
```objectivec
/**
The microphone data represented as CoreAudio's AudioBufferList useful for:
- Appending data to an audio file via the EZRecorder
- Playback via the EZOutput
*/
-(void) microphone:(EZMicrophone *)microphone
hasBufferList:(AudioBufferList *)bufferList
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
// Getting audio data as an AudioBufferList that can be directly fed into the EZRecorder or EZOutput. Say whattt...
}
```
####Pausing/Resuming The Microphone
Pause or resume fetching audio at any time like so:
```objectivec
// Stop fetching audio
[self.microphone stopFetchingAudio];
// Resume fetching audio
[self.microphone startFetchingAudio];
```
Alternatively, you could also toggle the `microphoneOn` property (safe to use with Cocoa Bindings)
```objectivec
// Stop fetching audio
self.microphone.microphoneOn = NO;
// Start fetching audio
self.microphone.microphoneOn = YES;
```
###EZOutput
Provides flexible playback to the default output device by asking the `EZOutputDataSource` for audio data to play. Doesn't care where the buffers come from (microphone, audio file, streaming audio, etc). The `EZOutputDataSource` has three functions that can provide audio data for the output callback. You should implement only **ONE** of these functions:
```objectivec
// Full override of the audio callback
-(void) output:(EZOutput*)output
callbackWithActionFlags:(AudioUnitRenderActionFlags*)ioActionFlags
inTimeStamp:(const AudioTimeStamp*)inTimeStamp
inBusNumber:(UInt32)inBusNumber
inNumberFrames:(UInt32)inNumberFrames
ioData:(AudioBufferList*)ioData;
// Provides the audio callback with a circular buffer holding the audio data
-(TPCircularBuffer*)outputShouldUseCircularBuffer:(EZOutput *)output;
// Provides the audio callback with a buffer list, number of frames, and buffer size to use
-(void) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames;
```
**_Relevant Example Projects_**
- EZAudioPlayFileExample (iOS)
- EZAudioPlayFileExample (OSX)
- EZAudioPassThroughExample (iOS)
- EZAudioPassThroughExample (OSX)
####Creating An Output
Create an `EZOutput` by declaring a property and initializing it like so:
```objectivec
// Declare the EZOutput as a strong property
@property (nonatomic,strong) EZOutput *output;
...
// Initialize the EZOutput instance and assign it a delegate to provide the output audio data
self.output = [EZOutput outputWithDataSource:self];
```
Alternatively, you could also use the shared output instance and just assign it an `EZOutputDataSource`. This is the preferred way to use the `EZOutput` (usually just have one per app).
```objectivec
// Assign a delegate to the shared instance of the output to provide the output audio data
[EZOutput sharedOutput].outputDataSource = self;
```
####Playback Using An AudioBufferList
One method to play back audio is to provide an AudioBufferList (for instance, reading from an `EZAudioFile`):
```objectivec
// Use the AudioBufferList datasource method to read from an EZAudioFile
-(void) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
{
if( self.audioFile )
{
UInt32 bufferSize;
[self.audioFile readFrames:frames
audioBufferList:audioBufferList
bufferSize:&bufferSize
eof:&_eof];
if( _eof )
{
[self seekToFrame:0];
}
}
}
```
####Playback Using A Circular Buffer
Another method is to provide a circular buffer via Michael Tyson's (who, btw is a serious badass and also wrote the Amazing Audio Engine for iOS) TPCircularBuffer containing the data. For instance, for passing the microphone input to the output for a basic passthrough:
```objectivec
// Declare circular buffer as global
TPCircularBuffer circularBuffer;
...
// Using an EZMicrophone, append the AudioBufferList from the microphone callback to the global circular buffer
-(void) microphone:(EZMicrophone *)microphone
hasBufferList:(AudioBufferList *)bufferList
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
/**
Append the audio data to a circular buffer
*/
[EZAudio appendDataToCircularBuffer:&circularBuffer
fromAudioBufferList:bufferList];
}
// Pass the circular buffer to the EZOutputDataSource using the circular buffer callback
-(TPCircularBuffer *)outputShouldUseCircularBuffer:(EZOutput *)output {
return &circularBuffer;
}
```
####Playback By Manual Override
And the last method is to completely override the output callback method and populate the AudioBufferList however you can imagine:
```objectivec
// Completely override the output callback function
-(void) output:(EZOutput *)output
callbackWithActionFlags:(AudioUnitRenderActionFlags *)ioActionFlags
inTimeStamp:(const AudioTimeStamp *)inTimeStamp
inBusNumber:(UInt32)inBusNumber
inNumberFrames:(UInt32)inNumberFrames
ioData:(AudioBufferList *)ioData {
// Fill the ioData with your audio data from anywhere
}
```
###EZRecorder
Provides a way to record any audio source to an audio file. This hooks into the other components quite nicely to do something like plot the audio waveform while recording to give visual feedback as to what is happening.
*Relevant Example Projects*
- EZAudioRecordExample (iOS)
- EZAudioRecordExample (OSX)
####Creating A Recorder
To create an `EZRecorder` you must start with an AudioStreamBasicDescription, which is just a CoreAudio structure representing the audio format of a file. The `EZMicrophone` and `EZAudioFile` both provide the AudioStreamBasicDescription as properties (for the `EZAudioFile` use the clientFormat property) that you can use when initializing the `EZRecorder`.
```objectivec
// Declare the EZRecorder as a strong property
@property (nonatomic,strong) EZRecorder *recorder;
...
// Here's how we would initialize the recorder for an EZMicrophone instance
self.recorder = [EZRecorder recorderWithDestinationURL:[NSURL fileURLWithPath:@"path/to/file.caf"]
andSourceFormat:microphone.audioStreamBasicDescription];
// Here's how we would initialize the recorder for an EZAudioFile instance
self.recorder = [EZRecorder recorderWithDestinationURL:[NSURL fileURLWithPath:@"path/to/file.caf"]
andSourceFormat:audioFile.clientFormat];
```
##Recording Some Audio
Once you've initialized your `EZRecorder` you can append data by passing in an AudioBufferList and its buffer size like so:
```objectivec
// Append the microphone data coming as a AudioBufferList with the specified buffer size to the recorder
-(void) microphone:(EZMicrophone *)microphone
hasBufferList:(AudioBufferList *)bufferList
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
// Getting audio data as a buffer list that can be directly fed into the EZRecorder. This is happening on the audio thread - any UI updating needs a GCD main queue block.
if( self.isRecording ){
[self.recorder appendDataFromBufferList:bufferList
withBufferSize:bufferSize];
}
}
```
###Interface Components
`EZAudio` currently offers two drop in audio waveform components that help simplify the process of visualizing audio.
###EZAudioPlot
Provides an audio waveform plot that uses CoreGraphics to perform the drawing. On iOS this is a subclass of UIView while on OSX this is a subclass of NSView. Best used on OSX as the drawing falls on the CPU and needs to redisplay after every audio data update, but useful in iOS apps for displaying full, static waveforms.
*Relevant Example Projects*
- EZAudioCoreGraphicsWaveformExample (iOS)
- EZAudioCoreGraphicsWaveformExample (OSX)
####Creating An Audio Plot
You can create an audio plot in the interface builder by dragging in a UIView on iOS or an NSView on OSX onto your content area. Then change the custom class of the UIView/NSView to `EZAudioPlot`.
See full Getting Started page for how to: http://syedharisali.com/projects/EZAudio/getting-started
Alternatively, you can could create the audio plot programmatically
```objectivec
// Programmatically create an audio plot
EZAudioPlot *audioPlot = [[EZAudioPlot alloc] initWithFrame:self.view.frame];
[self.view addSubview:audioPlot];
```
####Customizing The Audio Plot
All plots offer the ability to change the background color, waveform color, plot type (buffer or rolling), toggle between filled and stroked, and toggle between mirrored and unmirrored (about the x-axis). For iOS colors are of the type UIColor while on OSX colors are of the type NSColor.
```objectivec
// Background color (use UIColor for iOS)
audioPlot.backgroundColor = [NSColor colorWithCalibratedRed:0.816
green:0.349
blue:0.255
alpha:1];
// Waveform color (use UIColor for iOS)
audioPlot.color = [NSColor colorWithCalibratedRed:1.000
green:1.000
blue:1.000
alpha:1];
// Plot type
audioPlot.plotType = EZPlotTypeBuffer;
// Fill
audioPlot.shouldFill = YES;
// Mirror
audioPlot.shouldMirror = YES;
```
####Updating The Audio Plot
All plots have only one update function, `updateBuffer:withBufferSize:`, which expects a float array and its length.
```objectivec
// The microphone component provides audio data to its delegate as an array of float buffer arrays.
-(void) microphone:(EZMicrophone *)microphone
hasAudioReceived:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
/**
Update the audio plot using the float array provided by the microphone:
buffer[0] = left channel
buffer[1] = right channel
Note: Audio updates happen asynchronously so we need to make sure
sure to update the plot on the main thread
*/
dispatch_async(dispatch_get_main_queue(),^{
[self.audioPlot updateBuffer:buffer[0] withBufferSize:bufferSize];
});
}
```
###EZAudioPlotGL
Provides an audio waveform plot that uses OpenGL to perform the drawing. The API this class are exactly the same as those for the EZAudioPlot above. On iOS this is a subclass of the EZPlot and uses an embedded GLKViewController to perform the OpenGL drawing while on OSX this is a subclass of the NSOpenGLView. In most cases this is the plot you want to use, it's GPU-accelerated, has a low memory footprint, and performs amazingly on all devices.
*Relevant Example Projects*
- EZAudioOpenGLWaveformExample (iOS)
- EZAudioOpenGLWaveformExample (OSX)
####Creating An OpenGL Audio Plot
You can create an audio plot in the interface builder by dragging in a UIView on iOS or an NSOpenGLView on OSX onto your content area. Then change the custom class of the UIView/NSView to `EZAudioPlotGL`.
See full Getting Started page for how to: http://syedharisali.com/projects/EZAudio/getting-started
Alternatively, you can could create the `EZAudioPlotGL` programmatically
```objectivec
// Programmatically create an audio plot
EZAudioPlotGL *audioPlotGL = [[EZAudioPlotGL alloc] initWithFrame:self.view.frame];
[self.view addSubview:audioPlotGL];
```
####Customizing The OpenGL Audio Plot
All plots offer the ability to change the background color, waveform color, plot type (buffer or rolling), toggle between filled and stroked, and toggle between mirrored and unmirrored (about the x-axis). For iOS colors are of the type UIColor while on OSX colors are of the type NSColor.
```objectivec
// Background color (use UIColor for iOS)
audioPlotGL.backgroundColor = [NSColor colorWithCalibratedRed:0.816
green:0.349
blue:0.255
alpha:1];
// Waveform color (use UIColor for iOS)
audioPlotGL.color = [NSColor colorWithCalibratedRed:1.000
green:1.000
blue:1.000
alpha:1];
// Plot type
audioPlotGL.plotType = EZPlotTypeBuffer;
// Fill
audioPlotGL.shouldFill = YES;
// Mirror
audioPlotGL.shouldMirror = YES;
```
####Updating The OpenGL Audio Plot
All plots have only one update function, `updateBuffer:withBufferSize:`, which expects a float array and its length.
```objectivec
// The microphone component provides audio data to its delegate as an array of float buffer arrays.
-(void) microphone:(EZMicrophone *)microphone
hasAudioReceived:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels {
/**
Update the audio plot using the float array provided by the microphone:
buffer[0] = left channel
buffer[1] = right channel
Note: Audio updates happen asynchronously so we need to make sure
sure to update the plot on the main thread
*/
dispatch_async(dispatch_get_main_queue(),^{
[self.audioPlotGL updateBuffer:buffer[0] withBufferSize:bufferSize];
});
}
```
##License
EZAudio is available under the MIT license. See the LICENSE file for more info.
##Contact & Contributers
Syed Haris Ali
www.syedharisali.com
syedhali07[at]gmail.com
##Acknowledgements
EZAudio could not have been created without the invaluable help of:
- Michael Tyson for creating the TPCircularBuffer and the Amazing Audio Engine's `AEFloatConverter`.
- Chris Adamson and Kevin Avila for writing the amazing book Learning Core Audio
================================================
FILE: Sublime/Pods/Gifu/Carthage/Checkouts/Runes/Source/Runes.swift
================================================
/**
map a function over a value with context
Expected function type: `(a -> b) -> f a -> f b`
*/
infix operator <^> {
associativity left
// Same precedence as the equality operator (`==`)
precedence 130
}
/**
apply a function with context to a value with context
Expected function type: `f (a -> b) -> f a -> f b`
*/
infix operator <*> {
associativity left
// Same precedence as the equality operator (`==`)
precedence 130
}
/**
map a function over a value with context and flatten the result
Expected function type: `m a -> (a -> m b) -> m b`
*/
infix operator >>- {
associativity left
// Lower precedence than the logical comparison operators
// (`&&` and `||`), but higher precedence than the assignment
// operator (`=`)
precedence 100
}
/**
map a function over a value with context and flatten the result
Expected function type: `(a -> m b) -> m a -> m b`
*/
infix operator -<< {
associativity right
// Lower precedence than the logical comparison operators
// (`&&` and `||`), but higher precedence than the assignment
// operator (`=`)
precedence 100
}
================================================
FILE: Sublime/Pods/Gifu/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Kaishin & Co.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The name and characters used in the demo of this software are property of their
respective owners.
================================================
FILE: Sublime/Pods/Gifu/README.md
================================================
# 
Adds performant animated GIF support to UIKit. If you're looking for the Japanese prefecture, click [here](https://goo.gl/maps/CCeAc).
#### How?
Gifu uses a `UIImageView` subclass and an animator that keeps track of frames and their durations.
It uses `CADisplayLink` to animate the view and only keeps a limited number of
resized frames in-memory, which exponentially minimizes memory usage for large GIF files (+300 frames).
The figure below summarizes how this works in practice. Given an image
containing 10 frames, Gifu will load the current frame (red), pre-load the next two frames in this example (orange), and nullify all the other frames to free up memory (gray):
#### Install
#### [Carthage](https://github.com/Carthage/Carthage)
- Add the following to your Cartfile: `github "kaishin/Gifu"`
- Then run `carthage update`
- Follow the current instructions in [Carthage's README][carthage-installation]
for up to date installation instructions.
[carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
#### [CocoaPods](http://cocoapods.org)
- Add the following to your [Podfile](http://guides.cocoapods.org/using/the-podfile.html): `pod 'Gifu'`
- You will also need to make sure you're opting into using frameworks: `use_frameworks!`
- Then run `pod install` with CocoaPods 0.36 or newer.
#### Usage
Start by instantiating an `AnimatableImageView` either in code or Interface Builder, then call `animateWithImage(named:)` or `animateWithImageData(data:)` on it.
```swift
let imageView = AnimatableImageView(frame: CGRect(...))
imageView.animateWithImage(named: "mugen.gif")
```
You can stop the animation anytime using `imageView.stopAnimatingGIF()`, and resume
it using `imageView.startAnimatingGIF()`.
The `isAnimatingGIF()` method returns the current animation state of the view if it has an animatable image.
See the [full documentation](http://kaishin.github.io/gifu/).
#### Demo App
Clone or download the repository and open `Gifu.xcworkspace` to check out the demo app.
#### Compatibility
- iOS 8+
#### Roadmap
- Add ability to set the frame-rate
#### Contributors
- [Reda Lemeden](https://github.com/kaishin)
- [Tony DiPasquale](https://github.com/tonyd256)
#### Misc
- The font used in the logo is [Azuki](http://www.myfonts.com/fonts/bluevinyl/azuki/)
- The characters used in the icon and example image in the demo are from [Samurai Champloo](https://en.wikipedia.org/wiki/Samurai_Champloo).
#### License
See LICENSE.
================================================
FILE: Sublime/Pods/Gifu/Source/AnimatableImageView.swift
================================================
import UIKit
/// A subclass of `UIImageView` that can be animated using an image name string or raw data.
public class AnimatableImageView: UIImageView {
/// An `Animator` instance that holds the frames of a specific image in memory.
var animator: Animator?
/// A display link that keeps calling the `updateFrame` method on every screen refresh.
lazy var displayLink: CADisplayLink = CADisplayLink(target: self, selector: Selector("updateFrame"))
/// The size of the frame cache.
public var framePreloadCount = 50
/// A computed property that returns whether the image view is animating.
public var isAnimatingGIF: Bool {
return !displayLink.paused
}
/// Prepares the frames using a GIF image file name, without starting the animation.
/// The file name should include the `.gif` extension.
///
/// - parameter imageName: The name of the GIF file. The method looks for the file in the app bundle.
public func prepareForAnimation(imageNamed imageName: String) {
let imagePath = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent(imageName)
prepareForAnimation <^> NSData(contentsOfURL: imagePath)
}
/// Prepares the frames using raw GIF image data, without starting the animation.
///
/// - parameter data: GIF image data.
public func prepareForAnimation(imageData data: NSData) {
image = UIImage(data: data)
animator = Animator(data: data, size: frame.size, contentMode: contentMode, framePreloadCount: framePreloadCount)
animator?.prepareFrames()
attachDisplayLink()
}
/// Prepares the frames using a GIF image file name and starts animating the image view.
///
/// - parameter imageName: The name of the GIF file. The method looks for the file in the app bundle.
public func animateWithImage(named imageName: String) {
prepareForAnimation(imageNamed: imageName)
startAnimatingGIF()
}
/// Prepares the frames using raw GIF image data and starts animating the image view.
///
/// - parameter data: GIF image data.
public func animateWithImageData(data: NSData) {
prepareForAnimation(imageData: data)
startAnimatingGIF()
}
/// Updates the `image` property of the image view if necessary. This method should not be called manually.
override public func displayLayer(layer: CALayer) {
image = animator?.currentFrame
}
/// Starts the image view animation.
public func startAnimatingGIF() {
if animator?.isAnimatable ?? false {
displayLink.paused = false
}
}
/// Stops the image view animation.
public func stopAnimatingGIF() {
displayLink.paused = true
}
/// Update the current frame with the displayLink duration
func updateFrame() {
if animator?.updateCurrentFrame(displayLink.duration) ?? false {
layer.setNeedsDisplay()
}
}
/// Invalidate the displayLink so it releases this object.
deinit {
displayLink.invalidate()
}
/// Attaches the display link.
func attachDisplayLink() {
displayLink.addToRunLoop(.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/AnimatedFrame.swift
================================================
/// Keeps a reference to an `UIImage` instance and its duration as a GIF frame.
struct AnimatedFrame {
let image: UIImage?
let duration: NSTimeInterval
static func null() -> AnimatedFrame {
return AnimatedFrame(image: .None, duration: 0)
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/Animator.swift
================================================
import UIKit
import ImageIO
/// Responsible for storing and updating the frames of a `AnimatableImageView` instance via delegation.
class Animator {
/// Maximum duration to increment the frame timer with.
let maxTimeStep = 1.0
/// An array of animated frames from a single GIF image.
var animatedFrames = [AnimatedFrame]()
/// The size to resize all frames to
let size: CGSize
/// The content mode to use when resizing
let contentMode: UIViewContentMode
/// Maximum number of frames to load at once
let maxFrameCount: Int
/// The total number of frames in the GIF.
var frameCount = 0
/// A reference to the original image source.
var imageSource: CGImageSourceRef
/// The index of the current GIF frame.
var currentFrameIndex = 0
/// The index of the current GIF frame from the source.
var currentPreloadIndex = 0
/// Time elapsed since the last frame change. Used to determine when the frame should be updated.
var timeSinceLastFrameChange: NSTimeInterval = 0.0
/// The current image frame to show.
var currentFrame: UIImage? {
return frameAtIndex(currentFrameIndex)
}
/// Is this image animatable?
var isAnimatable: Bool {
return imageSource.isAnimatedGIF
}
/// Initializes an animator instance from raw GIF image data and an `Animatable` delegate.
///
/// - parameter data: The raw GIF image data.
/// - parameter delegate: An `Animatable` delegate.
init(data: NSData, size: CGSize, contentMode: UIViewContentMode, framePreloadCount: Int) {
let options = [String(kCGImageSourceShouldCache): kCFBooleanFalse]
self.imageSource = CGImageSourceCreateWithData(data, options) ?? CGImageSourceCreateIncremental(options)
self.size = size
self.contentMode = contentMode
self.maxFrameCount = framePreloadCount
}
// MARK: - Frames
/// Loads the frames from an image source, resizes them, then caches them in `animatedFrames`.
func prepareFrames() {
frameCount = Int(CGImageSourceGetCount(imageSource))
let framesToProcess = min(frameCount, maxFrameCount)
animatedFrames.reserveCapacity(framesToProcess)
animatedFrames = (0.. AnimatedFrame {
guard let frameImageRef = CGImageSourceCreateImageAtIndex(imageSource, index, nil) else {
return AnimatedFrame.null()
}
let frameDuration = CGImageSourceGIFFrameDuration(imageSource, index: index)
let image = UIImage(CGImage: frameImageRef)
let scaledImage: UIImage?
switch contentMode {
case .ScaleAspectFit: scaledImage = image.resizeAspectFit(size)
case .ScaleAspectFill: scaledImage = image.resizeAspectFill(size)
default: scaledImage = image.resize(size)
}
return AnimatedFrame(image: scaledImage, duration: frameDuration)
}
/// Returns the frame at a particular index.
///
/// - parameter index: The index of the frame.
/// - returns: An optional image at a given frame.
func frameAtIndex(index: Int) -> UIImage? {
return animatedFrames[index].image
}
/// Updates the current frame if necessary using the frame timer and the duration of each frame in `animatedFrames`.
///
/// - returns: An optional image at a given frame.
func updateCurrentFrame(duration: CFTimeInterval) -> Bool {
timeSinceLastFrameChange += min(maxTimeStep, duration)
guard let frameDuration = animatedFrames[safe:currentFrameIndex]?.duration where
frameDuration <= timeSinceLastFrameChange else { return false }
timeSinceLastFrameChange -= frameDuration
let lastFrameIndex = currentFrameIndex
currentFrameIndex = ++currentFrameIndex % animatedFrames.count
// Loads the next needed frame for progressive loading
if animatedFrames.count < frameCount {
animatedFrames[lastFrameIndex] = prepareFrame(currentPreloadIndex)
currentPreloadIndex = ++currentPreloadIndex % frameCount
}
return true
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/ArrayExtension.swift
================================================
extension Array {
subscript(safe index: Int) -> Element? {
return indices ~= index ? self[index] : .None
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/CGSizeExtension.swift
================================================
extension CGSize {
/// Calculates the aspect ratio of the size.
///
/// - returns: aspectRatio The aspect ratio of the size.
var aspectRatio: CGFloat {
if height == 0 { return 1 }
return width / height
}
/// Finds a new size constrained by a size keeping the aspect ratio.
///
/// - parameter size: The contraining size.
/// - returns: size A new size that fits inside the contraining size with the same aspect ratio.
func sizeConstrainedBySize(size: CGSize) -> CGSize {
let aspectWidth = round(aspectRatio * size.height)
let aspectHeight = round(size.width / aspectRatio)
if aspectWidth > size.width {
return CGSize(width: size.width, height: aspectHeight)
} else {
return CGSize(width: aspectWidth, height: size.height)
}
}
/// Finds a new size filling the given size while keeping the aspect ratio.
///
/// - parameter size: The contraining size.
/// - returns: size A new size that fills the contraining size keeping the same aspect ratio.
func sizeFillingSize(size: CGSize) -> CGSize {
let aspectWidth = round(aspectRatio * size.height)
let aspectHeight = round(size.width / aspectRatio)
if aspectWidth > size.width {
return CGSize(width: aspectWidth, height: size.height)
} else {
return CGSize(width: size.width, height: aspectHeight)
}
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/FunctionalHelpers.swift
================================================
func <^> (@noescape f: T -> U, a: T?) -> U? {
return a.map(f)
}
func <*> (f: (T -> U)?, a: T?) -> U? {
return a.apply(f)
}
func >>- (a: T?, @noescape f: T -> U?) -> U? {
return a.flatMap(f)
}
extension Optional {
func apply(f: (Wrapped -> U)?) -> U? {
return f.flatMap { self.map($0) }
}
}
func pure(a: T) -> [T] {
return [a]
}
================================================
FILE: Sublime/Pods/Gifu/Source/Gifu.h
================================================
#import
FOUNDATION_EXPORT double GifuVersionNumber;
FOUNDATION_EXPORT const unsigned char GifuVersionString[];
================================================
FILE: Sublime/Pods/Gifu/Source/ImageSourceHelpers.swift
================================================
import ImageIO
import MobileCoreServices
import UIKit
typealias GIFProperties = [String : Double]
let defaultDuration: Double = 0
/// Retruns the duration of a frame at a specific index using an image source (an `CGImageSource` instance).
///
/// - returns: A frame duration.
func CGImageSourceGIFFrameDuration(imageSource: CGImageSource, index: Int) -> NSTimeInterval {
if !imageSource.isAnimatedGIF { return 0.0 }
let duration = imageSource.GIFPropertiesAtIndex(index)
>>- durationFromGIFProperties
>>- capDuration
return duration ?? defaultDuration
}
/// Ensures that a duration is never smaller than a threshold value.
///
/// - returns: A capped frame duration.
func capDuration(duration: Double) -> Double? {
if duration < 0 { return .None }
let threshold = 0.02 - Double(FLT_EPSILON)
let cappedDuration = duration < threshold ? 0.1 : duration
return cappedDuration
}
/// Returns a frame duration from a `GIFProperties` dictionary.
///
/// - returns: A frame duration.
func durationFromGIFProperties(properties: GIFProperties) -> Double? {
let unclampedDelayTime = properties[String(kCGImagePropertyGIFUnclampedDelayTime)]
let delayTime = properties[String(kCGImagePropertyGIFDelayTime)]
return duration <^> unclampedDelayTime <*> delayTime
}
/// Calculates frame duration based on both clamped and unclamped times.
///
/// - returns: A frame duration.
func duration(unclampedDelayTime: Double)(delayTime: Double) -> Double {
let delayArray = [unclampedDelayTime, delayTime]
return delayArray.filter(isPositive).first ?? defaultDuration
}
/// Checks if a `Double` value is positive.
///
/// - returns: A boolean value that is `true` if the tested value is positive.
func isPositive(value: Double) -> Bool {
return value >= 0
}
/// An extension of `CGImageSourceRef` that add GIF introspection and easier property retrieval.
extension CGImageSourceRef {
/// Returns whether the image source contains an animated GIF.
///
/// - returns: A boolean value that is `true` if the image source contains animated GIF data.
var isAnimatedGIF: Bool {
let isTypeGIF = UTTypeConformsTo(CGImageSourceGetType(self) ?? "", kUTTypeGIF)
let imageCount = CGImageSourceGetCount(self)
return isTypeGIF != false && imageCount > 1
}
/// Returns the GIF properties at a specific index.
///
/// - parameter index: The index of the GIF properties to retrieve.
/// - returns: A dictionary containing the GIF properties at the passed in index.
func GIFPropertiesAtIndex(index: Int) -> GIFProperties? {
let imageProperties = CGImageSourceCopyPropertiesAtIndex(self, index, nil) as Dictionary?
return imageProperties?[String(kCGImagePropertyGIFDictionary)] as? GIFProperties
}
}
================================================
FILE: Sublime/Pods/Gifu/Source/UIImageExtension.swift
================================================
/// A `UIImage` extension that makes it easier to resize the image and inspect its size.
extension UIImage {
/// Resizes an image instance.
///
/// - parameter size: The new size of the image.
/// - returns: A new resized image instance.
func resize(size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
self.drawInRect(CGRect(origin: CGPointZero, size: size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage ?? self
}
/// Resizes an image instance to fit inside a constraining size while keeping the aspect ratio.
///
/// - parameter size: The constraining size of the image.
/// - returns: A new resized image instance.
func resizeAspectFit(size: CGSize) -> UIImage {
let newSize = self.size.sizeConstrainedBySize(size)
return resize(newSize)
}
/// Resizes an image instance to fill a constraining size while keeping the aspect ratio.
///
/// - parameter size: The constraining size of the image.
/// - returns: A new resized image instance.
func resizeAspectFill(size: CGSize) -> UIImage {
let newSize = self.size.sizeFillingSize(size)
return resize(newSize)
}
/// Returns a new `UIImage` instance using raw image data and a size.
///
/// - parameter data: Raw image data.
/// - parameter size: The size to be used to resize the new image instance.
/// - returns: A new image instance from the passed in data.
class func imageWithData(data: NSData, size: CGSize) -> UIImage? {
return UIImage(data: data)?.resize(size)
}
/// Returns an image size from raw image data.
///
/// - parameter data: Raw image data.
/// - returns: The size of the image contained in the data.
class func sizeForImageData(data: NSData) -> CGSize? {
return UIImage(data: data)?.size
}
}
================================================
FILE: Sublime/Pods/NMSSH/LICENSE
================================================
Copyright (c) 2013 Nine Muses AB
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Config/NMSSH+Protected.h
================================================
#ifndef NMSSH_Protected_h
#define NMSSH_Protected_h
#import
#import
#import
#import
#import "socket_helper.h"
#define kNMSSHBufferSize (0x4000)
#define NMSSHLogVerbose(frmt, ...) [[NMSSHLogger sharedLogger] logVerbose:[NSString stringWithFormat:frmt, ##__VA_ARGS__]]
#define NMSSHLogInfo(frmt, ...) [[NMSSHLogger sharedLogger] logInfo:[NSString stringWithFormat:frmt, ##__VA_ARGS__]]
#define NMSSHLogWarn(frmt, ...) [[NMSSHLogger sharedLogger] logWarn:[NSString stringWithFormat:frmt, ##__VA_ARGS__]]
#define NMSSHLogError(frmt, ...) [[NMSSHLogger sharedLogger] logError:[NSString stringWithFormat:frmt, ##__VA_ARGS__]]
#define strlen (unsigned int)strlen
#endif
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Config/NMSSHLogger.h
================================================
#import "NMSSH.h"
typedef NS_OPTIONS(NSUInteger, NMSSHLogLevel) {
NMSSHLogLevelVerbose = (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3),
NMSSHLogLevelInfo = (1 << 1 | 1 << 2 | 1 << 3),
NMSSHLogLevelWarn = (1 << 2 | 1 << 3),
NMSSHLogLevelError = (1 << 3)
};
/**
NMSSHLogger provides the functionality to customize the framework logging.
*/
@interface NMSSHLogger : NSObject
/// ----------------------------------------------------------------------------
/// @name Retrieve the shared logger
/// ----------------------------------------------------------------------------
/**
Retrieve the shared logger instance
@returns Shared logger
*/
+ (instancetype) sharedLogger;
/// ----------------------------------------------------------------------------
/// @name Logger settings
/// ----------------------------------------------------------------------------
/**
The block called to print the log message.
The default implementation print the log
message using NSLog.
The block takes two argument:
_level_ - Log level
_format_ - Log message
*/
@property (nonatomic, copy) void (^logBlock)(NMSSHLogLevel level, NSString *format);
/** The maximum log level */
@property (nonatomic, assign) NMSSHLogLevel logLevel;
/** Enable or disable the logging feature */
@property (nonatomic, assign, getter = isEnabled) BOOL enabled;
/// ----------------------------------------------------------------------------
/// @name Logging
/// ----------------------------------------------------------------------------
/**
Log with verbose level
@param format Log message
*/
- (void)logVerbose:(NSString *)format;
/**
Log with info level
@param format Log message
*/
- (void)logInfo:(NSString *)format;
/**
Log with warn level
@param format Log message
*/
- (void)logWarn:(NSString *)format;
/**
Log with error level
@param format Log message
*/
- (void)logError:(NSString *)format;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Config/NMSSHLogger.m
================================================
#import "NMSSHLogger.h"
#import "NMSSH+Protected.h"
typedef NS_OPTIONS(NSUInteger, NMSSHLogFlag) {
NMSSHLogFlagVerbose = (1 << 0),
NMSSHLogFlagInfo = (1 << 1),
NMSSHLogFlagWarn = (1 << 2),
NMSSHLogFlagError = (1 << 3)
};
@interface NMSSHLogger ()
/**
The shared logger instance, now private
*/
+ (NMSSHLogger *)logger;
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong) dispatch_queue_t loggerQueue;
#else
@property (nonatomic, assign) dispatch_queue_t loggerQueue;
#endif
@end
@implementation NMSSHLogger
// -----------------------------------------------------------------------------
#pragma mark - INITIALIZE THE LOGGER INSTANCE
// -----------------------------------------------------------------------------
+ (NMSSHLogger *)logger {
static NMSSHLogger *logger = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
logger = [[NMSSHLogger alloc] init];
[logger setEnabled:YES];
[logger setLogLevel:NMSSHLogLevelVerbose];
[logger setLogBlock:^(NMSSHLogLevel level, NSString *format) {
NSLog(@"%@", format);
}];
[logger setLoggerQueue:dispatch_queue_create("NMSSH.loggerQueue", DISPATCH_QUEUE_SERIAL)];
});
return logger;
}
+ (instancetype) sharedLogger
{
return NMSSHLogger.logger;
}
#if !(OS_OBJECT_USE_OBJC)
- (void)dealloc {
dispatch_release(self.loggerQueue);
}
#endif
// -----------------------------------------------------------------------------
#pragma mark - LOGGING
// -----------------------------------------------------------------------------
- (void)log:(NSString *)format level:(NMSSHLogLevel)level flag:(NMSSHLogFlag)flag {
if (flag & self.logLevel && self.enabled && self.logBlock) {
dispatch_async(self.loggerQueue, ^{
self.logBlock(level, [NSString stringWithFormat:@"NMSSH: %@", format]);
});
}
}
- (void)logVerbose:(NSString *)format {
[self log:format level:NMSSHLogLevelVerbose flag:NMSSHLogFlagVerbose];
}
- (void)logInfo:(NSString *)format{
[self log:format level:NMSSHLogLevelInfo flag:NMSSHLogFlagInfo];
}
- (void)logWarn:(NSString *)format{
[self log:format level:NMSSHLogLevelWarn flag:NMSSHLogFlagWarn];
}
- (void)logError:(NSString *)format{
[self log:format level:NMSSHLogLevelError flag:NMSSHLogFlagError];
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Config/socket_helper.h
================================================
#import "libssh2.h"
int waitsocket(int socket_fd, LIBSSH2_SESSION *session);
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Config/socket_helper.m
================================================
#import "socket_helper.h"
#import
int waitsocket(int socket_fd, LIBSSH2_SESSION *session) {
struct timeval timeout;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int rc;
int dir;
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
// Now make sure we wait in the correct direction
dir = libssh2_session_block_directions(session);
if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) {
readfd = &fd;
}
if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
writefd = &fd;
}
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
return rc;
}
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSFTP.h
================================================
#import "NMSSH.h"
@class NMSSHSession, NMSFTPFile;
/**
NMSFTP provides functionality for working with SFTP servers.
*/
@interface NMSFTP : NSObject
/** A valid NMSSHSession instance */
@property (nonatomic, readonly) NMSSHSession *session;
/** Property that keeps track of connection status to the server */
@property (nonatomic, readonly, getter = isConnected) BOOL connected;
/** Property that set/get read buffer size */
@property (nonatomic) NSUInteger bufferSize;
///-----------------------------------------------------------------------------
/// @name Initializer
/// ----------------------------------------------------------------------------
/**
Create a new NMSFTP instance and connect it.
@param session A valid, connected, NMSSHSession instance
@returns Connected NMSFTP instance
*/
+ (instancetype)connectWithSession:(NMSSHSession *)session;
/**
Create a new NMSFTP instance.
@param session A valid, connected, NMSSHSession instance
@returns New NMSFTP instance
*/
- (instancetype)initWithSession:(NMSSHSession *)session;
/// ----------------------------------------------------------------------------
/// @name Connection
/// ----------------------------------------------------------------------------
/**
Create and connect to a SFTP session
@returns Connection status
*/
- (BOOL)connect;
/**
Disconnect SFTP session
*/
- (void)disconnect;
/// ----------------------------------------------------------------------------
/// @name Manipulate file system entries
/// ----------------------------------------------------------------------------
/**
Move or rename an item
@param sourcePath Item to move
@param destPath Destination to move to
@returns Move success
*/
- (BOOL)moveItemAtPath:(NSString *)sourcePath toPath:(NSString *)destPath;
/// ----------------------------------------------------------------------------
/// @name Manipulate directories
/// ----------------------------------------------------------------------------
/**
Test if a directory exists at the specified path.
Note: Will return NO if a file exists at the path, but not a directory.
@param path Path to check
@returns YES if file exists
*/
- (BOOL)directoryExistsAtPath:(NSString *)path;
/**
Create a directory at path
@param path Path to directory
@returns Creation success
*/
- (BOOL)createDirectoryAtPath:(NSString *)path;
/**
Remove directory at path
@param path Existing directory
@returns Remove success
*/
- (BOOL)removeDirectoryAtPath:(NSString *)path;
/**
Get a list of files for a directory path
@param path Existing directory to list items from
@returns List of relative paths
*/
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path;
/// ----------------------------------------------------------------------------
/// @name Manipulate symlinks and files
/// ----------------------------------------------------------------------------
/**
Reads the attributes from a file.
@param path An existing file path
@return A NMSFTPFile that contains the fetched file attributes.
*/
- (NMSFTPFile *)infoForFileAtPath:(NSString *)path;
/**
Test if a file exists at the specified path.
Note: Will return NO if a directory exists at the path, but not a file.
@param path Path to check
@returns YES if file exists
*/
- (BOOL)fileExistsAtPath:(NSString *)path;
/**
Create a symbolic link
@param linkPath Path that will be linked to
@param destPath Path the link will be created at
@returns Creation success
*/
- (BOOL)createSymbolicLinkAtPath:(NSString *)linkPath
withDestinationPath:(NSString *)destPath;
/**
Remove file at path
@param path Path to existing file
@returns Remove success
*/
- (BOOL)removeFileAtPath:(NSString *)path;
/**
Read the contents of a file
@param path An existing file path
@returns File contents
*/
- (NSData *)contentsAtPath:(NSString *)path;
/**
Refer to contentsAtPath:
This adds the ability to get periodic updates to bytes received.
@param path An existing file path
@param progress Method called periodically with number of bytes downloaded and total file size.
Returns NO to abort.
@returns File contents
*/
- (NSData *)contentsAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger got, NSUInteger totalBytes))progress;
/**
Overwrite the contents of a file
If no file exists, one is created.
@param contents Bytes to write
@param path File path to write bytes at
@returns Write success
*/
- (BOOL)writeContents:(NSData *)contents toFileAtPath:(NSString *)path;
/**
Refer to writeContents:toFileAtPath:
This adds the ability to get periodic updates to bytes sent.
@param contents Bytes to write
@param path File path to write bytes at
@param progress Method called periodically with number of bytes sent.
Returns NO to abort.
@returns Write success
*/
- (BOOL)writeContents:(NSData *)contents toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger sent))progress;
/**
Overwrite the contents of a file
If no file exists, one is created.
@param localPath File path to read bytes at
@param path File path to write bytes at
@returns Write success
*/
- (BOOL)writeFileAtPath:(NSString *)localPath toFileAtPath:(NSString *)path;
/**
Refer to writeFileAtPath:toFileAtPath:
This adds the ability to get periodic updates to bytes sent.
@param localPath File path to read bytes at
@param path File path to write bytes at
@param progress Method called periodically with number of bytes sent.
Returns NO to abort.
@returns Write success
*/
- (BOOL)writeFileAtPath:(NSString *)localPath toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger sent))progress;
/**
Overwrite the contents of a file
If no file exists, one is created.
@param inputStream Stream to read bytes from
@param path File path to write bytes at
@returns Write success
*/
- (BOOL)writeStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path;
/**
Refer to writeStream:toFileAtPath:
This adds the ability to get periodic updates to bytes sent.
@param inputStream Stream to read bytes from
@param path File path to write bytes at
@param progress Method called periodically with number of bytes sent.
Returns NO to abort.
@returns Write success
*/
- (BOOL)writeStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger sent))progress;
/**
Append contents to the end of a file
If no file exists, one is created.
@param contents Bytes to write
@param path File path to write bytes at
@returns Append success
*/
- (BOOL)appendContents:(NSData *)contents toFileAtPath:(NSString *)path;
/**
Append contents to the end of a file
If no file exists, one is created.
@param inputStream Stream to write bytes from
@param path File path to write bytes at
@returns Append success
*/
- (BOOL)appendStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path;
/**
Copy a file remotely.
@param fromPath Path to copy from
@param toPath Path to copy to
*/
- (BOOL)copyContentsOfPath:(NSString *)fromPath toFileAtPath:(NSString *)toPath progress:(BOOL (^)(NSUInteger copied, NSUInteger totalBytes))progress;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSFTP.m
================================================
#import "NMSFTP.h"
#import "NMSSH+Protected.h"
@interface NMSFTP ()
@property (nonatomic, strong) NMSSHSession *session;
@property (nonatomic, assign) LIBSSH2_SFTP *sftpSession;
@property (nonatomic, readwrite, getter = isConnected) BOOL connected;
- (BOOL)writeStream:(NSInputStream *)inputStream toSFTPHandle:(LIBSSH2_SFTP_HANDLE *)handle;
- (BOOL)writeStream:(NSInputStream *)inputStream toSFTPHandle:(LIBSSH2_SFTP_HANDLE *)handle progress:(BOOL (^)(NSUInteger))progress;
@end
@implementation NMSFTP
// -----------------------------------------------------------------------------
#pragma mark - INITIALIZER
// -----------------------------------------------------------------------------
+ (instancetype)connectWithSession:(NMSSHSession *)session {
NMSFTP *sftp = [[NMSFTP alloc] initWithSession:session];
[sftp connect];
return sftp;
}
- (instancetype)initWithSession:(NMSSHSession *)session {
if ((self = [super init])) {
[self setSession:session];
// Make sure we were provided a valid session
if (![session isKindOfClass:[NMSSHSession class]]) {
@throw @"You have to provide a valid NMSSHSession!";
}
}
return self;
}
// -----------------------------------------------------------------------------
#pragma mark - CONNECTION
// -----------------------------------------------------------------------------
- (BOOL)connect {
// Set blocking mode
libssh2_session_set_blocking(self.session.rawSession, 1);
[self setSftpSession:libssh2_sftp_init(self.session.rawSession)];
if (!self.sftpSession) {
NMSSHLogError(@"Unable to init SFTP session");
return NO;
}
[self setConnected:YES];
[self setBufferSize:kNMSSHBufferSize];
return self.isConnected;
}
- (void)disconnect {
libssh2_sftp_shutdown(self.sftpSession);
[self setConnected:NO];
}
// -----------------------------------------------------------------------------
#pragma mark - MANIPULATE FILE SYSTEM ENTRIES
// -----------------------------------------------------------------------------
- (BOOL)moveItemAtPath:(NSString *)sourcePath toPath:(NSString *)destPath {
return libssh2_sftp_rename(self.sftpSession, [sourcePath UTF8String], [destPath UTF8String]) == 0;
}
// -----------------------------------------------------------------------------
#pragma mark - MANIPULATE DIRECTORIES
// -----------------------------------------------------------------------------
- (LIBSSH2_SFTP_HANDLE *)openDirectoryAtPath:(NSString *)path {
LIBSSH2_SFTP_HANDLE *handle = libssh2_sftp_opendir(self.sftpSession, [path UTF8String]);
if (!handle) {
NSError *error = [self.session lastError];
NMSSHLogError(@"Could not open directory at path %@ (Error %li: %@)", path, (long)error.code, error.localizedDescription);
if ([error code] == LIBSSH2_ERROR_SFTP_PROTOCOL) {
NMSSHLogError(@"SFTP error %lu", libssh2_sftp_last_error(self.sftpSession));
}
}
return handle;
}
- (BOOL)directoryExistsAtPath:(NSString *)path {
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path flags:LIBSSH2_FXF_READ mode:0];
if (!handle) {
return NO;
}
LIBSSH2_SFTP_ATTRIBUTES fileAttributes;
int rc = libssh2_sftp_fstat(handle, &fileAttributes);
libssh2_sftp_close(handle);
return rc == 0 && LIBSSH2_SFTP_S_ISDIR(fileAttributes.permissions);
}
- (BOOL)createDirectoryAtPath:(NSString *)path {
int rc = libssh2_sftp_mkdir(self.sftpSession, [path UTF8String],
LIBSSH2_SFTP_S_IRWXU|
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IXGRP|
LIBSSH2_SFTP_S_IROTH|LIBSSH2_SFTP_S_IXOTH);
return rc == 0;
}
- (BOOL)removeDirectoryAtPath:(NSString *)path {
return libssh2_sftp_rmdir(self.sftpSession, [path UTF8String]) == 0;
}
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path {
LIBSSH2_SFTP_HANDLE *handle = [self openDirectoryAtPath:path];
if (!handle) {
return nil;
}
NSArray *ignoredFiles = @[@".", @".."];
NSMutableArray *contents = [NSMutableArray array];
int rc;
do {
char buffer[512];
LIBSSH2_SFTP_ATTRIBUTES fileAttributes;
rc = libssh2_sftp_readdir(handle, buffer, sizeof(buffer), &fileAttributes);
if (rc > 0) {
NSString *fileName = [[NSString alloc] initWithBytes:buffer length:rc encoding:NSUTF8StringEncoding];
if (![ignoredFiles containsObject:fileName]) {
// Append a "/" at the end of all directories
if (LIBSSH2_SFTP_S_ISDIR(fileAttributes.permissions)) {
fileName = [fileName stringByAppendingString:@"/"];
}
NMSFTPFile *file = [[NMSFTPFile alloc] initWithFilename:fileName];
[file populateValuesFromSFTPAttributes:fileAttributes];
[contents addObject:file];
}
}
} while (rc > 0);
if (rc < 0) {
NMSSHLogError(@"Unable to read directory");
}
rc = libssh2_sftp_closedir(handle);
if (rc < 0) {
NMSSHLogError(@"Failed to close directory");
}
return [contents sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
}
// -----------------------------------------------------------------------------
#pragma mark - MANIPULATE SYMLINKS AND FILES
// -----------------------------------------------------------------------------
- (NMSFTPFile *)infoForFileAtPath:(NSString *)path {
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path flags:LIBSSH2_FXF_READ mode:0];
if (!handle) {
return nil;
}
LIBSSH2_SFTP_ATTRIBUTES fileAttributes;
ssize_t rc = libssh2_sftp_fstat(handle, &fileAttributes);
libssh2_sftp_close(handle);
if (rc < 0) {
return nil;
}
NMSFTPFile *file = [[NMSFTPFile alloc] initWithFilename:path.lastPathComponent];
[file populateValuesFromSFTPAttributes:fileAttributes];
return file;
}
- (LIBSSH2_SFTP_HANDLE *)openFileAtPath:(NSString *)path flags:(unsigned long)flags mode:(long)mode {
LIBSSH2_SFTP_HANDLE *handle = libssh2_sftp_open(self.sftpSession, [path UTF8String], flags, mode);
if (!handle) {
NSError *error = [self.session lastError];
NMSSHLogError(@"Could not open file at path %@ (Error %li: %@)", path, (long)error.code, error.localizedDescription);
if ([error code] == LIBSSH2_ERROR_SFTP_PROTOCOL) {
NMSSHLogError(@"SFTP error %lu", libssh2_sftp_last_error(self.sftpSession));
}
}
return handle;
}
- (BOOL)fileExistsAtPath:(NSString *)path {
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path flags:LIBSSH2_FXF_READ mode:0];
if (!handle) {
return NO;
}
LIBSSH2_SFTP_ATTRIBUTES fileAttributes;
int rc = libssh2_sftp_fstat(handle, &fileAttributes);
libssh2_sftp_close(handle);
return rc == 0 && !LIBSSH2_SFTP_S_ISDIR(fileAttributes.permissions);
}
- (BOOL)createSymbolicLinkAtPath:(NSString *)linkPath
withDestinationPath:(NSString *)destPath {
int rc = libssh2_sftp_symlink(self.sftpSession, [destPath UTF8String], (char *)[linkPath UTF8String]);
return rc == 0;
}
- (BOOL)removeFileAtPath:(NSString *)path {
return libssh2_sftp_unlink(self.sftpSession, [path UTF8String]) == 0;
}
- (NSData *)contentsAtPath:(NSString *)path {
return [self contentsAtPath:path progress:nil];
}
- (NSData *)contentsAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger, NSUInteger))progress {
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path flags:LIBSSH2_FXF_READ mode:0];
if (!handle) {
return nil;
}
NMSFTPFile *file = [self infoForFileAtPath:path];
if (!file) {
NMSSHLogWarn(@"contentsAtPath:progress: failed to get file attributes");
return nil;
}
char buffer[self.bufferSize];
NSMutableData *data = [[NSMutableData alloc] init];
ssize_t rc;
off_t got = 0;
while ((rc = libssh2_sftp_read(handle, buffer, (ssize_t)sizeof(buffer))) > 0) {
[data appendBytes:buffer length:rc];
got += rc;
if (progress && !progress((NSUInteger)got, (NSUInteger)[file.fileSize integerValue])) {
libssh2_sftp_close(handle);
return nil;
}
}
libssh2_sftp_close(handle);
if (rc < 0) {
return nil;
}
return [data copy];
}
- (BOOL)writeContents:(NSData *)contents toFileAtPath:(NSString *)path {
return [self writeContents:contents toFileAtPath:path progress:nil];
}
- (BOOL)writeContents:(NSData *)contents toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger))progress {
return [self writeStream:[NSInputStream inputStreamWithData:contents] toFileAtPath:path progress:progress];
}
- (BOOL)writeFileAtPath:(NSString *)localPath toFileAtPath:(NSString *)path {
return [self writeFileAtPath:localPath toFileAtPath:path progress:nil];
}
- (BOOL)writeFileAtPath:(NSString *)localPath toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger))progress {
return [self writeStream:[NSInputStream inputStreamWithFileAtPath:localPath] toFileAtPath:path progress:progress];
}
- (BOOL)writeStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path {
return [self writeStream:inputStream toFileAtPath:path progress:nil];
}
- (BOOL)writeStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path progress:(BOOL (^)(NSUInteger))progress {
if ([inputStream streamStatus] == NSStreamStatusNotOpen) {
[inputStream open];
}
if (![inputStream hasBytesAvailable]) {
NMSSHLogWarn(@"No bytes available in the stream");
return NO;
}
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path
flags:LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC
mode:LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH];
if (!handle) {
[inputStream close];
return NO;
}
BOOL success = [self writeStream:inputStream toSFTPHandle:handle progress:progress];
libssh2_sftp_close(handle);
[inputStream close];
return success;
}
- (BOOL)appendContents:(NSData *)contents toFileAtPath:(NSString *)path {
return [self appendStream:[NSInputStream inputStreamWithData:contents] toFileAtPath:path];
}
- (BOOL)appendStream:(NSInputStream *)inputStream toFileAtPath:(NSString *)path {
if ([inputStream streamStatus] == NSStreamStatusNotOpen) {
[inputStream open];
}
if (![inputStream hasBytesAvailable]) {
NMSSHLogWarn(@"No bytes available in the stream");
return NO;
}
LIBSSH2_SFTP_HANDLE *handle = [self openFileAtPath:path
flags:LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_READ
mode:LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH];
if (!handle) {
[inputStream close];
return NO;
}
LIBSSH2_SFTP_ATTRIBUTES attributes;
if (libssh2_sftp_fstat(handle, &attributes) < 0) {
[inputStream close];
NMSSHLogError(@"Unable to get attributes of file %@", path);
return NO;
}
libssh2_sftp_seek64(handle, attributes.filesize);
NMSSHLogVerbose(@"Seek to position %ld", (long)attributes.filesize);
BOOL success = [self writeStream:inputStream toSFTPHandle:handle];
libssh2_sftp_close(handle);
[inputStream close];
return success;
}
- (BOOL)writeStream:(NSInputStream *)inputStream toSFTPHandle:(LIBSSH2_SFTP_HANDLE *)handle {
return [self writeStream:inputStream toSFTPHandle:handle progress:nil];
}
- (BOOL)writeStream:(NSInputStream *)inputStream toSFTPHandle:(LIBSSH2_SFTP_HANDLE *)handle progress:(BOOL (^)(NSUInteger))progress {
uint8_t buffer[self.bufferSize];
NSInteger bytesRead = -1;
long rc = 0;
NSUInteger total = 0;
while (rc >= 0 && [inputStream hasBytesAvailable]) {
bytesRead = [inputStream read:buffer maxLength:self.bufferSize];
if (bytesRead > 0) {
uint8_t *ptr = buffer;
do {
rc = libssh2_sftp_write(handle, (const char *)ptr, bytesRead);
if(rc < 0){
NMSSHLogWarn(@"libssh2_sftp_write failed (Error %li)", rc);
break;
}
total += rc;
ptr += rc;
bytesRead -= rc;
if (progress && !progress(total))
{
return NO;
}
}while(bytesRead);
}
}
if (bytesRead < 0 || rc < 0) {
return NO;
}
return YES;
}
- (BOOL)copyContentsOfPath:(NSString *)fromPath toFileAtPath:(NSString *)toPath progress:(BOOL (^)(NSUInteger, NSUInteger))progress
{
// Open handle for reading.
LIBSSH2_SFTP_HANDLE *fromHandle = [self openFileAtPath:fromPath flags:LIBSSH2_FXF_READ mode:0];
// Open handle for writing.
LIBSSH2_SFTP_HANDLE *toHandle = [self openFileAtPath:toPath
flags:LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_READ
mode:LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH];
// Get information about the file to copy.
NMSFTPFile *file = [self infoForFileAtPath:fromPath];
if (!file) {
NMSSHLogWarn(@"contentsAtPath:progress: failed to get file attributes");
return NO;
}
char buffer[self.bufferSize];
ssize_t bytesRead;
off_t copied = 0;
long rc = 0;
while ((bytesRead = libssh2_sftp_read(fromHandle, buffer, (ssize_t)sizeof(buffer))) > 0) {
if (bytesRead > 0) {
char *ptr = buffer;
do {
rc = libssh2_sftp_write(toHandle, (const char *)ptr, (NSInteger)bytesRead);
if(rc < 0){
NMSSHLogWarn(@"libssh2_sftp_write failed (Error %li)", rc);
break;
}
copied += rc;
ptr += rc;
bytesRead -= rc;
if (progress && !progress((NSUInteger)copied, (NSUInteger)[file.fileSize integerValue])) {
libssh2_sftp_close(fromHandle);
libssh2_sftp_close(toHandle);
return NO;
}
}while(bytesRead);
}
}
libssh2_sftp_close(fromHandle);
libssh2_sftp_close(toHandle);
return YES;
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSFTPFile.h
================================================
#import "NMSSH.h"
/**
The NMSFTPFile class provides an interface to store file attributes retrieved
from a SFTP host.
*/
@interface NMSFTPFile : NSObject
/**
Property that stores the name of the underlaying file.
Note that the file may also be a directory.
*/
@property (nonatomic, readonly) NSString *filename;
/** Property that declares whether the file is a directory or a regular file */
@property (nonatomic, readonly) BOOL isDirectory;
/** Returns the last modification date of the file */
@property (nonatomic, readonly) NSDate *modificationDate;
/** Returns the date of the last access to the file */
@property (nonatomic, readonly) NSDate *lastAccess;
/** Property that returns the file size in bytes */
@property (nonatomic, readonly) NSNumber *fileSize;
/** Returns the numeric identifier of the user that is the owner of the file */
@property (nonatomic, readonly) unsigned long ownerUserID;
/** Returns the numeric identifier of the group that is the owner of the file */
@property (nonatomic, readonly) unsigned long ownerGroupID;
/** Returns the file permissions in symbolic notation. E.g. drwxr-xr-x */
@property (nonatomic, readonly) NSString *permissions;
/** Returns the user defined flags for the file */
@property (nonatomic, readonly) u_long flags;
/**
Initializes an NMSFTPFile instance and sets the filename.
@param filename The name of the underlaying file.
@return A new NMSFTPFile instance initialized with the corresponding filename.
*/
- (instancetype)initWithFilename:(NSString *)filename;
/**
Convenience initializer for creating an NMSFTPFile instance with a defined filename.
@param filename The name of the underlaying file.
@return A new NMSFTPFile instance initialized with the corresponding filename.
*/
+ (instancetype)fileWithName:(NSString *)filename;
/**
Populates the file properties with the attributes taken from the LIBSSH2_SFTP_ATTRIBUTES object.
@param fileAttributes The LIBSSH2_SFTP_ATTRIBUTES object that contains the attributes that are being extracted.
*/
- (void)populateValuesFromSFTPAttributes:(LIBSSH2_SFTP_ATTRIBUTES)fileAttributes;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSFTPFile.m
================================================
#import "NMSFTPFile.h"
#import "NMSSH+Protected.h"
@interface NMSFTPFile ()
@property (nonatomic, strong) NSString *filename;
@property (nonatomic, readwrite) BOOL isDirectory;
@property (nonatomic, strong) NSDate *modificationDate;
@property (nonatomic, strong) NSDate *lastAccess;
@property (nonatomic, strong) NSNumber *fileSize;
@property (nonatomic, readwrite) unsigned long ownerUserID;
@property (nonatomic, readwrite) unsigned long ownerGroupID;
@property (nonatomic, strong) NSString *permissions;
@property (nonatomic, readwrite) u_long flags;
@end
@implementation NMSFTPFile
- (instancetype)initWithFilename:(NSString *)filename {
if ((self = [super init])) {
[self setFilename:filename];
}
return self;
}
+ (instancetype)fileWithName:(NSString *)filename {
return [[self alloc] initWithFilename:filename];
}
- (void)populateValuesFromSFTPAttributes:(LIBSSH2_SFTP_ATTRIBUTES)fileAttributes {
[self setModificationDate:[NSDate dateWithTimeIntervalSince1970:fileAttributes.mtime]];
[self setLastAccess:[NSDate dateWithTimeIntervalSinceNow:fileAttributes.atime]];
[self setFileSize:@(fileAttributes.filesize)];
[self setOwnerUserID:fileAttributes.uid];
[self setOwnerGroupID:fileAttributes.gid];
[self setPermissions:[self convertPermissionToSymbolicNotation:fileAttributes.permissions]];
[self setIsDirectory:LIBSSH2_SFTP_S_ISDIR(fileAttributes.permissions)];
[self setFlags:fileAttributes.flags];
}
#pragma mark - Comparison and Equality
/**
Ensures that the sorting of the files is according to their filenames.
@param file The other file that it should be compared to.
@return The comparison result that determins the order of the two files.
*/
- (NSComparisonResult)compare:(NMSFTPFile *)file {
return [self.filename localizedCaseInsensitiveCompare:file.filename];
}
/**
Defines that two NMSFTPFile objects are equal, if their filenames are equal.
@param object The other file that it should be compared with
@return YES in case the two objects are considered equal, NO otherwise.
*/
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[NMSFTPFile class]]) {
return NO;
}
return [self.filename isEqualToString:((NMSFTPFile *)object).filename];
}
#pragma mark - Permissions conversion methods
/**
Convert a mode field into "ls -l" type perms field. By courtesy of Jonathan Leffler
http://stackoverflow.com/questions/10323060/printing-file-permissions-like-ls-l-using-stat2-in-c
@param mode The numeric mode that is returned by the 'stat' function
@return A string containing the symbolic representation of the file permissions.
*/
- (NSString *)convertPermissionToSymbolicNotation:(unsigned long)mode {
static char *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
char bits[11];
bits[0] = [self filetypeletter:mode];
strcpy(&bits[1], rwx[(mode >> 6)& 7]);
strcpy(&bits[4], rwx[(mode >> 3)& 7]);
strcpy(&bits[7], rwx[(mode & 7)]);
if (mode & S_ISUID) {
bits[3] = (mode & 0100) ? 's' : 'S';
}
if (mode & S_ISGID) {
bits[6] = (mode & 0010) ? 's' : 'l';
}
if (mode & S_ISVTX) {
bits[9] = (mode & 0100) ? 't' : 'T';
}
bits[10] = '\0';
return [NSString stringWithCString:bits encoding:NSUTF8StringEncoding];
}
/**
Extracts the unix letter for the file type of the given permission value.
@param mode The numeric mode that is returned by the 'stat' function
@return A character that represents the given file type.
*/
- (char)filetypeletter:(unsigned long)mode {
char c;
if (S_ISREG(mode)) {
c = '-';
}
else if (S_ISDIR(mode)) {
c = 'd';
}
else if (S_ISBLK(mode)) {
c = 'b';
}
else if (S_ISCHR(mode)) {
c = 'c';
}
#ifdef S_ISFIFO
else if (S_ISFIFO(mode)) {
c = 'p';
}
#endif
#ifdef S_ISLNK
else if (S_ISLNK(mode)) {
c = 'l';
}
#endif
#ifdef S_ISSOCK
else if (S_ISSOCK(mode)) {
c = 's';
}
#endif
#ifdef S_ISDOOR
// Solaris 2.6, etc.
else if (S_ISDOOR(mode)) {
c = 'D';
}
#endif
else {
// Unknown type -- possibly a regular file?
c = '?';
}
return c;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p> Filename: %@", NSStringFromClass([self class]), self, self.filename];
}
- (id)copyWithZone:(NSZone *)zone {
NMSFTPFile *object = [[[self class] allocWithZone:zone] init];
if (object) {
object.filename = [self.filename copyWithZone:zone];
object.modificationDate = [self.modificationDate copyWithZone:zone];
object.lastAccess = [self.lastAccess copyWithZone:zone];
object.fileSize = [self.fileSize copyWithZone:zone];
object.permissions = [self.permissions copyWithZone:zone];
object.isDirectory = self.isDirectory;
object.ownerUserID = self.ownerUserID;
object.ownerGroupID = self.ownerGroupID;
object.flags = self.flags;
}
return object;
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSH.h
================================================
#import
#ifndef _NMSSH_
#define _NMSSH_
#import "libssh2.h"
#import "libssh2_sftp.h"
#import "NMSSHSessionDelegate.h"
#import "NMSSHChannelDelegate.h"
#import "NMSSHSession.h"
#import "NMSSHChannel.h"
#import "NMSFTP.h"
#import "NMSFTPFile.h"
#import "NMSSHConfig.h"
#import "NMSSHHostConfig.h"
#import "NMSSHLogger.h"
#endif
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHChannel.h
================================================
#import "NMSSH.h"
@class NMSSHSession;
@protocol NMSSHChannelDelegate;
typedef NS_ENUM(NSInteger, NMSSHChannelError) {
NMSSHChannelExecutionError,
NMSSHChannelExecutionResponseError,
NMSSHChannelRequestPtyError,
NMSSHChannelExecutionTimeout,
NMSSHChannelAllocationError,
NMSSHChannelRequestShellError,
NMSSHChannelWriteError,
NMSSHChannelReadError
};
typedef NS_ENUM(NSInteger, NMSSHChannelPtyTerminal) {
NMSSHChannelPtyTerminalVanilla,
NMSSHChannelPtyTerminalVT100,
NMSSHChannelPtyTerminalVT102,
NMSSHChannelPtyTerminalVT220,
NMSSHChannelPtyTerminalAnsi,
NMSSHChannelPtyTerminalXterm
};
typedef NS_ENUM(NSInteger, NMSSHChannelType) {
NMSSHChannelTypeClosed, // Channel = NULL
NMSSHChannelTypeExec,
NMSSHChannelTypeShell,
NMSSHChannelTypeSCP,
NMSSHChannelTypeSubsystem // Not supported by NMSSH framework
};
/**
NMSSHChannel provides functionality to work with SSH shells and SCP.
*/
@interface NMSSHChannel : NSObject
/** A valid NMSSHSession instance */
@property (nonatomic, readonly) NMSSHSession *session;
/** Size of the buffers used by the channel, defaults to 0x4000 */
@property (nonatomic, assign) NSUInteger bufferSize;
/// ----------------------------------------------------------------------------
/// @name Setting the Delegate
/// ----------------------------------------------------------------------------
/**
The receiver’s `delegate`.
You can use the `delegate` to receive asynchronous read from a shell.
*/
@property (nonatomic, weak) id delegate;
/// ----------------------------------------------------------------------------
/// @name Initializer
/// ----------------------------------------------------------------------------
/** Current channel type or `NMSSHChannelTypeClosed` if the channel is closed */
@property (nonatomic, readonly) NMSSHChannelType type;
/**
Create a new NMSSHChannel instance.
@param session A valid, connected, NMSSHSession instance
@returns New NMSSHChannel instance
*/
- (instancetype)initWithSession:(NMSSHSession *)session;
/// ----------------------------------------------------------------------------
/// @name Shell command execution
/// ----------------------------------------------------------------------------
/** The last response from a shell command execution */
@property (nonatomic, readonly) NSString *lastResponse;
/** Request a pseudo terminal before executing a command */
@property (nonatomic, assign) BOOL requestPty;
/** Terminal emulation mode if a PTY is requested, defaults to vanilla */
@property (nonatomic, assign) NMSSHChannelPtyTerminal ptyTerminalType;
/**
Execute a shell command on the server.
If an error occurs, it will return `nil` and populate the error object.
If requestPty is enabled request a pseudo terminal before running the
command.
@param command Any shell script that is available on the server
@param error Error handler
@returns Shell command response
*/
- (NSString *)execute:(NSString *)command error:(NSError **)error;
/**
Execute a shell command on the server with a given timeout.
If an error occurs or the connection timed out, it will return `nil` and populate the error object.
If requestPty is enabled request a pseudo terminal before running the
command.
@param command Any shell script that is available on the server
@param error Error handler
@param timeout The time to wait (in seconds) before giving up on the request
@returns Shell command response
*/
- (NSString *)execute:(NSString *)command error:(NSError **)error timeout:(NSNumber *)timeout;
/// ----------------------------------------------------------------------------
/// @name Remote shell session
/// ----------------------------------------------------------------------------
/** User-defined environment variables for the session, defaults to `nil` */
@property (nonatomic, strong) NSDictionary *environmentVariables;
/**
Request a remote shell on the channel.
If an error occurs, it will return NO and populate the error object.
If requestPty is enabled request a pseudo terminal before running the
command.
@param error Error handler
@returns Shell initialization success
*/
- (BOOL)startShell:(NSError **)error;
/**
Close a remote shell on an active channel.
*/
- (void)closeShell;
/**
Write a command on the remote shell.
If an error occurs or the connection timed out, it will return NO and populate the error object.
@param command Any command that is available on the server
@param error Error handler
@returns Shell write success
*/
- (BOOL)write:(NSString *)command error:(NSError **)error;
/**
Write a command on the remote shell with a given timeout.
If an error occurs or the connection timed out, it will return NO and populate the error object.
@param command Any command that is available on the server
@param error Error handler
@param timeout The time to wait (in seconds) before giving up on the request
@returns Shell write success
*/
- (BOOL)write:(NSString *)command error:(NSError **)error timeout:(NSNumber *)timeout;
/**
Write data on the remote shell.
If an error occurs or the connection timed out, it will return NO and populate the error object.
@param data Any data
@param error Error handler
@returns Shell write success
*/
- (BOOL)writeData:(NSData *)data error:(NSError **)error;
/**
Write data on the remote shell with a given timeout.
If an error occurs or the connection timed out, it will return NO and populate the error object.
@param data Any data
@param error Error handler
@param timeout The time to wait (in seconds) before giving up on the request
@returns Shell write success
*/
- (BOOL)writeData:(NSData *)data error:(NSError **)error timeout:(NSNumber *)timeout;
/**
Request size for the remote pseudo terminal.
This method should be called only after startShell:
@param width Width in characters for terminal
@param height Height in characters for terminal
@returns Size change success
*/
- (BOOL)requestSizeWidth:(NSUInteger)width height:(NSUInteger)height;
/// ----------------------------------------------------------------------------
/// @name SCP file transfer
/// ----------------------------------------------------------------------------
/**
Upload a local file to a remote server.
If to: specifies a directory, the file name from the original file will be
used.
@param localPath Path to a file on the local computer
@param remotePath Path to save the file to
@returns SCP upload success
*/
- (BOOL)uploadFile:(NSString *)localPath to:(NSString *)remotePath;
/**
Download a remote file to local the filesystem.
If to: specifies a directory, the file name from the original file will be
used.
@param remotePath Path to a file on the remote server
@param localPath Path to save the file to
@returns SCP download success
*/
- (BOOL)downloadFile:(NSString *)remotePath to:(NSString *)localPath;
/**
Download a remote file to local the filesystem.
If to: specifies a directory, the file name from the original file will be
used.
@param remotePath Path to a file on the remote server
@param localPath Path to save the file to
@param progress Method called periodically with number of bytes downloaded and total file size.
Returns NO to abort.
@returns SCP download success
*/
- (BOOL)downloadFile:(NSString *)remotePath
to:(NSString *)localPath
progress:(BOOL (^)(NSUInteger, NSUInteger))progress;
/**
Upload a local file to a remote server.
If to: specifies a directory, the file name from the original file will be
used.
@param localPath Path to a file on the local computer
@param remotePath Path to save the file to
@param progress Method called periodically with number of bytes uploaded. Returns NO to abort.
@returns SCP upload success
*/
- (BOOL)uploadFile:(NSString *)localPath
to:(NSString *)remotePath
progress:(BOOL (^)(NSUInteger))progress;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHChannel.m
================================================
#import "NMSSHChannel.h"
#import "NMSSH+Protected.h"
@interface NMSSHChannel ()
@property (nonatomic, strong) NMSSHSession *session;
@property (nonatomic, assign) LIBSSH2_CHANNEL *channel;
@property (nonatomic, readwrite) NMSSHChannelType type;
@property (nonatomic, assign) const char *ptyTerminalName;
@property (nonatomic, strong) NSString *lastResponse;
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong) dispatch_source_t source;
#else
@property (nonatomic, assign) dispatch_source_t source;
#endif
@end
@implementation NMSSHChannel
// -----------------------------------------------------------------------------
#pragma mark - INITIALIZER
// -----------------------------------------------------------------------------
- (instancetype)initWithSession:(NMSSHSession *)session {
if ((self = [super init])) {
[self setSession:session];
[self setBufferSize:kNMSSHBufferSize];
[self setRequestPty:NO];
[self setPtyTerminalType:NMSSHChannelPtyTerminalVanilla];
[self setType:NMSSHChannelTypeClosed];
// Make sure we were provided a valid session
if (![self.session isKindOfClass:[NMSSHSession class]]) {
@throw @"You have to provide a valid NMSSHSession!";
}
}
return self;
}
- (BOOL)openChannel:(NSError *__autoreleasing *)error {
if (self.channel != NULL) {
NMSSHLogWarn(@"The channel will be closed before continue");
if (self.type == NMSSHChannelTypeShell) {
[self closeShell];
}
else {
[self closeChannel];
}
}
// Set blocking mode
libssh2_session_set_blocking(self.session.rawSession, 1);
// Open up the channel
LIBSSH2_CHANNEL *channel = libssh2_channel_open_session(self.session.rawSession);
if (channel == NULL){
NMSSHLogError(@"Unable to open a session");
if (error) {
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelAllocationError
userInfo:@{ NSLocalizedDescriptionKey : @"Channel allocation error" }];
}
return NO;
}
[self setChannel:channel];
// Try to set environment variables
if (self.environmentVariables) {
for (NSString *key in self.environmentVariables) {
if ([key isKindOfClass:[NSString class]] && [[self.environmentVariables objectForKey:key] isKindOfClass:[NSString class]]) {
libssh2_channel_setenv(self.channel, [key UTF8String], [[self.environmentVariables objectForKey:key] UTF8String]);
}
}
}
int rc = 0;
// If requested, try to allocate a pty
if (self.requestPty) {
rc = libssh2_channel_request_pty(self.channel, self.ptyTerminalName);
if (rc != 0) {
if (error) {
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error requesting %s pty: %@", self.ptyTerminalName, [[self.session lastError] localizedDescription]] };
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelRequestPtyError
userInfo:userInfo];
}
NMSSHLogError(@"Error requesting pseudo terminal");
[self closeChannel];
return NO;
}
}
return YES;
}
- (void)closeChannel {
// Set blocking mode
if (self.session.rawSession) {
libssh2_session_set_blocking(self.session.rawSession, 1);
}
if (self.channel) {
int rc;
rc = libssh2_channel_close(self.channel);
if (rc == 0) {
libssh2_channel_wait_closed(self.channel);
}
libssh2_channel_free(self.channel);
[self setType:NMSSHChannelTypeClosed];
[self setChannel:NULL];
}
}
- (BOOL)sendEOF {
int rc;
// Send EOF to host
rc = libssh2_channel_send_eof(self.channel);
NMSSHLogVerbose(@"Sent EOF to host (return code = %i)", rc);
return rc == 0;
}
- (void)waitEOF {
if (libssh2_channel_eof(self.channel) == 0) {
// Wait for host acknowledge
int rc = libssh2_channel_wait_eof(self.channel);
NMSSHLogVerbose(@"Received host acknowledge for EOF (return code = %i)", rc);
}
}
// -----------------------------------------------------------------------------
#pragma mark - SHELL COMMAND EXECUTION
// -----------------------------------------------------------------------------
- (const char *)ptyTerminalName {
switch (self.ptyTerminalType) {
case NMSSHChannelPtyTerminalVanilla:
return "vanilla";
case NMSSHChannelPtyTerminalVT100:
return "vt100";
case NMSSHChannelPtyTerminalVT102:
return "vt102";
case NMSSHChannelPtyTerminalVT220:
return "vt220";
case NMSSHChannelPtyTerminalAnsi:
return "ansi";
case NMSSHChannelPtyTerminalXterm:
return "xterm";
}
// catch invalid values
return "vanilla";
}
- (NSString *)execute:(NSString *)command error:(NSError *__autoreleasing *)error {
return [self execute:command error:error timeout:@0];
}
- (NSString *)execute:(NSString *)command error:(NSError *__autoreleasing *)error timeout:(NSNumber *)timeout {
NMSSHLogInfo(@"Exec command %@", command);
// In case of error...
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:command forKey:@"command"];
if (![self openChannel:error]) {
return nil;
}
[self setLastResponse:nil];
int rc = 0;
[self setType:NMSSHChannelTypeExec];
// Try executing command
rc = libssh2_channel_exec(self.channel, [command UTF8String]);
if (rc != 0) {
if (error) {
[userInfo setObject:[[self.session lastError] localizedDescription] forKey:NSLocalizedDescriptionKey];
[userInfo setObject:[NSString stringWithFormat:@"%zi", rc] forKey:NSLocalizedFailureReasonErrorKey];
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelExecutionError
userInfo:userInfo];
}
NMSSHLogError(@"Error executing command");
[self closeChannel];
return nil;
}
// Set non-blocking mode
libssh2_session_set_blocking(self.session.rawSession, 0);
// Set the timeout for blocking session
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent() + [timeout doubleValue];
// Fetch response from output buffer
NSMutableString *response = [[NSMutableString alloc] init];
for (;;) {
ssize_t rc;
char buffer[self.bufferSize];
char errorBuffer[self.bufferSize];
do {
rc = libssh2_channel_read(self.channel, buffer, (ssize_t)sizeof(buffer));
if (rc > 0) {
[response appendFormat:@"%@", [[NSString alloc] initWithBytes:buffer length:rc encoding:NSUTF8StringEncoding]];
}
// Store all errors that might occur
if (libssh2_channel_get_exit_status(self.channel)) {
if (error) {
ssize_t erc = libssh2_channel_read_stderr(self.channel, errorBuffer, (ssize_t)sizeof(errorBuffer));
NSString *desc = [[NSString alloc] initWithBytes:errorBuffer length:erc encoding:NSUTF8StringEncoding];
if (!desc) {
desc = @"An unspecified error occurred";
}
[userInfo setObject:desc forKey:NSLocalizedDescriptionKey];
[userInfo setObject:[NSString stringWithFormat:@"%zi", erc] forKey:NSLocalizedFailureReasonErrorKey];
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelExecutionError
userInfo:userInfo];
}
}
if (libssh2_channel_eof(self.channel) == 1 || rc == 0) {
while ((rc = libssh2_channel_read(self.channel, buffer, (ssize_t)sizeof(buffer))) > 0) {
[response appendFormat:@"%@", [[NSString alloc] initWithBytes:buffer length:rc encoding:NSUTF8StringEncoding] ];
}
[self setLastResponse:[response copy]];
[self closeChannel];
return self.lastResponse;
}
// Check if the connection timed out
if ([timeout longValue] > 0 && time < CFAbsoluteTimeGetCurrent()) {
if (error) {
NSString *desc = @"Connection timed out";
[userInfo setObject:desc forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelExecutionTimeout
userInfo:userInfo];
}
while ((rc = libssh2_channel_read(self.channel, buffer, (ssize_t)sizeof(buffer))) > 0) {
[response appendFormat:@"%@", [[NSString alloc] initWithBytes:buffer length:rc encoding:NSUTF8StringEncoding] ];
}
[self setLastResponse:[response copy]];
[self closeChannel];
return self.lastResponse;
}
} while (rc > 0);
if (rc != LIBSSH2_ERROR_EAGAIN) {
break;
}
waitsocket(CFSocketGetNative([self.session socket]), self.session.rawSession);
}
// If we've got this far, it means fetching execution response failed
if (error) {
[userInfo setObject:[[self.session lastError] localizedDescription] forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelExecutionResponseError
userInfo:userInfo];
}
NMSSHLogError(@"Error fetching response from command");
[self closeChannel];
return nil;
}
// -----------------------------------------------------------------------------
#pragma mark - REMOTE SHELL SESSION
// -----------------------------------------------------------------------------
- (BOOL)startShell:(NSError *__autoreleasing *)error {
NMSSHLogInfo(@"Starting shell");
if (![self openChannel:error]) {
return NO;
}
// Set non-blocking mode
libssh2_session_set_blocking(self.session.rawSession, 0);
// Fetch response from output buffer
#if !(OS_OBJECT_USE_OBJC)
if (self.source) {
dispatch_release(self.source);
}
#endif
[self setLastResponse:nil];
[self setSource:dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, CFSocketGetNative([self.session socket]),
0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0))];
dispatch_source_set_event_handler(self.source, ^{
NMSSHLogVerbose(@"Data available on the socket!");
ssize_t rc, erc=0;
char buffer[self.bufferSize];
while (self.channel != NULL) {
rc = libssh2_channel_read(self.channel, buffer, (ssize_t)sizeof(buffer));
erc = libssh2_channel_read_stderr(self.channel, buffer, (ssize_t)sizeof(buffer));
if (!(rc >=0 || erc >= 0)) {
NMSSHLogVerbose(@"Return code of response %ld, error %ld", (long)rc, (long)erc);
if (rc == LIBSSH2_ERROR_SOCKET_RECV || erc == LIBSSH2_ERROR_SOCKET_RECV) {
NMSSHLogVerbose(@"Error received, closing channel...");
[self closeShell];
}
return;
}
else if (rc > 0) {
NSData *data = [[NSData alloc] initWithBytes:buffer length:rc];
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self setLastResponse:[response copy]];
if (response && self.delegate && [self.delegate respondsToSelector:@selector(channel:didReadData:)]) {
[self.delegate channel:self didReadData:self.lastResponse];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(channel:didReadRawData:)]) {
[self.delegate channel:self didReadRawData:data];
}
}
else if (erc > 0) {
NSData *data = [[NSData alloc] initWithBytes:buffer length:erc];
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (response && self.delegate && [self.delegate respondsToSelector:@selector(channel:didReadError:)]) {
[self.delegate channel:self didReadError:response];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(channel:didReadRawError:)]) {
[self.delegate channel:self didReadRawError:data];
}
}
else if (libssh2_channel_eof(self.channel) == 1) {
NMSSHLogVerbose(@"Host EOF received, closing channel...");
[self closeShell];
return;
}
}
});
dispatch_source_set_cancel_handler(self.source, ^{
NMSSHLogVerbose(@"Shell source cancelled");
if (self.delegate && [self.delegate respondsToSelector:@selector(channelShellDidClose:)]) {
[self.delegate channelShellDidClose:self];
}
});
dispatch_resume(self.source);
int rc = 0;
// Try opening the shell
while ((rc = libssh2_channel_shell(self.channel)) == LIBSSH2_ERROR_EAGAIN) {
waitsocket(CFSocketGetNative([self.session socket]), [self.session rawSession]);
}
if (rc != 0) {
NMSSHLogError(@"Shell request error");
if (error) {
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelRequestShellError
userInfo:@{ NSLocalizedDescriptionKey : [[self.session lastError] localizedDescription] }];
}
[self closeShell];
return NO;
}
NMSSHLogVerbose(@"Shell allocated");
[self setType:NMSSHChannelTypeShell];
return YES;
}
- (void)closeShell {
if (self.source) {
dispatch_source_cancel(self.source);
#if !(OS_OBJECT_USE_OBJC)
dispatch_release(self.source);
#endif
[self setSource: nil];
}
if (self.type == NMSSHChannelTypeShell) {
// Set blocking mode
libssh2_session_set_blocking(self.session.rawSession, 1);
[self sendEOF];
}
[self closeChannel];
}
- (BOOL)write:(NSString *)command error:(NSError *__autoreleasing *)error {
return [self write:command error:error timeout:@0];
}
- (BOOL)write:(NSString *)command error:(NSError *__autoreleasing *)error timeout:(NSNumber *)timeout {
return [self writeData:[command dataUsingEncoding:NSUTF8StringEncoding] error:error timeout:timeout];
}
- (BOOL)writeData:(NSData *)data error:(NSError *__autoreleasing *)error {
return [self writeData:data error:error timeout:@0];
}
- (BOOL)writeData:(NSData *)data error:(NSError *__autoreleasing *)error timeout:(NSNumber *)timeout {
if (self.type != NMSSHChannelTypeShell) {
NMSSHLogError(@"Shell required");
return NO;
}
ssize_t rc;
// Set the timeout
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent() + [timeout doubleValue];
// Try writing on shell
while ((rc = libssh2_channel_write(self.channel, [data bytes], [data length])) == LIBSSH2_ERROR_EAGAIN) {
// Check if the connection timed out
if ([timeout longValue] > 0 && time < CFAbsoluteTimeGetCurrent()) {
if (error) {
NSString *description = @"Connection timed out";
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelExecutionTimeout
userInfo:@{ NSLocalizedDescriptionKey : description }];
}
return NO;
}
waitsocket(CFSocketGetNative([self.session socket]), self.session.rawSession);
}
if (rc < 0) {
NMSSHLogError(@"Error writing on the shell");
if (error) {
NSString *command = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
*error = [NSError errorWithDomain:@"NMSSH"
code:NMSSHChannelWriteError
userInfo:@{ NSLocalizedDescriptionKey : [[self.session lastError] localizedDescription],
@"command" : command }];
}
}
return YES;
}
- (BOOL)requestSizeWidth:(NSUInteger)width height:(NSUInteger)height {
int rc = libssh2_channel_request_pty_size(self.channel, (int)width, (int)height);
if (rc) {
NMSSHLogError(@"Request size failed with error %i", rc);
}
return rc == 0;
}
// -----------------------------------------------------------------------------
#pragma mark - SCP FILE TRANSFER
// -----------------------------------------------------------------------------
- (BOOL)uploadFile:(NSString *)localPath to:(NSString *)remotePath {
return [self uploadFile:localPath to:remotePath progress:NULL];
}
- (BOOL)uploadFile:(NSString *)localPath to:(NSString *)remotePath progress:(BOOL (^)(NSUInteger))progress {
if (self.channel != NULL) {
NMSSHLogWarn(@"The channel will be closed before continue");
if (self.type == NMSSHChannelTypeShell) {
[self closeShell];
}
else {
[self closeChannel];
}
}
localPath = [localPath stringByExpandingTildeInPath];
// Inherit file name if to: contains a directory
if ([remotePath hasSuffix:@"/"]) {
remotePath = [remotePath stringByAppendingString:
[[localPath componentsSeparatedByString:@"/"] lastObject]];
}
// Read local file
FILE *local = fopen([localPath UTF8String], "rb");
if (!local) {
NMSSHLogError(@"Can't read local file");
return NO;
}
// Set blocking mode
libssh2_session_set_blocking(self.session.rawSession, 1);
// Try to send a file via SCP.
struct stat fileinfo;
stat([localPath UTF8String], &fileinfo);
LIBSSH2_CHANNEL *channel = libssh2_scp_send64(self.session.rawSession, [remotePath UTF8String], fileinfo.st_mode & 0644,
(unsigned long)fileinfo.st_size, 0, 0);;
if (channel == NULL) {
NMSSHLogError(@"Unable to open SCP session");
fclose(local);
return NO;
}
[self setChannel:channel];
[self setType:NMSSHChannelTypeSCP];
// Wait for file transfer to finish
char mem[self.bufferSize];
size_t nread;
char *ptr;
long rc;
NSUInteger total = 0;
BOOL abort = NO;
while (!abort && (nread = fread(mem, 1, sizeof(mem), local)) > 0) {
ptr = mem;
do {
// Write the same data over and over, until error or completion
rc = libssh2_channel_write(self.channel, ptr, nread);
if (rc < 0) {
NMSSHLogError(@"Failed writing file");
[self closeChannel];
return NO;
}
else {
// rc indicates how many bytes were written this time
total += rc;
if (progress && !progress(total)) {
abort = YES;
break;
}
ptr += rc;
nread -= rc;
}
} while (nread);
};
fclose(local);
if ([self sendEOF]) {
[self waitEOF];
}
[self closeChannel];
return !abort;
}
- (BOOL)downloadFile:(NSString *)remotePath to:(NSString *)localPath {
return [self downloadFile:remotePath to:localPath progress:NULL];
}
- (BOOL)downloadFile:(NSString *)remotePath to:(NSString *)localPath progress:(BOOL (^)(NSUInteger, NSUInteger))progress {
if (self.channel != NULL) {
NMSSHLogWarn(@"The channel will be closed before continue");
if (self.type == NMSSHChannelTypeShell) {
[self closeShell];
}
else {
[self closeChannel];
}
}
localPath = [localPath stringByExpandingTildeInPath];
// Inherit file name if to: contains a directory
if ([localPath hasSuffix:@"/"]) {
localPath = [localPath stringByAppendingString:[[remotePath componentsSeparatedByString:@"/"] lastObject]];
}
// Set blocking mode
libssh2_session_set_blocking(self.session.rawSession, 1);
// Request a file via SCP
struct stat fileinfo;
LIBSSH2_CHANNEL *channel = libssh2_scp_recv(self.session.rawSession, [remotePath UTF8String], &fileinfo);
if (channel == NULL) {
NMSSHLogError(@"Unable to open SCP session");
return NO;
}
[self setChannel:channel];
[self setType:NMSSHChannelTypeSCP];
if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
NMSSHLogInfo(@"A file already exists at %@, it will be overwritten", localPath);
[[NSFileManager defaultManager] removeItemAtPath:localPath error:nil];
}
// Open local file in order to write to it
int localFile = open([localPath UTF8String], O_WRONLY|O_CREAT, 0644);
// Save data to local file
off_t got = 0;
while (got < fileinfo.st_size) {
char mem[self.bufferSize];
size_t amount = sizeof(mem);
if ((fileinfo.st_size - got) < amount) {
amount = (size_t)(fileinfo.st_size - got);
}
ssize_t rc = libssh2_channel_read(self.channel, mem, amount);
if (rc > 0) {
size_t n = write(localFile, mem, rc);
if (n < rc) {
NMSSHLogError(@"Failed to write to local file");
close(localFile);
[self closeChannel];
return NO;
}
got += rc;
if (progress && !progress((NSUInteger)got, (NSUInteger)fileinfo.st_size)) {
close(localFile);
[self closeChannel];
return NO;
}
}
else if (rc < 0) {
NMSSHLogError(@"Failed to read SCP data");
close(localFile);
[self closeChannel];
return NO;
}
memset(mem, 0x0, sizeof(mem));
}
close(localFile);
[self closeChannel];
return YES;
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHConfig.h
================================================
#import "NMSSH.h"
@class NMSSHHostConfig;
/**
NMSSHConfig parses ssh config files and returns matching entries for a given
host name.
*/
@interface NMSSHConfig : NSObject
/** The array of parsed NMSSHHostConfig objects. */
@property(nonatomic, readonly) NSArray *hostConfigs;
/**
Creates a new NMSSHConfig, reads the given {filename} and parses it.
@param filename Path to an ssh config file.
@returns NMSSHConfig instance or nil if the config file couldn't be parsed.
*/
+ (instancetype)configFromFile:(NSString *)filename;
/**
Initializes an NMSSHConfig from a config file's contents in a string.
@param contents A config file's contents.
@returns An NMSSHConfig object or nil if the contents were malformed.
*/
- (instancetype)initWithString:(NSString *)contents;
/**
Searches the config for an entry matching {host}.
@param host A host name to search for.
@returns An NMSSHHostConfig object whose patterns match host or nil if none is
found.
*/
- (NMSSHHostConfig *)hostConfigForHost:(NSString *)host;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHConfig.m
================================================
#import "NMSSHConfig.h"
#import "NMSSHHostConfig.h"
/** Describes how a host string matches a pattern in a NMSSHHostConfig. */
typedef enum {
/** Host matches a pattern */
NMSSHConfigMatchPositive,
/** Host matches a negated pattern */
NMSSHConfigMatchNegative,
/** Host matches no patterns */
NMSSHConfigMatchNone
} NMSSHConfigMatch;
@interface NMSSHConfig ()
@property(nonatomic, strong) NSArray *hostConfigs;
@end
@implementation NMSSHConfig
+ (instancetype)configFromFile:(NSString *)filename {
return [[self alloc] initWithFile:filename];
}
- (instancetype)initWithFile:(NSString *)filename {
NSString *contents = [NSString stringWithContentsOfFile:filename
encoding:NSUTF8StringEncoding
error:NULL];
return [self initWithString:contents];
}
- (instancetype)initWithString:(NSString *)contents {
if (contents == nil) {
return nil;
}
if ((self = [super init])) {
[self setHostConfigs:[self arrayFromString:contents]];
if (_hostConfigs == nil) {
return nil;
}
}
return self;
}
// -----------------------------------------------------------------------------
#pragma mark - PARSING
// -----------------------------------------------------------------------------
- (NSArray *)arrayFromString:(NSString *)contents {
if (contents == nil) {
return nil;
}
contents = [contents stringByReplacingOccurrencesOfString:@"\r\n"
withString:@"\n"];
NSArray *lines = [contents componentsSeparatedByString:@"\n"];
NSMutableArray *array = [NSMutableArray array];
for (NSString *line in lines) {
[self parseLine:line intoArray:array];
}
return [array copy];
}
- (void)parseLine:(NSString *)line intoArray:(NSMutableArray *)array {
// Trim spaces
line = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// Pull out the range of the first token.
NSString *arguments;
NSRange range = [self rangeOfFirstTokenInString:line suffix:&arguments];
if (range.location == NSNotFound) {
return;
}
// Get the string value of the first token.
NSString *keyword = [line substringWithRange:range];
if ([keyword hasPrefix:@"#"] ||
[keyword length] == 0) {
return;
}
// Parse the line based on the first token.
if ([keyword localizedCaseInsensitiveCompare:@"host"] == NSOrderedSame) {
[self parseHostWithArguments:arguments intoArray:array];
}
else if ([keyword localizedCaseInsensitiveCompare:@"hostname"] == NSOrderedSame) {
[self parseHostNameWithArguments:arguments intoArray:array];
}
else if ([keyword localizedCaseInsensitiveCompare:@"user"] == NSOrderedSame) {
[self parseUserWithArguments:arguments intoArray:array];
}
else if ([keyword localizedCaseInsensitiveCompare:@"port"] == NSOrderedSame) {
[self parsePortWithArguments:arguments intoArray:array];
}
else if ([keyword localizedCaseInsensitiveCompare:@"identityfile"] == NSOrderedSame) {
[self parseIdentityFileWithArguments:arguments intoArray:array];
}
}
- (void)parseHostWithArguments:(NSString *)arguments intoArray:(NSMutableArray *)array {
NMSSHHostConfig *config = [[NMSSHHostConfig alloc] init];
NSString *next;
NSRange hostRange = [self rangeOfFirstTokenInString:arguments suffix:&next];
while (hostRange.location != NSNotFound) {
if (hostRange.length > 0) {
NSString *hostPattern = [arguments substringWithRange:hostRange];
[config setHostPatterns:[config.hostPatterns arrayByAddingObject:hostPattern]];
}
arguments = next;
hostRange = [self rangeOfFirstTokenInString:arguments suffix:&next];
}
if ([config.hostPatterns count] > 0) {
[array addObject:config];
}
}
- (void)parseHostNameWithArguments:(NSString *)arguments
intoArray:(NSMutableArray *)array {
if ([array count] == 0) {
return;
}
NMSSHHostConfig *config = [array lastObject];
NSRange valueRange = [self rangeOfFirstTokenInString:arguments suffix:NULL];
if (valueRange.location != NSNotFound &&
valueRange.length > 0) {
[config setHostname:[arguments substringWithRange:valueRange]];
}
}
- (void)parseUserWithArguments:(NSString *)arguments
intoArray:(NSMutableArray *)array {
if ([array count] == 0) {
return;
}
NMSSHHostConfig *config = [array lastObject];
NSRange valueRange = [self rangeOfFirstTokenInString:arguments suffix:NULL];
if (valueRange.location != NSNotFound &&
valueRange.length > 0) {
[config setUser:[arguments substringWithRange:valueRange]];
}
}
- (void)parsePortWithArguments:(NSString *)arguments
intoArray:(NSMutableArray *)array {
if ([array count] == 0) {
return;
}
NMSSHHostConfig *config = [array lastObject];
NSRange valueRange = [self rangeOfFirstTokenInString:arguments suffix:NULL];
if (valueRange.location != NSNotFound &&
valueRange.length > 0) {
NSString *portString = [arguments substringWithRange:valueRange];
NSInteger port = [portString intValue];
if (port >= 0) {
[config setPort:@(port & 0xffff)];
}
}
}
- (void)parseIdentityFileWithArguments:(NSString *)arguments
intoArray:(NSMutableArray *)array {
if ([array count] == 0) {
return;
}
NMSSHHostConfig *config = [array lastObject];
NSRange valueRange = [self rangeOfFirstTokenInString:arguments suffix:NULL];
if (valueRange.location != NSNotFound &&
valueRange.length > 0) {
NSString *identityFile =
[[arguments substringWithRange:valueRange] stringByExpandingTildeInPath];
[config setIdentityFiles:[config.identityFiles arrayByAddingObject:identityFile]];
}
}
- (NSCharacterSet *)blanksCharacterSet {
NSMutableCharacterSet *blanksCharacterSet = [[NSMutableCharacterSet alloc] init];
[blanksCharacterSet addCharactersInRange:NSMakeRange(' ', 1)];
[blanksCharacterSet addCharactersInRange:NSMakeRange('\t', 1)];
return blanksCharacterSet;
}
// Returns the range of a quoted substring in line starting with a quote at location. If there is
// no matching close quote then a location of NSNotFound is returned. Otherwise, the range of the
// text inside the quotes (excluding the quotes) is returned.
- (NSRange)rangeOfQuotedSubstringInString:(NSString *)line
startingAtIndex:(NSUInteger)location {
NSUInteger start = location + 1;
NSRange possiblyQuotedRange = NSMakeRange(start,
[line length] - start);
NSRange rangeOfCloseQuote = [line rangeOfString:@"\""
options:0
range:possiblyQuotedRange];
if (rangeOfCloseQuote.location == NSNotFound) {
return NSMakeRange(NSNotFound, 0);
}
else {
return NSMakeRange(start, rangeOfCloseQuote.location - start);
}
}
- (NSRange)rangeInString:(NSString *)line fromLocationUntilBlankOrEnd:(NSUInteger)location {
NSRange tailRange = NSMakeRange(location,
[line length] - location);
NSRange terminatingBlank = [line rangeOfCharacterFromSet:[self blanksCharacterSet]
options:0
range:tailRange];
if (terminatingBlank.location == NSNotFound) {
return tailRange;
}
else {
return NSMakeRange(location, NSMaxRange(terminatingBlank) - location - 1);
}
}
- (NSRange)rangeOfFirstTokenInString:(NSString *)line suffix:(NSString **)suffixPtr {
NSCharacterSet *blanksCharacterSet = [self blanksCharacterSet];
NSMutableCharacterSet *nonBlanksCharacterSet = [blanksCharacterSet mutableCopy];
[nonBlanksCharacterSet invert];
NSRange rangeOfFirstNonBlank = [line rangeOfCharacterFromSet:nonBlanksCharacterSet];
if (rangeOfFirstNonBlank.location == NSNotFound) {
return rangeOfFirstNonBlank;
}
if ([line characterAtIndex:rangeOfFirstNonBlank.location] == '"') {
NSRange range = [self rangeOfQuotedSubstringInString:line
startingAtIndex:rangeOfFirstNonBlank.location];
if (suffixPtr != NULL && range.location != NSNotFound) {
*suffixPtr = [line substringFromIndex:NSMaxRange(range) + 1];
}
return range;
}
else {
NSRange range =
[self rangeInString:line fromLocationUntilBlankOrEnd:rangeOfFirstNonBlank.location];
if (suffixPtr != NULL) {
*suffixPtr = [line substringFromIndex:NSMaxRange(range)];
}
return range;
}
}
// -----------------------------------------------------------------------------
#pragma mark - MATCHING
// -----------------------------------------------------------------------------
- (NMSSHHostConfig *)hostConfigForHost:(NSString *)host {
NMSSHHostConfig *combinedConfig = [[NMSSHHostConfig alloc] init];
BOOL foundAny = NO;
for (NMSSHHostConfig *config in _hostConfigs) {
NMSSHConfigMatch match = NMSSHConfigMatchNone;
for (NSString *pattern in config.hostPatterns) {
switch ([self host:host matchesPatternList:pattern]) {
case NMSSHConfigMatchPositive:
match = NMSSHConfigMatchPositive;
break;
case NMSSHConfigMatchNegative:
match = NMSSHConfigMatchNegative;
break;
case NMSSHConfigMatchNone:
break;
}
if (match == NMSSHConfigMatchNegative) {
break;
}
}
if (match == NMSSHConfigMatchPositive) {
[combinedConfig mergeFrom:config];
foundAny = YES;
}
}
return foundAny ? combinedConfig : nil;
}
// A pattern list is a comma-delimited sequence of subpatterns. A subpattern is a string with
// wildcards optionally preceded by an !. If the host matches any negated subpattern then it is a
// negative match. Otherwise, if the host matches any non-negated subpattern then it is a positive
// match. If the host matches no patterns then it is a None match.
- (NMSSHConfigMatch)host:(NSString *)host matchesPatternList:(NSString *)patternList {
NSArray *patterns = [patternList componentsSeparatedByString:@","];
NMSSHConfigMatch match = NMSSHConfigMatchNone;
for (NSString *mixedCasePattern in patterns) {
NSString *pattern = [mixedCasePattern lowercaseString];
BOOL negated = NO;
if ([pattern hasPrefix:@"!"]) {
negated = YES;
pattern = [pattern substringFromIndex:1];
}
if ([self host:host matchesSubpattern:pattern]) {
if (negated) {
return NMSSHConfigMatchNegative;
}
else {
match = NMSSHConfigMatchPositive;
}
}
}
return match;
}
- (BOOL)host:(NSString *)host matchesSubpattern:(NSString *)subPattern {
if (host == nil || subPattern == nil) {
return NO;
}
NSUInteger patternIndex = 0;
NSUInteger patternLength = subPattern.length;
NSUInteger hostIndex = 0;
NSUInteger hostLength = host.length;
while (1) {
if (patternIndex == patternLength) {
return hostIndex == hostLength;
}
unichar patternChar = [subPattern characterAtIndex:patternIndex];
if (patternChar == '*') {
++patternIndex;
if (patternIndex == patternLength) {
// If at end of pattenr, accept immediately.
return YES;
}
// If next character in pattern is not a wildcard, optimize.
unichar patternPeek = [subPattern characterAtIndex:patternIndex];
if (patternPeek != '?' && patternPeek != '*') {
// Look for an instance in the host of the next char to match in the pattern.
for (; hostIndex < hostLength; hostIndex++) {
unichar hostChar = [host characterAtIndex:hostIndex];
if (hostChar == patternPeek) {
NSString *tailHost = [host substringFromIndex:hostIndex + 1];
NSString *tailSubpattern = [subPattern substringFromIndex:patternIndex + 1];
if ([self host:tailHost matchesSubpattern:tailSubpattern]) {
return YES;
}
}
}
// Failed.
return NO;
}
// Move ahead one char at a time and try to match at each position
for (; hostIndex < hostLength; ++hostIndex) {
NSString *tailHost = [host substringFromIndex:hostIndex];
NSString *tailPattern = [subPattern substringFromIndex:patternIndex];
if ([self host:tailHost matchesSubpattern:tailPattern]) {
return YES;
}
}
// Failed
return NO;
}
// There must be at least one more char in the string. If we reached the end, then fail.
if (hostIndex == hostLength) {
return NO;
}
unichar hostChar = [host characterAtIndex:hostIndex];
// Check if the next character of the string is acceptable.
if (patternChar != '?' && patternChar != hostChar) {
return NO;
}
++hostIndex;
++patternIndex;
}
// Unreachable code.
return NO;
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHHostConfig.h
================================================
#import "NMSSH.h"
/**
NMSSHHostConfig describes a single host's configuration.
*/
@interface NMSSHHostConfig : NSObject
/**
Patterns specified in the config file.
*/
@property(nonatomic, strong) NSArray *hostPatterns;
/**
Specifies the real host name to log into. If the hostname contains the
character sequence `%h', then the client should replace this with the
user-specified host name (this is useful for manipulating unqualified names).
This may be an IP address.
*/
@property(nonatomic, strong) NSString *hostname;
/**
Specifies the user name to log in as.
*/
@property(nonatomic, strong) NSString *user;
/**
Specifies the port number to connect on the remote host.
*/
@property(nonatomic, strong) NSNumber *port;
/**
Specifies alist of file names from which the user's DSA, ECDSA or RSA
authentication identity are read. It is empty by default. Tildes will be
expanded to the user's home directory. The client should perform the following
substitutions on each file name:
"%d" should be replaced with the local user home directory
"%u" should be replaced with the local user name
"%l" should be replaced with the local host name
"%h" should be replaced with the remote host name
"%r" should be replaced with the remote user name
If multiple identities are provided, the client should try them in order.
*/
@property(nonatomic, strong) NSArray *identityFiles;
/**
Values for {other} are copied to {self} if not already set. Arrays are
appended from {other} without adding duplicates.
*/
- (void)mergeFrom:(NMSSHHostConfig *)other;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHHostConfig.m
================================================
#import "NMSSHHostConfig.h"
@implementation NMSSHHostConfig
- (id)init {
if ((self = [super init])) {
[self setHostPatterns:@[ ]];
[self setIdentityFiles:@[ ]];
}
return self;
}
- (NSArray *)arrayByRemovingDuplicateElementsFromArray:(NSArray *)array {
NSMutableArray *deduped = [NSMutableArray array];
for (NSObject *object in array) {
if (![deduped containsObject:object]) {
[deduped addObject:object];
}
}
return [deduped copy];
}
- (NSArray *)mergedArray:(NSArray *)firstArray withArray:(NSArray *)secondArray {
NSArray *concatenated = [firstArray arrayByAddingObjectsFromArray:secondArray];
return [self arrayByRemovingDuplicateElementsFromArray:concatenated];
}
- (void)mergeFrom:(NMSSHHostConfig *)other {
[self setHostPatterns:[self mergedArray:self.hostPatterns
withArray:other.hostPatterns]];
if (!self.hostname) {
[self setHostname:other.hostname];
}
if (!self.user) {
[self setUser:other.user];
}
if (!self.port) {
[self setPort:other.port];
}
[self setIdentityFiles:[self mergedArray:self.identityFiles
withArray:other.identityFiles]];
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHSession.h
================================================
#import "NMSSH.h"
@class NMSSHHostConfig, NMSFTP;
@protocol NMSSHSessionDelegate;
typedef NS_ENUM(NSInteger, NMSSHSessionHash) {
NMSSHSessionHashMD5,
NMSSHSessionHashSHA1
};
typedef NS_ENUM(NSInteger, NMSSHKnownHostStatus) {
NMSSHKnownHostStatusMatch,
NMSSHKnownHostStatusMismatch,
NMSSHKnownHostStatusNotFound,
NMSSHKnownHostStatusFailure
};
/**
NMSSHSession provides the functionality required to setup a SSH connection
and authorize against it.
In its simplest form it works like this:
NMSSHSession *session = [NMSSHSession connectToHost:@"127.0.0.1:22"
withUsername:@"user"];
if (session.isConnected) {
NSLog(@"Successfully created a new session");
}
[session authenticateByPassword:@"pass"];
if (session.isAuthorized) {
NSLog(@"Successfully authorized");
}
## Thread safety
NMSSH classes are not thread safe, you should use them from the same thread
where you created the NMSSHSession instance.
If you want to use multiple NMSSHSession instances at once you should implement
the [crypto mutex callbacks](http://trac.libssh2.org/wiki/MultiThreading).
*/
@interface NMSSHSession : NSObject
/// ----------------------------------------------------------------------------
/// @name Setting the Delegate
/// ----------------------------------------------------------------------------
/**
The receiver’s `delegate`.
The `delegate` is sent messages when content is loading.
*/
@property (nonatomic, weak) id delegate;
/**
The synthesized config for the current host, produced by combining values from
all configs in the chain by priority, plus client-provided defaults. This is
only set if NMSSHSession was initialized with a config chain.
*/
@property (nonatomic, readonly) NMSSHHostConfig *hostConfig;
/// ----------------------------------------------------------------------------
/// @name Initialize a new SSH session
/// ----------------------------------------------------------------------------
/**
Shorthand method for initializing a NMSSHSession object and calling connect.
@param host The server hostname (a port number can be specified by appending
`@":{port}"`; for IPv6 addresses with a port, use
`@"[{host}]:{port}"`.
@param username A valid username the server will accept
@returns NMSSHSession instance
*/
+ (instancetype)connectToHost:(NSString *)host withUsername:(NSString *)username;
/**
Shorthand method for initializing a NMSSHSession object and calling connect,
(explicitly setting a port number).
@param host The server hostname
@param port The port number
@param username A valid username the server will accept
@returns NMSSHSession instance
*/
+ (instancetype)connectToHost:(NSString *)host port:(NSInteger)port withUsername:(NSString *)username;
/**
Create and setup a new NMSSH instance.
@param host The server hostname (a port number can be specified by appending
`@":{port}"`; for IPv6 addresses with a port, use
`@"[{host}]:{port}"`.
@param username A valid username the server will accept
@returns NMSSHSession instance
*/
- (instancetype)initWithHost:(NSString *)host andUsername:(NSString *)username;
/**
Create and setup a new NMSSH instance. This is the designated initializer.
@param host The server hostname
@param port The port number
@param username A valid username the server will accept
@returns NMSSHSession instance
*/
- (instancetype)initWithHost:(NSString *)host port:(NSInteger)port andUsername:(NSString *)username;
/**
Create and setup a new NMSSH instance using a chain of config files.
The {host} is used to perform a lookup in NMSSHConfig objects in the
{configs} array, which may alias the hostname and provide a port number or user
name. All information relevant to {host} in {configs} will be combined into
a single NMSSHHostConfig and saved in {self.hostConfig}. A config-
provided value will override {host}, {defaultUsername} or {defaultPort}. If no
match is found then {host} is used as the host name.
@param host Host to search {configs} with. If no matching config specifies a
hostname, then {host} is the server hostname.
@param configs An array of NMSSHHostConfig objects ordered from highest to
lowest priority
@param defaultPort The port number (may be overridden by a config)
@param defaultUsername A valid username the server will accept (may be
overridden by a config)
*/
- (instancetype)initWithHost:(NSString *)host
configs:(NSArray *)configs
withDefaultPort:(NSInteger)defaultPort
defaultUsername:(NSString *)defaultUsername;
/// ----------------------------------------------------------------------------
/// @name Connection settings
/// ----------------------------------------------------------------------------
/** Full server hostname in the format `@"{hostname}"`. */
@property (nonatomic, readonly) NSString *host;
/** The server port to connect to. */
@property (nonatomic, readonly) NSNumber *port;
/** Username that will authenticate against the server. */
@property (nonatomic, readonly) NSString *username;
/** Timeout for libssh2 blocking functions. */
@property (nonatomic, strong) NSNumber *timeout;
/** Last session error. */
@property (nonatomic, readonly) NSError *lastError;
/** The hash algorithm to use to encode the fingerprint during connection, default value is NMSSHSessionHashMD5. */
@property (nonatomic, assign) NMSSHSessionHash fingerprintHash;
/** The banner that will be sent to the remote host when the SSH session is started. */
@property (nonatomic, strong) NSString *banner;
/** The remote host banner. */
@property (nonatomic, readonly) NSString *remoteBanner;
/// ----------------------------------------------------------------------------
/// @name Raw libssh2 session and socket reference
/// ----------------------------------------------------------------------------
/** Raw libssh2 session instance. */
@property (nonatomic, readonly, getter = rawSession) LIBSSH2_SESSION *session;
/** Raw session socket. */
@property (nonatomic, readonly) CFSocketRef socket;
/// ----------------------------------------------------------------------------
/// @name Open/Close a connection to the server
/// ----------------------------------------------------------------------------
/**
A Boolean value indicating whether the session connected successfully
(read-only).
*/
@property (nonatomic, readonly, getter = isConnected) BOOL connected;
/**
Connect to the server using the default timeout (10 seconds)
@returns Connection status
*/
- (BOOL)connect;
/**
Connect to the server.
@param timeout The time, in seconds, to wait before giving up.
@returns Connection status
*/
- (BOOL)connectWithTimeout:(NSNumber *)timeout;
/**
Close the session
*/
- (void)disconnect;
/// ----------------------------------------------------------------------------
/// @name Authentication
/// ----------------------------------------------------------------------------
/**
A Boolean value indicating whether the session is successfully authorized
(read-only).
*/
@property (nonatomic, readonly, getter = isAuthorized) BOOL authorized;
/**
Authenticate by password
@param password Password for connected user
@returns Authentication success
*/
- (BOOL)authenticateByPassword:(NSString *)password;
/**
Authenticate by private key pair from file(s)
Use password:nil when the key is unencrypted
@param publicKey Filepath to public key
@param privateKey Filepath to private key
@param password Password for encrypted private key
@returns Authentication success
*/
- (BOOL)authenticateByPublicKey:(NSString *)publicKey
privateKey:(NSString *)privateKey
andPassword:(NSString *)password;
/**
Authenticate by private key pair
Use password:nil when the key is unencrypted
@param publicKey public key
@param privateKey private key
@param password Password for encrypted private key
@returns Authentication success
*/
- (BOOL)authenticateByInMemoryPublicKey:(NSString *)publicKey
privateKey:(NSString *)privateKey
andPassword:(NSString *)password;
/**
Authenticate by keyboard-interactive using delegate.
@returns Authentication success
*/
- (BOOL)authenticateByKeyboardInteractive;
/**
Authenticate by keyboard-interactive using block.
@param authenticationBlock The block to apply to server requests.
The block takes one argument:
_request_ - Question from server
The block returns a NSString object that represents a valid response
to the given question.
@returns Authentication success
*/
- (BOOL)authenticateByKeyboardInteractiveUsingBlock:(NSString *(^)(NSString *request))authenticationBlock;
/**
Setup and connect to an SSH agent
@returns Authentication success
*/
- (BOOL)connectToAgent;
/**
Get supported authentication methods
@returns Array of string descripting supported authentication methods
*/
- (NSArray *)supportedAuthenticationMethods;
/**
Get the fingerprint of the remote host.
The session must be connected to an host.
@param hashType The hash algorithm to use to encode the fingerprint
@returns The host's fingerprint
*/
- (NSString *)fingerprint:(NMSSHSessionHash)hashType;
/// ----------------------------------------------------------------------------
/// @name Known hosts
/// ----------------------------------------------------------------------------
/**
Checks if the hosts's key is recognized.
The session must be connected. Each file is checked in order,
returning as soon as the host is found.
@warning In a sandboxed Mac app or iOS app, _files_ must not be `nil` as the default files are not accessible.
@param files An array of filenames to check, or `nil` to use the default paths.
@returns Known host status for current host.
*/
- (NMSSHKnownHostStatus)knownHostStatusInFiles:(NSArray *)files;
/**
Adds the passed-in host to the user's known hosts file.
_hostName_ may be a numerical IP address or a full name. If it includes
a port number, it should be formatted as `@"[{host}]:{port}"` (e.g., `@"[example.com]:2222"`).
If _salt_ is set, then _hostName_ must contain a hostname salted and hashed with SHA1 and then base64-encoded.
A simple example:
[session addKnownHostName:session.host
port:[session.port intValue]
toFile:nil
withSalt:nil];
@warning On Mac OS, the default filename is `~/.ssh/known_hosts`, and will not be writable in a sandboxed environment.
@param hostName The hostname or IP address to add.
@param port The port number of the host to add.
@param fileName The path to the known_hosts file, or `nil` for the default.
@param salt The base64-encoded salt used for hashing. May be `nil`.
@returns Success status.
*/
- (BOOL)addKnownHostName:(NSString *)hostName
port:(NSInteger)port
toFile:(NSString *)fileName
withSalt:(NSString *)salt;
/// ----------------------------------------------------------------------------
/// @name Quick channel/sftp access
/// ----------------------------------------------------------------------------
/** Get a pre-configured NMSSHChannel object for the current session (read-only). */
@property (nonatomic, readonly) NMSSHChannel *channel;
/** Get a pre-configured NMSFTP object for the current session (read-only). */
@property (nonatomic, readonly) NMSFTP *sftp;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/NMSSHSession.m
================================================
#import "NMSSHSession.h"
#import "NMSSH+Protected.h"
#import "NMSSHConfig.h"
#import "NMSSHHostConfig.h"
@interface NMSSHSession ()
@property (nonatomic, assign) LIBSSH2_AGENT *agent;
@property (nonatomic, assign, getter = rawSession) LIBSSH2_SESSION *session;
@property (nonatomic, readwrite, getter = isConnected) BOOL connected;
@property (nonatomic, strong) NSString *host;
@property (nonatomic, strong) NSString *username;
@property (nonatomic, copy) NSString *(^kbAuthenticationBlock)(NSString *);
@property (nonatomic, strong) NMSSHChannel *channel;
@property (nonatomic, strong) NMSFTP *sftp;
@property (nonatomic, strong) NSNumber *port;
@property (nonatomic, strong) NMSSHHostConfig *hostConfig;
@property (nonatomic, assign) LIBSSH2_SESSION *sessionToFree;
@end
@implementation NMSSHSession
// -----------------------------------------------------------------------------
#pragma mark - INITIALIZE A NEW SSH SESSION
// -----------------------------------------------------------------------------
+ (instancetype)connectToHost:(NSString *)host port:(NSInteger)port withUsername:(NSString *)username {
NMSSHSession *session = [[NMSSHSession alloc] initWithHost:host
port:port
andUsername:username];
[session connect];
return session;
}
+ (instancetype)connectToHost:(NSString *)host withUsername:(NSString *)username {
NMSSHSession *session = [[NMSSHSession alloc] initWithHost:host
andUsername:username];
[session connect];
return session;
}
- (instancetype)initWithHost:(NSString *)host port:(NSInteger)port andUsername:(NSString *)username {
if ((self = [super init])) {
[self setHost:host];
[self setPort:@(port)];
[self setUsername:username];
[self setConnected:NO];
[self setFingerprintHash:NMSSHSessionHashMD5];
}
return self;
}
- (instancetype)initWithHost:(NSString *)host
configs:(NSArray *)configs
withDefaultPort:(NSInteger)defaultPort
defaultUsername:(NSString *)defaultUsername {
// Merge matching entries from configs together.
NMSSHHostConfig *hostConfig = [[NMSSHHostConfig alloc] init];
for (NMSSHConfig *config in configs) {
NMSSHHostConfig *matchingHostConfig = [config hostConfigForHost:host];
if (matchingHostConfig) {
[hostConfig mergeFrom:matchingHostConfig];
}
}
// Merge in defaults.
NMSSHHostConfig *defaultHostConfig = [[NMSSHHostConfig alloc] init];
[defaultHostConfig setHostname:host];
[defaultHostConfig setPort:@(defaultPort)];
[defaultHostConfig setUser:defaultUsername];
[hostConfig mergeFrom:defaultHostConfig];
// Initialize with resulting config.
self = [self initWithHost:hostConfig.hostname
port:[hostConfig.port integerValue]
andUsername:hostConfig.user];
if (self) {
[self setHostConfig:hostConfig];
}
return self;
}
- (instancetype)initWithHost:(NSString *)host andUsername:(NSString *)username {
NSURL *url = [[self class] URLForHost:host];
return [self initWithHost:[url host]
port:[([url port] ?: @22) intValue]
andUsername:username];
}
+ (NSURL *)URLForHost:(NSString *)host {
// Check if host is IPv6 and wrap in square brackets.
if ([[host componentsSeparatedByString:@":"] count] >= 3 &&
![host hasPrefix:@"["]) {
host = [NSString stringWithFormat:@"[%@]", host];
}
return [NSURL URLWithString:[@"ssh://" stringByAppendingString:host]];
}
- (void)dealloc {
if (self.sessionToFree) {
libssh2_session_free(self.sessionToFree);
}
}
// -----------------------------------------------------------------------------
#pragma mark - CONNECTION SETTINGS
// -----------------------------------------------------------------------------
- (NSArray *)hostIPAddresses {
NSArray *hostComponents = [_host componentsSeparatedByString:@":"];
NSInteger components = [hostComponents count];
NSString *address = hostComponents[0];
// Check if the host is [{IPv6}]:{port}
if (components >= 4 && [hostComponents[0] hasPrefix:@"["] && [hostComponents[components-2] hasSuffix:@"]"]) {
address = [_host substringWithRange:NSMakeRange(1, [_host rangeOfString:@"]" options:NSBackwardsSearch].location-1)];
} // Check if the host is {IPv6}
else if (components >= 3) {
address = _host;
}
CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)address);
CFStreamError error;
NSArray *addresses = nil;
if (host) {
NMSSHLogVerbose(@"Start %@ resolution", address);
if (CFHostStartInfoResolution(host, kCFHostAddresses, &error)) {
addresses = (__bridge NSArray *)(CFHostGetAddressing(host, NULL));
}
else {
NMSSHLogError(@"Unable to resolve host %@", address);
}
CFRelease(host);
}
else {
NMSSHLogError(@"Error allocating CFHost for %@", address);
}
return addresses;
}
- (NSNumber *)timeout {
if (self.session) {
return @(libssh2_session_get_timeout(self.session) / 1000);
}
return @0;
}
- (void)setTimeout:(NSNumber *)timeout {
if (self.session) {
libssh2_session_set_timeout(self.session, [timeout longValue] * 1000);
}
}
- (NSError *)lastError {
if(!self.rawSession) {
return [NSError errorWithDomain:@"libssh2" code:LIBSSH2_ERROR_NONE userInfo:@{NSLocalizedDescriptionKey : @"Error retrieving last session error due to absence of an active session."}];
}
char *message;
int error = libssh2_session_last_error(self.rawSession, &message, NULL, 0);
return [NSError errorWithDomain:@"libssh2"
code:error
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithUTF8String:message] }];
}
- (NSString *)remoteBanner {
const char *banner = libssh2_session_banner_get(self.session);
if (!banner) {
return nil;
}
return [[NSString alloc] initWithCString:banner encoding:NSUTF8StringEncoding];
}
// -----------------------------------------------------------------------------
#pragma mark - OPEN/CLOSE A CONNECTION TO THE SERVER
// -----------------------------------------------------------------------------
- (BOOL)connect {
return [self connectWithTimeout:[NSNumber numberWithLong:10]];
}
- (BOOL)connectWithTimeout:(NSNumber *)timeout {
if (self.isConnected) {
[self disconnect];
}
__block BOOL initialized = YES;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Try to initialize libssh2
if (libssh2_init(0) != 0) {
NMSSHLogError(@"libssh2 initialization failed");
initialized = NO;
}
NMSSHLogVerbose(@"libssh2 (v%s) initialized", libssh2_version(0));
});
if (!initialized) {
return NO;
}
// Try to establish a connection to the server
NSUInteger index = -1;
NSInteger port = [self.port integerValue];
NSArray *addresses = [self hostIPAddresses];
CFSocketError error = 1;
struct sockaddr_storage *address = NULL;
SInt32 addressFamily;
while (addresses && ++index < [addresses count] && error) {
NSData *addressData = addresses[index];
NSString *ipAddress;
// IPv4
if ([addressData length] == sizeof(struct sockaddr_in)) {
struct sockaddr_in address4;
[addressData getBytes:&address4 length:sizeof(address4)];
address4.sin_port = htons(port);
address = (struct sockaddr_storage *)(&address4);
address->ss_len = sizeof(address4);
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(address4.sin_addr), str, INET_ADDRSTRLEN);
ipAddress = [NSString stringWithCString:str encoding:NSUTF8StringEncoding];
addressFamily = AF_INET;
} // IPv6
else if([addressData length] == sizeof(struct sockaddr_in6)) {
struct sockaddr_in6 address6;
[addressData getBytes:&address6 length:sizeof(address6)];
address6.sin6_port = htons(port);
address = (struct sockaddr_storage *)(&address6);
address->ss_len = sizeof(address6);
char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(address6.sin6_addr), str, INET6_ADDRSTRLEN);
ipAddress = [NSString stringWithCString:str encoding:NSUTF8StringEncoding];
addressFamily = AF_INET6;
}
else {
NMSSHLogVerbose(@"Unknown address, it's not IPv4 or IPv6!");
continue;
}
// Try to create the socket
_socket = CFSocketCreate(kCFAllocatorDefault, addressFamily, SOCK_STREAM, IPPROTO_IP, kCFSocketNoCallBack, NULL, NULL);
if (!_socket) {
NMSSHLogError(@"Error creating the socket");
return NO;
}
// Set NOSIGPIPE
int set = 1;
if (setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(set)) != 0) {
NMSSHLogError(@"Error setting socket option");
[self disconnect];
return NO;
}
error = CFSocketConnectToAddress(_socket, (__bridge CFDataRef)[NSData dataWithBytes:address length:address->ss_len], [timeout doubleValue]);
if (error) {
NMSSHLogVerbose(@"Socket connection to %@ on port %ld failed with reason %li, trying next address...", ipAddress, (long)port, error);
}
else {
NMSSHLogInfo(@"Socket connection to %@ on port %ld succesful", ipAddress, (long)port);
}
}
if (error) {
NMSSHLogError(@"Failure establishing socket connection");
[self disconnect];
return NO;
}
// Create a session instance
[self setSession:libssh2_session_init_ex(NULL, NULL, NULL, (__bridge void *)(self))];
// Set a callback for disconnection
libssh2_session_callback_set(self.session, LIBSSH2_CALLBACK_DISCONNECT, &disconnect_callback);
// Set blocking mode
libssh2_session_set_blocking(self.session, 1);
// Set the custom banner
if (self.banner && libssh2_session_banner_set(self.session, [self.banner UTF8String])) {
NMSSHLogError(@"Failure setting the banner");
}
// Start the session
if (libssh2_session_handshake(self.session, CFSocketGetNative(_socket))) {
NMSSHLogError(@"Failure establishing SSH session");
[self disconnect];
return NO;
}
NMSSHLogVerbose(@"Remote host banner is %@", [self remoteBanner]);
// Get the fingerprint of the host
NSString *fingerprint = [self fingerprint:self.fingerprintHash];
NMSSHLogInfo(@"The host's fingerprint is %@", fingerprint);
if (self.delegate && [self.delegate respondsToSelector:@selector(session:shouldConnectToHostWithFingerprint:)] &&
![self.delegate session:self shouldConnectToHostWithFingerprint:fingerprint]) {
NMSSHLogWarn(@"Fingerprint refused, aborting connection...");
[self disconnect];
return NO;
}
NMSSHLogVerbose(@"SSH session started");
// We managed to successfully setup a connection
[self setConnected:YES];
return self.isConnected;
}
- (void)disconnect {
if (_channel) {
[_channel closeShell];
[self setChannel:nil];
}
if (_sftp) {
if ([_sftp isConnected]) {
[_sftp disconnect];
}
[self setSftp:nil];
}
if (self.agent) {
libssh2_agent_disconnect(self.agent);
libssh2_agent_free(self.agent);
[self setAgent:NULL];
}
if (self.session) {
libssh2_session_disconnect(self.session, "NMSSH: Disconnect");
[self setSessionToFree:self.session];
[self setSession:NULL];
}
if (_socket) {
CFSocketInvalidate(_socket);
CFRelease(_socket);
_socket = NULL;
}
NMSSHLogVerbose(@"Disconnected");
[self setConnected:NO];
}
// -----------------------------------------------------------------------------
#pragma mark - AUTHENTICATION
// -----------------------------------------------------------------------------
- (BOOL)isAuthorized {
if (self.session) {
return libssh2_userauth_authenticated(self.session) == 1;
}
return NO;
}
- (BOOL)authenticateByPassword:(NSString *)password {
if (!password) {
return NO;
}
if (![self supportsAuthenticationMethod:@"password"]) {
return NO;
}
// Try to authenticate by password
int error = libssh2_userauth_password(self.session, [self.username UTF8String], [password UTF8String]);
if (error) {
NMSSHLogError(@"Password authentication failed with reason %i", error);
return NO;
}
NMSSHLogVerbose(@"Password authentication succeeded.");
return self.isAuthorized;
}
- (BOOL)authenticateByPublicKey:(NSString *)publicKey
privateKey:(NSString *)privateKey
andPassword:(NSString *)password {
if (![self supportsAuthenticationMethod:@"publickey"]) {
return NO;
}
if (password == nil) {
password = @"";
}
// Get absolute paths for private/public key pair
const char *pubKey = [[publicKey stringByExpandingTildeInPath] UTF8String] ?: NULL;
const char *privKey = [[privateKey stringByExpandingTildeInPath] UTF8String] ?: NULL;
// Try to authenticate with key pair and password
int error = libssh2_userauth_publickey_fromfile(self.session,
[self.username UTF8String],
pubKey,
privKey,
[password UTF8String]);
if (error) {
NMSSHLogError(@"Public key authentication failed with reason %i", error);
return NO;
}
NMSSHLogVerbose(@"Public key authentication succeeded.");
return self.isAuthorized;
}
- (BOOL)authenticateByInMemoryPublicKey:(NSString *)publicKey
privateKey:(NSString *)privateKey
andPassword:(NSString *)password {
if (![self supportsAuthenticationMethod:@"publickey"]) {
return NO;
}
if (password == nil) {
password = @"";
}
// Try to authenticate with key pair and password
int error = libssh2_userauth_publickey_frommemory(self.session,
[self.username UTF8String],
[self.username length],
[publicKey UTF8String] ?: nil,
[publicKey length] ?: 0,
[privateKey UTF8String] ?: nil,
[privateKey length] ?: 0,
[password UTF8String]);
if (error) {
NMSSHLogError(@"Public key authentication failed with reason %i", error);
return NO;
}
NMSSHLogVerbose(@"Public key authentication succeeded.");
return self.isAuthorized;
}
- (BOOL)authenticateByKeyboardInteractive {
return [self authenticateByKeyboardInteractiveUsingBlock:nil];
}
- (BOOL)authenticateByKeyboardInteractiveUsingBlock:(NSString *(^)(NSString *request))authenticationBlock {
if (![self supportsAuthenticationMethod:@"keyboard-interactive"]) {
return NO;
}
self.kbAuthenticationBlock = authenticationBlock;
int rc = libssh2_userauth_keyboard_interactive(self.session, [self.username UTF8String], &kb_callback);
self.kbAuthenticationBlock = nil;
if (rc != 0) {
NMSSHLogError(@"Keyboard-interactive authentication failed with reason %i", rc);
return NO;
}
NMSSHLogVerbose(@"Keyboard-interactive authentication succeeded.");
return self.isAuthorized;
}
- (BOOL)connectToAgent {
if (![self supportsAuthenticationMethod:@"publickey"]) {
return NO;
}
// Try to setup a connection to the SSH-agent
[self setAgent:libssh2_agent_init(self.session)];
if (!self.agent) {
NMSSHLogError(@"Could not start a new agent");
return NO;
}
// Try connecting to the agent
if (libssh2_agent_connect(self.agent)) {
NMSSHLogError(@"Failed connection to agent");
return NO;
}
// Try to fetch available SSH identities
if (libssh2_agent_list_identities(self.agent)) {
NMSSHLogError(@"Failed to request agent identities");
return NO;
}
// Search for the correct identity and try to authenticate
struct libssh2_agent_publickey *identity, *prev_identity = NULL;
while (1) {
int error = libssh2_agent_get_identity(self.agent, &identity, prev_identity);
if (error) {
NMSSHLogError(@"Failed to find a valid identity for the agent");
return NO;
}
error = libssh2_agent_userauth(self.agent, [self.username UTF8String], identity);
if (!error) {
return self.isAuthorized;
}
prev_identity = identity;
}
return NO;
}
- (NSArray *)supportedAuthenticationMethods {
char *userauthlist = libssh2_userauth_list(self.session, [self.username UTF8String],
(unsigned int)strlen([self.username UTF8String]));
if (userauthlist == NULL){
NMSSHLogInfo(@"Failed to get authentication method for host %@:%@", self.host, self.port);
return nil;
}
NSString *authList = [NSString stringWithCString:userauthlist encoding:NSUTF8StringEncoding];
NMSSHLogVerbose(@"User auth list: %@", authList);
return [authList componentsSeparatedByString:@","];
}
- (BOOL)supportsAuthenticationMethod:(NSString *)method {
return [[self supportedAuthenticationMethods] containsObject:method];
}
- (NSString *)fingerprint:(NMSSHSessionHash)hashType {
if (!self.session) {
return nil;
}
int libssh2_hash, hashLength;
switch (hashType) {
case NMSSHSessionHashMD5:
libssh2_hash = LIBSSH2_HOSTKEY_HASH_MD5;
hashLength = 16;
break;
case NMSSHSessionHashSHA1:
libssh2_hash = LIBSSH2_HOSTKEY_HASH_SHA1;
hashLength = 20;
break;
}
const char *hash = libssh2_hostkey_hash(self.session, libssh2_hash);
if (!hash) {
NMSSHLogWarn(@"Unable to retrive host's fingerprint");
return nil;
}
NSMutableString *fingerprint = [[NSMutableString alloc] initWithFormat:@"%02X", (unsigned char)hash[0]];
for (int i = 1; i < hashLength; i++) {
[fingerprint appendFormat:@":%02X", (unsigned char)hash[i]];
}
return [fingerprint copy];
}
// -----------------------------------------------------------------------------
#pragma mark - KNOWN HOSTS
// -----------------------------------------------------------------------------
- (NSString *)applicationSupportDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *applicationSupportDirectory = paths[0];
NSString *nmsshDirectory = [applicationSupportDirectory stringByAppendingPathComponent:@"NMSSH"];
if (![[NSFileManager defaultManager] fileExistsAtPath:nmsshDirectory]) {
[[NSFileManager defaultManager] createDirectoryAtPath:nmsshDirectory
withIntermediateDirectories:YES
attributes:nil
error:NULL];
}
return nmsshDirectory;
}
- (NSString *)userKnownHostsFileName {
#if TARGET_OS_IPHONE
return [[self applicationSupportDirectory] stringByAppendingPathComponent:@"known_hosts"];
#else
return [@"~/.ssh/known_hosts" stringByExpandingTildeInPath];
#endif
}
#if !TARGET_OS_IPHONE
- (NSString *)systemKnownHostsFileName {
return @"/etc/ssh/ssh_known_hosts";
}
#endif
- (NMSSHKnownHostStatus)knownHostStatusInFiles:(NSArray *)files {
if (!files) {
#if TARGET_OS_IPHONE
files = @[[self userKnownHostsFileName]];
#else
files = @[[self systemKnownHostsFileName], [self userKnownHostsFileName]];
#endif
}
NMSSHKnownHostStatus status = NMSSHKnownHostStatusFailure;
for (NSString *filename in files) {
status = [self knownHostStatusWithFile:filename];
if (status != NMSSHKnownHostStatusNotFound && status != NMSSHKnownHostStatusFailure) {
return status;
}
}
return status;
}
- (NMSSHKnownHostStatus)knownHostStatusWithFile:(NSString *)filename {
LIBSSH2_KNOWNHOSTS *knownHosts = libssh2_knownhost_init(self.session);
if (!knownHosts) {
return NMSSHKnownHostStatusFailure;
}
int rc = libssh2_knownhost_readfile(knownHosts,
[filename UTF8String],
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if (rc < 0) {
libssh2_knownhost_free(knownHosts);
if (rc == LIBSSH2_ERROR_FILE) {
NMSSHLogInfo(@"No known hosts file %@.", filename);
return NMSSHKnownHostStatusNotFound;
}
else {
NMSSHLogError(@"Failed to read known hosts file %@.", filename);
return NMSSHKnownHostStatusFailure;
}
}
int keytype;
size_t keylen;
const char *remotekey = libssh2_session_hostkey(self.session, &keylen, &keytype);
if (!remotekey) {
NMSSHLogError(@"Failed to get host key.");
libssh2_knownhost_free(knownHosts);
return NMSSHKnownHostStatusFailure;
}
int keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA ? LIBSSH2_KNOWNHOST_KEY_SSHRSA : LIBSSH2_KNOWNHOST_KEY_SSHDSS);
struct libssh2_knownhost *host;
NMSSHLogInfo(@"Check for host %@, port %@ in file %@", self.host, self.port, filename);
int check = libssh2_knownhost_checkp(knownHosts,
[self.host UTF8String],
[self.port intValue],
remotekey,
keylen,
(LIBSSH2_KNOWNHOST_TYPE_PLAIN |
LIBSSH2_KNOWNHOST_KEYENC_RAW |
keybit),
&host);
libssh2_knownhost_free(knownHosts);
switch (check) {
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
NMSSHLogInfo(@"Match");
return NMSSHKnownHostStatusMatch;
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
NMSSHLogInfo(@"Mismatch");
return NMSSHKnownHostStatusMismatch;
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
NMSSHLogInfo(@"Not found");
return NMSSHKnownHostStatusNotFound;
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
default:
NMSSHLogInfo(@"Failure");
return NMSSHKnownHostStatusFailure;
}
}
- (BOOL)addKnownHostName:(NSString *)host port:(NSInteger)port toFile:(NSString *)fileName withSalt:(NSString *)salt {
const char *hostkey;
size_t hklen;
int hktype;
NSString *hostname; // Formatted as {host} or [{host}]:{port}.
if (port == 22) {
hostname = host;
}
else {
hostname = [NSString stringWithFormat:@"[%@]:%d", host, (int)port];
}
if (!fileName) {
fileName = [self userKnownHostsFileName];
}
hostkey = libssh2_session_hostkey(self.session, &hklen, &hktype);
if (!hostkey) {
NMSSHLogError(@"Failed to get host key.");
return NO;
}
LIBSSH2_KNOWNHOSTS *knownHosts = libssh2_knownhost_init(self.session);
if (!knownHosts) {
NMSSHLogError(@"Failed to initialize knownhosts.");
return NO;
}
int rc = libssh2_knownhost_readfile(knownHosts, [fileName UTF8String], LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if (rc < 0 && rc != LIBSSH2_ERROR_FILE) {
NMSSHLogError(@"Failed to read known hosts file.");
libssh2_knownhost_free(knownHosts);
return NO;
}
int keybit = LIBSSH2_KNOWNHOST_KEYENC_RAW;
if (hktype == LIBSSH2_HOSTKEY_TYPE_RSA) {
keybit |= LIBSSH2_KNOWNHOST_KEY_SSHRSA;
}
else {
keybit |= LIBSSH2_KNOWNHOST_KEY_SSHDSS;
}
if (salt) {
keybit |= LIBSSH2_KNOWNHOST_TYPE_SHA1;
}
else {
keybit |= LIBSSH2_KNOWNHOST_TYPE_PLAIN;
}
int result = libssh2_knownhost_addc(knownHosts,
[hostname UTF8String],
[salt UTF8String],
hostkey,
hklen,
NULL,
0,
keybit,
NULL);
if (result) {
NMSSHLogError(@"Failed to add host to known hosts: error %d (%@)",
result,
[self lastError]);
}
else {
result = libssh2_knownhost_writefile(knownHosts,
[fileName UTF8String],
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if (result < 0) {
NMSSHLogError(@"Couldn't write to %@: %@",
[self userKnownHostsFileName], [self lastError]);
}
else {
NMSSHLogInfo(@"Host added to known hosts.");
}
}
libssh2_knownhost_free(knownHosts);
return result == 0;
}
- (NSString *)keyboardInteractiveRequest:(NSString *)request {
NMSSHLogVerbose(@"Server request '%@'", request);
if (self.kbAuthenticationBlock) {
return self.kbAuthenticationBlock(request);
}
else if (self.delegate && [self.delegate respondsToSelector:@selector(session:keyboardInteractiveRequest:)]) {
return [self.delegate session:self keyboardInteractiveRequest:request];
}
NMSSHLogWarn(@"Keyboard interactive requires a delegate that responds to session:keyboardInteractiveRequest: or a block!");
return @"";
}
void kb_callback(const char *name, int name_len, const char *instr, int instr_len,
int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *res, void **abstract) {
int i;
NMSSHSession *self = (__bridge NMSSHSession *)*abstract;
for (i = 0; i < num_prompts; i++) {
NSString *request = [[NSString alloc] initWithBytes:prompts[i].text length:prompts[i].length encoding:NSUTF8StringEncoding];
NSString *response = [self keyboardInteractiveRequest:request];
if (!response) {
response = @"";
}
res[i].text = strdup([response UTF8String]);
res[i].length = (unsigned int)strlen([response UTF8String]);
}
}
void disconnect_callback(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract) {
NMSSHSession *self = (__bridge NMSSHSession *)*abstract;
// Build a raw error to encapsulate the disconnect
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:2];
if (message) {
NSString *string = [[NSString alloc] initWithBytes:message length:message_len encoding:NSUTF8StringEncoding];
[userInfo setObject:string forKey:NSLocalizedDescriptionKey];
}
if (language) {
NSString *string = [[NSString alloc] initWithBytes:language length:language_len encoding:NSUTF8StringEncoding];
[userInfo setObject:string forKey:@"language"];
}
NSError *error = [NSError errorWithDomain:@"NMSSH" code:reason userInfo:userInfo];
if (self.delegate && [self.delegate respondsToSelector:@selector(session:didDisconnectWithError:)]) {
[self.delegate session:self didDisconnectWithError:error];
}
[self disconnect];
}
// -----------------------------------------------------------------------------
#pragma mark - QUICK CHANNEL/SFTP ACCESS
// -----------------------------------------------------------------------------
- (NMSSHChannel *)channel {
if (!_channel) {
_channel = [[NMSSHChannel alloc] initWithSession:self];
}
return _channel;
}
- (NMSFTP *)sftp {
if (!_sftp) {
_sftp = [[NMSFTP alloc] initWithSession:self];
}
return _sftp;
}
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Protocols/NMSSHChannelDelegate.h
================================================
#import "NMSSH.h"
@class NMSSHChannel;
/**
Protocol for registering to receive messages from an active NMSSHChannel.
*/
@protocol NMSSHChannelDelegate
@optional
/**
Called when a channel read new data on the socket.
@param channel The channel that read the message
@param message The message that the channel has read
*/
- (void)channel:(NMSSHChannel *)channel didReadData:(NSString *)message;
/**
Called when a channel read new error on the socket.
@param channel The channel that read the error
@param error The error that the channel has read
*/
- (void)channel:(NMSSHChannel *)channel didReadError:(NSString *)error;
/**
Called when a channel read new data on the socket.
@param channel The channel that read the message
@param data The bytes that the channel has read
*/
- (void)channel:(NMSSHChannel *)channel didReadRawData:(NSData *)data;
/**
Called when a channel read new error on the socket.
@param channel The channel that read the error
@param error The error that the channel has read
*/
- (void)channel:(NMSSHChannel *)channel didReadRawError:(NSData *)error;
/**
Called when a channel in shell mode has been closed.
@param channel The channel that has been closed
*/
- (void)channelShellDidClose:(NMSSHChannel *)channel;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH/Protocols/NMSSHSessionDelegate.h
================================================
#import "NMSSH.h"
@class NMSSHSession;
/**
Protocol for registering to receive messages from an active NMSSHSession.
*/
@protocol NMSSHSessionDelegate
@optional
/**
Called when the session is setup to use keyboard interactive authentication,
and the server is sending back a question (e.g. a password request).
@param session The session that is asking
@param request Question from server
@returns A valid response to the given question
*/
- (NSString *)session:(NMSSHSession *)session keyboardInteractiveRequest:(NSString *)request;
/**
Called when a session has failed and disconnected.
@param session The session that was disconnected
@param error A description of the error that caused the disconnect
*/
- (void)session:(NMSSHSession *)session didDisconnectWithError:(NSError *)error;
/**
Called when a session is connecting to a host, the fingerprint is used
to verify the authenticity of the host.
@param session The session that is connecting
@param fingerprint The host's fingerprint
@returns YES if the session should trust the host, otherwise NO.
*/
- (BOOL)session:(NMSSHSession *)session shouldConnectToHostWithFingerprint:(NSString *)fingerprint;
@end
================================================
FILE: Sublime/Pods/NMSSH/NMSSH-iOS/Libraries/include/libssh2/libssh2.h
================================================
/* Copyright (c) 2004-2009, Sara Golemon
* Copyright (c) 2009-2015 Daniel Stenberg
* Copyright (c) 2010 Simon Josefsson
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_H
#define LIBSSH2_H 1
#define LIBSSH2_COPYRIGHT "2004-2015 The libssh2 project and its contributors."
/* We use underscore instead of dash when appending DEV in dev versions just
to make the BANNER define (used by src/session.c) be a valid SSH
banner. Release versions have no appended strings and may of course not
have dashes either. */
#define LIBSSH2_VERSION "1.6.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBSSH2_VERSION_MAJOR 1
#define LIBSSH2_VERSION_MINOR 6
#define LIBSSH2_VERSION_PATCH 0
/* This is the numeric version of the libssh2 version number, meant for easier
parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
always follow this syntax:
0xXXYYZZ
Where XX, YY and ZZ are the main version, release and patch numbers in
hexadecimal (using 8 bits each). All three numbers are always represented
using two digits. 1.2 would appear as "0x010200" while version 9.11.7
appears as "0x090b07".
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
and it is always a greater number in a more recent release. It makes
comparisons with greater than and less than work.
*/
#define LIBSSH2_VERSION_NUM 0x010600
/*
* This is the date and time when the full source package was created. The
* timestamp is not stored in the source code repo, as the timestamp is
* properly set in the tarballs by the maketgz script.
*
* The format of the date should follow this template:
*
* "Mon Feb 12 11:35:33 UTC 2007"
*/
#define LIBSSH2_TIMESTAMP "Fri Jun 12 06:58:26 UTC 2015"
#ifndef RC_INVOKED
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
# include
# include
#endif
#include
#include
#include
#include
/* Allow alternate API prefix from CFLAGS or calling app */
#ifndef LIBSSH2_API
# ifdef LIBSSH2_WIN32
# ifdef _WINDLL
# ifdef LIBSSH2_LIBRARY
# define LIBSSH2_API __declspec(dllexport)
# else
# define LIBSSH2_API __declspec(dllimport)
# endif /* LIBSSH2_LIBRARY */
# else
# define LIBSSH2_API
# endif
# else /* !LIBSSH2_WIN32 */
# define LIBSSH2_API
# endif /* LIBSSH2_WIN32 */
#endif /* LIBSSH2_API */
#ifdef HAVE_SYS_UIO_H
# include
#endif
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
# include
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
#endif
#ifdef _MSC_VER
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 libssh2_uint64_t;
typedef __int64 libssh2_int64_t;
#ifndef ssize_t
typedef SSIZE_T ssize_t;
#endif
#else
typedef unsigned long long libssh2_uint64_t;
typedef long long libssh2_int64_t;
#endif
#ifdef WIN32
typedef SOCKET libssh2_socket_t;
#define LIBSSH2_INVALID_SOCKET INVALID_SOCKET
#else /* !WIN32 */
typedef int libssh2_socket_t;
#define LIBSSH2_INVALID_SOCKET -1
#endif /* WIN32 */
/* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
/* We *could* add a comment here if we so chose */
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
#define LIBSSH2_DH_GEX_MINGROUP 1024
#define LIBSSH2_DH_GEX_OPTGROUP 1536
#define LIBSSH2_DH_GEX_MAXGROUP 2048
/* Defaults for pty requests */
#define LIBSSH2_TERM_WIDTH 80
#define LIBSSH2_TERM_HEIGHT 24
#define LIBSSH2_TERM_WIDTH_PX 0
#define LIBSSH2_TERM_HEIGHT_PX 0
/* 1/4 second */
#define LIBSSH2_SOCKET_POLL_UDELAY 250000
/* 0.25 * 120 == 30 seconds */
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
/* Maximum size to allow a payload to compress to, plays it safe by falling
short of spec limits */
#define LIBSSH2_PACKET_MAXCOMP 32000
/* Maximum size to allow a payload to deccompress to, plays it safe by
allowing more than spec requires */
#define LIBSSH2_PACKET_MAXDECOMP 40000
/* Maximum size for an inbound compressed payload, plays it safe by
overshooting spec limits */
#define LIBSSH2_PACKET_MAXPAYLOAD 40000
/* Malloc callbacks */
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, \
void **abstract)
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
{
char* text;
unsigned int length;
unsigned char echo;
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
{
char* text;
unsigned int length;
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
/* 'publickey' authentication callback */
#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \
const unsigned char *data, size_t data_len, void **abstract)
/* 'keyboard-interactive' authentication callback */
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \
void name_(const char* name, int name_len, const char* instruction, \
int instruction_len, int num_prompts, \
const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, \
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
/* Callbacks for special SSH packets */
#define LIBSSH2_IGNORE_FUNC(name) \
void name(LIBSSH2_SESSION *session, const char *message, int message_len, \
void **abstract)
#define LIBSSH2_DEBUG_FUNC(name) \
void name(LIBSSH2_SESSION *session, int always_display, const char *message, \
int message_len, const char *language, int language_len, \
void **abstract)
#define LIBSSH2_DISCONNECT_FUNC(name) \
void name(LIBSSH2_SESSION *session, int reason, const char *message, \
int message_len, const char *language, int language_len, \
void **abstract)
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \
void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \
void **abstract)
#define LIBSSH2_MACERROR_FUNC(name) \
int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \
void **abstract)
#define LIBSSH2_X11_OPEN_FUNC(name) \
void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \
const char *shost, int sport, void **abstract)
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \
void name(LIBSSH2_SESSION *session, void **session_abstract, \
LIBSSH2_CHANNEL *channel, void **channel_abstract)
/* I/O callbacks */
#define LIBSSH2_RECV_FUNC(name) ssize_t name(libssh2_socket_t socket, \
void *buffer, size_t length, \
int flags, void **abstract)
#define LIBSSH2_SEND_FUNC(name) ssize_t name(libssh2_socket_t socket, \
const void *buffer, size_t length,\
int flags, void **abstract)
/* libssh2_session_callback_set() constants */
#define LIBSSH2_CALLBACK_IGNORE 0
#define LIBSSH2_CALLBACK_DEBUG 1
#define LIBSSH2_CALLBACK_DISCONNECT 2
#define LIBSSH2_CALLBACK_MACERROR 3
#define LIBSSH2_CALLBACK_X11 4
#define LIBSSH2_CALLBACK_SEND 5
#define LIBSSH2_CALLBACK_RECV 6
/* libssh2_session_method_pref() constants */
#define LIBSSH2_METHOD_KEX 0
#define LIBSSH2_METHOD_HOSTKEY 1
#define LIBSSH2_METHOD_CRYPT_CS 2
#define LIBSSH2_METHOD_CRYPT_SC 3
#define LIBSSH2_METHOD_MAC_CS 4
#define LIBSSH2_METHOD_MAC_SC 5
#define LIBSSH2_METHOD_COMP_CS 6
#define LIBSSH2_METHOD_COMP_SC 7
#define LIBSSH2_METHOD_LANG_CS 8
#define LIBSSH2_METHOD_LANG_SC 9
/* flags */
#define LIBSSH2_FLAG_SIGPIPE 1
#define LIBSSH2_FLAG_COMPRESS 2
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS;
typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT;
typedef struct _LIBSSH2_POLLFD {
unsigned char type; /* LIBSSH2_POLLFD_* below */
union {
libssh2_socket_t socket; /* File descriptors -- examined with
system select() call */
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound
connections waiting to be accepted? */
} fd;
unsigned long events; /* Requested Events */
unsigned long revents; /* Returned Events */
} LIBSSH2_POLLFD;
/* Poll FD Descriptor Types */
#define LIBSSH2_POLLFD_SOCKET 1
#define LIBSSH2_POLLFD_CHANNEL 2
#define LIBSSH2_POLLFD_LISTENER 3
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these
values are faked with select() data */
/* Poll FD events/revents -- Match sys/poll.h where possible */
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or
connection available --
All */
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to
be read -- Socket only */
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to
be read -- Channel only */
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written --
Socket/Channel */
/* revents only */
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket
Only */
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition --
Socket/Win32 */
#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
/* Block Direction Types */
#define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001
#define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002
/* Hash Types */
#define LIBSSH2_HOSTKEY_HASH_MD5 1
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
/* Hostkey Types */
#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0
#define LIBSSH2_HOSTKEY_TYPE_RSA 1
#define LIBSSH2_HOSTKEY_TYPE_DSS 2
/* Disconnect Codes (defined by SSH protocol) */
#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
#define SSH_DISCONNECT_PROTOCOL_ERROR 2
#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3
#define SSH_DISCONNECT_RESERVED 4
#define SSH_DISCONNECT_MAC_ERROR 5
#define SSH_DISCONNECT_COMPRESSION_ERROR 6
#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7
#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
#define SSH_DISCONNECT_CONNECTION_LOST 10
#define SSH_DISCONNECT_BY_APPLICATION 11
#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12
#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
/* Error Codes (defined by libssh2) */
#define LIBSSH2_ERROR_NONE 0
/* The library once used -1 as a generic error return value on numerous places
through the code, which subsequently was converted to
LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code,
the goal is to never ever return this code but instead make sure that a
more accurate and descriptive error code is used. */
#define LIBSSH2_ERROR_SOCKET_NONE -1
#define LIBSSH2_ERROR_BANNER_RECV -2
#define LIBSSH2_ERROR_BANNER_SEND -3
#define LIBSSH2_ERROR_INVALID_MAC -4
#define LIBSSH2_ERROR_KEX_FAILURE -5
#define LIBSSH2_ERROR_ALLOC -6
#define LIBSSH2_ERROR_SOCKET_SEND -7
#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8
#define LIBSSH2_ERROR_TIMEOUT -9
#define LIBSSH2_ERROR_HOSTKEY_INIT -10
#define LIBSSH2_ERROR_HOSTKEY_SIGN -11
#define LIBSSH2_ERROR_DECRYPT -12
#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13
#define LIBSSH2_ERROR_PROTO -14
#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15
#define LIBSSH2_ERROR_FILE -16
#define LIBSSH2_ERROR_METHOD_NONE -17
#define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18
#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED LIBSSH2_ERROR_AUTHENTICATION_FAILED
#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19
#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20
#define LIBSSH2_ERROR_CHANNEL_FAILURE -21
#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22
#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23
#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24
#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25
#define LIBSSH2_ERROR_CHANNEL_CLOSED -26
#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
#define LIBSSH2_ERROR_ZLIB -29
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
#define LIBSSH2_ERROR_REQUEST_DENIED -32
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
#define LIBSSH2_ERROR_INVAL -34
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
#define LIBSSH2_ERROR_EAGAIN -37
#define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38
#define LIBSSH2_ERROR_BAD_USE -39
#define LIBSSH2_ERROR_COMPRESS -40
#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41
#define LIBSSH2_ERROR_AGENT_PROTOCOL -42
#define LIBSSH2_ERROR_SOCKET_RECV -43
#define LIBSSH2_ERROR_ENCRYPT -44
#define LIBSSH2_ERROR_BAD_SOCKET -45
#define LIBSSH2_ERROR_KNOWN_HOSTS -46
/* this is a define to provide the old (<= 1.2.7) name */
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
/* Global API */
#define LIBSSH2_INIT_NO_CRYPTO 0x0001
/*
* libssh2_init()
*
* Initialize the libssh2 functions. This typically initialize the
* crypto library. It uses a global state, and is not thread safe --
* you must make sure this function is not called concurrently.
*
* Flags can be:
* 0: Normal initialize
* LIBSSH2_INIT_NO_CRYPTO: Do not initialize the crypto library (ie.
* OPENSSL_add_cipher_algoritms() for OpenSSL
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int libssh2_init(int flags);
/*
* libssh2_exit()
*
* Exit the libssh2 functions and free's all memory used internal.
*/
LIBSSH2_API void libssh2_exit(void);
/*
* libssh2_free()
*
* Deallocate memory allocated by earlier call to libssh2 functions.
*/
LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr);
/*
* libssh2_session_supported_algs()
*
* Fills algs with a list of supported acryptographic algorithms. Returns a
* non-negative number (number of supported algorithms) on success or a
* negative number (an eror code) on failure.
*
* NOTE: on success, algs must be deallocated (by calling libssh2_free) when
* not needed anymore
*/
LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session,
int method_type,
const char*** algs);
/* Session API */
LIBSSH2_API LIBSSH2_SESSION *
libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
LIBSSH2_FREE_FUNC((*my_free)),
LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session,
int cbtype, void *callback);
LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session,
const char *banner);
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session,
const char *banner);
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock);
LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session,
libssh2_socket_t sock);
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session,
int reason,
const char *description,
const char *lang);
#define libssh2_session_disconnect(session, description) \
libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \
(description), "")
LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session);
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session,
int hash_type);
LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session,
size_t *len, int *type);
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session,
int method_type,
const char *prefs);
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session,
int method_type);
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session,
char **errmsg,
int *errmsg_len, int want_buf);
LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag,
int value);
LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session);
/* Userauth API */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len,
const char *password,
unsigned int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
#define libssh2_userauth_password(session, username, password) \
libssh2_userauth_password_ex((session), (username), \
(unsigned int)strlen(username), \
(password), (unsigned int)strlen(password), NULL)
LIBSSH2_API int
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len,
const char *publickey,
const char *privatekey,
const char *passphrase);
#define libssh2_userauth_publickey_fromfile(session, username, publickey, \
privatekey, passphrase) \
libssh2_userauth_publickey_fromfile_ex((session), (username), \
(unsigned int)strlen(username), \
(publickey), \
(privatekey), (passphrase))
LIBSSH2_API int
libssh2_userauth_publickey(LIBSSH2_SESSION *session,
const char *username,
const unsigned char *pubkeydata,
size_t pubkeydata_len,
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
void **abstract);
LIBSSH2_API int
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len,
const char *publickey,
const char *privatekey,
const char *passphrase,
const char *hostname,
unsigned int hostname_len,
const char *local_username,
unsigned int local_username_len);
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \
privatekey, passphrase, hostname) \
libssh2_userauth_hostbased_fromfile_ex((session), (username), \
(unsigned int)strlen(username), \
(publickey), \
(privatekey), (passphrase), \
(hostname), \
(unsigned int)strlen(hostname), \
(username), \
(unsigned int)strlen(username))
LIBSSH2_API int
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
const char *username,
size_t username_len,
const char *publickeyfiledata,
size_t publickeyfiledata_len,
const char *privatekeyfiledata,
size_t privatekeyfiledata_len,
const char *passphrase);
/*
* response_callback is provided with filled by library prompts array,
* but client must allocate and fill individual responses. Responses
* array is already allocated. Responses data will be freed by libssh2
* after callback return, but before subsequent callback invokation.
*/
LIBSSH2_API int
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session,
const char *username,
unsigned int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
#define libssh2_userauth_keyboard_interactive(session, username, \
response_callback) \
libssh2_userauth_keyboard_interactive_ex((session), (username), \
(unsigned int)strlen(username), \
(response_callback))
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
long timeout);
/* Channel API */
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (2*1024*1024)
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768
#define LIBSSH2_CHANNEL_MINADJUST 1024
/* Extended Data Handling */
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1
#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2
#define SSH_EXTENDED_DATA_STDERR 1
/* Returned by any function that would block during a read/write opperation */
#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type,
unsigned int channel_type_len,
unsigned int window_size, unsigned int packet_size,
const char *message, unsigned int message_len);
#define libssh2_channel_open_session(session) \
libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \
LIBSSH2_CHANNEL_WINDOW_DEFAULT, \
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host,
int port, const char *shost, int sport);
#define libssh2_channel_direct_tcpip(session, host, port) \
libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
LIBSSH2_API LIBSSH2_LISTENER *
libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host,
int port, int *bound_port, int queue_maxsize);
#define libssh2_channel_forward_listen(session, port) \
libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel,
const char *varname,
unsigned int varname_len,
const char *value,
unsigned int value_len);
#define libssh2_channel_setenv(channel, varname, value) \
libssh2_channel_setenv_ex((channel), (varname), \
(unsigned int)strlen(varname), (value), \
(unsigned int)strlen(value))
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel,
const char *term,
unsigned int term_len,
const char *modes,
unsigned int modes_len,
int width, int height,
int width_px, int height_px);
#define libssh2_channel_request_pty(channel, term) \
libssh2_channel_request_pty_ex((channel), (term), \
(unsigned int)strlen(term), \
NULL, 0, \
LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, \
LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel,
int width, int height,
int width_px,
int height_px);
#define libssh2_channel_request_pty_size(channel, width, height) \
libssh2_channel_request_pty_size_ex( (channel), (width), (height), 0, 0)
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel,
int single_connection,
const char *auth_proto,
const char *auth_cookie,
int screen_number);
#define libssh2_channel_x11_req(channel, screen_number) \
libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
const char *request,
unsigned int request_len,
const char *message,
unsigned int message_len);
#define libssh2_channel_shell(channel) \
libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \
NULL, 0)
#define libssh2_channel_exec(channel, command) \
libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \
(command), (unsigned int)strlen(command))
#define libssh2_channel_subsystem(channel, subsystem) \
libssh2_channel_process_startup((channel), "subsystem", \
sizeof("subsystem") - 1, (subsystem), \
(unsigned int)strlen(subsystem))
LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
int stream_id, char *buf,
size_t buflen);
#define libssh2_channel_read(channel, buf, buflen) \
libssh2_channel_read_ex((channel), 0, (buf), (buflen))
#define libssh2_channel_read_stderr(channel, buf, buflen) \
libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel,
int extended);
LIBSSH2_API unsigned long
libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
unsigned long *read_avail,
unsigned long *window_size_initial);
#define libssh2_channel_window_read(channel) \
libssh2_channel_window_read_ex((channel), NULL, NULL)
/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */
LIBSSH2_API unsigned long
libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel,
unsigned long adjustment,
unsigned char force);
LIBSSH2_API int
libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel,
unsigned long adjustment,
unsigned char force,
unsigned int *storewindow);
LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
int stream_id, const char *buf,
size_t buflen);
#define libssh2_channel_write(channel, buf, buflen) \
libssh2_channel_write_ex((channel), 0, (buf), (buflen))
#define libssh2_channel_write_stderr(channel, buf, buflen) \
libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
LIBSSH2_API unsigned long
libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel,
unsigned long *window_size_initial);
#define libssh2_channel_window_write(channel) \
libssh2_channel_window_write_ex((channel), NULL)
LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session,
int blocking);
LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel,
int blocking);
LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session,
long timeout);
LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session);
/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
int ignore_mode);
LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel,
int ignore_mode);
/* libssh2_channel_ignore_extended_data() is defined below for BC with version
* 0.1
*
* Future uses should use libssh2_channel_handle_extended_data() directly if
* LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read
* (FIFO) from the standard data channel
*/
/* DEPRECATED */
#define libssh2_channel_ignore_extended_data(channel, ignore) \
libssh2_channel_handle_extended_data((channel), \
(ignore) ? \
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \
LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1
#define LIBSSH2_CHANNEL_FLUSH_ALL -2
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel,
int streamid);
#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
#define libssh2_channel_flush_stderr(channel) \
libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel,
char **exitsignal,
size_t *exitsignal_len,
char **errmsg,
size_t *errmsg_len,
char **langtag,
size_t *langtag_len);
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session,
const char *path,
struct stat *sb);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session,
const char *path, int mode,
size_t size, long mtime,
long atime);
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode,
libssh2_int64_t size, time_t mtime, time_t atime);
#define libssh2_scp_send(session, path, mode, size) \
libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest,
unsigned int *dest_len,
const char *src, unsigned int src_len);
LIBSSH2_API
const char *libssh2_version(int req_version_num);
#define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */
#define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */
struct libssh2_knownhost {
unsigned int magic; /* magic stored by the library */
void *node; /* handle to the internal representation of this host */
char *name; /* this is NULL if no plain text host name exists */
char *key; /* key in base64/printable format */
int typemask;
};
/*
* libssh2_knownhost_init
*
* Init a collection of known hosts. Returns the pointer to a collection.
*
*/
LIBSSH2_API LIBSSH2_KNOWNHOSTS *
libssh2_knownhost_init(LIBSSH2_SESSION *session);
/*
* libssh2_knownhost_add
*
* Add a host and its associated key to the collection of known hosts.
*
* The 'type' argument specifies on what format the given host and keys are:
*
* plain - ascii "hostname.domain.tld"
* sha1 - SHA1( ) base64-encoded!
* custom - another hash
*
* If 'sha1' is selected as type, the salt must be provided to the salt
* argument. This too base64 encoded.
*
* The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If
* a custom type is used, salt is ignored and you must provide the host
* pre-hashed when checking for it in the libssh2_knownhost_check() function.
*
* The keylen parameter may be omitted (zero) if the key is provided as a
* NULL-terminated base64-encoded string.
*/
/* host format (2 bits) */
#define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff
#define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1
#define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */
#define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3
/* key format (2 bits) */
#define LIBSSH2_KNOWNHOST_KEYENC_MASK (3<<16)
#define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16)
#define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16)
/* type of key (2 bits) */
#define LIBSSH2_KNOWNHOST_KEY_MASK (7<<18)
#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18
#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18)
#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18)
#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18)
#define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (7<<18)
LIBSSH2_API int
libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
const char *host,
const char *salt,
const char *key, size_t keylen, int typemask,
struct libssh2_knownhost **store);
/*
* libssh2_knownhost_addc
*
* Add a host and its associated key to the collection of known hosts.
*
* Takes a comment argument that may be NULL. A NULL comment indicates
* there is no comment and the entry will end directly after the key
* when written out to a file. An empty string "" comment will indicate an
* empty comment which will cause a single space to be written after the key.
*
* The 'type' argument specifies on what format the given host and keys are:
*
* plain - ascii "hostname.domain.tld"
* sha1 - SHA1( ) base64-encoded!
* custom - another hash
*
* If 'sha1' is selected as type, the salt must be provided to the salt
* argument. This too base64 encoded.
*
* The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If
* a custom type is used, salt is ignored and you must provide the host
* pre-hashed when checking for it in the libssh2_knownhost_check() function.
*
* The keylen parameter may be omitted (zero) if the key is provided as a
* NULL-terminated base64-encoded string.
*/
LIBSSH2_API int
libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts,
const char *host,
const char *salt,
const char *key, size_t keylen,
const char *comment, size_t commentlen, int typemask,
struct libssh2_knownhost **store);
/*
* libssh2_knownhost_check
*
* Check a host and its associated key against the collection of known hosts.
*
* The type is the type/format of the given host name.
*
* plain - ascii "hostname.domain.tld"
* custom - prehashed base64 encoded. Note that this cannot use any salts.
*
*
* 'knownhost' may be set to NULL if you don't care about that info.
*
* Returns:
*
* LIBSSH2_KNOWNHOST_CHECK_* values, see below
*
*/
#define LIBSSH2_KNOWNHOST_CHECK_MATCH 0
#define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1
#define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2
#define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3
LIBSSH2_API int
libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
const char *host, const char *key, size_t keylen,
int typemask,
struct libssh2_knownhost **knownhost);
/* this function is identital to the above one, but also takes a port
argument that allows libssh2 to do a better check */
LIBSSH2_API int
libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts,
const char *host, int port,
const char *key, size_t keylen,
int typemask,
struct libssh2_knownhost **knownhost);
/*
* libssh2_knownhost_del
*
* Remove a host from the collection of known hosts. The 'entry' struct is
* retrieved by a call to libssh2_knownhost_check().
*
*/
LIBSSH2_API int
libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts,
struct libssh2_knownhost *entry);
/*
* libssh2_knownhost_free
*
* Free an entire collection of known hosts.
*
*/
LIBSSH2_API void
libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts);
/*
* libssh2_knownhost_readline()
*
* Pass in a line of a file of 'type'. It makes libssh2 read this line.
*
* LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type.
*
*/
LIBSSH2_API int
libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts,
const char *line, size_t len, int type);
/*
* libssh2_knownhost_readfile
*
* Add hosts+key pairs from a given file.
*
* Returns a negative value for error or number of successfully added hosts.
*
* This implementation currently only knows one 'type' (openssh), all others
* are reserved for future use.
*/
#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1
LIBSSH2_API int
libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts,
const char *filename, int type);
/*
* libssh2_knownhost_writeline()
*
* Ask libssh2 to convert a known host to an output line for storage.
*
* Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given
* output buffer is too small to hold the desired output.
*
* This implementation currently only knows one 'type' (openssh), all others
* are reserved for future use.
*
*/
LIBSSH2_API int
libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
struct libssh2_knownhost *known,
char *buffer, size_t buflen,
size_t *outlen, /* the amount of written data */
int type);
/*
* libssh2_knownhost_writefile
*
* Write hosts+key pairs to a given file.
*
* This implementation currently only knows one 'type' (openssh), all others
* are reserved for future use.
*/
LIBSSH2_API int
libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts,
const char *filename, int type);
/*
* libssh2_knownhost_get()
*
* Traverse the internal list of known hosts. Pass NULL to 'prev' to get
* the first one. Or pass a poiner to the previously returned one to get the
* next.
*
* Returns:
* 0 if a fine host was stored in 'store'
* 1 if end of hosts
* [negative] on errors
*/
LIBSSH2_API int
libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts,
struct libssh2_knownhost **store,
struct libssh2_knownhost *prev);
#define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */
struct libssh2_agent_publickey {
unsigned int magic; /* magic stored by the library */
void *node; /* handle to the internal representation of key */
unsigned char *blob; /* public key blob */
size_t blob_len; /* length of the public key blob */
char *comment; /* comment in printable format */
};
/*
* libssh2_agent_init
*
* Init an ssh-agent handle. Returns the pointer to the handle.
*
*/
LIBSSH2_API LIBSSH2_AGENT *
libssh2_agent_init(LIBSSH2_SESSION *session);
/*
* libssh2_agent_connect()
*
* Connect to an ssh-agent.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_connect(LIBSSH2_AGENT *agent);
/*
* libssh2_agent_list_identities()
*
* Request an ssh-agent to list identities.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_list_identities(LIBSSH2_AGENT *agent);
/*
* libssh2_agent_get_identity()
*
* Traverse the internal list of public keys. Pass NULL to 'prev' to get
* the first one. Or pass a poiner to the previously returned one to get the
* next.
*
* Returns:
* 0 if a fine public key was stored in 'store'
* 1 if end of public keys
* [negative] on errors
*/
LIBSSH2_API int
libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
struct libssh2_agent_publickey **store,
struct libssh2_agent_publickey *prev);
/*
* libssh2_agent_userauth()
*
* Do publickey user authentication with the help of ssh-agent.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_userauth(LIBSSH2_AGENT *agent,
const char *username,
struct libssh2_agent_publickey *identity);
/*
* libssh2_agent_disconnect()
*
* Close a connection to an ssh-agent.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_disconnect(LIBSSH2_AGENT *agent);
/*
* libssh2_agent_free()
*
* Free an ssh-agent handle. This function also frees the internal
* collection of public keys.
*/
LIBSSH2_API void
libssh2_agent_free(LIBSSH2_AGENT *agent);
/*
* libssh2_keepalive_config()
*
* Set how often keepalive messages should be sent. WANT_REPLY
* indicates whether the keepalive messages should request a response
* from the server. INTERVAL is number of seconds that can pass
* without any I/O, use 0 (the default) to disable keepalives. To
* avoid some busy-loop corner-cases, if you specify an interval of 1
* it will be treated as 2.
*
* Note that non-blocking applications are responsible for sending the
* keepalive messages using libssh2_keepalive_send().
*/
LIBSSH2_API void libssh2_keepalive_config (LIBSSH2_SESSION *session,
int want_reply,
unsigned interval);
/*
* libssh2_keepalive_send()
*
* Send a keepalive message if needed. SECONDS_TO_NEXT indicates how
* many seconds you can sleep after this call before you need to call
* it again. Returns 0 on success, or LIBSSH2_ERROR_SOCKET_SEND on
* I/O errors.
*/
LIBSSH2_API int libssh2_keepalive_send (LIBSSH2_SESSION *session,
int *seconds_to_next);
/* NOTE NOTE NOTE
libssh2_trace() has no function in builds that aren't built with debug
enabled
*/
LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask);
#define LIBSSH2_TRACE_TRANS (1<<1)
#define LIBSSH2_TRACE_KEX (1<<2)
#define LIBSSH2_TRACE_AUTH (1<<3)
#define LIBSSH2_TRACE_CONN (1<<4)
#define LIBSSH2_TRACE_SCP (1<<5)
#define LIBSSH2_TRACE_SFTP (1<<6)
#define LIBSSH2_TRACE_ERROR (1<<7)
#define LIBSSH2_TRACE_PUBLICKEY (1<<8)
#define LIBSSH2_TRACE_SOCKET (1<<9)
typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*,
void*,
const char *,
size_t);
LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session,
void* context,
libssh2_trace_handler_func callback);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* !RC_INVOKED */
#endif /* LIBSSH2_H */
================================================
FILE: Sublime/Pods/NMSSH/NMSSH-iOS/Libraries/include/libssh2/libssh2_publickey.h
================================================
/* Copyright (c) 2004-2006, Sara Golemon
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/* Note: This include file is only needed for using the
* publickey SUBSYSTEM which is not the same as publickey
* authentication. For authentication you only need libssh2.h
*
* For more information on the publickey subsystem,
* refer to IETF draft: secsh-publickey
*/
#ifndef LIBSSH2_PUBLICKEY_H
#define LIBSSH2_PUBLICKEY_H 1
#include "libssh2.h"
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
typedef struct _libssh2_publickey_attribute {
const char *name;
unsigned long name_len;
const char *value;
unsigned long value_len;
char mandatory;
} libssh2_publickey_attribute;
typedef struct _libssh2_publickey_list {
unsigned char *packet; /* For freeing */
const unsigned char *name;
unsigned long name_len;
const unsigned char *blob;
unsigned long blob_len;
unsigned long num_attrs;
libssh2_publickey_attribute *attrs; /* free me */
} libssh2_publickey_list;
/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
#define libssh2_publickey_attribute(name, value, mandatory) \
{ (name), strlen(name), (value), strlen(value), (mandatory) },
#define libssh2_publickey_attribute_fast(name, value, mandatory) \
{ (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
#ifdef __cplusplus
extern "C" {
#endif
/* Publickey Subsystem */
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey,
const unsigned char *name,
unsigned long name_len,
const unsigned char *blob,
unsigned long blob_len, char overwrite,
unsigned long num_attrs,
const libssh2_publickey_attribute attrs[]);
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \
num_attrs, attrs) \
libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \
(overwrite), (num_attrs), (attrs))
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey,
const unsigned char *name,
unsigned long name_len,
const unsigned char *blob,
unsigned long blob_len);
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
LIBSSH2_API int
libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey,
unsigned long *num_keys,
libssh2_publickey_list **pkey_list);
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey,
libssh2_publickey_list *pkey_list);
LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef: LIBSSH2_PUBLICKEY_H */
================================================
FILE: Sublime/Pods/NMSSH/NMSSH-iOS/Libraries/include/libssh2/libssh2_sftp.h
================================================
/* Copyright (c) 2004-2008, Sara Golemon
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_SFTP_H
#define LIBSSH2_SFTP_H 1
#include "libssh2.h"
#ifndef WIN32
#include
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Note: Version 6 was documented at the time of writing
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
*
* Let's start with Version 3 (The version found in OpenSSH) and go from there
*/
#define LIBSSH2_SFTP_VERSION 3
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS;
/* Flags for open_ex() */
#define LIBSSH2_SFTP_OPENFILE 0
#define LIBSSH2_SFTP_OPENDIR 1
/* Flags for rename_ex() */
#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
/* Flags for stat_ex() */
#define LIBSSH2_SFTP_STAT 0
#define LIBSSH2_SFTP_LSTAT 1
#define LIBSSH2_SFTP_SETSTAT 2
/* Flags for symlink_ex() */
#define LIBSSH2_SFTP_SYMLINK 0
#define LIBSSH2_SFTP_READLINK 1
#define LIBSSH2_SFTP_REALPATH 2
/* SFTP attribute flag bits */
#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
/* SFTP statvfs flag bits */
#define LIBSSH2_SFTP_ST_RDONLY 0x00000001
#define LIBSSH2_SFTP_ST_NOSUID 0x00000002
struct _LIBSSH2_SFTP_ATTRIBUTES {
/* If flags & ATTR_* bit is set, then the value in this struct will be
* meaningful Otherwise it should be ignored
*/
unsigned long flags;
libssh2_uint64_t filesize;
unsigned long uid, gid;
unsigned long permissions;
unsigned long atime, mtime;
};
struct _LIBSSH2_SFTP_STATVFS {
libssh2_uint64_t f_bsize; /* file system block size */
libssh2_uint64_t f_frsize; /* fragment size */
libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */
libssh2_uint64_t f_bfree; /* # free blocks */
libssh2_uint64_t f_bavail; /* # free blocks for non-root */
libssh2_uint64_t f_files; /* # inodes */
libssh2_uint64_t f_ffree; /* # free inodes */
libssh2_uint64_t f_favail; /* # free inodes for non-root */
libssh2_uint64_t f_fsid; /* file system ID */
libssh2_uint64_t f_flag; /* mount flags */
libssh2_uint64_t f_namemax; /* maximum filename length */
};
/* SFTP filetypes */
#define LIBSSH2_SFTP_TYPE_REGULAR 1
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
#define LIBSSH2_SFTP_TYPE_SYMLINK 3
#define LIBSSH2_SFTP_TYPE_SPECIAL 4
#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
#define LIBSSH2_SFTP_TYPE_SOCKET 6
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
#define LIBSSH2_SFTP_TYPE_FIFO 9
/*
* Reproduce the POSIX file modes here for systems that are not POSIX
* compliant.
*
* These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
*/
/* File type */
#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */
#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */
#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */
#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */
#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */
#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */
#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */
#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */
/* File mode */
/* Read, write, execute/search by owner */
#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */
#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */
#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */
#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */
/* Read, write, execute/search by group */
#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */
#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */
#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */
#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */
/* Read, write, execute/search by others */
#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */
#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */
#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */
#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */
/* macros to check for specific file types, added in 1.2.5 */
#define LIBSSH2_SFTP_S_ISLNK(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)
#define LIBSSH2_SFTP_S_ISREG(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG)
#define LIBSSH2_SFTP_S_ISDIR(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR)
#define LIBSSH2_SFTP_S_ISCHR(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR)
#define LIBSSH2_SFTP_S_ISBLK(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK)
#define LIBSSH2_SFTP_S_ISFIFO(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO)
#define LIBSSH2_SFTP_S_ISSOCK(m) \
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK)
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
#define LIBSSH2_FXF_READ 0x00000001
#define LIBSSH2_FXF_WRITE 0x00000002
#define LIBSSH2_FXF_APPEND 0x00000004
#define LIBSSH2_FXF_CREAT 0x00000008
#define LIBSSH2_FXF_TRUNC 0x00000010
#define LIBSSH2_FXF_EXCL 0x00000020
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
#define LIBSSH2_FX_OK 0
#define LIBSSH2_FX_EOF 1
#define LIBSSH2_FX_NO_SUCH_FILE 2
#define LIBSSH2_FX_PERMISSION_DENIED 3
#define LIBSSH2_FX_FAILURE 4
#define LIBSSH2_FX_BAD_MESSAGE 5
#define LIBSSH2_FX_NO_CONNECTION 6
#define LIBSSH2_FX_CONNECTION_LOST 7
#define LIBSSH2_FX_OP_UNSUPPORTED 8
#define LIBSSH2_FX_INVALID_HANDLE 9
#define LIBSSH2_FX_NO_SUCH_PATH 10
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
#define LIBSSH2_FX_WRITE_PROTECT 12
#define LIBSSH2_FX_NO_MEDIA 13
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
#define LIBSSH2_FX_QUOTA_EXCEEDED 15
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16
#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */
#define LIBSSH2_FX_LOCK_CONFLICT 17
#define LIBSSH2_FX_DIR_NOT_EMPTY 18
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
#define LIBSSH2_FX_INVALID_FILENAME 20
#define LIBSSH2_FX_LINK_LOOP 21
/* Returned by any function that would block during a read/write opperation */
#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
/* SFTP API */
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp);
/* File / Directory Ops */
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp,
const char *filename,
unsigned int filename_len,
unsigned long flags,
long mode, int open_type);
#define libssh2_sftp_open(sftp, filename, flags, mode) \
libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \
(mode), LIBSSH2_SFTP_OPENFILE)
#define libssh2_sftp_opendir(sftp, path) \
libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \
LIBSSH2_SFTP_OPENDIR)
LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
char *buffer, size_t buffer_maxlen);
LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
char *buffer, size_t buffer_maxlen,
char *longentry,
size_t longentry_maxlen,
LIBSSH2_SFTP_ATTRIBUTES *attrs);
#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \
libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \
(attrs))
LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
const char *buffer, size_t count);
LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle,
libssh2_uint64_t offset);
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0)
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle);
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle,
LIBSSH2_SFTP_ATTRIBUTES *attrs,
int setstat);
#define libssh2_sftp_fstat(handle, attrs) \
libssh2_sftp_fstat_ex((handle), (attrs), 0)
#define libssh2_sftp_fsetstat(handle, attrs) \
libssh2_sftp_fstat_ex((handle), (attrs), 1)
/* Miscellaneous Ops */
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,
const char *source_filename,
unsigned int srouce_filename_len,
const char *dest_filename,
unsigned int dest_filename_len,
long flags);
#define libssh2_sftp_rename(sftp, sourcefile, destfile) \
libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \
(destfile), strlen(destfile), \
LIBSSH2_SFTP_RENAME_OVERWRITE | \
LIBSSH2_SFTP_RENAME_ATOMIC | \
LIBSSH2_SFTP_RENAME_NATIVE)
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp,
const char *filename,
unsigned int filename_len);
#define libssh2_sftp_unlink(sftp, filename) \
libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
LIBSSH2_SFTP_STATVFS *st);
LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp,
const char *path,
size_t path_len,
LIBSSH2_SFTP_STATVFS *st);
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len, long mode);
#define libssh2_sftp_mkdir(sftp, path, mode) \
libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len);
#define libssh2_sftp_rmdir(sftp, path) \
libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len,
int stat_type,
LIBSSH2_SFTP_ATTRIBUTES *attrs);
#define libssh2_sftp_stat(sftp, path, attrs) \
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \
(attrs))
#define libssh2_sftp_lstat(sftp, path, attrs) \
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \
(attrs))
#define libssh2_sftp_setstat(sftp, path, attrs) \
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \
(attrs))
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len,
char *target,
unsigned int target_len, int link_type);
#define libssh2_sftp_symlink(sftp, orig, linkpath) \
libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \
strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
#define libssh2_sftp_readlink(sftp, path, target, maxlen) \
libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
LIBSSH2_SFTP_READLINK)
#define libssh2_sftp_realpath(sftp, path, target, maxlen) \
libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
LIBSSH2_SFTP_REALPATH)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSSH2_SFTP_H */
================================================
FILE: Sublime/Pods/NMSSH/NMSSH-iOS/Libraries/lib/libcrypto.a
================================================
[File too large to display: 32.1 MB]
================================================
FILE: Sublime/Pods/NMSSH/NMSSH-iOS/NMSSH.h
================================================
#import
//! Project version number for NMSSH.
FOUNDATION_EXPORT double NMSSHVersionNumber;
//! Project version string for NMSSH.
FOUNDATION_EXPORT const unsigned char NMSSHVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import
#import "libssh2.h"
#import "libssh2_sftp.h"
#import "NMSSHSessionDelegate.h"
#import "NMSSHChannelDelegate.h"
#import "NMSSHSession.h"
#import "NMSSHChannel.h"
#import "NMSFTP.h"
#import "NMSFTPFile.h"
#import "NMSSHConfig.h"
#import "NMSSHHostConfig.h"
#import "NMSSHLogger.h"
================================================
FILE: Sublime/Pods/NMSSH/README.md
================================================
# NMSSH
NMSSH is a clean, easy-to-use, unit tested framework for iOS and OSX that wraps libssh2.
## Questions & Issues
If you encounter an issue or have any questions about implementing NMSSH, please post them in [the issue tracker](https://github.com/NMSSH/NMSSH/issues) – we do not offer free support via email.
## Installation
### CocoaPods
pod 'NMSSH'
### Build from source
Consult the Wiki for detailed information about how to:
* [Build for OSX](https://github.com/NMSSH/NMSSH/wiki/Build-and-use-in-your-OSX-project) or
* [Build for iOS](https://github.com/NMSSH/NMSSH/wiki/Build-and-use-in-your-iOS-project).
### Include it in your project
Add `#import ` to your source file.
## What does it look like?
```objc
NMSSHSession *session = [NMSSHSession connectToHost:@"127.0.0.1:22"
withUsername:@"user"];
if (session.isConnected) {
[session authenticateByPassword:@"pass"];
if (session.isAuthorized) {
NSLog(@"Authentication succeeded");
}
}
NSError *error = nil;
NSString *response = [session.channel execute:@"ls -l /var/www/" error:&error];
NSLog(@"List of my sites: %@", response);
BOOL success = [session.channel uploadFile:@"~/index.html" to:@"/var/www/9muses.se/"];
[session disconnect];
```
## API Documentation
API documentation for NMSSH is available at [http://cocoadocs.org/docsets/NMSSH/](http://cocoadocs.org/docsets/NMSSH/).
## Guidelines for contributions
* Follow the [code conventions](https://github.com/Lejdborg/cocoa-conventions/).
* Fork NMSSH and create a feature branch. Develop your feature.
* Open a pull request.
**Note:** Make sure that you have _documented your code_ and that you _follow the code conventions_ before opening a pull request.
## NMSSH is used in
* [iTerm2](https://github.com/gnachman/iTerm2)
* [DogeWallet](https://github.com/SlayterDev/DogeWallet)
## Developed by
### Core team
* [Christoffer Lejdborg (@Lejdborg)](https://github.com/Lejdborg) (creator)
* [Tommaso Madonia (@Frugghi)](https://github.com/Frugghi)
### Contributors
* [Sebastian Hunkeler (@lightforce)](https://github.com/lightforce)
* [Endika Gutiérrez (@endSly)](https://github.com/endSly)
* [Clemens Gruber (@clemensg)](https://github.com/clemensg)
* [@gnachman](https://github.com/gnachman)
* [@Shirk](https://github.com/Shirk)
* [@touta](https://github.com/touta)
## License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Sublime/Pods/Pods.xcodeproj/project.pbxproj
================================================
archiveVersion
1
classes
objectVersion
46
objects
003EBB47E856DBB92F4A63FC2AD8C892
fileRef
C989B85CAE2F73F5FFAA2EFB44C56081
isa
PBXBuildFile
009369000D8CF5B8C1E3E6BF283CA73A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
Charts-dummy.m
sourceTree
<group>
00ED322AD74E086D0DBE4FAC8A72856D
children
59639868BF0B29D1419BB3F9312567AF
6BAE05E7054A14414B907DD7F37AC8B7
B02BF2860C124E9C66C26D2E4913EC5B
4620E80B337EA9F040BEB93DF08BD134
5FA31142FE846A63B3CDCF338C03AF0F
6B173C46DF90109FE17024B11AD202E2
isa
PBXGroup
name
Support Files
path
../Target Support Files/ZLSinusWaveView
sourceTree
<group>
01776C25A5DB30E5FB22DABA2D28B271
fileRef
C7B98156605B0AC4C70830469ABB06A4
isa
PBXBuildFile
settings
ATTRIBUTES
Public
0256D63626119843AC1248D91D38C551
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
F49E17CE595BF7A7A46139779E891F78
remoteInfo
SSZipArchive
02787AB0F80C11B895A72337338D4CB7
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
Gifu.framework
path
Gifu.framework
sourceTree
BUILT_PRODUCTS_DIR
0282FE2D0C3A9B3705A974193237B978
isa
PBXTargetDependency
name
Alamofire
target
79C040AFDDCE1BCBF6D8B5EB0B85887F
targetProxy
FB8A97E23B00E9EE80BB504728D87825
0294DCA76D64937CF8D8ADF477A4FA11
includeInIndex
1
isa
PBXFileReference
name
pwd2key.c
path
SSZipArchive/aes/pwd2key.c
sourceTree
<group>
02C1BEA6FE84433F6C6A713533B7B9BD
fileRef
BE3F1A095E8DF60F568AC3C16C9CD9CC
isa
PBXBuildFile
02E32AEB8ABF1AF925416098365CE932
fileRef
78FCECFF404AD0FD74BACA1C1FC9FFBE
isa
PBXBuildFile
033590E1C2397DA8E570B55810775B8E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IBarLineScatterCandleBubbleChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift
sourceTree
<group>
034548B827C03622818B97E6F50C78EC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Swifter.xcconfig
sourceTree
<group>
0354751919E03C8001824EA2F707F272
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
DGElasticPullToRefresh-umbrella.h
sourceTree
<group>
035FEBC2FF9B0AA63626D2CB12316222
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
0380D2B912CDE029522351D67E39310E
fileRef
D5F44E638D27C282B496D1999C8B754A
isa
PBXBuildFile
settings
ATTRIBUTES
Public
03F0D41F8726403C1B0B5F3D93915906
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpServerIO.swift
path
Sources/HttpServerIO.swift
sourceTree
<group>
03FC642C1EF0F16D7AB31F4AC6D6F719
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSFTPFile.h
path
NMSSH/NMSFTPFile.h
sourceTree
<group>
040B16E53C2CBFE2007A0A70EE690D77
includeInIndex
1
isa
PBXFileReference
path
Alamofire.modulemap
sourceTree
<group>
04A4F1E8E6A3624871B2EE0C687248B2
baseConfigurationReference
C29238134AE5C4B8C2352C6C11C495EB
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView-prefix.pch
INFOPLIST_FILE
Target Support Files/ZLMusicFlowWaveView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
ZLMusicFlowWaveView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
05B129043462F91B458D18AFB8F529C2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
05BA62425D43DD87EC6390A0FAE74D1E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartAnimationEasing.swift
path
Charts/Classes/Animation/ChartAnimationEasing.swift
sourceTree
<group>
05D9707C1A350638ECD52006A481F077
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ParameterEncoding.swift
path
Source/ParameterEncoding.swift
sourceTree
<group>
06FD8F213BF2DF4860A3890A3F6C9943
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpServer.swift
path
Sources/HttpServer.swift
sourceTree
<group>
0727A4243F3B7D3216AAC08CA047DA60
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
ZLMusicFlowWaveView.framework
path
ZLMusicFlowWaveView.framework
sourceTree
BUILT_PRODUCTS_DIR
07C1897D80CE662EEE2BB582594B5752
fileRef
D7C1E15DAA48F123231A498172D38967
isa
PBXBuildFile
settings
ATTRIBUTES
Public
07F0E71CC75B65CD371F8F56F53D86F0
fileRef
53F1005ADB78F4613F8C29A68E8B9909
isa
PBXBuildFile
0832C378A14BA80BA5856826F1530746
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
CYRTextView-prefix.pch
sourceTree
<group>
087A04860A4A8EC54E6A1A5AF7F73E23
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ScatterChartRenderer.swift
path
Charts/Classes/Renderers/ScatterChartRenderer.swift
sourceTree
<group>
095406039B4D371E48D08B38A2975AC8
fileRef
86A4F33244B76027A52DC18FE83F6FA8
isa
PBXBuildFile
095B4CA441317582AEAB49625A56CC8D
children
17E57B8F489EA569011B8678EC392493
AE9410D9B1C05916CA1D2817FB0F45F1
29FE1468A9F2C8D913EAD260E4E8B852
A0688D041EA5E1060A50787E5D0A8B88
82D6671E6434CBE40C23F48ECD063E9B
isa
PBXGroup
name
ZLMusicFlowWaveView
path
ZLMusicFlowWaveView
sourceTree
<group>
0A0B1AD12AF0AAF31F2FE461AEDD6AC9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSSHSession.m
path
NMSSH/NMSSHSession.m
sourceTree
<group>
0A3248BA59E025188FAAD1071189AA40
buildConfigurations
3E5B420A73875137D4437E73149DCAEA
5F0A3448A6BD1FAE4B4F4E61EFD3DDCF
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
0A55876558D0DC9160E5F6D64ADBA9F8
buildActionMask
2147483647
files
69FC867B9095871D1CDC05702AD7F41B
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
0B180880779669D029654CA4D9E08852
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
0B93148101A5531681949F675D41538E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IRadarChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IRadarChartDataSet.swift
sourceTree
<group>
0BD8E73E6A192F43B39F876E1E07146C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHConfig.h
path
NMSSH/NMSSHConfig.h
sourceTree
<group>
0BDAAEDEF5A3BBD3D36419ADBC621E43
baseConfigurationReference
36D90A99286A433572F91AB604418967
buildSettings
ENABLE_STRICT_OBJC_MSGSEND
YES
PRODUCT_NAME
AlamofireRSS
SDKROOT
iphoneos
SKIP_INSTALL
YES
WRAPPER_EXTENSION
bundle
isa
XCBuildConfiguration
name
Release
0BE89C1211FB9D34E28695028E028BC5
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
PieChartData.swift
path
Charts/Classes/Data/Implementations/Standard/PieChartData.swift
sourceTree
<group>
0C2C052032470959CD56614BF9453DC8
fileRef
4ED7C61B5475997505191F07F768B0E2
isa
PBXBuildFile
0C8EFD8D5CCE9A85C27C92ACCD85C521
children
2E7E02258E9A5195895517F8E2465FB8
E5055FEB2A2A322A90311B7874DC9092
146F9CE3135B0F3E12EAB93142B6C6DC
12E1D0B1AD9B09A7E6ED15D5F09F4FAB
0354751919E03C8001824EA2F707F272
0B180880779669D029654CA4D9E08852
isa
PBXGroup
name
Support Files
path
../Target Support Files/DGElasticPullToRefresh
sourceTree
<group>
0CCE916C80D42C6943D73D1A829DA787
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SJCSimplePDFView-umbrella.h
sourceTree
<group>
0CFA654DBD993FD0F891ECD3B7432064
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSSHChannel.m
path
NMSSH/NMSSHChannel.m
sourceTree
<group>
0D30D4EC5DBB217F591F99D492225B04
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
entropy.h
path
SSZipArchive/aes/entropy.h
sourceTree
<group>
0D9E3E8557D628F179DC72179BE68873
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DGElasticPullToRefreshView.swift
path
DGElasticPullToRefresh/DGElasticPullToRefreshView.swift
sourceTree
<group>
0DD8F6D8387DB0C06C39A8FA16AB65F2
buildConfigurations
B90A6C426043472FEECCAD567C74CD38
9D4F76E63FE32EDCFE411B47AADE7C20
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
0E579C8B6EC88FD31F0C2B47C9058B48
buildConfigurationList
BFBFE3DE50EEDD42B2CC58CF2F499BCE
buildPhases
453AE9B30136CD292073FFCB386A111C
A46427534DD269E2ED45FE9190F4F819
A001EF9508D510E336B414095A84EC0F
buildRules
dependencies
isa
PBXNativeTarget
name
AASquaresLoading
productName
AASquaresLoading
productReference
2993BE53CEB9368C1FD283A26A8DC3CF
productType
com.apple.product-type.framework
0E5DECF96C58C0F18CD5F7C5221CC7A7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataBaseFilter.swift
path
Charts/Classes/Filters/ChartDataBaseFilter.swift
sourceTree
<group>
0F92FE99CE8E162CBD0DC7F965008A6E
fileRef
0BD8E73E6A192F43B39F876E1E07146C
isa
PBXBuildFile
settings
ATTRIBUTES
Public
0FAAC91F636F7A42B8D0A2D53351CB33
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
SwiftyJSON.swift
path
Source/SwiftyJSON.swift
sourceTree
<group>
0FBCB9B828FF98812A1EE98817048C46
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ILineRadarChartDataSet.swift
path
Charts/Classes/Data/Interfaces/ILineRadarChartDataSet.swift
sourceTree
<group>
0FCE52111ED6A874AB515E76EA8BF894
children
EF2C26926BC90B457BF77F1F5C3864A5
40F968A172478FA1FF7BC61E5E43A165
2A54E14C2D0994A8370C91E5B536A105
E1802D1110A2554B9624857DFBA4126A
FFCB6492484858E07ECCD87017C470A1
80DD5455D2185F4B63EC6AFA95A51E88
7404D532E36CB49046A6B5F2B4CB9E68
9B4184FC9E303824C5756A811AB09E31
5C5512B13DBD171651F6D19C66DCBB1B
997199E72131063A4BBCAE8FBC3CAECC
2B7CE3EB8CB44E72DC0954A7CCE3CD35
1877516BBE621827BE92D407A3C73851
DCE911485FE993C88C00E6FC8F301448
74CDEF8BA057A6BB4453A748E70EA142
095B4CA441317582AEAB49625A56CC8D
ADD71B1DEF5A923A72F5BD91617A3BFA
isa
PBXGroup
name
Pods
sourceTree
<group>
0FDD62CA863BD5DBE7F5C375C207C7EF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudioPlotGLKViewController.h
path
EZAudio/EZAudioPlotGLKViewController.h
sourceTree
<group>
10DA9C9D58BDE4AEBC101C70A645E315
fileRef
B88349DF809DD951EF76B2B561C15983
isa
PBXBuildFile
114543CA2F4712B855C440FC1C01B461
fileRef
278A8E9A676F2861EE04688763C40773
isa
PBXBuildFile
settings
ATTRIBUTES
Project
115824B7CB2E76E5ACB836A251E79404
buildConfigurationList
74DF8A9CBE6EAEB8C19105D047645443
buildPhases
3943D764C0D525CFAF94F943648E17BE
9E138A11AB568FDD962F892987F6F048
F60BC667495022BB71DE0C146D3C99EA
buildRules
dependencies
isa
PBXNativeTarget
name
DGElasticPullToRefresh
productName
DGElasticPullToRefresh
productReference
F7852FD543BD5C8EEF81095A19EAD332
productType
com.apple.product-type.framework
1167F2A0B491A489F337578AC16A5F11
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxisRendererBarChart.swift
path
Charts/Classes/Renderers/ChartXAxisRendererBarChart.swift
sourceTree
<group>
11BA64BC0B2FE8DDB41883B7241A8C49
fileRef
146F9CE3135B0F3E12EAB93142B6C6DC
isa
PBXBuildFile
11F862EDC00E98340C3E6E46BA922E26
fileRef
B990718DD6D67073DBCDCF8E6ABED5A5
isa
PBXBuildFile
124CC709A273ED2691A47C5CEA065111
buildActionMask
2147483647
files
5FF6421A0B1404F43C1F56F99853EC96
3A06439A9A5AE0F27374CF4A27AB4A0B
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
124D0BAABE6160B5E0B6ADC527C58418
fileRef
78A8CAE0A08DC8E818F6E7C79557A27D
isa
PBXBuildFile
1260E1D284190E2A3D00903698C9D2F3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
CYRTextView.xcconfig
sourceTree
<group>
1268FBA2F4CEE4DC3577E8DD52D25975
fileRef
22059022078636D0B5F42A74AF4B5A22
isa
PBXBuildFile
127AB4661AC9A5832C3D5A4077C1A58C
fileRef
55AB31E45DC84ECFF7CC6FC6AB1ACC81
isa
PBXBuildFile
129963BBCBF40DB2189A0EB7993EDF12
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudioPlayer.m
path
EZAudio/EZAudioPlayer.m
sourceTree
<group>
12E1D0B1AD9B09A7E6ED15D5F09F4FAB
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
DGElasticPullToRefresh-prefix.pch
sourceTree
<group>
131D95D3FCDF7799E1D69213A378638E
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
136FA39293487CFA2EA9129427511420
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpHandlers+WebSockets.swift
path
Sources/HttpHandlers+WebSockets.swift
sourceTree
<group>
137FDB371251B06FCC2593DBA88272D2
buildConfigurationList
0DD8F6D8387DB0C06C39A8FA16AB65F2
buildPhases
809023B98C9FF6044DF1314603EE8B91
2F9FD76D50F8510D46C22FB03BF984DF
DD3A008898F33BA6A93E536EF2E82A41
buildRules
dependencies
6357E4DF80060A4CD9B6E9B06D5DBFE3
269A73CB99FCBCBFAB8CFE698D4AEFB0
6C4C1217EC8BF9E5E6DC8386FEAA0C3A
4D8F6F5FDD8AE252C8D21C76F72CEC9F
D903133FE593BA39A527BFD1887D43BE
CB8943577E424C7F4E953DE7A18FA12C
76820BB8A343CE818398366E3787913C
FC9D79D0CC991302B49BFA48C4BE2AB9
1F8A1467F981A8E370A8939AA38A7367
E714E7EE552ED72453DB7F1AB1FE9DC9
409962F3CD08FB4947DAEFF94EDEFC86
ABFB4E32ADD23D5E47758C89919D0EAD
976A24EA83BF3467025D3580ED456D06
38C869AE53183F93DD743ED2C7192EB8
8F96B72A2D016C2925132ED704A6D6F4
isa
PBXNativeTarget
name
Pods
productName
Pods
productReference
1A85B3DEA68DBE452583A860BFC25D68
productType
com.apple.product-type.framework
146F9CE3135B0F3E12EAB93142B6C6DC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
DGElasticPullToRefresh-dummy.m
sourceTree
<group>
14E2A18762B2C933AF7EF481D1079936
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
Alamofire.framework
path
Alamofire.framework
sourceTree
BUILT_PRODUCTS_DIR
1568D9F321313FECF78F199CE4E7B442
fileRef
4E2E3D5588060B9FF52974B06D2DB9B7
isa
PBXBuildFile
15796F12649F437721B9C3177EE84A7F
includeInIndex
1
isa
PBXFileReference
name
aescrypt.c
path
SSZipArchive/aes/aescrypt.c
sourceTree
<group>
158958FF49153EA1D61DF28C680C441B
fileRef
EFAF93ECA6E252EF29AB51A210E6D8E4
isa
PBXBuildFile
settings
ATTRIBUTES
Public
15AD01DB1A64F162CCBC2E4D02B1458A
fileRef
2A19DB845AD3D3E62C87A8183C450FC5
isa
PBXBuildFile
16102E4E35FAA0FC4161282FECE56469
fileRef
B5EEC8A63E90F6F8F85DEF5514D52ED8
isa
PBXBuildFile
161961ABCAFC8D944C13F6B003163607
includeInIndex
1
isa
PBXFileReference
name
fileenc.c
path
SSZipArchive/aes/fileenc.c
sourceTree
<group>
163CCB0ED553E79B03AC5CE313F1DD77
fileRef
CE787D2E7219B1CE32FB1F9F3BB56BC6
isa
PBXBuildFile
settings
ATTRIBUTES
Project
16707D24276E0D4BA984EAD7829AFC3B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSSHLogger.m
path
NMSSH/Config/NMSSHLogger.m
sourceTree
<group>
1677FAD2A148DA1DDE73736B4848878B
fileRef
46E1873E64EC87857800E9B2C2A793A7
isa
PBXBuildFile
169B552578427611CD64555A461D8A88
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpParser.swift
path
Sources/HttpParser.swift
sourceTree
<group>
16B29AE122AF64257C643FA13FBBA52B
fileRef
BD11BD25E12B54CC641E519B27C11B66
isa
PBXBuildFile
settings
ATTRIBUTES
Public
16BED61439C924D34FF25EC21932E8AF
includeInIndex
1
isa
PBXFileReference
name
zip.c
path
SSZipArchive/minizip/zip.c
sourceTree
<group>
1711226039A0CD668F7DBEEE45D9E238
fileRef
1167F2A0B491A489F337578AC16A5F11
isa
PBXBuildFile
1792949332E845FCE9745F455932668C
fileRef
2A6A25FC0A0B5FF53D4D6302464DF0A2
isa
PBXBuildFile
17C4E6CB67D0446387655B959DA3A951
fileRef
15796F12649F437721B9C3177EE84A7F
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
17C841636A1F7BAB561CE0585060E01F
buildActionMask
2147483647
files
423A9BA046AD7AEAED121ABE70F42763
511493881CA40859A5E2279BD386A7AB
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
17E57B8F489EA569011B8678EC392493
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
ZLMusicFlowDecorativeView.h
path
ZLMusicFlowWaveView/ZLMusicFlowDecorativeView.h
sourceTree
<group>
17E8ECFF7879DDE903F47869DEBAA874
fileRef
4FF58A41D7B6111B458ADE82268C1178
isa
PBXBuildFile
17F30271B79E8344F95C3FA89632ADC8
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
17FA4A36C2BDDC132AF9A0B1CE9E02F4
fileRef
DCECD6AAC84A0BDBE43081FFF891F3FF
isa
PBXBuildFile
settings
ATTRIBUTES
Project
1845D98CE7CF2F3174B2E68C1E535445
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartView.swift
path
Charts/Classes/Charts/BubbleChartView.swift
sourceTree
<group>
1877516BBE621827BE92D407A3C73851
children
4E488569CDEF3276C1BC982119CE0914
278A8E9A676F2861EE04688763C40773
15796F12649F437721B9C3177EE84A7F
CEEC903A8A88FC7DAC58821172A38152
B801611949F9A65BDAD1BA9E75AC4B43
BFE4C92C7B56F5BE2EDB6693B5B01F06
86662528AE34D79C3BA78439C0D9D01E
71C68E3AFFC61709566D8EA695CFB5E7
2E0EC03652FA915F8E96EFC2558A5439
C832BE8F84718CAD9B5B7A0F2296F628
F3E8A533B0FA4678233C985618BEEEA6
67016485CE0220DF8AF0DDC343E3F51C
0D30D4EC5DBB217F591F99D492225B04
161961ABCAFC8D944C13F6B003163607
DC0D405095C90FB4035A2F0243192579
86909353BB4657C029BB5008942330ED
DFCF6A958A237C3D561F2830085A3000
87D7DAF7937EAF3CF65F1B022D9A8BDB
22B30496E9D4C59ABF59F254C49FF122
35D6A246A5B602182B55996C79DEC3B7
9D7EF092E912A37841FC7F3316B1EE46
66289F09E2686DE08ED6DE071A0D5077
CE787D2E7219B1CE32FB1F9F3BB56BC6
0294DCA76D64937CF8D8ADF477A4FA11
DCECD6AAC84A0BDBE43081FFF891F3FF
BB8BF3A20530EBB622CA33D5AEFB739D
ED50758E863F122346C9C2E1873E53DE
3A04E2A8DAC2E69D929439C0D50562D4
CE9719F08048A9825AEAE45D13A0F9DF
A1B31917F302790BEE2C7CA37EFBA0DF
31A8AB41E1FF5C54D0970DF38969E324
16BED61439C924D34FF25EC21932E8AF
216C34E27969A0794EC8C460C31FA2CE
DA3C0B91AFC44531B8A01A3F0562457C
F1022A0213E11D4057BBBF840A3B335C
isa
PBXGroup
name
SSZipArchive
path
SSZipArchive
sourceTree
<group>
1891931FD0A3F4CC78749D9E977A8505
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Result.swift
path
Source/Result.swift
sourceTree
<group>
191955118642709970DA6F35F57D57A6
fileRef
71E013AE8742AF9DE782F24E90B5E1DB
isa
PBXBuildFile
191F7183D2E17767A8B14716B9453747
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartYAxisRendererHorizontalBarChart.swift
path
Charts/Classes/Renderers/ChartYAxisRendererHorizontalBarChart.swift
sourceTree
<group>
19318C4AE0C9FF87FDC7C34424E9305F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxisRendererRadarChart.swift
path
Charts/Classes/Renderers/ChartXAxisRendererRadarChart.swift
sourceTree
<group>
1946E9116D8062A9DA249B5276ECE602
baseConfigurationReference
7F87651AE9B6CA0E7F4A0114F19A7924
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/AASquaresLoading/AASquaresLoading-prefix.pch
INFOPLIST_FILE
Target Support Files/AASquaresLoading/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/AASquaresLoading/AASquaresLoading.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
AASquaresLoading
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
1966257DFF573B123534D86FB2A461BE
fileRef
71023FBED2BFC50D42DB8F5E48E31B48
isa
PBXBuildFile
1976D47319F44DDEB11B1DB5E28BEC84
isa
PBXTargetDependency
name
ZLSinusWaveView
target
ADD0B8D536C47FE797C15119D29AFC71
targetProxy
6789ABF735324868C1342E25DEC4AF09
19954D5FC84330E551F6CF2AECCCEC23
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
1A576993F97A4BD21C20CE9685D55B45
fileRef
3127828983CBDF4E8CBE8579564A7ACC
isa
PBXBuildFile
1A7CD22F5ED03019E906E471DD59388F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartViewPortJob.swift
path
Charts/Classes/Jobs/ChartViewPortJob.swift
sourceTree
<group>
1A85B3DEA68DBE452583A860BFC25D68
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
Pods.framework
path
Pods.framework
sourceTree
BUILT_PRODUCTS_DIR
1AA2BFF6AAA29B3C65D9109C6D89B631
fileRef
F38A27EE294EDDE1BCEA87D82E418D06
isa
PBXBuildFile
1AC2B93F71120CA50074113DD62725AC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CombinedHighlighter.swift
path
Charts/Classes/Highlight/CombinedHighlighter.swift
sourceTree
<group>
1B09B90650E7E94D067EEA465021ECFC
fileRef
86662528AE34D79C3BA78439C0D9D01E
isa
PBXBuildFile
settings
ATTRIBUTES
Project
1B8C2B556D484533F17C49F31CFE9279
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartDataEntry.swift
path
Charts/Classes/Data/Implementations/Standard/BarChartDataEntry.swift
sourceTree
<group>
1B8D79A74968EFE68A03C339F93BE40A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ScatterChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/ScatterChartDataSet.swift
sourceTree
<group>
1C13EE24977DA9B45CDE1309CB51D90E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ResponseSerialization.swift
path
Source/ResponseSerialization.swift
sourceTree
<group>
1CF9B76B2F64B9518142C0E419278E19
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
115824B7CB2E76E5ACB836A251E79404
remoteInfo
DGElasticPullToRefresh
1D0D77460730EC30F5AFC5241DE8C317
fileRef
87D7DAF7937EAF3CF65F1B022D9A8BDB
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
1D0F56E661286DC8431D8887DD690692
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpHandlers+Files.swift
path
Sources/HttpHandlers+Files.swift
sourceTree
<group>
1D80AF552B91E3AC0E007F8B3D1C423B
fileRef
8F7A7A4CBF39B0995A17F5F10F25F3A1
isa
PBXBuildFile
settings
ATTRIBUTES
Public
1E5B2E2366403FF3F48D14E0344AB088
buildConfigurations
9F898C8AC3124C1B95F382C093800963
2375931066B859121A3D2FE02DE198F9
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
1E99A621975C1DDBF7CD0F92C076D716
fileRef
AC2EF1AE40274FFDC401667516F473E2
isa
PBXBuildFile
settings
ATTRIBUTES
Public
1ED95865A0F35E6479942C08DC17E359
fileRef
009369000D8CF5B8C1E3E6BF283CA73A
isa
PBXBuildFile
1EF3386A084C9BF7F3B05704CD56DBE6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
EZAudio-dummy.m
sourceTree
<group>
1F2A324FC0B075A00AEE84CC028D8F1F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
libssh2.h
path
NMSSH-iOS/Libraries/include/libssh2/libssh2.h
sourceTree
<group>
1F8A1467F981A8E370A8939AA38A7367
isa
PBXTargetDependency
name
NMSSH
target
3881764D412915AEE2FDC3677F741D9A
targetProxy
DD7AF476E0F820613312BA057B209D07
1F8B22539695E07FA9762AFF2D92CB5A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSSHHostConfig.m
path
NMSSH/NMSSHHostConfig.m
sourceTree
<group>
1FFA88C4B3A1DAF8DA3FBD1FB22358B5
fileRef
1B8C2B556D484533F17C49F31CFE9279
isa
PBXBuildFile
2070C04C1ABE2C3A69159596D2E1DF51
fileRef
1F2A324FC0B075A00AEE84CC028D8F1F
isa
PBXBuildFile
settings
ATTRIBUTES
Public
20C5E87C1DF07DEA65CD74B8D07D6D1C
fileRef
0354751919E03C8001824EA2F707F272
isa
PBXBuildFile
settings
ATTRIBUTES
Public
20DCE1442556CA5F41805570F5B5844F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
UIImageExtension.swift
path
Source/UIImageExtension.swift
sourceTree
<group>
211BF217FEF65CFAFA0595009B57B795
buildActionMask
2147483647
files
A0718C652496BAA16F3007BE63680091
78905BC064EA7CAE6515516D704002CF
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
216C34E27969A0794EC8C460C31FA2CE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
zip.h
path
SSZipArchive/minizip/zip.h
sourceTree
<group>
21B7F68E83AB3158AC18BB512498ECE0
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
SJCSimplePDFView.framework
path
SJCSimplePDFView.framework
sourceTree
BUILT_PRODUCTS_DIR
22059022078636D0B5F42A74AF4B5A22
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataEntry.swift
path
Charts/Classes/Data/Implementations/Standard/ChartDataEntry.swift
sourceTree
<group>
223648D2D9A87589BDD0F2446CC1BF2A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
AlamofireRSSParser-umbrella.h
sourceTree
<group>
224F8C8DCD27EA9658A028C095C4F275
fileRef
6DC1C46D160F2B2BB3AA0C6940A03914
isa
PBXBuildFile
228471249CCDB44C2C2793EFEAF06C43
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
ZLMusicFlowWaveView-umbrella.h
sourceTree
<group>
22B30496E9D4C59ABF59F254C49FF122
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
ioapi.h
path
SSZipArchive/minizip/ioapi.h
sourceTree
<group>
22CC997358A22BFFD42637B6A1E3868C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RadarChartData.swift
path
Charts/Classes/Data/Implementations/Standard/RadarChartData.swift
sourceTree
<group>
2375931066B859121A3D2FE02DE198F9
baseConfigurationReference
8EC66117408FE5D27B57F58550E978C0
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch
INFOPLIST_FILE
Target Support Files/SwiftyJSON/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SwiftyJSON/SwiftyJSON.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
SwiftyJSON
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
23EB4B1F1FB528E10C5030501D4C3454
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Alamofire.xcconfig
sourceTree
<group>
241D3259D8743003561A971C917C0C14
fileRef
66289F09E2686DE08ED6DE071A0D5077
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
242B71AC1ED8BF10BFB8883D7A043B57
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartView.swift
path
Charts/Classes/Charts/BarChartView.swift
sourceTree
<group>
243E707501F994F3795FFB8D67694A89
fileRef
2E0EC03652FA915F8E96EFC2558A5439
isa
PBXBuildFile
settings
ATTRIBUTES
Project
24A9C720DFCC621D045671BF48493E8A
fileRef
4D08E45167845B9A49C6D44EB035AEE6
isa
PBXBuildFile
254EA72DFADAB5F3286B8726A554C9E6
buildConfigurationList
0A3248BA59E025188FAAD1071189AA40
buildPhases
B50658E33EBBEE7C9364A18D8514154E
9303B618AC39FB9AC08C2C49BF74EB55
AAD9F83548ADC849E712A6A4D7A6D789
buildRules
dependencies
isa
PBXNativeTarget
name
EZAudio
productName
EZAudio
productReference
870CD4D0ED37DE3295E8E96C29756E48
productType
com.apple.product-type.framework
25502F3A70A00FFB9812245EC0ECD0F6
fileRef
D09B82E039368828B6E7C5FE88975F8F
isa
PBXBuildFile
25E5BE8AC9996AEF5235FB7EEB1A801D
buildConfigurations
F818CCD384C18AFDD6BDA68C6D1C19A0
E4097C8AD80F7FA95C14816874CD3B28
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
268957DD1BCCEB3ABCE0BA4DED45EA01
fileRef
D40D65B89CE20F485FF2173D31AF3853
isa
PBXBuildFile
268C17FB4A1B500FAE4A02E1F7D87D5C
fileRef
46D3F6AF317B0CA613B0F2C91085FBED
isa
PBXBuildFile
269A73CB99FCBCBFAB8CFE698D4AEFB0
isa
PBXTargetDependency
name
Alamofire
target
79C040AFDDCE1BCBF6D8B5EB0B85887F
targetProxy
6DD9C4273AD1566E52B7A375025B0C89
26CA2DF100EC60422EB34B611F67ACD6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpHandlers.swift
path
Sources/HttpHandlers.swift
sourceTree
<group>
272BAEFC0F1D27DEF0B82A5B2705399E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartData.swift
path
Charts/Classes/Data/Implementations/Standard/BubbleChartData.swift
sourceTree
<group>
27801E482F53A81CBFF8F018F3A098C6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZMicrophone.m
path
EZAudio/EZMicrophone.m
sourceTree
<group>
278A8E9A676F2861EE04688763C40773
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
aes_via_ace.h
path
SSZipArchive/aes/aes_via_ace.h
sourceTree
<group>
284973C8BAF3B75F23E5BF288A890A05
includeInIndex
1
isa
PBXFileReference
path
Charts.modulemap
sourceTree
<group>
290CE55BDCD4E03FA2A31B6B142A4F4C
fileRef
DFCF6A958A237C3D561F2830085A3000
isa
PBXBuildFile
settings
ATTRIBUTES
Project
2993BE53CEB9368C1FD283A26A8DC3CF
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
AASquaresLoading.framework
path
AASquaresLoading.framework
sourceTree
BUILT_PRODUCTS_DIR
29FE1468A9F2C8D913EAD260E4E8B852
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
ZLMusicFlowWaveView.h
path
ZLMusicFlowWaveView/ZLMusicFlowWaveView.h
sourceTree
<group>
2A19DB845AD3D3E62C87A8183C450FC5
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartColorTemplates.swift
path
Charts/Classes/Utils/ChartColorTemplates.swift
sourceTree
<group>
2A54E14C2D0994A8370C91E5B536A105
children
D5F44E638D27C282B496D1999C8B754A
6EA1BE8E8A6172B255E1C74432F2F569
FA6606E69ACCD1B09D98F9CC5F9A98C3
3CB03ADC16519670885B618511A8CFED
791E8610412F77070BC5BCD5A394FEAF
isa
PBXGroup
name
AlamofireRSSParser
path
AlamofireRSSParser
sourceTree
<group>
2A6A25FC0A0B5FF53D4D6302464DF0A2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineScatterCandleRadarChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift
sourceTree
<group>
2AF403E88078E69FABBBF24E83B55823
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
EZAudio-umbrella.h
sourceTree
<group>
2B44A572F8A1ACA0F3964493F4D3228D
fileRef
34DCEA82E5AD0D0D34C17E1A5C318343
isa
PBXBuildFile
2B478D3A308B7A2B85319239F72DE289
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
F60C777A2655795B8C4DD4476D3522F5
remoteInfo
SJCSimplePDFView
2B5256614B1DBAD79986FA7800D8B7E9
baseConfigurationReference
36D90A99286A433572F91AB604418967
buildSettings
ENABLE_STRICT_OBJC_MSGSEND
YES
PRODUCT_NAME
AlamofireRSS
SDKROOT
iphoneos
SKIP_INSTALL
YES
WRAPPER_EXTENSION
bundle
isa
XCBuildConfiguration
name
Debug
2B7CE3EB8CB44E72DC0954A7CCE3CD35
children
8F7A7A4CBF39B0995A17F5F10F25F3A1
6DA6701753BDEEF59EA50F2CB8CDC7EC
49F9110F9B868DCF1D1E766EDDDBD25E
isa
PBXGroup
name
SJCSimplePDFView
path
SJCSimplePDFView
sourceTree
<group>
2BCC458FDD5F692BBB2BFC64BB5701FC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Pods-umbrella.h
sourceTree
<group>
2C7B70526524E165EB80DFFC1D36CFF2
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
254EA72DFADAB5F3286B8726A554C9E6
remoteInfo
EZAudio
2D3405986FC586FA6C0A5E0B6BA7E64E
fileRef
B76F74C8F9438C97CE81DA0817A9D699
isa
PBXBuildFile
2D8E8EC45A3A1A1D94AE762CB5028504
buildConfigurations
A70CDAD61F90AC503C7D04CC22DA2923
FB45FFD90572718D82AB9092B750F0CA
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
2D987F8F1DA56251215C8670CD1FA485
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HorizontalBarChartRenderer.swift
path
Charts/Classes/Renderers/HorizontalBarChartRenderer.swift
sourceTree
<group>
2DDDE6A2D911CE26FD721A694DA7D986
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AnimatedMoveViewJob.swift
path
Charts/Classes/Jobs/AnimatedMoveViewJob.swift
sourceTree
<group>
2DFEDFAB407EBB39DF8E289418A7BE63
fileRef
2D987F8F1DA56251215C8670CD1FA485
isa
PBXBuildFile
2E0EC03652FA915F8E96EFC2558A5439
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
brg_types.h
path
SSZipArchive/aes/brg_types.h
sourceTree
<group>
2E176E84663592A2EB1DF3E23B6D3225
fileRef
44CD3303CF2B64BFC1180928240316D4
isa
PBXBuildFile
2E6846DB220C35EF387C119161A37580
fileRef
B80A7F9A2E84C0DE81E907E12076A4A1
isa
PBXBuildFile
2E70CA0E5B5063FA1695EC714491B22A
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
Charts.framework
path
Charts.framework
sourceTree
BUILT_PRODUCTS_DIR
2E7E02258E9A5195895517F8E2465FB8
includeInIndex
1
isa
PBXFileReference
path
DGElasticPullToRefresh.modulemap
sourceTree
<group>
2EBAA77DF6F106BCE20CADC931D8C84F
fileRef
E8F096851EC41151C5B6B0F804F678F0
isa
PBXBuildFile
2EC5A9E72CC8EBAA5DC6255EB89C5879
fileRef
9D98F0DEB1F6A637347AA210314D3648
isa
PBXBuildFile
2F9E24C3EB88806401EAEE690D73F1A1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
AASquaresLoading-prefix.pch
sourceTree
<group>
2F9FD76D50F8510D46C22FB03BF984DF
buildActionMask
2147483647
files
55BDB9FB19967DED8857D3A0749C44B9
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
30092F63FB79CD827CB85D797464FB40
fileRef
C5CF886AF69707824E7BE68FCA944D76
isa
PBXBuildFile
3103D8A7D64FE15C94380056D5AB453E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ScatterChartData.swift
path
Charts/Classes/Data/Implementations/Standard/ScatterChartData.swift
sourceTree
<group>
3127828983CBDF4E8CBE8579564A7ACC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift
sourceTree
<group>
317A3E7B043018C7BD7F857B76FE1462
fileRef
D3602C188ACB17FC40AC72FB96C5EB35
isa
PBXBuildFile
31A8AB41E1FF5C54D0970DF38969E324
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
unzip.h
path
SSZipArchive/minizip/unzip.h
sourceTree
<group>
32146DB6CF24E5D003FAB31AC7628C3E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DGElasticPullToRefreshExtensions.swift
path
DGElasticPullToRefresh/DGElasticPullToRefreshExtensions.swift
sourceTree
<group>
3262168D3B02149E7F1E85F8F5095D73
fileRef
38A041658F28816244E23069CB89C403
isa
PBXBuildFile
settings
ATTRIBUTES
Public
329F9F0BFAE5C4683145EC1BA2C6C00C
buildActionMask
2147483647
files
3EB5F541CA07593B3D83A2457671CAB8
114543CA2F4712B855C440FC1C01B461
ACE29C6EE9323028266DA51A3449336F
1B09B90650E7E94D067EEA465021ECFC
F90D7168D47857A3578EC1A796A202DB
243E707501F994F3795FFB8D67694A89
97B071F74774C182E2EBD5319D1F565F
D8A45F2D53B5C2246CB9D246A16F678F
C8D8C67006FDDEAC7E7CCB7553FFB573
7CE91BF36DAB7B3EE3B25D14480AFC34
290CE55BDCD4E03FA2A31B6B142A4F4C
9B0170C2DE85A2CED19A6FB95B59CD25
4C339F83D74F78D45E8C20728644C28C
163CCB0ED553E79B03AC5CE313F1DD77
17FA4A36C2BDDC132AF9A0B1CE9E02F4
6BC72123E48899694DE9CDD0C31A175C
CDD0E4686262A0C5C4CBF479DA08F122
67E7A49B20A3F7CCEAC2BBE05281DFA8
E618C6E4AE74F180898BC4052A0BA056
F14AEB3CA1EC057579980D73111BA153
F16A3CAE58D32CAAECC25DDD2BEEA158
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
32BAF7044096F3B8947FFBDDEBDF5E04
buildActionMask
2147483647
files
E56EA2D2498EDB9C4058F8E9A8989FAE
79081B3C3FFC3A41C57FF8AE876CAEE7
F2F301CD8741E18EEB9C1AA349323CFC
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
339174A0A2DC9E27C74F079867D82284
buildConfigurationList
5809E9CAB89A9C5C7FD30607412F4301
buildPhases
B90D9DCA72327E7BB3D9A76CD30DF985
7055AA29B8603B5BE107C3CB363252C9
4930899EE714CB61540C9EFC03EFA944
buildRules
dependencies
isa
PBXNativeTarget
name
CYRTextView
productName
CYRTextView
productReference
83D33D34F7967099E1E8112180FB7D03
productType
com.apple.product-type.framework
33B9BFC9E784B2CD678E24E68652504C
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
6DCD8E0D46E3E688EABD466D9ECB53BE
remoteInfo
AlamofireRSSParser-AlamofireRSS
33CB5E4C130C28C458CD4F7AA1DF99E6
fileRef
C617DC78B1A377E48CF0C244D1511F26
isa
PBXBuildFile
3425AFC5A5E5B97A4E085DC58D7BDE5C
fileRef
988F0BEB31938ED3D03BD2F30C2178DF
isa
PBXBuildFile
settings
ATTRIBUTES
Public
34CCDCA848A701466256BC2927DA8856
fileRef
8BB0BD9B1B6EB8ABF67E29EED3D628B6
isa
PBXBuildFile
34CEA003BE26A7286C83A2E59C4A7A2F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
CYRLayoutManager.m
path
CYRTextView/CYRLayoutManager.m
sourceTree
<group>
34DCEA82E5AD0D0D34C17E1A5C318343
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDefaultFillFormatter.swift
path
Charts/Classes/Formatters/ChartDefaultFillFormatter.swift
sourceTree
<group>
3519CBA7EE38A591227561F3B974D709
fileRef
5EB6FE7C7C16E4C6E5B20F2437CB1D4F
isa
PBXBuildFile
35220F594E860391A0ED1DF9ECA6EBCA
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
Swifter.framework
path
Swifter.framework
sourceTree
BUILT_PRODUCTS_DIR
352EF1AF94125D67FEAA040F32449B24
fileRef
56FE5CA50503474A58BE5ECE692210F7
isa
PBXBuildFile
3584EC2F1BC97974759791C0DAA32891
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Upload.swift
path
Source/Upload.swift
sourceTree
<group>
35D6A246A5B602182B55996C79DEC3B7
includeInIndex
1
isa
PBXFileReference
name
mztools.c
path
SSZipArchive/minizip/mztools.c
sourceTree
<group>
361CB8CE5FB0F7E9DADD6D243BA09A05
fileRef
BCD583736D388CAD44C261B79972B86B
isa
PBXBuildFile
settings
ATTRIBUTES
Public
362C15B9D5B743CE94949C267A11A11F
fileRef
B8024D22C71DD62C706C2DA89005F3EE
isa
PBXBuildFile
366B695AE31536E5AB0C83E287A6DBC6
fileRef
67016485CE0220DF8AF0DDC343E3F51C
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
36D90A99286A433572F91AB604418967
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
AlamofireRSSParser.xcconfig
sourceTree
<group>
371FCB701E2FA5156BA218C0C95A1C5E
fileRef
699DF9D7711902133747EB23BB003CD3
isa
PBXBuildFile
37F47C35B2ADE059B4D7AF6334776FC9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
SwiftyJSON-dummy.m
sourceTree
<group>
38482CD39B3757452D67AE22C1DA5F29
fileRef
85822A6D7AF455601F1786BFBCCDCDC3
isa
PBXBuildFile
384EFED9AD5C956EA205110FCC14C384
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CombinedChartData.swift
path
Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift
sourceTree
<group>
3873DACF51A2F4E637F48FC9EE28FAA0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
ZLMusicFlowWaveView-prefix.pch
sourceTree
<group>
3881764D412915AEE2FDC3677F741D9A
buildConfigurationList
B497794704BDE793D7B8264F55B3EC9F
buildPhases
755AFCA09D3807CB6C260E7115234963
CDE3C54614B1F64A979844A035DA0BA6
6CFD8C2D899AC6725E477D0BF4033CE2
buildRules
dependencies
isa
PBXNativeTarget
name
NMSSH
productName
NMSSH
productReference
94914325FB30736386431FA57CAE5AE4
productType
com.apple.product-type.framework
38A041658F28816244E23069CB89C403
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
CYRLayoutManager.h
path
CYRTextView/CYRLayoutManager.h
sourceTree
<group>
38C869AE53183F93DD743ED2C7192EB8
isa
PBXTargetDependency
name
ZLMusicFlowWaveView
target
F8C233736FECBA33C0E71D949DF017CA
targetProxy
86ACE2887B0A55399595618D8A2A847D
38E5AE8278D6C47639BB70049876C110
fileRef
83CE5B92F7A625F5DAF1A110BF2F174D
isa
PBXBuildFile
391D473F1E22B03F1E1DA498562A0F38
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
Alamofire-dummy.m
sourceTree
<group>
39225A7983DD89DC9CD0F0A9DE3F508A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
PieChartRenderer.swift
path
Charts/Classes/Renderers/PieChartRenderer.swift
sourceTree
<group>
3943D764C0D525CFAF94F943648E17BE
buildActionMask
2147483647
files
11BA64BC0B2FE8DDB41883B7241A8C49
7A88BF95853A69E550E9F63A060BED12
6B058FB2BD6B6B55995F631EE4B61D8E
B2F9711D635766F4754D415B41FFC818
ECDF2C04EED904A4AFC64DED8EA45544
501198AA5B6723D71C0194BAD075BF02
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
395E75AD0A89CABE845F7299D0509640
children
2DDDE6A2D911CE26FD721A694DA7D986
BD8D5708635D65BB93AC3037C5DCA03E
E42B1F498AF0874C6DE8124BB795F15E
91827F8492FCBB8348FC58AEF693B03A
1B8C2B556D484533F17C49F31CFE9279
8F13815876589E1C113CACCF6B677AF1
48F9BF534FE68A179559BAE0103EED67
4A95A4BFE3F28F360C93177FFB7FF31D
4313A1E9F9BFAE03053BBCE38418C9AB
242B71AC1ED8BF10BFB8883D7A043B57
56FE5CA50503474A58BE5ECE692210F7
BE3F1A095E8DF60F568AC3C16C9CD9CC
B972BD02DECCFEB0CD404ED449764022
7D7776EE0E7EB45C6F665800D9385648
272BAEFC0F1D27DEF0B82A5B2705399E
A1E5E540A44850D55021393D3B56D093
F7B3565EFC793DB0CE40900A2C1F3244
768CC1338D4B027D4517DD3611152862
E2F0E619F4A90A088378D7A28F583D02
1845D98CE7CF2F3174B2E68C1E535445
B7931B4F53CD6EDE5CF224FA1404C794
80875D1812BC200BAB068CBC75B74E7A
5259950BB229583DFC6DD1984E696407
B80A7F9A2E84C0DE81E907E12076A4A1
BA7AA59D2E9F556A528840EA05378089
44CD3303CF2B64BFC1180928240316D4
05BA62425D43DD87EC6390A0FAE74D1E
E56D64DF36156ED67576CCA614D0618F
ED3BCC1E1780692338F70AA5634917DF
D21CB11D4389FD174002BD2E4714DF56
398AF30D80C1481DE30A977A180903ED
2A19DB845AD3D3E62C87A8183C450FC5
D40D65B89CE20F485FF2173D31AF3853
83CE5B92F7A625F5DAF1A110BF2F174D
C989B85CAE2F73F5FFAA2EFB44C56081
0E5DECF96C58C0F18CD5F7C5221CC7A7
22059022078636D0B5F42A74AF4B5A22
877DB484F7698974CCC1D66B51116FE1
4FF58A41D7B6111B458ADE82268C1178
78A8CAE0A08DC8E818F6E7C79557A27D
34DCEA82E5AD0D0D34C17E1A5C318343
6B53E7009C09C0B74CCBE630C56B20C1
FFAF70D9A0BFA84F517D08E78C3A8EF4
6DC1C46D160F2B2BB3AA0C6940A03914
631FB7E22898D4FDDBEB4FF4CC88BD80
6C4D119999C4945F085509808EEAD9CA
B70483F68DA580907714FF534F1A20DA
D7D019D2275A7A64B3188D36B0F5F8F4
50C1B0FE72BD421266EBFB4B2B74F13B
EA714E8F4EBC70B2C11E2BCA2854D037
48B20F6AB1D5D3424D043726D66C8BC0
4D08E45167845B9A49C6D44EB035AEE6
57231F627385962A90CE6C6BC2D18C38
699DF9D7711902133747EB23BB003CD3
F5A144C28EEF910B35FCD66B9ACB13AE
C9B9AD22764D9774AC7E4C72CEE64C60
7D67EB40B9B5DAC7A2A758E1C8EEF4BC
D3602C188ACB17FC40AC72FB96C5EB35
C5CF886AF69707824E7BE68FCA944D76
1A7CD22F5ED03019E906E471DD59388F
7E299BF9A615998682A1A05F5F0E42EE
761F2AE2A08681D34B98C5205A398BF9
1167F2A0B491A489F337578AC16A5F11
85822A6D7AF455601F1786BFBCCDCDC3
19318C4AE0C9FF87FDC7C34424E9305F
A99843CE4BE0995346C06785127AB91C
46E1873E64EC87857800E9B2C2A793A7
6C61009912177D3D77B80D65EC5B2AA4
191F7183D2E17767A8B14716B9453747
7E387B67B1AB63AFDB74AEAA00DD821D
384EFED9AD5C956EA205110FCC14C384
B06192AD341CDBCD0D19BD7B8DCF3B4E
C0FF762D04F76D834E1291819067E12A
1AC2B93F71120CA50074113DD62725AC
BE0A3BFD226BAF44617BFBB3DB345624
2D987F8F1DA56251215C8670CD1FA485
534D8D488609E2DA3DBE7CA778E2D5DC
9F45FA658BE59059A916A5F98B6F70A7
033590E1C2397DA8E570B55810775B8E
BE6178583E3411E5621C8AB2CB79014F
5EB6FE7C7C16E4C6E5B20F2437CB1D4F
5C0B9516684CF8E715F8B7D047F76709
E6CC8802D5BE9DF62F444322062597D0
0FBCB9B828FF98812A1EE98817048C46
543700860208A4CDC32C58B8636E5827
DA3AA58FE349027A794BEA3358EED800
0B93148101A5531681949F675D41538E
CC1086A80586AA695872978B4DCA7686
72DC6BB442C0770DBB5A839ECD805ADB
E8F096851EC41151C5B6B0F804F678F0
3127828983CBDF4E8CBE8579564A7ACC
9A72A7D51819C4D550B5473E909F71FF
B85E049096D02564EBABAB2D5BF6B6BE
4E2E3D5588060B9FF52974B06D2DB9B7
D170993D4633F76FF548FD13C3B84EC3
2A6A25FC0A0B5FF53D4D6302464DF0A2
6CDE7B54911112B22403C6B83659EE77
8621EC900E9540E855F2A45193465CE6
0BE89C1211FB9D34E28695028E028BC5
B88349DF809DD951EF76B2B561C15983
39225A7983DD89DC9CD0F0A9DE3F508A
50DD5592D089DE7626D6837A4E9EA1AC
55AB31E45DC84ECFF7CC6FC6AB1ACC81
22CC997358A22BFFD42637B6A1E3868C
BF20B8C23E028DAAB8B003D153FABE87
63B79EFF01B2EE5390F1C6930E5D9E13
C6DC7B869C1C73B1B12FFF994EEFAAA3
3103D8A7D64FE15C94380056D5AB453E
F38A27EE294EDDE1BCEA87D82E418D06
1B8D79A74968EFE68A03C339F93BE40A
087A04860A4A8EC54E6A1A5AF7F73E23
69FE1C8A369E61A2B5F16F781CC4C612
FD194E12D7F3D8DAA667A3A52EB221CA
isa
PBXGroup
name
Core
sourceTree
<group>
398AF30D80C1481DE30A977A180903ED
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartBaseDataSet.swift
path
Charts/Classes/Data/Implementations/ChartBaseDataSet.swift
sourceTree
<group>
3993828B63B3AC6BE59C92C303685F61
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
39E179F4DAB57EC19626D1DCC4F5F007
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Stream.swift
path
Source/Stream.swift
sourceTree
<group>
3A04E2A8DAC2E69D929439C0D50562D4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
SSZipArchive.h
path
SSZipArchive/SSZipArchive.h
sourceTree
<group>
3A06439A9A5AE0F27374CF4A27AB4A0B
fileRef
EB00AA6939C22D418E0231F5C736BC44
isa
PBXBuildFile
3B1F9EB02DD6CBB544A332E7F8A4A716
fileRef
75671DCD2C65E9A11B1E6F09B6854AA0
isa
PBXBuildFile
3B2ED386492166C28D7631B4488EA230
fileRef
48B20F6AB1D5D3424D043726D66C8BC0
isa
PBXBuildFile
3C50B55F32F9344B641ACF672F0220A4
fileRef
6C4D119999C4945F085509808EEAD9CA
isa
PBXBuildFile
3CB03ADC16519670885B618511A8CFED
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RSSItem.swift
path
Pod/Classes/RSSItem.swift
sourceTree
<group>
3CFB42910790CF0BDBCCEBAACD6B9367
buildConfigurations
C3746E36F91278C40D0DCBA78D124E88
74F7FAC78E5CB4D327B99F47BF099326
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
3D8DDA0FEB1A3AFF6643F9121E19D044
fileRef
C6DC7B869C1C73B1B12FFF994EEFAAA3
isa
PBXBuildFile
3DB99C22AB1CE344BFE50941C299F2AB
fileRef
9A72A7D51819C4D550B5473E909F71FF
isa
PBXBuildFile
3E5B420A73875137D4437E73149DCAEA
baseConfigurationReference
DCC866ED59787599F6878FA3408C9E43
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/EZAudio/EZAudio-prefix.pch
INFOPLIST_FILE
Target Support Files/EZAudio/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/EZAudio/EZAudio.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
EZAudio
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
3E620824BFA4001189C1AA5EEE595C67
fileRef
5EFA7A6FD03F0353C6F5CA04653120C7
isa
PBXBuildFile
3E678AB82500885E6B28B0A982617ED8
buildActionMask
2147483647
files
928CDEDEA8EC3C437DB27409A17C998B
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
3EA8F215C9C1432D74E5CCA4834AA8C0
fileRef
1C13EE24977DA9B45CDE1309CB51D90E
isa
PBXBuildFile
3EB5F541CA07593B3D83A2457671CAB8
fileRef
4E488569CDEF3276C1BC982119CE0914
isa
PBXBuildFile
settings
ATTRIBUTES
Project
3EED0E841D10FEAA033A3C645CB219D3
fileRef
761F2AE2A08681D34B98C5205A398BF9
isa
PBXBuildFile
3EF3C6E2D5466E70A62B0CE90DA2604C
fileRef
8F13815876589E1C113CACCF6B677AF1
isa
PBXBuildFile
3F35D9D6BE5B906A940193BD32AEA736
fileRef
BB8BF3A20530EBB622CA33D5AEFB739D
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
3F37EE1C6EE59F78A3A5E60EF31FFA3A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZPlot.m
path
EZAudio/EZPlot.m
sourceTree
<group>
3F853DCA000D97FD5D823E8C262B2A64
buildActionMask
2147483647
files
D7AC85CBA5CACB37DD2CDA0B13E3DC0D
8ACA70A9D45E782647B8995535544861
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
40043CBCDD93A301F8437421D53D02A3
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
Foundation.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework
sourceTree
DEVELOPER_DIR
4081EA628AF0B73AC51FFB9D7AB3B89E
fileRef
CDD10EA7FDB7BA6CF457E5EC0E4174A3
isa
PBXBuildFile
409737D7933980737EC1592FBD4AAADE
fileRef
1D0F56E661286DC8431D8887DD690692
isa
PBXBuildFile
409962F3CD08FB4947DAEFF94EDEFC86
isa
PBXTargetDependency
name
SSZipArchive
target
F49E17CE595BF7A7A46139779E891F78
targetProxy
0256D63626119843AC1248D91D38C551
40F968A172478FA1FF7BC61E5E43A165
children
8EA7C01FA9014E4AC4EB52DEBC568005
B4E6B408AA61BA919AA4B1D77012E3F6
86A4F33244B76027A52DC18FE83F6FA8
CDD10EA7FDB7BA6CF457E5EC0E4174A3
776ECCE5529B00F6D7F372E0F8AB6002
8BB0BD9B1B6EB8ABF67E29EED3D628B6
9AB9C30C29CCEEC9315ABE415511676B
05D9707C1A350638ECD52006A481F077
A792226DBE4257340C826C75A0DC208F
854D9C81549E59B2145F57291D9C9E01
1C13EE24977DA9B45CDE1309CB51D90E
1891931FD0A3F4CC78749D9E977A8505
B756C6158B1743F24242A4F20F07ECCA
39E179F4DAB57EC19626D1DCC4F5F007
B5EEC8A63E90F6F8F85DEF5514D52ED8
3584EC2F1BC97974759791C0DAA32891
B76F74C8F9438C97CE81DA0817A9D699
7EE6C232195755A42DEAECB46E888B18
isa
PBXGroup
name
Alamofire
path
Alamofire
sourceTree
<group>
421EC967AD86F44E9BDB88301D94B33B
fileRef
FFAF70D9A0BFA84F517D08E78C3A8EF4
isa
PBXBuildFile
423A9BA046AD7AEAED121ABE70F42763
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
4276EB8AC31314ED23699BF489AAA02A
includeInIndex
1
isa
PBXFileReference
path
SwiftyJSON.modulemap
sourceTree
<group>
42787649B04F8FCB3363DE9C7642B645
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CGSizeExtension.swift
path
Source/CGSizeExtension.swift
sourceTree
<group>
4313A1E9F9BFAE03053BBCE38418C9AB
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartRenderer.swift
path
Charts/Classes/Renderers/BarChartRenderer.swift
sourceTree
<group>
43FD5AF8E2E268BB58C2BEE180302F51
buildConfigurationList
D24B9254E2DE0C6C7A2339323E1BF0A4
buildPhases
98760AA9A7D6FB3DA51581FB5D81023D
3F853DCA000D97FD5D823E8C262B2A64
616D4647E855D8293CF8A0E0A253D067
9D4E866B71A9C1336273DDC9164734A2
buildRules
dependencies
0282FE2D0C3A9B3705A974193237B978
C69E27AE1864F2E73BFE3829B41BFE3F
isa
PBXNativeTarget
name
AlamofireRSSParser
productName
AlamofireRSSParser
productReference
86D972F433A3176BF77299B3526C71AF
productType
com.apple.product-type.framework
4458DADC90FBB23CF881C195DC1D4980
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
String+BASE64.swift
path
Sources/String+BASE64.swift
sourceTree
<group>
44CD3303CF2B64BFC1180928240316D4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleStickChartView.swift
path
Charts/Classes/Charts/CandleStickChartView.swift
sourceTree
<group>
450044A6490A439394B0F3A67CCFBD00
fileRef
CF9D51D988643E797BAE8A9A54D9F2CD
isa
PBXBuildFile
settings
ATTRIBUTES
Public
453AE9B30136CD292073FFCB386A111C
buildActionMask
2147483647
files
B5971F611DFCB1DBE9E29202C26D4163
268C17FB4A1B500FAE4A02E1F7D87D5C
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
4544CA2498B23C5B3295862D2F20901A
fileRef
626CCE81FCEDAE7AEF6B6A9403E58F03
isa
PBXBuildFile
settings
ATTRIBUTES
Public
4567150A2B071C2DA321F4CE18FF8364
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Animator.swift
path
Source/Animator.swift
sourceTree
<group>
45B1D072665424E0D9FEAA51DE27E6E3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
45DA8587F08705657CBBFF27A51A0143
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
45DDC4029E0C5A71CC9136854BFC8AB1
fileRef
ECB77A2F7E083C88A4C9EAEF40CB8D17
isa
PBXBuildFile
settings
ATTRIBUTES
Public
45FA3456C69B0437B37A006EFB69674D
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
FB6A25C88BCCDB159C1C71A2C484100D
remoteInfo
SwiftyJSON
4620E80B337EA9F040BEB93DF08BD134
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
ZLSinusWaveView-dummy.m
sourceTree
<group>
465CB044A4902D7BAA80597E096B0E67
fileRef
4A95A4BFE3F28F360C93177FFB7FF31D
isa
PBXBuildFile
4684964FE77650C6E9F3ED93AC79C87D
children
EAF5382389A29BF0B9ECFE46E3F5AC4D
DC9FDA0AFC976AC147511622F5DB1860
87FEA49CACDD9BA7901D248871C94118
61C249EB2452D0503C05988D568A9C4D
isa
PBXGroup
name
Resources
sourceTree
<group>
46D3F6AF317B0CA613B0F2C91085FBED
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AASquaresLoading.swift
path
Source/AASquaresLoading.swift
sourceTree
<group>
46E1873E64EC87857800E9B2C2A793A7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartYAxis.swift
path
Charts/Classes/Components/ChartYAxis.swift
sourceTree
<group>
46EC9DD508AF1269E9D7DAB50594AB66
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
AEFloatConverter.m
path
EZAudio/AEFloatConverter.m
sourceTree
<group>
470A19320682236DEF0633151EF7F01C
fileRef
86909353BB4657C029BB5008942330ED
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
4846448B6998275139FBF24E87C11D42
fileRef
57231F627385962A90CE6C6BC2D18C38
isa
PBXBuildFile
4888A76CCC22B207C2B0D3B6741688DA
fileRef
20DCE1442556CA5F41805570F5B5844F
isa
PBXBuildFile
48B20F6AB1D5D3424D043726D66C8BC0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartPlatform.swift
path
Charts/Classes/Utils/ChartPlatform.swift
sourceTree
<group>
48F9BF534FE68A179559BAE0103EED67
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift
sourceTree
<group>
490570C4EC2C7DD9D5FCA37164C6442D
fileRef
F0230F9740EC7A507AC92A65994E63C9
isa
PBXBuildFile
4930899EE714CB61540C9EFC03EFA944
buildActionMask
2147483647
files
3262168D3B02149E7F1E85F8F5095D73
5E569414E49052AC549E22C1B4C794E7
5526DF3081392B7D302F2574F8844AA6
DD7D8BD19010A140BBD01B5E92541182
4B3340DEA17E06019D3C98663AC362D6
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
49459EAB6B6631BA931AAD932786D029
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DemoServer.swift
path
Sources/DemoServer.swift
sourceTree
<group>
49F9110F9B868DCF1D1E766EDDDBD25E
children
97CA0B8036338914727FF40447D5C34C
826CDEA3F474B8670FB6244F7842DE73
A16184B99AC1C6FBC8F177C124589651
F5C563FFB56C2F264F8F6B3EF31B074F
E0CAE9A4EC3948A0E48F0096EAF93132
0CCE916C80D42C6943D73D1A829DA787
isa
PBXGroup
name
Support Files
path
../Target Support Files/SJCSimplePDFView
sourceTree
<group>
4A10B4FB2E8D14A92065018A75A6EEF1
buildActionMask
2147483647
files
isa
PBXResourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
4A649E5F7B4737DC7A6645E6EBE61690
fileRef
42787649B04F8FCB3363DE9C7642B645
isa
PBXBuildFile
4A95A4BFE3F28F360C93177FFB7FF31D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartHighlighter.swift
path
Charts/Classes/Highlight/BarChartHighlighter.swift
sourceTree
<group>
4ABE19F043A4FECE8C2A3F1F72AB3F7F
fileRef
B972BD02DECCFEB0CD404ED449764022
isa
PBXBuildFile
4ADAD0E91F5DCCDC1EEF2C11C99034AC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHSessionDelegate.h
path
NMSSH/Protocols/NMSSHSessionDelegate.h
sourceTree
<group>
4AF8AA804B2142B26DC1B5186720048A
includeInIndex
1
isa
PBXFileReference
path
AlamofireRSSParser.modulemap
sourceTree
<group>
4B3340DEA17E06019D3C98663AC362D6
fileRef
62FD1B17D0F7FFDE4730993A41302A52
isa
PBXBuildFile
settings
ATTRIBUTES
Public
4BABE59E39A193B562EFEBE6E5626154
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
CYRTextView-umbrella.h
sourceTree
<group>
4BD7EE6ED468BE4A70A0739940369D7D
fileRef
C0FF762D04F76D834E1291819067E12A
isa
PBXBuildFile
4C339F83D74F78D45E8C20728644C28C
fileRef
9D7EF092E912A37841FC7F3316B1EE46
isa
PBXBuildFile
settings
ATTRIBUTES
Project
4CDBCAF32D84C52F6A5CD9D53D1C8686
children
284973C8BAF3B75F23E5BF288A890A05
C0964599C373EAF8F5D4F77150B2E585
009369000D8CF5B8C1E3E6BF283CA73A
7E24079B28DAF8D9128CA7E7D33E6F7C
BCD583736D388CAD44C261B79972B86B
19954D5FC84330E551F6CF2AECCCEC23
isa
PBXGroup
name
Support Files
path
../Target Support Files/Charts
sourceTree
<group>
4D08E45167845B9A49C6D44EB035AEE6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartRange.swift
path
Charts/Classes/Highlight/ChartRange.swift
sourceTree
<group>
4D8F6F5FDD8AE252C8D21C76F72CEC9F
isa
PBXTargetDependency
name
CYRTextView
target
339174A0A2DC9E27C74F079867D82284
targetProxy
FE7F3C43D504E49A918DA967538283F8
4E2E3D5588060B9FF52974B06D2DB9B7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineRadarChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/LineRadarChartDataSet.swift
sourceTree
<group>
4E488569CDEF3276C1BC982119CE0914
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
aes.h
path
SSZipArchive/aes/aes.h
sourceTree
<group>
4EAAC8A84A3397BCC528C8DAC72AE2F9
baseConfigurationReference
1260E1D284190E2A3D00903698C9D2F3
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/CYRTextView/CYRTextView-prefix.pch
INFOPLIST_FILE
Target Support Files/CYRTextView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/CYRTextView/CYRTextView.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
CYRTextView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
4EBF65047A668987D122EE46E359FF4D
fileRef
61441E6010D0E49F26DDACBC74B8FCC2
isa
PBXBuildFile
settings
ATTRIBUTES
Public
4EC9879E9DEB9D169929ADA6EEFB18FD
fileRef
BD8D5708635D65BB93AC3037C5DCA03E
isa
PBXBuildFile
4ED7C61B5475997505191F07F768B0E2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
CYRTextView.m
path
CYRTextView/CYRTextView.m
sourceTree
<group>
4EEF9EF82DBD9FA2F25E1ABDE291AC02
fileRef
91827F8492FCBB8348FC58AEF693B03A
isa
PBXBuildFile
4FF58A41D7B6111B458ADE82268C1178
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataRendererBase.swift
path
Charts/Classes/Renderers/ChartDataRendererBase.swift
sourceTree
<group>
501198AA5B6723D71C0194BAD075BF02
fileRef
0D9E3E8557D628F179DC72179BE68873
isa
PBXBuildFile
5016FC849FB311577714D8BF17D07034
buildActionMask
2147483647
files
EC840730B431C4C5CCBC36514D28D17A
D879768BF616B126D71B6BA5F638D96A
8AF188560381C1B97D9E46B09B146DE0
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
50AE3A2D24BA4DE093FC4BD2657AC1FB
fileRef
C9B9AD22764D9774AC7E4C72CEE64C60
isa
PBXBuildFile
50C1B0FE72BD421266EBFB4B2B74F13B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartLimitLine.swift
path
Charts/Classes/Components/ChartLimitLine.swift
sourceTree
<group>
50DD5592D089DE7626D6837A4E9EA1AC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
PieChartView.swift
path
Charts/Classes/Charts/PieChartView.swift
sourceTree
<group>
511493881CA40859A5E2279BD386A7AB
fileRef
F31DF6C5B30A988A0B2DB360615D985B
isa
PBXBuildFile
51F55670AE3232AEAA1C0CE9575ACACC
baseConfigurationReference
A16184B99AC1C6FBC8F177C124589651
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SJCSimplePDFView/SJCSimplePDFView-prefix.pch
INFOPLIST_FILE
Target Support Files/SJCSimplePDFView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SJCSimplePDFView/SJCSimplePDFView.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
SJCSimplePDFView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
52136F9F39CC2759B6CC1922BCB1AB41
fileRef
57723204FBD830B51D546A0059298711
isa
PBXBuildFile
52183AB70293B3C29450264A392FA4F5
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
254EA72DFADAB5F3286B8726A554C9E6
remoteInfo
EZAudio
522FF8BB85FE7B2A94BB4A2EBACA89AB
fileRef
ECA049105DF827404AAEC0CD3E189C64
isa
PBXBuildFile
settings
ATTRIBUTES
Private
52349732EBA58888E9A0DBEB887F361B
fileRef
B8CDE1803E298A956357E75C96E49EE7
isa
PBXBuildFile
5259950BB229583DFC6DD1984E696407
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleChartDataProvider.swift
path
Charts/Classes/Interfaces/CandleChartDataProvider.swift
sourceTree
<group>
52ADA7A4A97CBF5879F6167136D1E715
fileRef
35D6A246A5B602182B55996C79DEC3B7
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
5334BFFDC74B5BC33AB2F29E413CD99A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SSZipArchive-prefix.pch
sourceTree
<group>
534D8D488609E2DA3DBE7CA778E2D5DC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HorizontalBarChartView.swift
path
Charts/Classes/Charts/HorizontalBarChartView.swift
sourceTree
<group>
53F1005ADB78F4613F8C29A68E8B9909
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZRecorder.m
path
EZAudio/EZRecorder.m
sourceTree
<group>
543700860208A4CDC32C58B8636E5827
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ILineScatterCandleRadarChartDataSet.swift
path
Charts/Classes/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift
sourceTree
<group>
54E862294530B7914A37F408C0DFF74C
fileRef
ED3BCC1E1780692338F70AA5634917DF
isa
PBXBuildFile
5526DF3081392B7D302F2574F8844AA6
fileRef
4BABE59E39A193B562EFEBE6E5626154
isa
PBXBuildFile
settings
ATTRIBUTES
Public
552BBD1E199D776755E294481BAE70BD
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
RongIMKit.framework
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework
sourceTree
<group>
556344573F293DFD06C18EC7B51B812B
fileRef
6EA1BE8E8A6172B255E1C74432F2F569
isa
PBXBuildFile
55AB31E45DC84ECFF7CC6FC6AB1ACC81
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
PieRadarChartViewBase.swift
path
Charts/Classes/Charts/PieRadarChartViewBase.swift
sourceTree
<group>
55BDB9FB19967DED8857D3A0749C44B9
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
56942D4AE3FE1A0B97040C17F2AAA7BD
children
6A2D73BF1B684C56E7FEF0F452537CCF
A89C4B4FA34F489CCA9D61165EA98AF9
F31DF6C5B30A988A0B2DB360615D985B
6FD6A0D37E4C38641DCB2885397E1488
isa
PBXGroup
name
Frameworks
sourceTree
<group>
56E802F711F304E380A745ED755A25F2
buildConfigurations
2B5256614B1DBAD79986FA7800D8B7E9
0BDAAEDEF5A3BBD3D36419ADBC621E43
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
56FE5CA50503474A58BE5ECE692210F7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarLineChartViewBase.swift
path
Charts/Classes/Charts/BarLineChartViewBase.swift
sourceTree
<group>
5721DA804A3926404ADB80D27EB9D7F2
baseConfigurationReference
B02BF2860C124E9C66C26D2E4913EC5B
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/ZLSinusWaveView/ZLSinusWaveView-prefix.pch
INFOPLIST_FILE
Target Support Files/ZLSinusWaveView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/ZLSinusWaveView/ZLSinusWaveView.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
ZLSinusWaveView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
57231F627385962A90CE6C6BC2D18C38
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartRendererBase.swift
path
Charts/Classes/Renderers/ChartRendererBase.swift
sourceTree
<group>
5768DCD828BCB3B8A372407BA137B249
fileRef
A481946E2B03D2D461A9D9942194D32C
isa
PBXBuildFile
settings
ATTRIBUTES
Public
57723204FBD830B51D546A0059298711
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpRouter.swift
path
Sources/HttpRouter.swift
sourceTree
<group>
5798CFA7BDB78019CBD837FA245CCF7C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
libssh2_sftp.h
path
NMSSH-iOS/Libraries/include/libssh2/libssh2_sftp.h
sourceTree
<group>
57D859C2DD2A786A0EC902A7DE9F864C
fileRef
A1B31917F302790BEE2C7CA37EFBA0DF
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
57EB7F801E937056D8EA61707A156023
fileRef
69E2158C4EE02BF8D175828AD9D93C69
isa
PBXBuildFile
5809E9CAB89A9C5C7FD30607412F4301
buildConfigurations
4EAAC8A84A3397BCC528C8DAC72AE2F9
8849F4F8A02D3B41E46CF24A28485E5B
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
586EA2D58EF199363C2C23823C092089
fileRef
C5AA30790616DFD31FB6E41D32920A1A
isa
PBXBuildFile
settings
ATTRIBUTES
Public
59639868BF0B29D1419BB3F9312567AF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
5A7F1D5307EAD796E3AA22EA222AA8FA
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SSZipArchive-umbrella.h
sourceTree
<group>
5BAE1115B0F38B2B700C84FCE61FDD87
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
archive.ar
name
libssh2.a
path
NMSSH-iOS/Libraries/lib/libssh2.a
sourceTree
<group>
5BBC00FA891515A4337DFE7D18C0BD00
baseConfigurationReference
95C3D67F3A2378FDCAD498AF576A36D7
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Gifu/Gifu-prefix.pch
INFOPLIST_FILE
Target Support Files/Gifu/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Gifu/Gifu.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
Gifu
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
5BC19E6E0F199276003F0AF96838BCE5
fileRef
3584EC2F1BC97974759791C0DAA32891
isa
PBXBuildFile
5C0B9516684CF8E715F8B7D047F76709
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IChartDataSet.swift
sourceTree
<group>
5C4566FE7B7461D8601278AE68C50358
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
5C5512B13DBD171651F6D19C66DCBB1B
children
1F2A324FC0B075A00AEE84CC028D8F1F
A020A04A30303EBCC97F078481030B44
5798CFA7BDB78019CBD837FA245CCF7C
988F0BEB31938ED3D03BD2F30C2178DF
F0230F9740EC7A507AC92A65994E63C9
03FC642C1EF0F16D7AB31F4AC6D6F719
638DF91968A81A91C75221EC0671A73C
95A51226875B54D2C24099FABD65F9A4
E349CFCDAD29F7182C472495FBBFCF0F
ECA049105DF827404AAEC0CD3E189C64
74190DEE29D1C7C27FD494EE3CB59F14
0CFA654DBD993FD0F891ECD3B7432064
7394AB9A3BB12133D1798B57561E2552
0BD8E73E6A192F43B39F876E1E07146C
79AF06EC7F78F59EDAC780C88DB961AE
D7C1E15DAA48F123231A498172D38967
1F8B22539695E07FA9762AFF2D92CB5A
EFAF93ECA6E252EF29AB51A210E6D8E4
16707D24276E0D4BA984EAD7829AFC3B
F6A855C0E5EE0EC482325EB94815F74A
0A0B1AD12AF0AAF31F2FE461AEDD6AC9
4ADAD0E91F5DCCDC1EEF2C11C99034AC
8353E819C2C6AE2417C900DE0705D1A8
71023FBED2BFC50D42DB8F5E48E31B48
E14C8107646EC3F8588ED97956DCC65A
93E203BDEABA3092CDF443A1AA4202FD
isa
PBXGroup
name
NMSSH
path
NMSSH
sourceTree
<group>
5C8F85E0EEBB7F9DDADE1D67E310ACAF
fileRef
2AF403E88078E69FABBBF24E83B55823
isa
PBXBuildFile
settings
ATTRIBUTES
Public
5CB05FBCB32D21E194B5ECF680CB6AE0
fileRef
B4E6B408AA61BA919AA4B1D77012E3F6
isa
PBXBuildFile
5D33D52D318CF2F7B66A1D73DDCE436D
fileRef
9B8983A42745CE241C8FE81ADFB76218
isa
PBXBuildFile
5D48CB591598D53251BDB48146F61D43
fileRef
0FAAC91F636F7A42B8D0A2D53351CB33
isa
PBXBuildFile
5DCEC268DB930EF58F5B13FE3A59EC8B
fileRef
7394AB9A3BB12133D1798B57561E2552
isa
PBXBuildFile
settings
ATTRIBUTES
Public
5E2CC216EEF82AC984AE8D61A9177113
fileRef
638DF91968A81A91C75221EC0671A73C
isa
PBXBuildFile
5E3EC164F92FFE16F448E27839FDFF32
buildActionMask
2147483647
files
BA48D6CA288389ECA1569120A6333992
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
5E49AAF37C2B40CB0957F56DF1A3E620
fileRef
E2FAD92811C5785C55D927D4BBF05C68
isa
PBXBuildFile
5E569414E49052AC549E22C1B4C794E7
fileRef
E772910ED9BD048407A4D78E5020A45F
isa
PBXBuildFile
settings
ATTRIBUTES
Public
5E8334E4B9A3934776155BFEA1ADCCC7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SwiftyJSON-umbrella.h
sourceTree
<group>
5EA97C7D866AB0A63806FDC3C86EDCFE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudioPlot.h
path
EZAudio/EZAudioPlot.h
sourceTree
<group>
5EB6FE7C7C16E4C6E5B20F2437CB1D4F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ICandleChartDataSet.swift
path
Charts/Classes/Data/Interfaces/ICandleChartDataSet.swift
sourceTree
<group>
5EFA7A6FD03F0353C6F5CA04653120C7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudioPlotGLKViewController.m
path
EZAudio/EZAudioPlotGLKViewController.m
sourceTree
<group>
5F0A3448A6BD1FAE4B4F4E61EFD3DDCF
baseConfigurationReference
DCC866ED59787599F6878FA3408C9E43
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/EZAudio/EZAudio-prefix.pch
INFOPLIST_FILE
Target Support Files/EZAudio/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/EZAudio/EZAudio.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
EZAudio
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
5F74650537FAFA0C20CFECF3870638C4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
archive.ar
name
libcrypto.a
path
NMSSH-iOS/Libraries/lib/libcrypto.a
sourceTree
<group>
5FA31142FE846A63B3CDCF338C03AF0F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
ZLSinusWaveView-prefix.pch
sourceTree
<group>
5FF6421A0B1404F43C1F56F99853EC96
fileRef
4620E80B337EA9F040BEB93DF08BD134
isa
PBXBuildFile
604D5A1EF4ABD6E0ACB3B5C820C9F841
fileRef
B85E049096D02564EBABAB2D5BF6B6BE
isa
PBXBuildFile
61441E6010D0E49F26DDACBC74B8FCC2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
ZLSinusWaveView.h
path
ZLSinusWaveView/ZLSinusWaveView.h
sourceTree
<group>
616D4647E855D8293CF8A0E0A253D067
buildActionMask
2147483647
files
72168557B70D4C7AFD3AD754069E2370
isa
PBXResourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
61C249EB2452D0503C05988D568A9C4D
includeInIndex
1
isa
PBXFileReference
name
zh-Hans.lproj
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/zh-Hans.lproj
sourceTree
<group>
620860DD966F93A5BB284ECA65E3FF68
fileRef
7D7776EE0E7EB45C6F665800D9385648
isa
PBXBuildFile
626CCE81FCEDAE7AEF6B6A9403E58F03
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZPlot.h
path
EZAudio/EZPlot.h
sourceTree
<group>
62BD10A1EFF551EEE3D51229E3A5A135
includeInIndex
1
isa
PBXFileReference
name
TPCircularBuffer.c
path
EZAudio/TPCircularBuffer.c
sourceTree
<group>
62D919A2C9C2C955FA825CB474A9F16B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AnimatedFrame.swift
path
Source/AnimatedFrame.swift
sourceTree
<group>
62E8346F03C03E7F4D631361F325689E
fileRef
854D9C81549E59B2145F57291D9C9E01
isa
PBXBuildFile
62FD1B17D0F7FFDE4730993A41302A52
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
CYRToken.h
path
CYRTextView/CYRToken.h
sourceTree
<group>
63002BFF3EE441011E71DD87CDA49484
includeInIndex
1
isa
PBXFileReference
path
Swifter.modulemap
sourceTree
<group>
631BAC0B955DDA472F2092F853D8624D
fileRef
72DC6BB442C0770DBB5A839ECD805ADB
isa
PBXBuildFile
631FB7E22898D4FDDBEB4FF4CC88BD80
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartHighlight.swift
path
Charts/Classes/Highlight/ChartHighlight.swift
sourceTree
<group>
63537D19F4231AD1D75CAAD2AFE1EC84
fileRef
74190DEE29D1C7C27FD494EE3CB59F14
isa
PBXBuildFile
settings
ATTRIBUTES
Public
6357E4DF80060A4CD9B6E9B06D5DBFE3
isa
PBXTargetDependency
name
AASquaresLoading
target
0E579C8B6EC88FD31F0C2B47C9058B48
targetProxy
998667BFE20E591A5EF6D4412B709E4B
638DF91968A81A91C75221EC0671A73C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSFTPFile.m
path
NMSSH/NMSFTPFile.m
sourceTree
<group>
63A42196CB86BF9D7F26EC16B135E0CF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Alamofire-umbrella.h
sourceTree
<group>
63B79EFF01B2EE5390F1C6930E5D9E13
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RadarChartRenderer.swift
path
Charts/Classes/Renderers/RadarChartRenderer.swift
sourceTree
<group>
655EC23C173F625425EFCDC75BE0A4D2
buildActionMask
2147483647
files
B3C1BBCF776752C05DDE5AAFAF11F696
1D80AF552B91E3AC0E007F8B3D1C423B
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
65C7C81B8FCE42F70895210309838E7D
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
C6828C2508515BC0428D6BDAA1292DC9
remoteInfo
Charts
65FB4C3B9C6D3DF8ED9A60732536021D
fileRef
EA714E8F4EBC70B2C11E2BCA2854D037
isa
PBXBuildFile
6626187A5C620C82B45EA50B60E531EC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
66289F09E2686DE08ED6DE071A0D5077
includeInIndex
1
isa
PBXFileReference
name
prng.c
path
SSZipArchive/aes/prng.c
sourceTree
<group>
667AE18ABE1BD4A574755ED111198F89
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
ZLMusicFlowWaveView-dummy.m
sourceTree
<group>
66F42930FE68C6E4BD9E882D382F237C
fileRef
5EA97C7D866AB0A63806FDC3C86EDCFE
isa
PBXBuildFile
settings
ATTRIBUTES
Public
67016485CE0220DF8AF0DDC343E3F51C
includeInIndex
1
isa
PBXFileReference
name
entropy.c
path
SSZipArchive/aes/entropy.c
sourceTree
<group>
67184F1852A59AB997108F4DB5AF70B0
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
6744F19C73C44705160ECB1E7C7FB733
fileRef
22CC997358A22BFFD42637B6A1E3868C
isa
PBXBuildFile
6789ABF735324868C1342E25DEC4AF09
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
ADD0B8D536C47FE797C15119D29AFC71
remoteInfo
ZLSinusWaveView
679ABE39538CF97A7B169D851D0D472D
children
A962F3A2F35704A852AC7D38910200D9
552BBD1E199D776755E294481BAE70BD
AF2CF0BAA5DF6BABFC217F2495AD6FBA
isa
PBXGroup
name
Frameworks
sourceTree
<group>
67E7A49B20A3F7CCEAC2BBE05281DFA8
fileRef
3A04E2A8DAC2E69D929439C0D50562D4
isa
PBXBuildFile
settings
ATTRIBUTES
Public
69693BA8A71B1AB49790F1AEA9F54D84
baseConfigurationReference
7F87651AE9B6CA0E7F4A0114F19A7924
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/AASquaresLoading/AASquaresLoading-prefix.pch
INFOPLIST_FILE
Target Support Files/AASquaresLoading/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/AASquaresLoading/AASquaresLoading.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
AASquaresLoading
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
698765A4EF927BBD85BC37EE2FF01903
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Socket.swift
path
Sources/Socket.swift
sourceTree
<group>
699DF9D7711902133747EB23BB003CD3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartSelectionDetail.swift
path
Charts/Classes/Utils/ChartSelectionDetail.swift
sourceTree
<group>
69B023D17AE27F4AFA2514F22965C5D0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
NMSSH-umbrella.h
sourceTree
<group>
69E2158C4EE02BF8D175828AD9D93C69
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
FunctionalHelpers.swift
path
Source/FunctionalHelpers.swift
sourceTree
<group>
69FC867B9095871D1CDC05702AD7F41B
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
69FE1C8A369E61A2B5F16F781CC4C612
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ScatterChartView.swift
path
Charts/Classes/Charts/ScatterChartView.swift
sourceTree
<group>
6A2D73BF1B684C56E7FEF0F452537CCF
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
path
Alamofire.framework
sourceTree
BUILT_PRODUCTS_DIR
6B058FB2BD6B6B55995F631EE4B61D8E
fileRef
32146DB6CF24E5D003FAB31AC7628C3E
isa
PBXBuildFile
6B173C46DF90109FE17024B11AD202E2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
ZLSinusWaveView-umbrella.h
sourceTree
<group>
6B53E7009C09C0B74CCBE630C56B20C1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDefaultXAxisValueFormatter.swift
path
Charts/Classes/Formatters/ChartDefaultXAxisValueFormatter.swift
sourceTree
<group>
6BAE05E7054A14414B907DD7F37AC8B7
includeInIndex
1
isa
PBXFileReference
path
ZLSinusWaveView.modulemap
sourceTree
<group>
6BC72123E48899694DE9CDD0C31A175C
fileRef
ED50758E863F122346C9C2E1873E53DE
isa
PBXBuildFile
settings
ATTRIBUTES
Project
6C3C1BD7C759507F7AE5B2380506F232
children
F7210A9C5D404BB2ED9A06FE29F3AC73
DCC866ED59787599F6878FA3408C9E43
1EF3386A084C9BF7F3B05704CD56DBE6
7783EB9441B8701156D49F3429E4F627
2AF403E88078E69FABBBF24E83B55823
035FEBC2FF9B0AA63626D2CB12316222
isa
PBXGroup
name
Support Files
path
../Target Support Files/EZAudio
sourceTree
<group>
6C4C1217EC8BF9E5E6DC8386FEAA0C3A
isa
PBXTargetDependency
name
AlamofireRSSParser
target
43FD5AF8E2E268BB58C2BEE180302F51
targetProxy
B8E903F30171A1D853877248B25C11D5
6C4D119999C4945F085509808EEAD9CA
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartHighlighter.swift
path
Charts/Classes/Highlight/ChartHighlighter.swift
sourceTree
<group>
6C61009912177D3D77B80D65EC5B2AA4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartYAxisRenderer.swift
path
Charts/Classes/Renderers/ChartYAxisRenderer.swift
sourceTree
<group>
6C77A1B3D784E94C0A704E5758AF6E14
fileRef
DA3AA58FE349027A794BEA3358EED800
isa
PBXBuildFile
6CDE7B54911112B22403C6B83659EE77
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineScatterCandleRadarChartRenderer.swift
path
Charts/Classes/Renderers/LineScatterCandleRadarChartRenderer.swift
sourceTree
<group>
6CFD8C2D899AC6725E477D0BF4033CE2
buildActionMask
2147483647
files
2070C04C1ABE2C3A69159596D2E1DF51
BFEF228FE25034EB7CF784D634E0B10E
8D0C814DACA85184D823E6AD381D5A78
3425AFC5A5E5B97A4E085DC58D7BDE5C
87DC6F96269BFB9C6744C1089FC0E92E
522FF8BB85FE7B2A94BB4A2EBACA89AB
C17EA91E38478C5DF425AFCDBDFBB3A1
87647570FDAA4D851BD145A8FECA08D4
AC8B33D9041AD680F9D5317FAAF423E0
63537D19F4231AD1D75CAAD2AFE1EC84
5DCEC268DB930EF58F5B13FE3A59EC8B
0F92FE99CE8E162CBD0DC7F965008A6E
07C1897D80CE662EEE2BB582594B5752
158958FF49153EA1D61DF28C680C441B
F0C215D509673D9BE13B73AC1B1CCB15
D5AB4F80FDD82F7FD614CB3F000E615B
8D8C1022173EA10270DC8917557A6AFC
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
6DA6701753BDEEF59EA50F2CB8CDC7EC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
SJCSimplePDFView.m
path
SJCSimplePDFView/SJCSimplePDFView.m
sourceTree
<group>
6DC1C46D160F2B2BB3AA0C6940A03914
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartFillFormatter.swift
path
Charts/Classes/Formatters/ChartFillFormatter.swift
sourceTree
<group>
6DCD8E0D46E3E688EABD466D9ECB53BE
buildConfigurationList
56E802F711F304E380A745ED755A25F2
buildPhases
9A33333E6963F5910C2F9B4A21ED1C16
B76F8A1C0154EDBE0747BBB72FE5E62B
4A10B4FB2E8D14A92065018A75A6EEF1
buildRules
dependencies
isa
PBXNativeTarget
name
AlamofireRSSParser-AlamofireRSS
productName
AlamofireRSSParser-AlamofireRSS
productReference
A868E1FE16614BD1F1336EC1C9D8A8A8
productType
com.apple.product-type.bundle
6DD9C4273AD1566E52B7A375025B0C89
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
79C040AFDDCE1BCBF6D8B5EB0B85887F
remoteInfo
Alamofire
6EA1BE8E8A6172B255E1C74432F2F569
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AlamofireRSSParser.swift
path
Pod/Classes/AlamofireRSSParser.swift
sourceTree
<group>
6EC148C19BB64CE3477E95F7CA39F711
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Gifu-prefix.pch
sourceTree
<group>
6F27F0A0E87FC39880EE7BC442E7525C
fileRef
1845D98CE7CF2F3174B2E68C1E535445
isa
PBXBuildFile
6F68A3567B15E1ECA46E4CF4E50A7211
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
ADD0B8D536C47FE797C15119D29AFC71
remoteInfo
ZLSinusWaveView
6F96FF4172FE4DDDA8BB660DD50ABA6A
baseConfigurationReference
EA55530B8CFA1390B85AD2EAE503944D
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SSZipArchive/SSZipArchive-prefix.pch
INFOPLIST_FILE
Target Support Files/SSZipArchive/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SSZipArchive/SSZipArchive.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
SSZipArchive
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
6FB01F35A58B096070AD063AE6B3459A
includeInIndex
1
isa
PBXFileReference
path
AASquaresLoading.modulemap
sourceTree
<group>
6FD6A0D37E4C38641DCB2885397E1488
children
98D75CBF835E0513551169EAFCDB35B3
A28C94FC58D7492A6E64E2C97EBAFE0B
F209FD4822C5866ECCA569B37842FBBA
CFA3D4558500E9CC96C07F908B66D6B5
40043CBCDD93A301F8437421D53D02A3
A3415EFF6AEA35162B52EC0734DE1761
71E013AE8742AF9DE782F24E90B5E1DB
isa
PBXGroup
name
iOS
sourceTree
<group>
70073C35619976BCC6D659E523A9375E
fileRef
5259950BB229583DFC6DD1984E696407
isa
PBXBuildFile
702840BAC90AC4754E17FD68C4B8DEAC
baseConfigurationReference
EA55530B8CFA1390B85AD2EAE503944D
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SSZipArchive/SSZipArchive-prefix.pch
INFOPLIST_FILE
Target Support Files/SSZipArchive/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SSZipArchive/SSZipArchive.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
SSZipArchive
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
70525166CB057B3EDE7449F355542038
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DGElasticPullToRefreshLoadingView.swift
path
DGElasticPullToRefresh/DGElasticPullToRefreshLoadingView.swift
sourceTree
<group>
7055AA29B8603B5BE107C3CB363252C9
buildActionMask
2147483647
files
F27960E09751B596BEBF7019989E8BA3
83C6D53EFB4BAFB4A64B3E76D664197B
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
70A566A1797B301E45BC4F43633CF81A
children
99901C3BB68EEFED23AD5D68A6D00DD9
1260E1D284190E2A3D00903698C9D2F3
C617DC78B1A377E48CF0C244D1511F26
0832C378A14BA80BA5856826F1530746
4BABE59E39A193B562EFEBE6E5626154
B8BBF24C6E5985DBBE1D91820E19E613
isa
PBXGroup
name
Support Files
path
../Target Support Files/CYRTextView
sourceTree
<group>
71023FBED2BFC50D42DB8F5E48E31B48
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
socket_helper.m
path
NMSSH/Config/socket_helper.m
sourceTree
<group>
717A214D47C4467FB7418FB121F803FD
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
CYRTextStorage.m
path
CYRTextView/CYRTextStorage.m
sourceTree
<group>
71C68E3AFFC61709566D8EA695CFB5E7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
brg_endian.h
path
SSZipArchive/aes/brg_endian.h
sourceTree
<group>
71E013AE8742AF9DE782F24E90B5E1DB
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
UIKit.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/UIKit.framework
sourceTree
DEVELOPER_DIR
71EB9AFCBF7ABE58DCC9C10DEB02906A
baseConfigurationReference
A16184B99AC1C6FBC8F177C124589651
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SJCSimplePDFView/SJCSimplePDFView-prefix.pch
INFOPLIST_FILE
Target Support Files/SJCSimplePDFView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SJCSimplePDFView/SJCSimplePDFView.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
SJCSimplePDFView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
72085F8624E47C76F715EBE276B125EB
fileRef
27801E482F53A81CBFF8F018F3A098C6
isa
PBXBuildFile
72168557B70D4C7AFD3AD754069E2370
fileRef
A868E1FE16614BD1F1336EC1C9D8A8A8
isa
PBXBuildFile
729F9E9B68A861150F91F93D765BD254
fileRef
9F45FA658BE59059A916A5F98B6F70A7
isa
PBXBuildFile
72C2EC0D8143C4CE2FF8091B233306BF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
CYRToken.m
path
CYRTextView/CYRToken.m
sourceTree
<group>
72DC6BB442C0770DBB5A839ECD805ADB
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineChartData.swift
path
Charts/Classes/Data/Implementations/Standard/LineChartData.swift
sourceTree
<group>
7394AB9A3BB12133D1798B57561E2552
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHChannelDelegate.h
path
NMSSH/Protocols/NMSSHChannelDelegate.h
sourceTree
<group>
7404D532E36CB49046A6B5F2B4CB9E68
children
AE6C6B2C0EB874E9337C85BFF8DC4358
46EC9DD508AF1269E9D7DAB50594AB66
C5AA30790616DFD31FB6E41D32920A1A
B28621795FA91577FCF3525D161A891E
CF9D51D988643E797BAE8A9A54D9F2CD
B8024D22C71DD62C706C2DA89005F3EE
ECB77A2F7E083C88A4C9EAEF40CB8D17
129963BBCBF40DB2189A0EB7993EDF12
5EA97C7D866AB0A63806FDC3C86EDCFE
75671DCD2C65E9A11B1E6F09B6854AA0
F298F979D3ED9894044C72F2C66925E6
FD04474CE1E00D47F9010D3A6526EA81
0FDD62CA863BD5DBE7F5C375C207C7EF
5EFA7A6FD03F0353C6F5CA04653120C7
C7B98156605B0AC4C70830469ABB06A4
27801E482F53A81CBFF8F018F3A098C6
BD11BD25E12B54CC641E519B27C11B66
78FCECFF404AD0FD74BACA1C1FC9FFBE
626CCE81FCEDAE7AEF6B6A9403E58F03
3F37EE1C6EE59F78A3A5E60EF31FFA3A
DA8F020D6AA506F0106F80186BDA93E4
53F1005ADB78F4613F8C29A68E8B9909
62BD10A1EFF551EEE3D51229E3A5A135
74118FFA1C9E2B5C51D5D121489141E7
6C3C1BD7C759507F7AE5B2380506F232
isa
PBXGroup
name
EZAudio
path
EZAudio
sourceTree
<group>
74118FFA1C9E2B5C51D5D121489141E7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
TPCircularBuffer.h
path
EZAudio/TPCircularBuffer.h
sourceTree
<group>
74190DEE29D1C7C27FD494EE3CB59F14
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHChannel.h
path
NMSSH/NMSSHChannel.h
sourceTree
<group>
74A1509B9BC47C1B4C479FB033E06B24
fileRef
74118FFA1C9E2B5C51D5D121489141E7
isa
PBXBuildFile
settings
ATTRIBUTES
Public
74CDEF8BA057A6BB4453A748E70EA142
children
0FAAC91F636F7A42B8D0A2D53351CB33
B1AC36AEB4A84D49B74BB6F8E0AEF018
isa
PBXGroup
name
SwiftyJSON
path
SwiftyJSON
sourceTree
<group>
74DAF567B850F3FC5893C8CBDB828616
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
74DF8A9CBE6EAEB8C19105D047645443
buildConfigurations
9AC1C9FD1210EC02AAB22EE0DE3F2B60
9F67093900083070A89BDF2635A435DB
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
74F7FAC78E5CB4D327B99F47BF099326
baseConfigurationReference
23EB4B1F1FB528E10C5030501D4C3454
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Alamofire/Alamofire-prefix.pch
INFOPLIST_FILE
Target Support Files/Alamofire/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Alamofire/Alamofire.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
Alamofire
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
755AFCA09D3807CB6C260E7115234963
buildActionMask
2147483647
files
490570C4EC2C7DD9D5FCA37164C6442D
5E2CC216EEF82AC984AE8D61A9177113
5E49AAF37C2B40CB0957F56DF1A3E620
FA3529BA5DD86B6E59A2A2C589EA5884
C85C98983FF1862632F74F4104DB6E68
D7292846D89C548856055AEC24A11827
F36B8EEC5A75332E7C25AF70B7FF19EF
9E03F9A988688B18599B93160471758E
1966257DFF573B123534D86FB2A461BE
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
75671DCD2C65E9A11B1E6F09B6854AA0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudioPlot.m
path
EZAudio/EZAudioPlot.m
sourceTree
<group>
75694EB52988796CCDEC1C4A50560B6D
fileRef
698765A4EF927BBD85BC37EE2FF01903
isa
PBXBuildFile
75B5B409862E7A82A20C878277D303AF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
NMSSH-prefix.pch
sourceTree
<group>
75D98FF52E597A11900E131B6C4E1ADA
children
E8446514FBAD26C0E18F24A5715AEF67
79A9DEDC89FE8336BF5FEDAAF75BF7FC
D0405803033A2A777B8E4DFA0C1800ED
87B213035BAC5F75386F62D3C75D2342
894E5DA93A9F359521A89826BE6DA777
E7F21354943D9F42A70697D5A5EF72E9
CBC0F7C552B739C909B650A0F42F7F38
2BCC458FDD5F692BBB2BFC64BB5701FC
977577C045EDA9D9D1F46E2598D19FC7
DA312349A49333542E6F4B36B329960E
isa
PBXGroup
name
Pods
path
Target Support Files/Pods
sourceTree
<group>
761F2AE2A08681D34B98C5205A398BF9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxisRenderer.swift
path
Charts/Classes/Renderers/ChartXAxisRenderer.swift
sourceTree
<group>
7643F494404131680430018F7EC92AE2
isa
PBXTargetDependency
name
EZAudio
target
254EA72DFADAB5F3286B8726A554C9E6
targetProxy
52183AB70293B3C29450264A392FA4F5
76820BB8A343CE818398366E3787913C
isa
PBXTargetDependency
name
EZAudio
target
254EA72DFADAB5F3286B8726A554C9E6
targetProxy
2C7B70526524E165EB80DFFC1D36CFF2
768CC1338D4B027D4517DD3611152862
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift
sourceTree
<group>
770318C2100C2A9A4D14D224B041B0E5
fileRef
384EFED9AD5C956EA205110FCC14C384
isa
PBXBuildFile
776ECCE5529B00F6D7F372E0F8AB6002
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
MultipartFormData.swift
path
Source/MultipartFormData.swift
sourceTree
<group>
778126769FD6E223F9574C2E19DD5453
fileRef
D7D019D2275A7A64B3188D36B0F5F8F4
isa
PBXBuildFile
7783EB9441B8701156D49F3429E4F627
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
EZAudio-prefix.pch
sourceTree
<group>
783C44EF16D4C79ADC985C8C86C458D5
fileRef
F5A144C28EEF910B35FCD66B9ACB13AE
isa
PBXBuildFile
784DED0AA95B4F0087AD1FCA0D438BE0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
78905BC064EA7CAE6515516D704002CF
fileRef
D07DAD252FED8A056A4085E49639E5D7
isa
PBXBuildFile
settings
ATTRIBUTES
Public
78A8CAE0A08DC8E818F6E7C79557A27D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift
sourceTree
<group>
78FCECFF404AD0FD74BACA1C1FC9FFBE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZOutput.m
path
EZAudio/EZOutput.m
sourceTree
<group>
79081B3C3FFC3A41C57FF8AE876CAEE7
fileRef
228471249CCDB44C2C2793EFEAF06C43
isa
PBXBuildFile
settings
ATTRIBUTES
Public
791E8610412F77070BC5BCD5A394FEAF
children
4AF8AA804B2142B26DC1B5186720048A
36D90A99286A433572F91AB604418967
AF04A68FC019D3EAB4159D21638A42F1
A2F9F4EDE9E30138049A5CE2A7BDE3A5
223648D2D9A87589BDD0F2446CC1BF2A
ADDD22883EB4304A18264D3F48B70486
isa
PBXGroup
name
Support Files
path
../Target Support Files/AlamofireRSSParser
sourceTree
<group>
797C9F2528F449390500C4FECCBAA135
fileRef
50C1B0FE72BD421266EBFB4B2B74F13B
isa
PBXBuildFile
79A9DEDC89FE8336BF5FEDAAF75BF7FC
includeInIndex
1
isa
PBXFileReference
path
Pods.modulemap
sourceTree
<group>
79AF06EC7F78F59EDAC780C88DB961AE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSSHConfig.m
path
NMSSH/NMSSHConfig.m
sourceTree
<group>
79C040AFDDCE1BCBF6D8B5EB0B85887F
buildConfigurationList
3CFB42910790CF0BDBCCEBAACD6B9367
buildPhases
95CC2C7E06DC188A05DAAEE9CAA555A3
B1729F851F648EC60EE93CDB3C8BAEAD
EFDF3B631BBB965A372347705CA14854
buildRules
dependencies
isa
PBXNativeTarget
name
Alamofire
productName
Alamofire
productReference
14E2A18762B2C933AF7EF481D1079936
productType
com.apple.product-type.framework
7A88BF95853A69E550E9F63A060BED12
fileRef
B2C2A2977AC39FB8A1FC7FAE64E26072
isa
PBXBuildFile
7B234F4406FD51E392E7B688A295E8FB
fileRef
0B93148101A5531681949F675D41538E
isa
PBXBuildFile
7B48852C4D848FA2DA416A98F6425869
fileRef
B756C6158B1743F24242A4F20F07ECCA
isa
PBXBuildFile
7C204B9F7D811C860F446BAB1575C344
fileRef
0E5DECF96C58C0F18CD5F7C5221CC7A7
isa
PBXBuildFile
7CE0E9D851E9395C41EF6AFA7AE47423
fileRef
B28621795FA91577FCF3525D161A891E
isa
PBXBuildFile
7CE91BF36DAB7B3EE3B25D14480AFC34
fileRef
DC0D405095C90FB4035A2F0243192579
isa
PBXBuildFile
settings
ATTRIBUTES
Project
7D67EB40B9B5DAC7A2A758E1C8EEF4BC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartUtils.swift
path
Charts/Classes/Utils/ChartUtils.swift
sourceTree
<group>
7D70BAF35B5E41ECAA00CC8B49CAF3FB
baseConfigurationReference
36D90A99286A433572F91AB604418967
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/AlamofireRSSParser/AlamofireRSSParser-prefix.pch
INFOPLIST_FILE
Target Support Files/AlamofireRSSParser/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/AlamofireRSSParser/AlamofireRSSParser.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
AlamofireRSSParser
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
7D7776EE0E7EB45C6F665800D9385648
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarLineScatterCandleBubbleChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift
sourceTree
<group>
7DB346D0F39D3F0E887471402A8071AB
children
BA6428E9F66FD5A23C0A2E06ED26CD2F
56942D4AE3FE1A0B97040C17F2AAA7BD
0FCE52111ED6A874AB515E76EA8BF894
92151B6A7B2524A1BABEEE69E0CA7861
B7B80995527643776607AFFA75B91E24
isa
PBXGroup
sourceTree
<group>
7E24079B28DAF8D9128CA7E7D33E6F7C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Charts-prefix.pch
sourceTree
<group>
7E299BF9A615998682A1A05F5F0E42EE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxis.swift
path
Charts/Classes/Components/ChartXAxis.swift
sourceTree
<group>
7E387B67B1AB63AFDB74AEAA00DD821D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartYAxisRendererRadarChart.swift
path
Charts/Classes/Renderers/ChartYAxisRendererRadarChart.swift
sourceTree
<group>
7E3FD9DA3AAA3363CA2108CF49E0D9BE
includeInIndex
1
isa
PBXFileReference
path
SSZipArchive.modulemap
sourceTree
<group>
7E65716D77F599EDDB5E6EA1E6734088
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
7E9DCF48CA71A987E38B65E8EA1BC65E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ArrayExtension.swift
path
Source/ArrayExtension.swift
sourceTree
<group>
7EE6C232195755A42DEAECB46E888B18
children
040B16E53C2CBFE2007A0A70EE690D77
23EB4B1F1FB528E10C5030501D4C3454
391D473F1E22B03F1E1DA498562A0F38
CBC7A5017D4527A9E94D74915C54ACB8
63A42196CB86BF9D7F26EC16B135E0CF
3993828B63B3AC6BE59C92C303685F61
isa
PBXGroup
name
Support Files
path
../Target Support Files/Alamofire
sourceTree
<group>
7F87651AE9B6CA0E7F4A0114F19A7924
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
AASquaresLoading.xcconfig
sourceTree
<group>
80109CAB3AB2A64C968C7FE0171B89F1
fileRef
FA6606E69ACCD1B09D98F9CC5F9A98C3
isa
PBXBuildFile
80875D1812BC200BAB068CBC75B74E7A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleChartDataEntry.swift
path
Charts/Classes/Data/Implementations/Standard/CandleChartDataEntry.swift
sourceTree
<group>
809023B98C9FF6044DF1314603EE8B91
buildActionMask
2147483647
files
FA6B4510586447CB081BC8FA92CE4357
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
80DD5455D2185F4B63EC6AFA95A51E88
children
B2C2A2977AC39FB8A1FC7FAE64E26072
32146DB6CF24E5D003FAB31AC7628C3E
70525166CB057B3EDE7449F355542038
94FA3A77E6FC614EA18C169BA609056E
0D9E3E8557D628F179DC72179BE68873
0C8EFD8D5CCE9A85C27C92ACCD85C521
isa
PBXGroup
name
DGElasticPullToRefresh
path
DGElasticPullToRefresh
sourceTree
<group>
821EB8A5F1FC9B2F4EAB51C67F4DE2C6
fileRef
D170993D4633F76FF548FD13C3B84EC3
isa
PBXBuildFile
826CDEA3F474B8670FB6244F7842DE73
includeInIndex
1
isa
PBXFileReference
path
SJCSimplePDFView.modulemap
sourceTree
<group>
82D6671E6434CBE40C23F48ECD063E9B
children
7E65716D77F599EDDB5E6EA1E6734088
C9E6D695EAE6C1062DEA079BB751B87F
C29238134AE5C4B8C2352C6C11C495EB
667AE18ABE1BD4A574755ED111198F89
3873DACF51A2F4E637F48FC9EE28FAA0
228471249CCDB44C2C2793EFEAF06C43
isa
PBXGroup
name
Support Files
path
../Target Support Files/ZLMusicFlowWaveView
sourceTree
<group>
83489AF05AC1B719AA183B3AFC2BE3AA
fileRef
98D75CBF835E0513551169EAFCDB35B3
isa
PBXBuildFile
8353E819C2C6AE2417C900DE0705D1A8
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
socket_helper.h
path
NMSSH/Config/socket_helper.h
sourceTree
<group>
8364C5015494EEDBFB7AC551266741BB
buildActionMask
2147483647
files
E74514FEF953E9C25CBFE0645FADFC41
E7BD9D0FF2125D7C3A92D70C380B3261
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
83C6D53EFB4BAFB4A64B3E76D664197B
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
83CE5B92F7A625F5DAF1A110BF2F174D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartData.swift
path
Charts/Classes/Data/Implementations/Standard/ChartData.swift
sourceTree
<group>
83D33D34F7967099E1E8112180FB7D03
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
CYRTextView.framework
path
CYRTextView.framework
sourceTree
BUILT_PRODUCTS_DIR
854D9C81549E59B2145F57291D9C9E01
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Response.swift
path
Source/Response.swift
sourceTree
<group>
85822A6D7AF455601F1786BFBCCDCDC3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxisRendererHorizontalBarChart.swift
path
Charts/Classes/Renderers/ChartXAxisRendererHorizontalBarChart.swift
sourceTree
<group>
85F1FA1A04887000AE6D42617A155669
buildActionMask
2147483647
files
361CB8CE5FB0F7E9DADD6D243BA09A05
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
8621EC900E9540E855F2A45193465CE6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
MoveChartViewJob.swift
path
Charts/Classes/Jobs/MoveChartViewJob.swift
sourceTree
<group>
86662528AE34D79C3BA78439C0D9D01E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
aestab.h
path
SSZipArchive/aes/aestab.h
sourceTree
<group>
86712FE294355019927A4B113B072F63
fileRef
0FBCB9B828FF98812A1EE98817048C46
isa
PBXBuildFile
86909353BB4657C029BB5008942330ED
includeInIndex
1
isa
PBXFileReference
name
hmac.c
path
SSZipArchive/aes/hmac.c
sourceTree
<group>
86A4F33244B76027A52DC18FE83F6FA8
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Error.swift
path
Source/Error.swift
sourceTree
<group>
86ACE2887B0A55399595618D8A2A847D
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
F8C233736FECBA33C0E71D949DF017CA
remoteInfo
ZLMusicFlowWaveView
86D56E9B7AD7546729AD442A3D02478A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
NMSSH.xcconfig
sourceTree
<group>
86D972F433A3176BF77299B3526C71AF
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
AlamofireRSSParser.framework
path
AlamofireRSSParser.framework
sourceTree
BUILT_PRODUCTS_DIR
86F265DD248E17D2B6A3C5E4AA8B6800
fileRef
BA7AA59D2E9F556A528840EA05378089
isa
PBXBuildFile
870CD4D0ED37DE3295E8E96C29756E48
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
EZAudio.framework
path
EZAudio.framework
sourceTree
BUILT_PRODUCTS_DIR
87647570FDAA4D851BD145A8FECA08D4
fileRef
E349CFCDAD29F7182C472495FBBFCF0F
isa
PBXBuildFile
settings
ATTRIBUTES
Public
877DB484F7698974CCC1D66B51116FE1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataProvider.swift
path
Charts/Classes/Interfaces/ChartDataProvider.swift
sourceTree
<group>
87B213035BAC5F75386F62D3C75D2342
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Pods-acknowledgements.plist
sourceTree
<group>
87D7DAF7937EAF3CF65F1B022D9A8BDB
includeInIndex
1
isa
PBXFileReference
name
ioapi.c
path
SSZipArchive/minizip/ioapi.c
sourceTree
<group>
87DC6F96269BFB9C6744C1089FC0E92E
fileRef
03FC642C1EF0F16D7AB31F4AC6D6F719
isa
PBXBuildFile
settings
ATTRIBUTES
Public
87FEA49CACDD9BA7901D248871C94118
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
wrapper.plug-in
name
RongCloud.bundle
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongCloud.bundle
sourceTree
<group>
8849F4F8A02D3B41E46CF24A28485E5B
baseConfigurationReference
1260E1D284190E2A3D00903698C9D2F3
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/CYRTextView/CYRTextView-prefix.pch
INFOPLIST_FILE
Target Support Files/CYRTextView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/CYRTextView/CYRTextView.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
CYRTextView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
894E5DA93A9F359521A89826BE6DA777
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
Pods-dummy.m
sourceTree
<group>
897752D9150F684990F930BCC8BD5619
fileRef
62BD10A1EFF551EEE3D51229E3A5A135
isa
PBXBuildFile
89CC9FB44A3C41E010E2D4EE388B8D07
buildConfigurations
EFC93C11F16B90228BA386D77AA69400
5721DA804A3926404ADB80D27EB9D7F2
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
8ACA70A9D45E782647B8995535544861
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
8AF188560381C1B97D9E46B09B146DE0
fileRef
A0688D041EA5E1060A50787E5D0A8B88
isa
PBXBuildFile
8B6EF9C34F1E4597938A09B5A8086C08
fileRef
E51BBFF2074DA4267B550E1D58ADF58A
isa
PBXBuildFile
8BB0BD9B1B6EB8ABF67E29EED3D628B6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
NetworkReachabilityManager.swift
path
Source/NetworkReachabilityManager.swift
sourceTree
<group>
8BCFC48792C0183444EC97C43A6E3BB4
fileRef
717A214D47C4467FB7418FB121F803FD
isa
PBXBuildFile
8C29735442BC85B0F88470642089405D
baseConfigurationReference
C29238134AE5C4B8C2352C6C11C495EB
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView-prefix.pch
INFOPLIST_FILE
Target Support Files/ZLMusicFlowWaveView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
ZLMusicFlowWaveView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
8D0C814DACA85184D823E6AD381D5A78
fileRef
5798CFA7BDB78019CBD837FA245CCF7C
isa
PBXBuildFile
settings
ATTRIBUTES
Public
8D8C1022173EA10270DC8917557A6AFC
fileRef
8353E819C2C6AE2417C900DE0705D1A8
isa
PBXBuildFile
settings
ATTRIBUTES
Private
8D901D00C6FF59773C631FE0557B8845
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
archive.ar
name
libssl.a
path
NMSSH-iOS/Libraries/lib/libssl.a
sourceTree
<group>
8E8CBDC117A589EB2A32FDEE22A5921C
fileRef
DA8F020D6AA506F0106F80186BDA93E4
isa
PBXBuildFile
settings
ATTRIBUTES
Public
8EA7C01FA9014E4AC4EB52DEBC568005
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Alamofire.swift
path
Source/Alamofire.swift
sourceTree
<group>
8EB11202167FCDDF1257AAAB1D1FB244
fileRef
8EA7C01FA9014E4AC4EB52DEBC568005
isa
PBXBuildFile
8EC66117408FE5D27B57F58550E978C0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
SwiftyJSON.xcconfig
sourceTree
<group>
8EDF3AE7833D667E4C4D8478FD4B5447
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
SSZipArchive.framework
path
SSZipArchive.framework
sourceTree
BUILT_PRODUCTS_DIR
8F13815876589E1C113CACCF6B677AF1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartDataProvider.swift
path
Charts/Classes/Interfaces/BarChartDataProvider.swift
sourceTree
<group>
8F77C82F0C8760528390313D44756D9B
buildActionMask
2147483647
files
67184F1852A59AB997108F4DB5AF70B0
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
8F7A7A4CBF39B0995A17F5F10F25F3A1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
SJCSimplePDFView.h
path
SJCSimplePDFView/SJCSimplePDFView.h
sourceTree
<group>
8F96B72A2D016C2925132ED704A6D6F4
isa
PBXTargetDependency
name
ZLSinusWaveView
target
ADD0B8D536C47FE797C15119D29AFC71
targetProxy
6F68A3567B15E1ECA46E4CF4E50A7211
8FC086E0146293F873A3FA450C0C3731
fileRef
6B173C46DF90109FE17024B11AD202E2
isa
PBXBuildFile
settings
ATTRIBUTES
Public
905C0B7980F791438B4754D9AB323CBE
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
9151874C2B5F097360208EB0315C6297
fileRef
E80999E723F79EDC7D4FD8BF79BCA5F5
isa
PBXBuildFile
9181C57B0D5E511D518D6ED675AC30A6
fileRef
5C0B9516684CF8E715F8B7D047F76709
isa
PBXBuildFile
91827F8492FCBB8348FC58AEF693B03A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarChartData.swift
path
Charts/Classes/Data/Implementations/Standard/BarChartData.swift
sourceTree
<group>
92151B6A7B2524A1BABEEE69E0CA7861
children
2993BE53CEB9368C1FD283A26A8DC3CF
14E2A18762B2C933AF7EF481D1079936
A868E1FE16614BD1F1336EC1C9D8A8A8
86D972F433A3176BF77299B3526C71AF
2E70CA0E5B5063FA1695EC714491B22A
83D33D34F7967099E1E8112180FB7D03
F7852FD543BD5C8EEF81095A19EAD332
870CD4D0ED37DE3295E8E96C29756E48
02787AB0F80C11B895A72337338D4CB7
94914325FB30736386431FA57CAE5AE4
1A85B3DEA68DBE452583A860BFC25D68
21B7F68E83AB3158AC18BB512498ECE0
8EDF3AE7833D667E4C4D8478FD4B5447
35220F594E860391A0ED1DF9ECA6EBCA
F51D8948E1F5D0E0FA3161D641164C0E
0727A4243F3B7D3216AAC08CA047DA60
B4CA9869A1F71DB60F8D8B061D814CC5
isa
PBXGroup
name
Products
sourceTree
<group>
928CDEDEA8EC3C437DB27409A17C998B
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
9303B618AC39FB9AC08C2C49BF74EB55
buildActionMask
2147483647
files
83489AF05AC1B719AA183B3AFC2BE3AA
D06A2482F5337777E2FD81594035B829
45DA8587F08705657CBBFF27A51A0143
F8803DAD17AC9CE8BCAD6B0594646D64
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
93E203BDEABA3092CDF443A1AA4202FD
children
05B129043462F91B458D18AFB8F529C2
B388A0A92CD8B2C9CD1F9297453C50BA
86D56E9B7AD7546729AD442A3D02478A
E2FAD92811C5785C55D927D4BBF05C68
75B5B409862E7A82A20C878277D303AF
69B023D17AE27F4AFA2514F22965C5D0
isa
PBXGroup
name
Support Files
path
../Target Support Files/NMSSH
sourceTree
<group>
942DE51F25BA046A971321558B6BEA5A
fileRef
D5EB8839E96EE9D01C2BF4D48D8EDF36
isa
PBXBuildFile
9469DF81ECB494E84675969B5E13374C
fileRef
63A42196CB86BF9D7F26EC16B135E0CF
isa
PBXBuildFile
settings
ATTRIBUTES
Public
94914325FB30736386431FA57CAE5AE4
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
NMSSH.framework
path
NMSSH.framework
sourceTree
BUILT_PRODUCTS_DIR
94FA3A77E6FC614EA18C169BA609056E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DGElasticPullToRefreshLoadingViewCircle.swift
path
DGElasticPullToRefresh/DGElasticPullToRefreshLoadingViewCircle.swift
sourceTree
<group>
9505960D18F60DAA70871C006CA302EF
fileRef
7D67EB40B9B5DAC7A2A758E1C8EEF4BC
isa
PBXBuildFile
95A51226875B54D2C24099FABD65F9A4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSH.h
path
NMSSH/NMSSH.h
sourceTree
<group>
95BDB0879B32F78AD2E6AC781320E7C2
fileRef
223648D2D9A87589BDD0F2446CC1BF2A
isa
PBXBuildFile
settings
ATTRIBUTES
Public
95C3D67F3A2378FDCAD498AF576A36D7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Gifu.xcconfig
sourceTree
<group>
95CC2C7E06DC188A05DAAEE9CAA555A3
buildActionMask
2147483647
files
ADF19C953CE2A7D0B72EC93A81FCCC26
8EB11202167FCDDF1257AAAB1D1FB244
5CB05FBCB32D21E194B5ECF680CB6AE0
095406039B4D371E48D08B38A2975AC8
4081EA628AF0B73AC51FFB9D7AB3B89E
C7B6DD7C0456C50289A2C381DFE9FA3F
34CCDCA848A701466256BC2927DA8856
BE41196F6A3903E59C3306FE3F8B43FE
C0DB70AB368765DC64BFB5FEA75E0696
EFE92E8D3813DD26E78E93EEAF6D7E7E
62E8346F03C03E7F4D631361F325689E
3EA8F215C9C1432D74E5CCA4834AA8C0
AA314156AC500125F4078EE968DB14C6
7B48852C4D848FA2DA416A98F6425869
AE4CF87C02C042DF13ED5B21C4FDC1E0
16102E4E35FAA0FC4161282FECE56469
5BC19E6E0F199276003F0AF96838BCE5
2D3405986FC586FA6C0A5E0B6BA7E64E
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
95D4FD4EE6EC9C7566AFDCB870E6A978
fileRef
AF04A68FC019D3EAB4159D21638A42F1
isa
PBXBuildFile
976A24EA83BF3467025D3580ED456D06
isa
PBXTargetDependency
name
SwiftyJSON
target
FB6A25C88BCCDB159C1C71A2C484100D
targetProxy
45FA3456C69B0437B37A006EFB69674D
977577C045EDA9D9D1F46E2598D19FC7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Pods.debug.xcconfig
sourceTree
<group>
97B071F74774C182E2EBD5319D1F565F
fileRef
C832BE8F84718CAD9B5B7A0F2296F628
isa
PBXBuildFile
settings
ATTRIBUTES
Public
97CA0B8036338914727FF40447D5C34C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
97E1CBD3DF590CB3415D629A4ECBC776
children
45B1D072665424E0D9FEAA51DE27E6E3
63002BFF3EE441011E71DD87CDA49484
034548B827C03622818B97E6F50C78EC
9B8983A42745CE241C8FE81ADFB76218
E75768524ABD0E737765714AE4677C48
AC2EF1AE40274FFDC401667516F473E2
isa
PBXGroup
name
Support Files
path
../Target Support Files/Swifter
sourceTree
<group>
9838C7578BE14F947489DA4D1C595898
fileRef
A1E5E540A44850D55021393D3B56D093
isa
PBXBuildFile
98760AA9A7D6FB3DA51581FB5D81023D
buildActionMask
2147483647
files
95D4FD4EE6EC9C7566AFDCB870E6A978
556344573F293DFD06C18EC7B51B812B
80109CAB3AB2A64C968C7FE0171B89F1
CEE3227590AFA556D61A75618381AFB4
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
988F0BEB31938ED3D03BD2F30C2178DF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSFTP.h
path
NMSSH/NMSFTP.h
sourceTree
<group>
98D75CBF835E0513551169EAFCDB35B3
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
AudioToolbox.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/AudioToolbox.framework
sourceTree
DEVELOPER_DIR
997199E72131063A4BBCAE8FBC3CAECC
children
679ABE39538CF97A7B169D851D0D472D
4684964FE77650C6E9F3ED93AC79C87D
isa
PBXGroup
name
RongCloudIMKit
path
RongCloudIMKit
sourceTree
<group>
998667BFE20E591A5EF6D4412B709E4B
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
0E579C8B6EC88FD31F0C2B47C9058B48
remoteInfo
AASquaresLoading
99901C3BB68EEFED23AD5D68A6D00DD9
includeInIndex
1
isa
PBXFileReference
path
CYRTextView.modulemap
sourceTree
<group>
99DC0137E12C0E6A0CF0626CB80CB1D5
fileRef
E56D64DF36156ED67576CCA614D0618F
isa
PBXBuildFile
9A33333E6963F5910C2F9B4A21ED1C16
buildActionMask
2147483647
files
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
9A72A7D51819C4D550B5473E909F71FF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineChartRenderer.swift
path
Charts/Classes/Renderers/LineChartRenderer.swift
sourceTree
<group>
9A8A6001F3E0387D56C0CB3189D0CF54
buildActionMask
2147483647
files
FD0CC0A859DB9231444E62D7E971B22A
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
9AB9C30C29CCEEC9315ABE415511676B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Notifications.swift
path
Source/Notifications.swift
sourceTree
<group>
9AC1C9FD1210EC02AAB22EE0DE3F2B60
baseConfigurationReference
E5055FEB2A2A322A90311B7874DC9092
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh-prefix.pch
INFOPLIST_FILE
Target Support Files/DGElasticPullToRefresh/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
DGElasticPullToRefresh
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
9ACB6C78F78F1EF04CBFD24FBF52D12C
buildActionMask
2147483647
files
E8E725C145C99E05F90D6F5141B56754
B28D9E00358A3BFC146406A9E9D84CCF
CF82ED8D2AAF0100798F74B82004713B
B3F888A903C9E8B6C17D5FD59576A722
4A649E5F7B4737DC7A6645E6EBE61690
57EB7F801E937056D8EA61707A156023
AE7C99A546378A3B72C0A2F4B1F1DE56
942DE51F25BA046A971321558B6BEA5A
AAFB9E75081EEE8503740F8E73FC1563
4888A76CCC22B207C2B0D3B6741688DA
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
9B0170C2DE85A2CED19A6FB95B59CD25
fileRef
22B30496E9D4C59ABF59F254C49FF122
isa
PBXBuildFile
settings
ATTRIBUTES
Project
9B4184FC9E303824C5756A811AB09E31
children
C109982F8C877B91A290E88A1EBC1E1D
62D919A2C9C2C955FA825CB474A9F16B
4567150A2B071C2DA321F4CE18FF8364
7E9DCF48CA71A987E38B65E8EA1BC65E
42787649B04F8FCB3363DE9C7642B645
69E2158C4EE02BF8D175828AD9D93C69
D07DAD252FED8A056A4085E49639E5D7
D5EB8839E96EE9D01C2BF4D48D8EDF36
FF2C748C341F3E0FA03FC7D890D54304
20DCE1442556CA5F41805570F5B5844F
A50FBF61AC12A13CE4B7E629E19DB144
isa
PBXGroup
name
Gifu
path
Gifu
sourceTree
<group>
9B8983A42745CE241C8FE81ADFB76218
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
Swifter-dummy.m
sourceTree
<group>
9BBB90314EEDCAA33FB3160A02862010
fileRef
05BA62425D43DD87EC6390A0FAE74D1E
isa
PBXBuildFile
9BCA03B2F0B3C0EA0D3499F966194E75
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
AASquaresLoading-dummy.m
sourceTree
<group>
9C01EAB768BB47EB46A5760C4E164C3A
fileRef
129963BBCBF40DB2189A0EB7993EDF12
isa
PBXBuildFile
9C29B71FB70AAEC2242DDF5BD50C55A3
buildConfigurationList
25E5BE8AC9996AEF5235FB7EEB1A801D
buildPhases
AD5E022434C2CCBE447351CEC813EB1E
9A8A6001F3E0387D56C0CB3189D0CF54
FB566F69981E2F14222BE796DC7474B5
buildRules
dependencies
isa
PBXNativeTarget
name
Swifter
productName
Swifter
productReference
35220F594E860391A0ED1DF9ECA6EBCA
productType
com.apple.product-type.framework
9D4E866B71A9C1336273DDC9164734A2
buildActionMask
2147483647
files
95BDB0879B32F78AD2E6AC781320E7C2
0380D2B912CDE029522351D67E39310E
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
9D4F76E63FE32EDCFE411B47AADE7C20
baseConfigurationReference
DA312349A49333542E6F4B36B329960E
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
INFOPLIST_FILE
Target Support Files/Pods/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MACH_O_TYPE
staticlib
MODULEMAP_FILE
Target Support Files/Pods/Pods.modulemap
MTL_ENABLE_DEBUG_INFO
NO
OTHER_LDFLAGS
OTHER_LIBTOOLFLAGS
PODS_ROOT
$(SRCROOT)
PRODUCT_NAME
Pods
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
9D7EF092E912A37841FC7F3316B1EE46
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
mztools.h
path
SSZipArchive/minizip/mztools.h
sourceTree
<group>
9D98F0DEB1F6A637347AA210314D3648
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
SSZipArchive-dummy.m
sourceTree
<group>
9DD2A8006D79DC4469F9BD2FFB55F071
fileRef
E2F0E619F4A90A088378D7A28F583D02
isa
PBXBuildFile
9E03F9A988688B18599B93160471758E
fileRef
0A0B1AD12AF0AAF31F2FE461AEDD6AC9
isa
PBXBuildFile
9E138A11AB568FDD962F892987F6F048
buildActionMask
2147483647
files
131D95D3FCDF7799E1D69213A378638E
E8429EE77E177E3DDF7BDF57797AB2EC
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
9E1EEA656E59AB9E30DC8D0385F289B4
fileRef
63B79EFF01B2EE5390F1C6930E5D9E13
isa
PBXBuildFile
9F1272B6E005ED49F1C4BCCDD73D1F58
fileRef
16BED61439C924D34FF25EC21932E8AF
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
9F45FA658BE59059A916A5F98B6F70A7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IBarChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IBarChartDataSet.swift
sourceTree
<group>
9F67093900083070A89BDF2635A435DB
baseConfigurationReference
E5055FEB2A2A322A90311B7874DC9092
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh-prefix.pch
INFOPLIST_FILE
Target Support Files/DGElasticPullToRefresh/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
DGElasticPullToRefresh
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
9F76D67DEC97A5BBB9AD3546ED28FFDE
fileRef
03F0D41F8726403C1B0B5F3D93915906
isa
PBXBuildFile
9F898C8AC3124C1B95F382C093800963
baseConfigurationReference
8EC66117408FE5D27B57F58550E978C0
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch
INFOPLIST_FILE
Target Support Files/SwiftyJSON/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/SwiftyJSON/SwiftyJSON.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
SwiftyJSON
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
9FD26D6C00634178B74170103B48A9CF
fileRef
242B71AC1ED8BF10BFB8883D7A043B57
isa
PBXBuildFile
A001EF9508D510E336B414095A84EC0F
buildActionMask
2147483647
files
5768DCD828BCB3B8A372407BA137B249
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
A00CBCB935830FEE99F6E645C95E834D
fileRef
B70483F68DA580907714FF534F1A20DA
isa
PBXBuildFile
A020A04A30303EBCC97F078481030B44
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
libssh2_publickey.h
path
NMSSH-iOS/Libraries/include/libssh2/libssh2_publickey.h
sourceTree
<group>
A0688D041EA5E1060A50787E5D0A8B88
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
ZLMusicFlowWaveView.m
path
ZLMusicFlowWaveView/ZLMusicFlowWaveView.m
sourceTree
<group>
A0718C652496BAA16F3007BE63680091
fileRef
D131D943789EC727F15929276BBBD8BD
isa
PBXBuildFile
settings
ATTRIBUTES
Public
A16184B99AC1C6FBC8F177C124589651
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
SJCSimplePDFView.xcconfig
sourceTree
<group>
A1B31917F302790BEE2C7CA37EFBA0DF
includeInIndex
1
isa
PBXFileReference
name
unzip.c
path
SSZipArchive/minizip/unzip.c
sourceTree
<group>
A1E5E540A44850D55021393D3B56D093
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartDataEntry.swift
path
Charts/Classes/Data/Implementations/Standard/BubbleChartDataEntry.swift
sourceTree
<group>
A20419267FBC2600623140053A2AA8F7
fileRef
B06192AD341CDBCD0D19BD7B8DCF3B4E
isa
PBXBuildFile
A28C94FC58D7492A6E64E2C97EBAFE0B
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
AVFoundation.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/AVFoundation.framework
sourceTree
DEVELOPER_DIR
A2F9F4EDE9E30138049A5CE2A7BDE3A5
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
AlamofireRSSParser-prefix.pch
sourceTree
<group>
A3415EFF6AEA35162B52EC0734DE1761
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
GLKit.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/GLKit.framework
sourceTree
DEVELOPER_DIR
A46427534DD269E2ED45FE9190F4F819
buildActionMask
2147483647
files
BD97C1D6886F4A540BA21C18DE70A47A
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
A473EE5B6E7552F583A7E6C0411A63FE
fileRef
161961ABCAFC8D944C13F6B003163607
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
A481946E2B03D2D461A9D9942194D32C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
AASquaresLoading-umbrella.h
sourceTree
<group>
A48B96C6FBB609A286F182ED83923097
fileRef
BE0A3BFD226BAF44617BFBB3DB345624
isa
PBXBuildFile
A50FBF61AC12A13CE4B7E629E19DB144
children
C2F4A628275A3E441F742896335D7FF5
95C3D67F3A2378FDCAD498AF576A36D7
FE28E020C32C8DA2DA56BAB6494D030A
6EC148C19BB64CE3477E95F7CA39F711
D131D943789EC727F15929276BBBD8BD
17F30271B79E8344F95C3FA89632ADC8
isa
PBXGroup
name
Support Files
path
../Target Support Files/Gifu
sourceTree
<group>
A525E68A31198AD8B3B5CAC519F1A43E
fileRef
6B53E7009C09C0B74CCBE630C56B20C1
isa
PBXBuildFile
A5F486B6DA397786F31EB6A27CBA10F5
fileRef
A99843CE4BE0995346C06785127AB91C
isa
PBXBuildFile
A70CDAD61F90AC503C7D04CC22DA2923
buildSettings
ALWAYS_SEARCH_USER_PATHS
NO
CLANG_CXX_LANGUAGE_STANDARD
gnu++0x
CLANG_CXX_LIBRARY
libc++
CLANG_ENABLE_MODULES
YES
CLANG_ENABLE_OBJC_ARC
YES
CLANG_WARN_BOOL_CONVERSION
YES
CLANG_WARN_CONSTANT_CONVERSION
YES
CLANG_WARN_DIRECT_OBJC_ISA_USAGE
YES
CLANG_WARN_EMPTY_BODY
YES
CLANG_WARN_ENUM_CONVERSION
YES
CLANG_WARN_INT_CONVERSION
YES
CLANG_WARN_OBJC_ROOT_CLASS
YES
CLANG_WARN_UNREACHABLE_CODE
YES
CLANG_WARN__DUPLICATE_METHOD_MATCH
YES
COPY_PHASE_STRIP
NO
GCC_C_LANGUAGE_STANDARD
gnu99
GCC_DYNAMIC_NO_PIC
NO
GCC_OPTIMIZATION_LEVEL
0
GCC_PREPROCESSOR_DEFINITIONS
DEBUG=1
$(inherited)
GCC_SYMBOLS_PRIVATE_EXTERN
NO
GCC_WARN_64_TO_32_BIT_CONVERSION
YES
GCC_WARN_ABOUT_RETURN_TYPE
YES
GCC_WARN_UNDECLARED_SELECTOR
YES
GCC_WARN_UNINITIALIZED_AUTOS
YES
GCC_WARN_UNUSED_FUNCTION
YES
GCC_WARN_UNUSED_VARIABLE
YES
IPHONEOS_DEPLOYMENT_TARGET
8.0
ONLY_ACTIVE_ARCH
YES
STRIP_INSTALLED_PRODUCT
NO
SYMROOT
${SRCROOT}/../build
isa
XCBuildConfiguration
name
Debug
A792226DBE4257340C826C75A0DC208F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Request.swift
path
Source/Request.swift
sourceTree
<group>
A79BA180FB0AAA9758E33B6FC43DD7F2
fileRef
BFE4C92C7B56F5BE2EDB6693B5B01F06
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
A808AE4EBFE37F90FE49C2715FB330F2
fileRef
B7931B4F53CD6EDE5CF224FA1404C794
isa
PBXBuildFile
A8095458ED6EE84FC61C7A523DD5E84D
fileRef
0294DCA76D64937CF8D8ADF477A4FA11
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
A868E1FE16614BD1F1336EC1C9D8A8A8
explicitFileType
wrapper.cfbundle
includeInIndex
0
isa
PBXFileReference
name
AlamofireRSS.bundle
path
AlamofireRSS.bundle
sourceTree
BUILT_PRODUCTS_DIR
A89C4B4FA34F489CCA9D61165EA98AF9
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
path
EZAudio.framework
sourceTree
BUILT_PRODUCTS_DIR
A962F3A2F35704A852AC7D38910200D9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
archive.ar
name
libopencore-amrnb.a
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/libopencore-amrnb.a
sourceTree
<group>
A99843CE4BE0995346C06785127AB91C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartXAxisValueFormatter.swift
path
Charts/Classes/Formatters/ChartXAxisValueFormatter.swift
sourceTree
<group>
AA314156AC500125F4078EE968DB14C6
fileRef
1891931FD0A3F4CC78749D9E977A8505
isa
PBXBuildFile
AAD9F83548ADC849E712A6A4D7A6D789
buildActionMask
2147483647
files
EB42675237B2858B723331F045DB2FB4
5C8F85E0EEBB7F9DDADE1D67E310ACAF
586EA2D58EF199363C2C23823C092089
450044A6490A439394B0F3A67CCFBD00
45DDC4029E0C5A71CC9136854BFC8AB1
66F42930FE68C6E4BD9E882D382F237C
C4B3C15B8ACB8B8ECC0466781B5838BD
E3E49AEE7447C2756D79CBF55AEBDF02
01776C25A5DB30E5FB22DABA2D28B271
16B29AE122AF64257C643FA13FBBA52B
4544CA2498B23C5B3295862D2F20901A
8E8CBDC117A589EB2A32FDEE22A5921C
74A1509B9BC47C1B4C479FB033E06B24
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
AAFB9E75081EEE8503740F8E73FC1563
fileRef
FF2C748C341F3E0FA03FC7D890D54304
isa
PBXBuildFile
ABEF8242948249F9A5BF7C36F57CD8DB
fileRef
877DB484F7698974CCC1D66B51116FE1
isa
PBXBuildFile
ABFB4E32ADD23D5E47758C89919D0EAD
isa
PBXTargetDependency
name
Swifter
target
9C29B71FB70AAEC2242DDF5BD50C55A3
targetProxy
F96AE71D5D1E0E91E4AB3E8EB2B2612A
AC2EF1AE40274FFDC401667516F473E2
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Swifter-umbrella.h
sourceTree
<group>
AC8B33D9041AD680F9D5317FAAF423E0
fileRef
95A51226875B54D2C24099FABD65F9A4
isa
PBXBuildFile
settings
ATTRIBUTES
Public
ACE29C6EE9323028266DA51A3449336F
fileRef
B801611949F9A65BDAD1BA9E75AC4B43
isa
PBXBuildFile
settings
ATTRIBUTES
Project
AD5E022434C2CCBE447351CEC813EB1E
buildActionMask
2147483647
files
D22E0FDFD7709E9736B0A7D27CFA1FFC
8B6EF9C34F1E4597938A09B5A8086C08
409737D7933980737EC1592FBD4AAADE
D2C4ADCAC2A7308D24784C168825A6CC
B8FCA3C53C645E5E3C2497744767DA06
FD6B3B6081C8329BA2B82C48DEAA71C8
52349732EBA58888E9A0DBEB887F361B
11F862EDC00E98340C3E6E46BA922E26
52136F9F39CC2759B6CC1922BCB1AB41
BC112F174DA60C5E98C5F62DC222A8CF
9F76D67DEC97A5BBB9AD3546ED28FFDE
75694EB52988796CCDEC1C4A50560B6D
B464B42CACD04405291A2DAB52398E9B
9151874C2B5F097360208EB0315C6297
25502F3A70A00FFB9812245EC0ECD0F6
5D33D52D318CF2F7B66A1D73DDCE436D
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
ADD0B8D536C47FE797C15119D29AFC71
buildConfigurationList
89CC9FB44A3C41E010E2D4EE388B8D07
buildPhases
124CC709A273ED2691A47C5CEA065111
FC5B42B4BAB1F773C37B0B7916361BB0
BEF74F5A1537A0F36703A7B86CC67092
buildRules
dependencies
7643F494404131680430018F7EC92AE2
isa
PBXNativeTarget
name
ZLSinusWaveView
productName
ZLSinusWaveView
productReference
B4CA9869A1F71DB60F8D8B061D814CC5
productType
com.apple.product-type.framework
ADD71B1DEF5A923A72F5BD91617A3BFA
children
61441E6010D0E49F26DDACBC74B8FCC2
EB00AA6939C22D418E0231F5C736BC44
00ED322AD74E086D0DBE4FAC8A72856D
isa
PBXGroup
name
ZLSinusWaveView
path
ZLSinusWaveView
sourceTree
<group>
ADDD22883EB4304A18264D3F48B70486
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
ADF19C953CE2A7D0B72EC93A81FCCC26
fileRef
391D473F1E22B03F1E1DA498562A0F38
isa
PBXBuildFile
AE1566BD32F907C4B66DEF43A2CEFC05
fileRef
191F7183D2E17767A8B14716B9453747
isa
PBXBuildFile
AE2091E6977D6C16528F5BCCDF7FCDC9
buildActionMask
2147483647
files
74DAF567B850F3FC5893C8CBDB828616
191955118642709970DA6F35F57D57A6
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
AE2C11E6B5332F82FE14C6CDB59D57FA
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
AEA56EBE1B518C71721209FB26701898
remoteInfo
Gifu
AE4CF87C02C042DF13ED5B21C4FDC1E0
fileRef
39E179F4DAB57EC19626D1DCC4F5F007
isa
PBXBuildFile
AE6C6B2C0EB874E9337C85BFF8DC4358
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
AEFloatConverter.h
path
EZAudio/AEFloatConverter.h
sourceTree
<group>
AE7C99A546378A3B72C0A2F4B1F1DE56
fileRef
FE28E020C32C8DA2DA56BAB6494D030A
isa
PBXBuildFile
AE9410D9B1C05916CA1D2817FB0F45F1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
ZLMusicFlowDecorativeView.m
path
ZLMusicFlowWaveView/ZLMusicFlowDecorativeView.m
sourceTree
<group>
AEA56EBE1B518C71721209FB26701898
buildConfigurationList
B4096C390FF4F7F3535818EA64A6377C
buildPhases
9ACB6C78F78F1EF04CBFD24FBF52D12C
E6780F645E1E0B045D81802B23CA1195
211BF217FEF65CFAFA0595009B57B795
buildRules
dependencies
isa
PBXNativeTarget
name
Gifu
productName
Gifu
productReference
02787AB0F80C11B895A72337338D4CB7
productType
com.apple.product-type.framework
AF04A68FC019D3EAB4159D21638A42F1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
AlamofireRSSParser-dummy.m
sourceTree
<group>
AF2CF0BAA5DF6BABFC217F2495AD6FBA
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
RongIMLib.framework
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework
sourceTree
<group>
B02BF2860C124E9C66C26D2E4913EC5B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
ZLSinusWaveView.xcconfig
sourceTree
<group>
B06192AD341CDBCD0D19BD7B8DCF3B4E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CombinedChartRenderer.swift
path
Charts/Classes/Renderers/CombinedChartRenderer.swift
sourceTree
<group>
B0EF69E356D3A304384FA0E56A5CD630
buildActionMask
2147483647
files
17C4E6CB67D0446387655B959DA3A951
B1F334FD78AE10A3AE1DFACE03F36892
A79BA180FB0AAA9758E33B6FC43DD7F2
366B695AE31536E5AB0C83E287A6DBC6
A473EE5B6E7552F583A7E6C0411A63FE
470A19320682236DEF0633151EF7F01C
1D0D77460730EC30F5AFC5241DE8C317
52ADA7A4A97CBF5879F6167136D1E715
241D3259D8743003561A971C917C0C14
A8095458ED6EE84FC61C7A523DD5E84D
3F35D9D6BE5B906A940193BD32AEA736
2EC5A9E72CC8EBAA5DC6255EB89C5879
BF25A6BDAC99AE9978881DAEEC73426C
57D859C2DD2A786A0EC902A7DE9F864C
9F1272B6E005ED49F1C4BCCDD73D1F58
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
B1729F851F648EC60EE93CDB3C8BAEAD
buildActionMask
2147483647
files
F82198F34DD14753A42F4328CD5E7A6B
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
B19032CD69D4606E7EEBB7E0BCAA9AD6
fileRef
4313A1E9F9BFAE03053BBCE38418C9AB
isa
PBXBuildFile
B1AC36AEB4A84D49B74BB6F8E0AEF018
children
784DED0AA95B4F0087AD1FCA0D438BE0
4276EB8AC31314ED23699BF489AAA02A
8EC66117408FE5D27B57F58550E978C0
37F47C35B2ADE059B4D7AF6334776FC9
CF3C78D8B69FFFBF68081511B212DEC9
5E8334E4B9A3934776155BFEA1ADCCC7
isa
PBXGroup
name
Support Files
path
../Target Support Files/SwiftyJSON
sourceTree
<group>
B1F334FD78AE10A3AE1DFACE03F36892
fileRef
CEEC903A8A88FC7DAC58821172A38152
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
B28621795FA91577FCF3525D161A891E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudio.m
path
EZAudio/EZAudio.m
sourceTree
<group>
B28D9E00358A3BFC146406A9E9D84CCF
fileRef
62D919A2C9C2C955FA825CB474A9F16B
isa
PBXBuildFile
B2C2A2977AC39FB8A1FC7FAE64E26072
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
DGElasticPullToRefreshConstants.swift
path
DGElasticPullToRefresh/DGElasticPullToRefreshConstants.swift
sourceTree
<group>
B2F9711D635766F4754D415B41FFC818
fileRef
70525166CB057B3EDE7449F355542038
isa
PBXBuildFile
B388A0A92CD8B2C9CD1F9297453C50BA
includeInIndex
1
isa
PBXFileReference
path
NMSSH.modulemap
sourceTree
<group>
B3C1BBCF776752C05DDE5AAFAF11F696
fileRef
0CCE916C80D42C6943D73D1A829DA787
isa
PBXBuildFile
settings
ATTRIBUTES
Public
B3E49DEC5C3E2B45976F07322793CC64
fileRef
768CC1338D4B027D4517DD3611152862
isa
PBXBuildFile
B3F888A903C9E8B6C17D5FD59576A722
fileRef
7E9DCF48CA71A987E38B65E8EA1BC65E
isa
PBXBuildFile
B4096C390FF4F7F3535818EA64A6377C
buildConfigurations
5BBC00FA891515A4337DFE7D18C0BD00
BBB4FB5074AF70904472427EAB2C66DF
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
B464B42CACD04405291A2DAB52398E9B
fileRef
4458DADC90FBB23CF881C195DC1D4980
isa
PBXBuildFile
B497794704BDE793D7B8264F55B3EC9F
buildConfigurations
F9AA2C518CD3B5220C9D0F81F8289BCF
C4CF426251F31AE4420AFC8273807D28
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
B4CA9869A1F71DB60F8D8B061D814CC5
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
ZLSinusWaveView.framework
path
ZLSinusWaveView.framework
sourceTree
BUILT_PRODUCTS_DIR
B4E6B408AA61BA919AA4B1D77012E3F6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Download.swift
path
Source/Download.swift
sourceTree
<group>
B50658E33EBBEE7C9364A18D8514154E
buildActionMask
2147483647
files
E7EBFB9C050DC8C1E889D6089F119DBF
D1317396D19297E6736AFF6DACCE392F
7CE0E9D851E9395C41EF6AFA7AE47423
362C15B9D5B743CE94949C267A11A11F
9C01EAB768BB47EB46A5760C4E164C3A
3B1F9EB02DD6CBB544A332E7F8A4A716
CF90390BE8B0052175B720A6F7A4DA7C
3E620824BFA4001189C1AA5EEE595C67
72085F8624E47C76F715EBE276B125EB
02E32AEB8ABF1AF925416098365CE932
FA8EFDE6A60AE635795BEF328FE32AED
07F0E71CC75B65CD371F8F56F53D86F0
897752D9150F684990F930BCC8BD5619
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
B5916DB8C1387ACAFA0EBB944E15F3E3
fileRef
7E387B67B1AB63AFDB74AEAA00DD821D
isa
PBXBuildFile
B5971F611DFCB1DBE9E29202C26D4163
fileRef
9BCA03B2F0B3C0EA0D3499F966194E75
isa
PBXBuildFile
B5EEC8A63E90F6F8F85DEF5514D52ED8
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Timeline.swift
path
Source/Timeline.swift
sourceTree
<group>
B70483F68DA580907714FF534F1A20DA
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartLegend.swift
path
Charts/Classes/Components/ChartLegend.swift
sourceTree
<group>
B756C6158B1743F24242A4F20F07ECCA
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ServerTrustPolicy.swift
path
Source/ServerTrustPolicy.swift
sourceTree
<group>
B76F74C8F9438C97CE81DA0817A9D699
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Validation.swift
path
Source/Validation.swift
sourceTree
<group>
B76F8A1C0154EDBE0747BBB72FE5E62B
buildActionMask
2147483647
files
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
B774655DA50556217BC45010C800332E
fileRef
272BAEFC0F1D27DEF0B82A5B2705399E
isa
PBXBuildFile
B7931B4F53CD6EDE5CF224FA1404C794
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleChartData.swift
path
Charts/Classes/Data/Implementations/Standard/CandleChartData.swift
sourceTree
<group>
B7B80995527643776607AFFA75B91E24
children
75D98FF52E597A11900E131B6C4E1ADA
isa
PBXGroup
name
Targets Support Files
sourceTree
<group>
B801611949F9A65BDAD1BA9E75AC4B43
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
aesopt.h
path
SSZipArchive/aes/aesopt.h
sourceTree
<group>
B8024D22C71DD62C706C2DA89005F3EE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudioFile.m
path
EZAudio/EZAudioFile.m
sourceTree
<group>
B80A7F9A2E84C0DE81E907E12076A4A1
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift
sourceTree
<group>
B85E049096D02564EBABAB2D5BF6B6BE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineChartView.swift
path
Charts/Classes/Charts/LineChartView.swift
sourceTree
<group>
B88349DF809DD951EF76B2B561C15983
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
PieChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/PieChartDataSet.swift
sourceTree
<group>
B8BBF24C6E5985DBBE1D91820E19E613
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
B8CDE1803E298A956357E75C96E49EE7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpRequest.swift
path
Sources/HttpRequest.swift
sourceTree
<group>
B8E903F30171A1D853877248B25C11D5
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
43FD5AF8E2E268BB58C2BEE180302F51
remoteInfo
AlamofireRSSParser
B8FCA3C53C645E5E3C2497744767DA06
fileRef
26CA2DF100EC60422EB34B611F67ACD6
isa
PBXBuildFile
B90A6C426043472FEECCAD567C74CD38
baseConfigurationReference
977577C045EDA9D9D1F46E2598D19FC7
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
INFOPLIST_FILE
Target Support Files/Pods/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MACH_O_TYPE
staticlib
MODULEMAP_FILE
Target Support Files/Pods/Pods.modulemap
MTL_ENABLE_DEBUG_INFO
YES
OTHER_LDFLAGS
OTHER_LIBTOOLFLAGS
PODS_ROOT
$(SRCROOT)
PRODUCT_NAME
Pods
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
B90D9DCA72327E7BB3D9A76CD30DF985
buildActionMask
2147483647
files
C9A6539E4BB6E9D4FBA65ABF94AC03BB
8BCFC48792C0183444EC97C43A6E3BB4
33CB5E4C130C28C458CD4F7AA1DF99E6
0C2C052032470959CD56614BF9453DC8
F4D16626DE6568E42E73DDF1FED85EE6
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
B972BD02DECCFEB0CD404ED449764022
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarLineScatterCandleBubbleChartDataProvider.swift
path
Charts/Classes/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift
sourceTree
<group>
B9764BA1C1B4139220BE15EBBCD6CECE
fileRef
543700860208A4CDC32C58B8636E5827
isa
PBXBuildFile
B990718DD6D67073DBCDCF8E6ABED5A5
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HttpResponse.swift
path
Sources/HttpResponse.swift
sourceTree
<group>
BA48D6CA288389ECA1569120A6333992
fileRef
5E8334E4B9A3934776155BFEA1ADCCC7
isa
PBXBuildFile
settings
ATTRIBUTES
Public
BA6428E9F66FD5A23C0A2E06ED26CD2F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text
name
Podfile
path
../Podfile
sourceTree
SOURCE_ROOT
xcLanguageSpecificationIdentifier
xcode.lang.ruby
BA7AA59D2E9F556A528840EA05378089
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CandleStickChartRenderer.swift
path
Charts/Classes/Renderers/CandleStickChartRenderer.swift
sourceTree
<group>
BB2FFAA7E97AA17F0DB5FA6C24617400
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
CYRTextView.h
path
CYRTextView/CYRTextView.h
sourceTree
<group>
BB3A8D7FC41ED300CAA4DF3D0527DEAE
fileRef
1B8D79A74968EFE68A03C339F93BE40A
isa
PBXBuildFile
BB8BF3A20530EBB622CA33D5AEFB739D
includeInIndex
1
isa
PBXFileReference
name
sha1.c
path
SSZipArchive/aes/sha1.c
sourceTree
<group>
BBB4FB5074AF70904472427EAB2C66DF
baseConfigurationReference
95C3D67F3A2378FDCAD498AF576A36D7
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Gifu/Gifu-prefix.pch
INFOPLIST_FILE
Target Support Files/Gifu/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Gifu/Gifu.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
Gifu
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
BC112F174DA60C5E98C5F62DC222A8CF
fileRef
06FD8F213BF2DF4860A3890A3F6C9943
isa
PBXBuildFile
BCD5071CB4E5FAEE7FC51746F4B17B62
fileRef
033590E1C2397DA8E570B55810775B8E
isa
PBXBuildFile
BCD583736D388CAD44C261B79972B86B
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Charts-umbrella.h
sourceTree
<group>
BD11BD25E12B54CC641E519B27C11B66
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZOutput.h
path
EZAudio/EZOutput.h
sourceTree
<group>
BD8D5708635D65BB93AC3037C5DCA03E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AnimatedViewPortJob.swift
path
Charts/Classes/Jobs/AnimatedViewPortJob.swift
sourceTree
<group>
BD97C1D6886F4A540BA21C18DE70A47A
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
BDFFD562F6F4A7DA2EB850BC744C7541
buildConfigurations
04A4F1E8E6A3624871B2EE0C687248B2
8C29735442BC85B0F88470642089405D
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
BE0A3BFD226BAF44617BFBB3DB345624
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
HorizontalBarChartHighlighter.swift
path
Charts/Classes/Highlight/HorizontalBarChartHighlighter.swift
sourceTree
<group>
BE3F1A095E8DF60F568AC3C16C9CD9CC
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BarLineScatterCandleBubbleChartData.swift
path
Charts/Classes/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift
sourceTree
<group>
BE41196F6A3903E59C3306FE3F8B43FE
fileRef
9AB9C30C29CCEEC9315ABE415511676B
isa
PBXBuildFile
BE6178583E3411E5621C8AB2CB79014F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IBubbleChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IBubbleChartDataSet.swift
sourceTree
<group>
BEF74F5A1537A0F36703A7B86CC67092
buildActionMask
2147483647
files
8FC086E0146293F873A3FA450C0C3731
4EBF65047A668987D122EE46E359FF4D
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
BF20B8C23E028DAAB8B003D153FABE87
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RadarChartDataSet.swift
path
Charts/Classes/Data/Implementations/Standard/RadarChartDataSet.swift
sourceTree
<group>
BF25A6BDAC99AE9978881DAEEC73426C
fileRef
CE9719F08048A9825AEAE45D13A0F9DF
isa
PBXBuildFile
settings
COMPILER_FLAGS
-DOS_OBJECT_USE_OBJC=0
BF69C7BFB84A04FFD493D9B9FA9BDD58
fileRef
BE6178583E3411E5621C8AB2CB79014F
isa
PBXBuildFile
BFBFE3DE50EEDD42B2CC58CF2F499BCE
buildConfigurations
1946E9116D8062A9DA249B5276ECE602
69693BA8A71B1AB49790F1AEA9F54D84
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
BFE4C92C7B56F5BE2EDB6693B5B01F06
includeInIndex
1
isa
PBXFileReference
name
aestab.c
path
SSZipArchive/aes/aestab.c
sourceTree
<group>
BFEF228FE25034EB7CF784D634E0B10E
fileRef
A020A04A30303EBCC97F078481030B44
isa
PBXBuildFile
settings
ATTRIBUTES
Public
C0964599C373EAF8F5D4F77150B2E585
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Charts.xcconfig
sourceTree
<group>
C0DB70AB368765DC64BFB5FEA75E0696
fileRef
05D9707C1A350638ECD52006A481F077
isa
PBXBuildFile
C0FF762D04F76D834E1291819067E12A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
CombinedChartView.swift
path
Charts/Classes/Charts/CombinedChartView.swift
sourceTree
<group>
C109982F8C877B91A290E88A1EBC1E1D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AnimatableImageView.swift
path
Source/AnimatableImageView.swift
sourceTree
<group>
C12599A3FB6E4A5ACCBAB8DF11AE7381
fileRef
398AF30D80C1481DE30A977A180903ED
isa
PBXBuildFile
C17EA91E38478C5DF425AFCDBDFBB3A1
fileRef
69B023D17AE27F4AFA2514F22965C5D0
isa
PBXBuildFile
settings
ATTRIBUTES
Public
C29238134AE5C4B8C2352C6C11C495EB
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
ZLMusicFlowWaveView.xcconfig
sourceTree
<group>
C2A17F16FEDD054EA6CCD34CC92A7594
fileRef
D21CB11D4389FD174002BD2E4714DF56
isa
PBXBuildFile
C2F12F2C42BADD59AA7540A3C8107D51
fileRef
6C61009912177D3D77B80D65EC5B2AA4
isa
PBXBuildFile
C2F4A628275A3E441F742896335D7FF5
includeInIndex
1
isa
PBXFileReference
path
Gifu.modulemap
sourceTree
<group>
C32F09F394641163865197D9A3C0BEF2
fileRef
631FB7E22898D4FDDBEB4FF4CC88BD80
isa
PBXBuildFile
C3746E36F91278C40D0DCBA78D124E88
baseConfigurationReference
23EB4B1F1FB528E10C5030501D4C3454
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Alamofire/Alamofire-prefix.pch
INFOPLIST_FILE
Target Support Files/Alamofire/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Alamofire/Alamofire.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
Alamofire
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
C40C801B9D221B9D29844EB7E276D83B
buildActionMask
2147483647
files
CA0C9E24A1D5EE5E5CEC3A7677E450BA
5D48CB591598D53251BDB48146F61D43
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
C4B3C15B8ACB8B8ECC0466781B5838BD
fileRef
F298F979D3ED9894044C72F2C66925E6
isa
PBXBuildFile
settings
ATTRIBUTES
Public
C4CF426251F31AE4420AFC8273807D28
baseConfigurationReference
86D56E9B7AD7546729AD442A3D02478A
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/NMSSH/NMSSH-prefix.pch
INFOPLIST_FILE
Target Support Files/NMSSH/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/NMSSH/NMSSH.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
NMSSH
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
C5AA30790616DFD31FB6E41D32920A1A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudio.h
path
EZAudio/EZAudio.h
sourceTree
<group>
C5CF886AF69707824E7BE68FCA944D76
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartViewPortHandler.swift
path
Charts/Classes/Utils/ChartViewPortHandler.swift
sourceTree
<group>
C617DC78B1A377E48CF0C244D1511F26
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
CYRTextView-dummy.m
sourceTree
<group>
C6828C2508515BC0428D6BDAA1292DC9
buildConfigurationList
E03408AFB82FEE195F7C04419FF416EA
buildPhases
DB4D428C23AD783427D44B1957F195F2
8F77C82F0C8760528390313D44756D9B
85F1FA1A04887000AE6D42617A155669
buildRules
dependencies
isa
PBXNativeTarget
name
Charts
productName
Charts
productReference
2E70CA0E5B5063FA1695EC714491B22A
productType
com.apple.product-type.framework
C68300FA475B7BF7E3419859C05D8AA8
fileRef
0BE89C1211FB9D34E28695028E028BC5
isa
PBXBuildFile
C69E27AE1864F2E73BFE3829B41BFE3F
isa
PBXTargetDependency
name
AlamofireRSSParser-AlamofireRSS
target
6DCD8E0D46E3E688EABD466D9ECB53BE
targetProxy
33B9BFC9E784B2CD678E24E68652504C
C6C515B057B0700ADA865B63CA1A0C6B
fileRef
3103D8A7D64FE15C94380056D5AB453E
isa
PBXBuildFile
C6CB3768F4481A3D58397BABD408885A
fileRef
BF20B8C23E028DAAB8B003D153FABE87
isa
PBXBuildFile
C6DC7B869C1C73B1B12FFF994EEFAAA3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RadarChartView.swift
path
Charts/Classes/Charts/RadarChartView.swift
sourceTree
<group>
C6F18733027EAC1685B8E3E304C5357A
fileRef
1AC2B93F71120CA50074113DD62725AC
isa
PBXBuildFile
C6F5785A49C245BD02BBD3DCA2FD6C53
fileRef
69FE1C8A369E61A2B5F16F781CC4C612
isa
PBXBuildFile
C7B6DD7C0456C50289A2C381DFE9FA3F
fileRef
776ECCE5529B00F6D7F372E0F8AB6002
isa
PBXBuildFile
C7B98156605B0AC4C70830469ABB06A4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZMicrophone.h
path
EZAudio/EZMicrophone.h
sourceTree
<group>
C832BE8F84718CAD9B5B7A0F2296F628
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
Common.h
path
SSZipArchive/Common.h
sourceTree
<group>
C85C98983FF1862632F74F4104DB6E68
fileRef
79AF06EC7F78F59EDAC780C88DB961AE
isa
PBXBuildFile
C89A56E617144FEA3136394B712452A5
fileRef
087A04860A4A8EC54E6A1A5AF7F73E23
isa
PBXBuildFile
C8D8C67006FDDEAC7E7CCB7553FFB573
fileRef
0D30D4EC5DBB217F591F99D492225B04
isa
PBXBuildFile
settings
ATTRIBUTES
Project
C989B85CAE2F73F5FFAA2EFB44C56081
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartDataApproximatorFilter.swift
path
Charts/Classes/Filters/ChartDataApproximatorFilter.swift
sourceTree
<group>
C9A6539E4BB6E9D4FBA65ABF94AC03BB
fileRef
34CEA003BE26A7286C83A2E59C4A7A2F
isa
PBXBuildFile
C9B9AD22764D9774AC7E4C72CEE64C60
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartTransformerHorizontalBarChart.swift
path
Charts/Classes/Utils/ChartTransformerHorizontalBarChart.swift
sourceTree
<group>
C9E6D695EAE6C1062DEA079BB751B87F
includeInIndex
1
isa
PBXFileReference
path
ZLMusicFlowWaveView.modulemap
sourceTree
<group>
CA0C9E24A1D5EE5E5CEC3A7677E450BA
fileRef
37F47C35B2ADE059B4D7AF6334776FC9
isa
PBXBuildFile
CB4B3C6333DFEB6D8B46D3F9908CBE2A
baseConfigurationReference
C0964599C373EAF8F5D4F77150B2E585
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Charts/Charts-prefix.pch
INFOPLIST_FILE
Target Support Files/Charts/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Charts/Charts.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
Charts
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
CB8943577E424C7F4E953DE7A18FA12C
isa
PBXTargetDependency
name
DGElasticPullToRefresh
target
115824B7CB2E76E5ACB836A251E79404
targetProxy
1CF9B76B2F64B9518142C0E419278E19
CBC0F7C552B739C909B650A0F42F7F38
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.script.sh
path
Pods-resources.sh
sourceTree
<group>
CBC7A5017D4527A9E94D74915C54ACB8
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Alamofire-prefix.pch
sourceTree
<group>
CBDFB1F7E57AACF12D6C4BC2E29B8283
children
6FB01F35A58B096070AD063AE6B3459A
7F87651AE9B6CA0E7F4A0114F19A7924
9BCA03B2F0B3C0EA0D3499F966194E75
2F9E24C3EB88806401EAEE690D73F1A1
A481946E2B03D2D461A9D9942194D32C
FC9680DA45C4F4007DF7852E9D4CD965
isa
PBXGroup
name
Support Files
path
../Target Support Files/AASquaresLoading
sourceTree
<group>
CC1086A80586AA695872978B4DCA7686
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IScatterChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IScatterChartDataSet.swift
sourceTree
<group>
CD50BB7E7708FCBA8DAAB65D3B0E3A04
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
CDD0E4686262A0C5C4CBF479DA08F122
fileRef
5A7F1D5307EAD796E3AA22EA222AA8FA
isa
PBXBuildFile
settings
ATTRIBUTES
Public
CDD10EA7FDB7BA6CF457E5EC0E4174A3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Manager.swift
path
Source/Manager.swift
sourceTree
<group>
CDE3C54614B1F64A979844A035DA0BA6
buildActionMask
2147483647
files
E3946A371A05F0C0CB253C741C19F897
905C0B7980F791438B4754D9AB323CBE
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
CE787D2E7219B1CE32FB1F9F3BB56BC6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
prng.h
path
SSZipArchive/aes/prng.h
sourceTree
<group>
CE9719F08048A9825AEAE45D13A0F9DF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
SSZipArchive.m
path
SSZipArchive/SSZipArchive.m
sourceTree
<group>
CEBB2FD70283D5A17132F1B8566E0D2E
fileRef
50DD5592D089DE7626D6837A4E9EA1AC
isa
PBXBuildFile
CEE3227590AFA556D61A75618381AFB4
fileRef
3CB03ADC16519670885B618511A8CFED
isa
PBXBuildFile
CEEC903A8A88FC7DAC58821172A38152
includeInIndex
1
isa
PBXFileReference
name
aeskey.c
path
SSZipArchive/aes/aeskey.c
sourceTree
<group>
CF3C78D8B69FFFBF68081511B212DEC9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SwiftyJSON-prefix.pch
sourceTree
<group>
CF82ED8D2AAF0100798F74B82004713B
fileRef
4567150A2B071C2DA321F4CE18FF8364
isa
PBXBuildFile
CF90390BE8B0052175B720A6F7A4DA7C
fileRef
FD04474CE1E00D47F9010D3A6526EA81
isa
PBXBuildFile
CF9D51D988643E797BAE8A9A54D9F2CD
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudioFile.h
path
EZAudio/EZAudioFile.h
sourceTree
<group>
CFA3D4558500E9CC96C07F908B66D6B5
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
CoreText.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CoreText.framework
sourceTree
DEVELOPER_DIR
D0405803033A2A777B8E4DFA0C1800ED
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text
path
Pods-acknowledgements.markdown
sourceTree
<group>
D06A2482F5337777E2FD81594035B829
fileRef
A28C94FC58D7492A6E64E2C97EBAFE0B
isa
PBXBuildFile
D07DAD252FED8A056A4085E49639E5D7
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
Gifu.h
path
Source/Gifu.h
sourceTree
<group>
D09B82E039368828B6E7C5FE88975F8F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
String+SHA1.swift
path
Sources/String+SHA1.swift
sourceTree
<group>
D1317396D19297E6736AFF6DACCE392F
fileRef
1EF3386A084C9BF7F3B05704CD56DBE6
isa
PBXBuildFile
D131D943789EC727F15929276BBBD8BD
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Gifu-umbrella.h
sourceTree
<group>
D170993D4633F76FF548FD13C3B84EC3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineRadarChartRenderer.swift
path
Charts/Classes/Renderers/LineRadarChartRenderer.swift
sourceTree
<group>
D1B2C2D29810BC661B81102DBD76A35D
buildConfigurations
6F96FF4172FE4DDDA8BB660DD50ABA6A
702840BAC90AC4754E17FD68C4B8DEAC
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
D1F1695E20DD0A70DA19C6226F3E6BEF
fileRef
7E299BF9A615998682A1A05F5F0E42EE
isa
PBXBuildFile
D20A7E639C045BD6532B3CA94A1DBBE2
fileRef
48F9BF534FE68A179559BAE0103EED67
isa
PBXBuildFile
D21CB11D4389FD174002BD2E4714DF56
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartAxisRendererBase.swift
path
Charts/Classes/Renderers/ChartAxisRendererBase.swift
sourceTree
<group>
D22E0FDFD7709E9736B0A7D27CFA1FFC
fileRef
49459EAB6B6631BA931AAD932786D029
isa
PBXBuildFile
D24B9254E2DE0C6C7A2339323E1BF0A4
buildConfigurations
DFEB11ACE1629F94671A20E833C4DC7E
7D70BAF35B5E41ECAA00CC8B49CAF3FB
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
D2C4ADCAC2A7308D24784C168825A6CC
fileRef
136FA39293487CFA2EA9129427511420
isa
PBXBuildFile
D337D7308207F3411F5DD32CB88A5F1B
fileRef
2BCC458FDD5F692BBB2BFC64BB5701FC
isa
PBXBuildFile
settings
ATTRIBUTES
Public
D3602C188ACB17FC40AC72FB96C5EB35
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartViewBase.swift
path
Charts/Classes/Charts/ChartViewBase.swift
sourceTree
<group>
D383B7AF516798B5F9C43DB0E5E55AA6
fileRef
F7B3565EFC793DB0CE40900A2C1F3244
isa
PBXBuildFile
D40D65B89CE20F485FF2173D31AF3853
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartComponentBase.swift
path
Charts/Classes/Components/ChartComponentBase.swift
sourceTree
<group>
D41D8CD98F00B204E9800998ECF8427E
attributes
LastSwiftUpdateCheck
0700
LastUpgradeCheck
0700
buildConfigurationList
2D8E8EC45A3A1A1D94AE762CB5028504
compatibilityVersion
Xcode 3.2
developmentRegion
English
hasScannedForEncodings
0
isa
PBXProject
knownRegions
en
mainGroup
7DB346D0F39D3F0E887471402A8071AB
productRefGroup
92151B6A7B2524A1BABEEE69E0CA7861
projectDirPath
projectReferences
projectRoot
targets
0E579C8B6EC88FD31F0C2B47C9058B48
79C040AFDDCE1BCBF6D8B5EB0B85887F
43FD5AF8E2E268BB58C2BEE180302F51
6DCD8E0D46E3E688EABD466D9ECB53BE
C6828C2508515BC0428D6BDAA1292DC9
339174A0A2DC9E27C74F079867D82284
115824B7CB2E76E5ACB836A251E79404
254EA72DFADAB5F3286B8726A554C9E6
AEA56EBE1B518C71721209FB26701898
3881764D412915AEE2FDC3677F741D9A
137FDB371251B06FCC2593DBA88272D2
F60C777A2655795B8C4DD4476D3522F5
F49E17CE595BF7A7A46139779E891F78
9C29B71FB70AAEC2242DDF5BD50C55A3
FB6A25C88BCCDB159C1C71A2C484100D
F8C233736FECBA33C0E71D949DF017CA
ADD0B8D536C47FE797C15119D29AFC71
D5AB4F80FDD82F7FD614CB3F000E615B
fileRef
4ADAD0E91F5DCCDC1EEF2C11C99034AC
isa
PBXBuildFile
settings
ATTRIBUTES
Public
D5E75CD283EA586FB4A33BD1E70116F8
baseConfigurationReference
C0964599C373EAF8F5D4F77150B2E585
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Charts/Charts-prefix.pch
INFOPLIST_FILE
Target Support Files/Charts/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Charts/Charts.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
Charts
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
D5EB8839E96EE9D01C2BF4D48D8EDF36
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ImageSourceHelpers.swift
path
Source/ImageSourceHelpers.swift
sourceTree
<group>
D5EC2A1F955556DA0724C612A78C674B
fileRef
8621EC900E9540E855F2A45193465CE6
isa
PBXBuildFile
D5F44E638D27C282B496D1999C8B754A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
AlamofireRSSParser.h
path
Pod/Classes/AlamofireRSSParser.h
sourceTree
<group>
D7292846D89C548856055AEC24A11827
fileRef
1F8B22539695E07FA9762AFF2D92CB5A
isa
PBXBuildFile
D73CA5EABA732B046927C93C476FC634
fileRef
534D8D488609E2DA3DBE7CA778E2D5DC
isa
PBXBuildFile
D7AC85CBA5CACB37DD2CDA0B13E3DC0D
fileRef
6A2D73BF1B684C56E7FEF0F452537CCF
isa
PBXBuildFile
D7C1E15DAA48F123231A498172D38967
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHHostConfig.h
path
NMSSH/NMSSHHostConfig.h
sourceTree
<group>
D7D019D2275A7A64B3188D36B0F5F8F4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartLegendRenderer.swift
path
Charts/Classes/Renderers/ChartLegendRenderer.swift
sourceTree
<group>
D879768BF616B126D71B6BA5F638D96A
fileRef
667AE18ABE1BD4A574755ED111198F89
isa
PBXBuildFile
D8A45F2D53B5C2246CB9D246A16F678F
fileRef
F3E8A533B0FA4678233C985618BEEEA6
isa
PBXBuildFile
settings
ATTRIBUTES
Project
D903133FE593BA39A527BFD1887D43BE
isa
PBXTargetDependency
name
Charts
target
C6828C2508515BC0428D6BDAA1292DC9
targetProxy
65C7C81B8FCE42F70895210309838E7D
DA312349A49333542E6F4B36B329960E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
Pods.release.xcconfig
sourceTree
<group>
DA3AA58FE349027A794BEA3358EED800
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
IPieChartDataSet.swift
path
Charts/Classes/Data/Interfaces/IPieChartDataSet.swift
sourceTree
<group>
DA3C0B91AFC44531B8A01A3F0562457C
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
ZipArchive.h
path
SSZipArchive/ZipArchive.h
sourceTree
<group>
DA8F020D6AA506F0106F80186BDA93E4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZRecorder.h
path
EZAudio/EZRecorder.h
sourceTree
<group>
DB4D428C23AD783427D44B1957F195F2
buildActionMask
2147483647
files
DD580D63E4D76F53372817544FDB8882
4EC9879E9DEB9D169929ADA6EEFB18FD
FC8A29D1F192FF1FDA3BB7D0935A1B3F
4EEF9EF82DBD9FA2F25E1ABDE291AC02
1FFA88C4B3A1DAF8DA3FBD1FB22358B5
3EF3C6E2D5466E70A62B0CE90DA2604C
D20A7E639C045BD6532B3CA94A1DBBE2
465CB044A4902D7BAA80597E096B0E67
B19032CD69D4606E7EEBB7E0BCAA9AD6
9FD26D6C00634178B74170103B48A9CF
352EF1AF94125D67FEAA040F32449B24
02C1BEA6FE84433F6C6A713533B7B9BD
4ABE19F043A4FECE8C2A3F1F72AB3F7F
620860DD966F93A5BB284ECA65E3FF68
B774655DA50556217BC45010C800332E
9838C7578BE14F947489DA4D1C595898
D383B7AF516798B5F9C43DB0E5E55AA6
B3E49DEC5C3E2B45976F07322793CC64
9DD2A8006D79DC4469F9BD2FFB55F071
6F27F0A0E87FC39880EE7BC442E7525C
A808AE4EBFE37F90FE49C2715FB330F2
FC34E76E2F5CB664B627A6F1192888FA
70073C35619976BCC6D659E523A9375E
2E6846DB220C35EF387C119161A37580
86F265DD248E17D2B6A3C5E4AA8B6800
2E176E84663592A2EB1DF3E23B6D3225
9BBB90314EEDCAA33FB3160A02862010
99DC0137E12C0E6A0CF0626CB80CB1D5
54E862294530B7914A37F408C0DFF74C
C2A17F16FEDD054EA6CCD34CC92A7594
C12599A3FB6E4A5ACCBAB8DF11AE7381
15AD01DB1A64F162CCBC2E4D02B1458A
268957DD1BCCEB3ABCE0BA4DED45EA01
38E5AE8278D6C47639BB70049876C110
003EBB47E856DBB92F4A63FC2AD8C892
7C204B9F7D811C860F446BAB1575C344
1268FBA2F4CEE4DC3577E8DD52D25975
ABEF8242948249F9A5BF7C36F57CD8DB
17E8ECFF7879DDE903F47869DEBAA874
124D0BAABE6160B5E0B6ADC527C58418
2B44A572F8A1ACA0F3964493F4D3228D
A525E68A31198AD8B3B5CAC519F1A43E
421EC967AD86F44E9BDB88301D94B33B
224F8C8DCD27EA9658A028C095C4F275
C32F09F394641163865197D9A3C0BEF2
3C50B55F32F9344B641ACF672F0220A4
A00CBCB935830FEE99F6E645C95E834D
778126769FD6E223F9574C2E19DD5453
797C9F2528F449390500C4FECCBAA135
65FB4C3B9C6D3DF8ED9A60732536021D
3B2ED386492166C28D7631B4488EA230
24A9C720DFCC621D045671BF48493E8A
4846448B6998275139FBF24E87C11D42
1ED95865A0F35E6479942C08DC17E359
371FCB701E2FA5156BA218C0C95A1C5E
783C44EF16D4C79ADC985C8C86C458D5
50AE3A2D24BA4DE093FC4BD2657AC1FB
9505960D18F60DAA70871C006CA302EF
317A3E7B043018C7BD7F857B76FE1462
30092F63FB79CD827CB85D797464FB40
E1BAD342EFFB5E062959C14B5E07DC68
D1F1695E20DD0A70DA19C6226F3E6BEF
3EED0E841D10FEAA033A3C645CB219D3
1711226039A0CD668F7DBEEE45D9E238
38482CD39B3757452D67AE22C1DA5F29
DE042C08F7F3A2A3B4546F8EADFCDEC5
A5F486B6DA397786F31EB6A27CBA10F5
1677FAD2A148DA1DDE73736B4848878B
C2F12F2C42BADD59AA7540A3C8107D51
AE1566BD32F907C4B66DEF43A2CEFC05
B5916DB8C1387ACAFA0EBB944E15F3E3
770318C2100C2A9A4D14D224B041B0E5
A20419267FBC2600623140053A2AA8F7
4BD7EE6ED468BE4A70A0739940369D7D
C6F18733027EAC1685B8E3E304C5357A
A48B96C6FBB609A286F182ED83923097
2DFEDFAB407EBB39DF8E289418A7BE63
D73CA5EABA732B046927C93C476FC634
729F9E9B68A861150F91F93D765BD254
BCD5071CB4E5FAEE7FC51746F4B17B62
BF69C7BFB84A04FFD493D9B9FA9BDD58
3519CBA7EE38A591227561F3B974D709
9181C57B0D5E511D518D6ED675AC30A6
E1EC4988F56A7D8818978CF0E11235B6
86712FE294355019927A4B113B072F63
B9764BA1C1B4139220BE15EBBCD6CECE
6C77A1B3D784E94C0A704E5758AF6E14
7B234F4406FD51E392E7B688A295E8FB
FEAAEDF7FAFA3134CA836F1AB6E0FDF5
631BAC0B955DDA472F2092F853D8624D
2EBAA77DF6F106BCE20CADC931D8C84F
1A576993F97A4BD21C20CE9685D55B45
3DB99C22AB1CE344BFE50941C299F2AB
604D5A1EF4ABD6E0ACB3B5C820C9F841
1568D9F321313FECF78F199CE4E7B442
821EB8A5F1FC9B2F4EAB51C67F4DE2C6
1792949332E845FCE9745F455932668C
FF383AB25605A99106208E2F7CBC811E
D5EC2A1F955556DA0724C612A78C674B
C68300FA475B7BF7E3419859C05D8AA8
10DA9C9D58BDE4AEBC101C70A645E315
F9E9A2403A8E8D7D3509ABF2A40A5CD7
CEBB2FD70283D5A17132F1B8566E0D2E
127AB4661AC9A5832C3D5A4077C1A58C
6744F19C73C44705160ECB1E7C7FB733
C6CB3768F4481A3D58397BABD408885A
9E1EEA656E59AB9E30DC8D0385F289B4
3D8DDA0FEB1A3AFF6643F9121E19D044
C6C515B057B0700ADA865B63CA1A0C6B
1AA2BFF6AAA29B3C65D9109C6D89B631
BB3A8D7FC41ED300CAA4DF3D0527DEAE
C89A56E617144FEA3136394B712452A5
C6F5785A49C245BD02BBD3DCA2FD6C53
E90141BF332560ED9C3BA829889E51CD
isa
PBXSourcesBuildPhase
runOnlyForDeploymentPostprocessing
0
DC0D405095C90FB4035A2F0243192579
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
fileenc.h
path
SSZipArchive/aes/fileenc.h
sourceTree
<group>
DC9FDA0AFC976AC147511622F5DB1860
includeInIndex
1
isa
PBXFileReference
name
en.lproj
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/en.lproj
sourceTree
<group>
DCC866ED59787599F6878FA3408C9E43
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
EZAudio.xcconfig
sourceTree
<group>
DCE911485FE993C88C00E6FC8F301448
children
49459EAB6B6631BA931AAD932786D029
E51BBFF2074DA4267B550E1D58ADF58A
26CA2DF100EC60422EB34B611F67ACD6
1D0F56E661286DC8431D8887DD690692
136FA39293487CFA2EA9129427511420
169B552578427611CD64555A461D8A88
B8CDE1803E298A956357E75C96E49EE7
B990718DD6D67073DBCDCF8E6ABED5A5
57723204FBD830B51D546A0059298711
06FD8F213BF2DF4860A3890A3F6C9943
03F0D41F8726403C1B0B5F3D93915906
698765A4EF927BBD85BC37EE2FF01903
4458DADC90FBB23CF881C195DC1D4980
E80999E723F79EDC7D4FD8BF79BCA5F5
D09B82E039368828B6E7C5FE88975F8F
97E1CBD3DF590CB3415D629A4ECBC776
isa
PBXGroup
name
Swifter
path
Swifter
sourceTree
<group>
DCECD6AAC84A0BDBE43081FFF891F3FF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
pwd2key.h
path
SSZipArchive/aes/pwd2key.h
sourceTree
<group>
DD3A008898F33BA6A93E536EF2E82A41
buildActionMask
2147483647
files
D337D7308207F3411F5DD32CB88A5F1B
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
DD580D63E4D76F53372817544FDB8882
fileRef
2DDDE6A2D911CE26FD721A694DA7D986
isa
PBXBuildFile
DD7AF476E0F820613312BA057B209D07
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
3881764D412915AEE2FDC3677F741D9A
remoteInfo
NMSSH
DD7D8BD19010A140BBD01B5E92541182
fileRef
BB2FFAA7E97AA17F0DB5FA6C24617400
isa
PBXBuildFile
settings
ATTRIBUTES
Public
DE042C08F7F3A2A3B4546F8EADFCDEC5
fileRef
19318C4AE0C9FF87FDC7C34424E9305F
isa
PBXBuildFile
DFCF6A958A237C3D561F2830085A3000
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
hmac.h
path
SSZipArchive/aes/hmac.h
sourceTree
<group>
DFEB11ACE1629F94671A20E833C4DC7E
baseConfigurationReference
36D90A99286A433572F91AB604418967
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/AlamofireRSSParser/AlamofireRSSParser-prefix.pch
INFOPLIST_FILE
Target Support Files/AlamofireRSSParser/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/AlamofireRSSParser/AlamofireRSSParser.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
AlamofireRSSParser
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
E03408AFB82FEE195F7C04419FF416EA
buildConfigurations
D5E75CD283EA586FB4A33BD1E70116F8
CB4B3C6333DFEB6D8B46D3F9908CBE2A
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
E0CAE9A4EC3948A0E48F0096EAF93132
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
SJCSimplePDFView-prefix.pch
sourceTree
<group>
E14C8107646EC3F8588ED97956DCC65A
children
5F74650537FAFA0C20CFECF3870638C4
5BAE1115B0F38B2B700C84FCE61FDD87
8D901D00C6FF59773C631FE0557B8845
isa
PBXGroup
name
Frameworks
sourceTree
<group>
E1802D1110A2554B9624857DFBA4126A
children
395E75AD0A89CABE845F7299D0509640
4CDBCAF32D84C52F6A5CD9D53D1C8686
isa
PBXGroup
name
Charts
path
Charts
sourceTree
<group>
E1BAD342EFFB5E062959C14B5E07DC68
fileRef
1A7CD22F5ED03019E906E471DD59388F
isa
PBXBuildFile
E1EC4988F56A7D8818978CF0E11235B6
fileRef
E6CC8802D5BE9DF62F444322062597D0
isa
PBXBuildFile
E2F0E619F4A90A088378D7A28F583D02
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartRenderer.swift
path
Charts/Classes/Renderers/BubbleChartRenderer.swift
sourceTree
<group>
E2FAD92811C5785C55D927D4BBF05C68
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
NMSSH-dummy.m
sourceTree
<group>
E349CFCDAD29F7182C472495FBBFCF0F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSH.h
path
NMSSH-iOS/NMSSH.h
sourceTree
<group>
E3946A371A05F0C0CB253C741C19F897
fileRef
F209FD4822C5866ECCA569B37842FBBA
isa
PBXBuildFile
E3E49AEE7447C2756D79CBF55AEBDF02
fileRef
0FDD62CA863BD5DBE7F5C375C207C7EF
isa
PBXBuildFile
settings
ATTRIBUTES
Public
E4097C8AD80F7FA95C14816874CD3B28
baseConfigurationReference
034548B827C03622818B97E6F50C78EC
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Swifter/Swifter-prefix.pch
INFOPLIST_FILE
Target Support Files/Swifter/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Swifter/Swifter.modulemap
MTL_ENABLE_DEBUG_INFO
NO
PRODUCT_NAME
Swifter
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Release
E42B1F498AF0874C6DE8124BB795F15E
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
AnimatedZoomViewJob.swift
path
Charts/Classes/Jobs/AnimatedZoomViewJob.swift
sourceTree
<group>
E5055FEB2A2A322A90311B7874DC9092
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
DGElasticPullToRefresh.xcconfig
sourceTree
<group>
E51BBFF2074DA4267B550E1D58ADF58A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
File.swift
path
Sources/File.swift
sourceTree
<group>
E56D64DF36156ED67576CCA614D0618F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartAnimator.swift
path
Charts/Classes/Animation/ChartAnimator.swift
sourceTree
<group>
E56EA2D2498EDB9C4058F8E9A8989FAE
fileRef
17E57B8F489EA569011B8678EC392493
isa
PBXBuildFile
settings
ATTRIBUTES
Public
E618C6E4AE74F180898BC4052A0BA056
fileRef
31A8AB41E1FF5C54D0970DF38969E324
isa
PBXBuildFile
settings
ATTRIBUTES
Project
E6780F645E1E0B045D81802B23CA1195
buildActionMask
2147483647
files
CD50BB7E7708FCBA8DAAB65D3B0E3A04
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
E6CC8802D5BE9DF62F444322062597D0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ILineChartDataSet.swift
path
Charts/Classes/Data/Interfaces/ILineChartDataSet.swift
sourceTree
<group>
E714E7EE552ED72453DB7F1AB1FE9DC9
isa
PBXTargetDependency
name
SJCSimplePDFView
target
F60C777A2655795B8C4DD4476D3522F5
targetProxy
2B478D3A308B7A2B85319239F72DE289
E74514FEF953E9C25CBFE0645FADFC41
fileRef
F5C563FFB56C2F264F8F6B3EF31B074F
isa
PBXBuildFile
E75768524ABD0E737765714AE4677C48
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
path
Swifter-prefix.pch
sourceTree
<group>
E772910ED9BD048407A4D78E5020A45F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
CYRTextStorage.h
path
CYRTextView/CYRTextStorage.h
sourceTree
<group>
E7BD9D0FF2125D7C3A92D70C380B3261
fileRef
6DA6701753BDEEF59EA50F2CB8CDC7EC
isa
PBXBuildFile
E7DB65F9F86D73C2E1F34D7832CD69DF
buildConfigurations
71EB9AFCBF7ABE58DCC9C10DEB02906A
51F55670AE3232AEAA1C0CE9575ACACC
defaultConfigurationIsVisible
0
defaultConfigurationName
Release
isa
XCConfigurationList
E7EBFB9C050DC8C1E889D6089F119DBF
fileRef
46EC9DD508AF1269E9D7DAB50594AB66
isa
PBXBuildFile
E7F21354943D9F42A70697D5A5EF72E9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.script.sh
path
Pods-frameworks.sh
sourceTree
<group>
E80999E723F79EDC7D4FD8BF79BCA5F5
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
String+Misc.swift
path
Sources/String+Misc.swift
sourceTree
<group>
E8429EE77E177E3DDF7BDF57797AB2EC
fileRef
71E013AE8742AF9DE782F24E90B5E1DB
isa
PBXBuildFile
E8446514FBAD26C0E18F24A5715AEF67
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
E8E725C145C99E05F90D6F5141B56754
fileRef
C109982F8C877B91A290E88A1EBC1E1D
isa
PBXBuildFile
E8F096851EC41151C5B6B0F804F678F0
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
LineChartDataProvider.swift
path
Charts/Classes/Interfaces/LineChartDataProvider.swift
sourceTree
<group>
E90141BF332560ED9C3BA829889E51CD
fileRef
FD194E12D7F3D8DAA667A3A52EB221CA
isa
PBXBuildFile
EA55530B8CFA1390B85AD2EAE503944D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.xcconfig
path
SSZipArchive.xcconfig
sourceTree
<group>
EA714E8F4EBC70B2C11E2BCA2854D037
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartMarker.swift
path
Charts/Classes/Components/ChartMarker.swift
sourceTree
<group>
EAF5382389A29BF0B9ECFE46E3F5AC4D
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
name
Emoji.plist
path
Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/Emoji.plist
sourceTree
<group>
EB00AA6939C22D418E0231F5C736BC44
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
ZLSinusWaveView.m
path
ZLSinusWaveView/ZLSinusWaveView.m
sourceTree
<group>
EB42675237B2858B723331F045DB2FB4
fileRef
AE6C6B2C0EB874E9337C85BFF8DC4358
isa
PBXBuildFile
settings
ATTRIBUTES
Public
EC840730B431C4C5CCBC36514D28D17A
fileRef
AE9410D9B1C05916CA1D2817FB0F45F1
isa
PBXBuildFile
ECA049105DF827404AAEC0CD3E189C64
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSH+Protected.h
path
NMSSH/Config/NMSSH+Protected.h
sourceTree
<group>
ECB77A2F7E083C88A4C9EAEF40CB8D17
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudioPlayer.h
path
EZAudio/EZAudioPlayer.h
sourceTree
<group>
ECDF2C04EED904A4AFC64DED8EA45544
fileRef
94FA3A77E6FC614EA18C169BA609056E
isa
PBXBuildFile
ED3BCC1E1780692338F70AA5634917DF
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartAxisBase.swift
path
Charts/Classes/Components/ChartAxisBase.swift
sourceTree
<group>
ED50758E863F122346C9C2E1873E53DE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
sha1.h
path
SSZipArchive/aes/sha1.h
sourceTree
<group>
ED564D8B303131454DDC6593B8982939
fileRef
A89C4B4FA34F489CCA9D61165EA98AF9
isa
PBXBuildFile
EF2C26926BC90B457BF77F1F5C3864A5
children
46D3F6AF317B0CA613B0F2C91085FBED
CBDFB1F7E57AACF12D6C4BC2E29B8283
isa
PBXGroup
name
AASquaresLoading
path
AASquaresLoading
sourceTree
<group>
EFAF93ECA6E252EF29AB51A210E6D8E4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHLogger.h
path
NMSSH/Config/NMSSHLogger.h
sourceTree
<group>
EFC93C11F16B90228BA386D77AA69400
baseConfigurationReference
B02BF2860C124E9C66C26D2E4913EC5B
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/ZLSinusWaveView/ZLSinusWaveView-prefix.pch
INFOPLIST_FILE
Target Support Files/ZLSinusWaveView/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/ZLSinusWaveView/ZLSinusWaveView.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
ZLSinusWaveView
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
EFDF3B631BBB965A372347705CA14854
buildActionMask
2147483647
files
9469DF81ECB494E84675969B5E13374C
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
EFE92E8D3813DD26E78E93EEAF6D7E7E
fileRef
A792226DBE4257340C826C75A0DC208F
isa
PBXBuildFile
F0230F9740EC7A507AC92A65994E63C9
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
NMSFTP.m
path
NMSSH/NMSFTP.m
sourceTree
<group>
F0C215D509673D9BE13B73AC1B1CCB15
fileRef
F6A855C0E5EE0EC482325EB94815F74A
isa
PBXBuildFile
settings
ATTRIBUTES
Public
F1022A0213E11D4057BBBF840A3B335C
children
6626187A5C620C82B45EA50B60E531EC
7E3FD9DA3AAA3363CA2108CF49E0D9BE
EA55530B8CFA1390B85AD2EAE503944D
9D98F0DEB1F6A637347AA210314D3648
5334BFFDC74B5BC33AB2F29E413CD99A
5A7F1D5307EAD796E3AA22EA222AA8FA
isa
PBXGroup
name
Support Files
path
../Target Support Files/SSZipArchive
sourceTree
<group>
F14AEB3CA1EC057579980D73111BA153
fileRef
216C34E27969A0794EC8C460C31FA2CE
isa
PBXBuildFile
settings
ATTRIBUTES
Project
F16A3CAE58D32CAAECC25DDD2BEEA158
fileRef
DA3C0B91AFC44531B8A01A3F0562457C
isa
PBXBuildFile
settings
ATTRIBUTES
Public
F209FD4822C5866ECCA569B37842FBBA
isa
PBXFileReference
lastKnownFileType
wrapper.framework
name
CFNetwork.framework
path
Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CFNetwork.framework
sourceTree
DEVELOPER_DIR
F27960E09751B596BEBF7019989E8BA3
fileRef
CFA3D4558500E9CC96C07F908B66D6B5
isa
PBXBuildFile
F298F979D3ED9894044C72F2C66925E6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
EZAudioPlotGL.h
path
EZAudio/EZAudioPlotGL.h
sourceTree
<group>
F2F301CD8741E18EEB9C1AA349323CFC
fileRef
29FE1468A9F2C8D913EAD260E4E8B852
isa
PBXBuildFile
settings
ATTRIBUTES
Public
F31DF6C5B30A988A0B2DB360615D985B
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
path
ZLSinusWaveView.framework
sourceTree
BUILT_PRODUCTS_DIR
F36B8EEC5A75332E7C25AF70B7FF19EF
fileRef
16707D24276E0D4BA984EAD7829AFC3B
isa
PBXBuildFile
F38A27EE294EDDE1BCEA87D82E418D06
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ScatterChartDataProvider.swift
path
Charts/Classes/Interfaces/ScatterChartDataProvider.swift
sourceTree
<group>
F3E8A533B0FA4678233C985618BEEEA6
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
crypt.h
path
SSZipArchive/minizip/crypt.h
sourceTree
<group>
F49E17CE595BF7A7A46139779E891F78
buildConfigurationList
D1B2C2D29810BC661B81102DBD76A35D
buildPhases
B0EF69E356D3A304384FA0E56A5CD630
0A55876558D0DC9160E5F6D64ADBA9F8
329F9F0BFAE5C4683145EC1BA2C6C00C
buildRules
dependencies
isa
PBXNativeTarget
name
SSZipArchive
productName
SSZipArchive
productReference
8EDF3AE7833D667E4C4D8478FD4B5447
productType
com.apple.product-type.framework
F4D16626DE6568E42E73DDF1FED85EE6
fileRef
72C2EC0D8143C4CE2FF8091B233306BF
isa
PBXBuildFile
F51D8948E1F5D0E0FA3161D641164C0E
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
SwiftyJSON.framework
path
SwiftyJSON.framework
sourceTree
BUILT_PRODUCTS_DIR
F5A144C28EEF910B35FCD66B9ACB13AE
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartTransformer.swift
path
Charts/Classes/Utils/ChartTransformer.swift
sourceTree
<group>
F5C563FFB56C2F264F8F6B3EF31B074F
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
SJCSimplePDFView-dummy.m
sourceTree
<group>
F60BC667495022BB71DE0C146D3C99EA
buildActionMask
2147483647
files
20C5E87C1DF07DEA65CD74B8D07D6D1C
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
F60C777A2655795B8C4DD4476D3522F5
buildConfigurationList
E7DB65F9F86D73C2E1F34D7832CD69DF
buildPhases
8364C5015494EEDBFB7AC551266741BB
AE2091E6977D6C16528F5BCCDF7FCDC9
655EC23C173F625425EFCDC75BE0A4D2
buildRules
dependencies
isa
PBXNativeTarget
name
SJCSimplePDFView
productName
SJCSimplePDFView
productReference
21B7F68E83AB3158AC18BB512498ECE0
productType
com.apple.product-type.framework
F6A855C0E5EE0EC482325EB94815F74A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.h
name
NMSSHSession.h
path
NMSSH/NMSSHSession.h
sourceTree
<group>
F7210A9C5D404BB2ED9A06FE29F3AC73
includeInIndex
1
isa
PBXFileReference
path
EZAudio.modulemap
sourceTree
<group>
F7852FD543BD5C8EEF81095A19EAD332
explicitFileType
wrapper.framework
includeInIndex
0
isa
PBXFileReference
name
DGElasticPullToRefresh.framework
path
DGElasticPullToRefresh.framework
sourceTree
BUILT_PRODUCTS_DIR
F7B3565EFC793DB0CE40900A2C1F3244
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
BubbleChartDataProvider.swift
path
Charts/Classes/Interfaces/BubbleChartDataProvider.swift
sourceTree
<group>
F818CCD384C18AFDD6BDA68C6D1C19A0
baseConfigurationReference
034548B827C03622818B97E6F50C78EC
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/Swifter/Swifter-prefix.pch
INFOPLIST_FILE
Target Support Files/Swifter/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/Swifter/Swifter.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
Swifter
SDKROOT
iphoneos
SKIP_INSTALL
YES
SWIFT_OPTIMIZATION_LEVEL
-Onone
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
F82198F34DD14753A42F4328CD5E7A6B
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
F8803DAD17AC9CE8BCAD6B0594646D64
fileRef
A3415EFF6AEA35162B52EC0734DE1761
isa
PBXBuildFile
F8C233736FECBA33C0E71D949DF017CA
buildConfigurationList
BDFFD562F6F4A7DA2EB850BC744C7541
buildPhases
5016FC849FB311577714D8BF17D07034
17C841636A1F7BAB561CE0585060E01F
32BAF7044096F3B8947FFBDDEBDF5E04
buildRules
dependencies
1976D47319F44DDEB11B1DB5E28BEC84
isa
PBXNativeTarget
name
ZLMusicFlowWaveView
productName
ZLMusicFlowWaveView
productReference
0727A4243F3B7D3216AAC08CA047DA60
productType
com.apple.product-type.framework
F90D7168D47857A3578EC1A796A202DB
fileRef
71C68E3AFFC61709566D8EA695CFB5E7
isa
PBXBuildFile
settings
ATTRIBUTES
Project
F96AE71D5D1E0E91E4AB3E8EB2B2612A
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
9C29B71FB70AAEC2242DDF5BD50C55A3
remoteInfo
Swifter
F9AA2C518CD3B5220C9D0F81F8289BCF
baseConfigurationReference
86D56E9B7AD7546729AD442A3D02478A
buildSettings
CODE_SIGN_IDENTITY[sdk=iphoneos*]
iPhone Developer
CURRENT_PROJECT_VERSION
1
DEFINES_MODULE
YES
DYLIB_COMPATIBILITY_VERSION
1
DYLIB_CURRENT_VERSION
1
DYLIB_INSTALL_NAME_BASE
@rpath
ENABLE_STRICT_OBJC_MSGSEND
YES
GCC_PREFIX_HEADER
Target Support Files/NMSSH/NMSSH-prefix.pch
INFOPLIST_FILE
Target Support Files/NMSSH/Info.plist
INSTALL_PATH
$(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET
8.0
LD_RUNPATH_SEARCH_PATHS
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
MODULEMAP_FILE
Target Support Files/NMSSH/NMSSH.modulemap
MTL_ENABLE_DEBUG_INFO
YES
PRODUCT_NAME
NMSSH
SDKROOT
iphoneos
SKIP_INSTALL
YES
TARGETED_DEVICE_FAMILY
1,2
VERSIONING_SYSTEM
apple-generic
VERSION_INFO_PREFIX
isa
XCBuildConfiguration
name
Debug
F9E9A2403A8E8D7D3509ABF2A40A5CD7
fileRef
39225A7983DD89DC9CD0F0A9DE3F508A
isa
PBXBuildFile
FA3529BA5DD86B6E59A2A2C589EA5884
fileRef
0CFA654DBD993FD0F891ECD3B7432064
isa
PBXBuildFile
FA6606E69ACCD1B09D98F9CC5F9A98C3
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
RSSFeed.swift
path
Pod/Classes/RSSFeed.swift
sourceTree
<group>
FA6B4510586447CB081BC8FA92CE4357
fileRef
894E5DA93A9F359521A89826BE6DA777
isa
PBXBuildFile
FA8EFDE6A60AE635795BEF328FE32AED
fileRef
3F37EE1C6EE59F78A3A5E60EF31FFA3A
isa
PBXBuildFile
FB45FFD90572718D82AB9092B750F0CA
buildSettings
ALWAYS_SEARCH_USER_PATHS
NO
CLANG_CXX_LANGUAGE_STANDARD
gnu++0x
CLANG_CXX_LIBRARY
libc++
CLANG_ENABLE_MODULES
YES
CLANG_ENABLE_OBJC_ARC
YES
CLANG_WARN_BOOL_CONVERSION
YES
CLANG_WARN_CONSTANT_CONVERSION
YES
CLANG_WARN_DIRECT_OBJC_ISA_USAGE
YES
CLANG_WARN_EMPTY_BODY
YES
CLANG_WARN_ENUM_CONVERSION
YES
CLANG_WARN_INT_CONVERSION
YES
CLANG_WARN_OBJC_ROOT_CLASS
YES
CLANG_WARN_UNREACHABLE_CODE
YES
CLANG_WARN__DUPLICATE_METHOD_MATCH
YES
COPY_PHASE_STRIP
YES
ENABLE_NS_ASSERTIONS
NO
GCC_C_LANGUAGE_STANDARD
gnu99
GCC_PREPROCESSOR_DEFINITIONS
RELEASE=1
GCC_WARN_64_TO_32_BIT_CONVERSION
YES
GCC_WARN_ABOUT_RETURN_TYPE
YES
GCC_WARN_UNDECLARED_SELECTOR
YES
GCC_WARN_UNINITIALIZED_AUTOS
YES
GCC_WARN_UNUSED_FUNCTION
YES
GCC_WARN_UNUSED_VARIABLE
YES
IPHONEOS_DEPLOYMENT_TARGET
8.0
STRIP_INSTALLED_PRODUCT
NO
SYMROOT
${SRCROOT}/../build
VALIDATE_PRODUCT
YES
isa
XCBuildConfiguration
name
Release
FB566F69981E2F14222BE796DC7474B5
buildActionMask
2147483647
files
1E99A621975C1DDBF7CD0F92C076D716
isa
PBXHeadersBuildPhase
runOnlyForDeploymentPostprocessing
0
FB6A25C88BCCDB159C1C71A2C484100D
buildConfigurationList
1E5B2E2366403FF3F48D14E0344AB088
buildPhases
C40C801B9D221B9D29844EB7E276D83B
3E678AB82500885E6B28B0A982617ED8
5E3EC164F92FFE16F448E27839FDFF32
buildRules
dependencies
isa
PBXNativeTarget
name
SwiftyJSON
productName
SwiftyJSON
productReference
F51D8948E1F5D0E0FA3161D641164C0E
productType
com.apple.product-type.framework
FB8A97E23B00E9EE80BB504728D87825
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
79C040AFDDCE1BCBF6D8B5EB0B85887F
remoteInfo
Alamofire
FC34E76E2F5CB664B627A6F1192888FA
fileRef
80875D1812BC200BAB068CBC75B74E7A
isa
PBXBuildFile
FC5B42B4BAB1F773C37B0B7916361BB0
buildActionMask
2147483647
files
ED564D8B303131454DDC6593B8982939
5C4566FE7B7461D8601278AE68C50358
isa
PBXFrameworksBuildPhase
runOnlyForDeploymentPostprocessing
0
FC8A29D1F192FF1FDA3BB7D0935A1B3F
fileRef
E42B1F498AF0874C6DE8124BB795F15E
isa
PBXBuildFile
FC9680DA45C4F4007DF7852E9D4CD965
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
text.plist.xml
path
Info.plist
sourceTree
<group>
FC9D79D0CC991302B49BFA48C4BE2AB9
isa
PBXTargetDependency
name
Gifu
target
AEA56EBE1B518C71721209FB26701898
targetProxy
AE2C11E6B5332F82FE14C6CDB59D57FA
FD04474CE1E00D47F9010D3A6526EA81
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
name
EZAudioPlotGL.m
path
EZAudio/EZAudioPlotGL.m
sourceTree
<group>
FD0CC0A859DB9231444E62D7E971B22A
fileRef
40043CBCDD93A301F8437421D53D02A3
isa
PBXBuildFile
FD194E12D7F3D8DAA667A3A52EB221CA
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ZoomChartViewJob.swift
path
Charts/Classes/Jobs/ZoomChartViewJob.swift
sourceTree
<group>
FD6B3B6081C8329BA2B82C48DEAA71C8
fileRef
169B552578427611CD64555A461D8A88
isa
PBXBuildFile
FE28E020C32C8DA2DA56BAB6494D030A
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.c.objc
path
Gifu-dummy.m
sourceTree
<group>
FE7F3C43D504E49A918DA967538283F8
containerPortal
D41D8CD98F00B204E9800998ECF8427E
isa
PBXContainerItemProxy
proxyType
1
remoteGlobalIDString
339174A0A2DC9E27C74F079867D82284
remoteInfo
CYRTextView
FEAAEDF7FAFA3134CA836F1AB6E0FDF5
fileRef
CC1086A80586AA695872978B4DCA7686
isa
PBXBuildFile
FF2C748C341F3E0FA03FC7D890D54304
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
Runes.swift
path
Carthage/Checkouts/Runes/Source/Runes.swift
sourceTree
<group>
FF383AB25605A99106208E2F7CBC811E
fileRef
6CDE7B54911112B22403C6B83659EE77
isa
PBXBuildFile
FFAF70D9A0BFA84F517D08E78C3A8EF4
includeInIndex
1
isa
PBXFileReference
lastKnownFileType
sourcecode.swift
name
ChartFill.swift
path
Charts/Classes/Utils/ChartFill.swift
sourceTree
<group>
FFCB6492484858E07ECCD87017C470A1
children
38A041658F28816244E23069CB89C403
34CEA003BE26A7286C83A2E59C4A7A2F
E772910ED9BD048407A4D78E5020A45F
717A214D47C4467FB7418FB121F803FD
BB2FFAA7E97AA17F0DB5FA6C24617400
4ED7C61B5475997505191F07F768B0E2
62FD1B17D0F7FFDE4730993A41302A52
72C2EC0D8143C4CE2FF8091B233306BF
70A566A1797B301E45BC4F43633CF81A
isa
PBXGroup
name
CYRTextView
path
CYRTextView
sourceTree
<group>
rootObject
D41D8CD98F00B204E9800998ECF8427E
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/Emoji.plist
================================================
😊
😨
😍
😳
😎
😭
😌
😵
😴
😢
😅
😡
😜
😀
😲
😟
😤
😞
😫
😣
😈
😉
😯
😕
😰
😋
😝
😓
😃
😂
😘
😒
😏
😶
😱
😖
😩
😔
😑
😚
😪
😇
🙊
👊
👎
☝
✌
😬
😷
🙈
👌
👏
✊
💪
😆
☺
🙉
👍
🙏
✋
☀
☕
⛄
📚
🎁
🎉
🍦
☁
❄
⚡
💰
🎂
🎓
🍖
☔
⛅
✏
💩
🎄
🍷
🎤
🏀
🀄
💣
📢
🌏
🍫
🎲
🏂
💡
💤
🚫
🌻
🍻
🎵
🏡
💢
📞
🚿
🍚
👪
👼
💊
🔫
🌹
🐶
💄
👫
👽
💋
🌙
🍉
🐷
💔
👻
👿
💍
🌲
🐴
👑
🔥
⭐
⚽
🕖
⏰
😁
🚀
⏳
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongCloud.bundle/unicode_to_hanyu_pinyin.txt
================================================
3007 (ling2)
4E00 (yi1)
4E01 (ding1,zheng1)
4E02 (kao3)
4E03 (qi1)
4E04 (shang4,shang3)
4E05 (xia4)
4E06 (none0)
4E07 (wan4,mo4)
4E08 (zhang4)
4E09 (san1)
4E0A (shang4,shang3)
4E0B (xia4)
4E0C (ji1)
4E0D (bu4,bu2,fou3)
4E0E (yu3,yu4,yu2)
4E0F (mian3)
4E10 (gai4)
4E11 (chou3)
4E12 (chou3)
4E13 (zhuan1)
4E14 (qie3,ju1)
4E15 (pi1)
4E16 (shi4)
4E17 (shi4)
4E18 (qiu1)
4E19 (bing3)
4E1A (ye4)
4E1B (cong2)
4E1C (dong1)
4E1D (si1)
4E1E (cheng2)
4E1F (diu1)
4E20 (qiu1)
4E21 (liang3)
4E22 (diu1)
4E23 (you3)
4E24 (liang3)
4E25 (yan2)
4E26 (bing4)
4E27 (sang1,sang4,sang5)
4E28 (shu4)
4E29 (jiu1)
4E2A (ge4,ge3)
4E2B (ya1)
4E2C (qiang2,pan2)
4E2D (zhong1,zhong4)
4E2E (ji3)
4E2F (jie4)
4E30 (feng1)
4E31 (guan4)
4E32 (chuan4)
4E33 (chan3)
4E34 (lin2)
4E35 (zhuo1)
4E36 (zhu3,dian3)
4E37 (none0)
4E38 (wan2)
4E39 (dan1)
4E3A (wei2,wei4)
4E3B (zhu3)
4E3C (jing3,dan3)
4E3D (li4,li2)
4E3E (ju3)
4E3F (pie3)
4E40 (fu2)
4E41 (yi2)
4E42 (yi4,ai4)
4E43 (nai3)
4E44 (none0)
4E45 (jiu3)
4E46 (jiu3)
4E47 (tuo1)
4E48 (me5,ma5,yao1)
4E49 (yi4)
4E4A (none0)
4E4B (zhi1)
4E4C (wu1,wu4)
4E4D (zha4)
4E4E (hu1)
4E4F (fa2)
4E50 (le4,yue4)
4E51 (zhong4)
4E52 (ping1)
4E53 (pang1)
4E54 (qiao2)
4E55 (hu3,hu4)
4E56 (guai1)
4E57 (cheng2,sheng4)
4E58 (cheng2,sheng4)
4E59 (yi3)
4E5A (yin3)
4E5B (none0)
4E5C (mie1,nie4)
4E5D (jiu3)
4E5E (qi3)
4E5F (ye3)
4E60 (xi2)
4E61 (xiang1)
4E62 (gai4)
4E63 (diu1)
4E64 (none0)
4E65 (none0)
4E66 (shu1)
4E67 (none0)
4E68 (shi3)
4E69 (ji1)
4E6A (nang1)
4E6B (jia1)
4E6C (none0)
4E6D (shi2)
4E6E (none0)
4E6F (none0)
4E70 (mai3)
4E71 (luan4)
4E72 (none0)
4E73 (ru3)
4E74 (xi3)
4E75 (yan3)
4E76 (fu3)
4E77 (sha1)
4E78 (na3)
4E79 (gan1,qian2)
4E7A (none0)
4E7B (none0)
4E7C (none0)
4E7D (none0)
4E7E (qian2,gan1)
4E7F (zhi4)
4E80 (gui1,jun1,qiu1)
4E81 (gan1)
4E82 (luan4)
4E83 (lin3)
4E84 (yi4)
4E85 (jue2)
4E86 (le5,liao3,liao4)
4E87 (none0)
4E88 (yu3,yu2)
4E89 (zheng1)
4E8A (shi4)
4E8B (shi4)
4E8C (er4)
4E8D (chu4)
4E8E (yu2)
4E8F (kui1)
4E90 (yu2)
4E91 (yun2)
4E92 (hu4)
4E93 (qi2)
4E94 (wu3)
4E95 (jing3)
4E96 (si4)
4E97 (sui4)
4E98 (gen4)
4E99 (gen4,geng4)
4E9A (ya4)
4E9B (xie1,xie5)
4E9C (ya4)
4E9D (qi2)
4E9E (ya4,ya3)
4E9F (ji2,qi4)
4EA0 (tou2)
4EA1 (wang2,wu2)
4EA2 (kang4)
4EA3 (ta4)
4EA4 (jiao1)
4EA5 (hai4)
4EA6 (yi4)
4EA7 (chan3)
4EA8 (heng1)
4EA9 (mu3)
4EAA (none0)
4EAB (xiang3)
4EAC (jing1)
4EAD (ting2)
4EAE (liang4)
4EAF (heng1)
4EB0 (jing1)
4EB1 (ye4)
4EB2 (qin1,qin5,qing4)
4EB3 (bo2)
4EB4 (you4)
4EB5 (xie4)
4EB6 (dan3,dan4)
4EB7 (lian2)
4EB8 (duo3)
4EB9 (wei3,wei4)
4EBA (ren2)
4EBB (ren2)
4EBC (ji2)
4EBD (none0)
4EBE (wang2)
4EBF (yi4)
4EC0 (shen2,shi2,she2)
4EC1 (ren2)
4EC2 (le4)
4EC3 (ding1)
4EC4 (ze4)
4EC5 (jin3,jin4)
4EC6 (pu1,pu2)
4EC7 (chou2,qiu2)
4EC8 (ba1)
4EC9 (zhang3)
4ECA (jin1)
4ECB (jie4)
4ECC (bing1)
4ECD (reng2)
4ECE (cong2,cong1)
4ECF (fo2,fu2)
4ED0 (san3)
4ED1 (lun2)
4ED2 (none0)
4ED3 (cang1)
4ED4 (zi3,zai3,zi1)
4ED5 (shi4)
4ED6 (ta1)
4ED7 (zhang4)
4ED8 (fu4)
4ED9 (xian1)
4EDA (xian1)
4EDB (cha4)
4EDC (hong2)
4EDD (tong2)
4EDE (ren4)
4EDF (qian1)
4EE0 (gan3)
4EE1 (ge1,yi4)
4EE2 (di2)
4EE3 (dai4)
4EE4 (ling4,ling2,ling3)
4EE5 (yi3)
4EE6 (chao4)
4EE7 (chang2)
4EE8 (sa1)
4EE9 (shang4)
4EEA (yi2)
4EEB (mu4)
4EEC (men5,men2)
4EED (ren4)
4EEE (jia3,jia4)
4EEF (chao4)
4EF0 (yang3)
4EF1 (qian2)
4EF2 (zhong4)
4EF3 (pi3)
4EF4 (wan4)
4EF5 (wu3)
4EF6 (jian4)
4EF7 (jia4,jie4,jie5)
4EF8 (yao3)
4EF9 (feng1)
4EFA (cang1)
4EFB (ren4,ren2)
4EFC (wang2)
4EFD (fen4)
4EFE (di1)
4EFF (fang3)
4F00 (zhong1)
4F01 (qi3,qi4)
4F02 (pei4)
4F03 (yu2)
4F04 (diao4)
4F05 (dun4)
4F06 (wen4)
4F07 (yi4)
4F08 (xin3)
4F09 (kang4)
4F0A (yi1)
4F0B (ji2)
4F0C (ai4)
4F0D (wu3)
4F0E (ji4)
4F0F (fu2)
4F10 (fa2,fa1)
4F11 (xiu1)
4F12 (jin4)
4F13 (bei1)
4F14 (chen2)
4F15 (fu1)
4F16 (tang3)
4F17 (zhong4)
4F18 (you1)
4F19 (huo3)
4F1A (hui4,kuai4)
4F1B (yu3)
4F1C (cui4,zu2)
4F1D (yun2)
4F1E (san3)
4F1F (wei3)
4F20 (chuan2,zhuan4)
4F21 (che1)
4F22 (ya2)
4F23 (xian4)
4F24 (shang1)
4F25 (chang1,tang3)
4F26 (lun2)
4F27 (cang1,chen5)
4F28 (xun4)
4F29 (xin4)
4F2A (wei3)
4F2B (zhu4)
4F2C (chi3)
4F2D (xuan2)
4F2E (nao2,nu3)
4F2F (bo2,bai3,ba4)
4F30 (gu1,gu4)
4F31 (ni3)
4F32 (ni4)
4F33 (xie4)
4F34 (ban4)
4F35 (xu4)
4F36 (ling2)
4F37 (zhou4)
4F38 (shen1)
4F39 (qu1)
4F3A (si4,ci4)
4F3B (beng1)
4F3C (si4,shi4)
4F3D (jia1,ga1,qie2,qia1)
4F3E (pi1)
4F3F (yi4)
4F40 (si4,shi4)
4F41 (ai3)
4F42 (zheng1,zheng4)
4F43 (dian4,tian2)
4F44 (han2)
4F45 (mai4)
4F46 (dan4)
4F47 (zhu4)
4F48 (bu4)
4F49 (qu1)
4F4A (bi3)
4F4B (shao4)
4F4C (ci3)
4F4D (wei4)
4F4E (di1)
4F4F (zhu4)
4F50 (zuo3)
4F51 (you4)
4F52 (yang1)
4F53 (ti3,ben4,ti1)
4F54 (zhan4)
4F55 (he2,he4)
4F56 (bi4)
4F57 (tuo2)
4F58 (she2)
4F59 (yu2,tu2)
4F5A (yi4,die2)
4F5B (fo2,fu2)
4F5C (zuo4,zuo1,zuo2)
4F5D (gou1)
4F5E (ning4)
4F5F (tong2)
4F60 (ni3)
4F61 (xuan1,san3)
4F62 (ju4)
4F63 (yong1,yong4)
4F64 (wa3)
4F65 (qian1)
4F66 (none0)
4F67 (ka3)
4F68 (none0)
4F69 (pei4)
4F6A (huai2)
4F6B (he4)
4F6C (lao3)
4F6D (xiang2)
4F6E (ge2)
4F6F (yang2)
4F70 (bai3)
4F71 (fa3)
4F72 (ming2)
4F73 (jia1)
4F74 (nai4,er4)
4F75 (bing4)
4F76 (ji2)
4F77 (heng2)
4F78 (huo2)
4F79 (gui3)
4F7A (quan2)
4F7B (tiao1,tiao2)
4F7C (jiao3,jia3)
4F7D (ci4)
4F7E (yi4)
4F7F (shi3,shi4)
4F80 (xing2)
4F81 (shen1)
4F82 (tuo1)
4F83 (kan3)
4F84 (zhi2)
4F85 (gai1,kai1)
4F86 (lai2)
4F87 (yi2)
4F88 (chi3)
4F89 (kua3)
4F8A (guang1)
4F8B (li4)
4F8C (yin1)
4F8D (shi4)
4F8E (mi3)
4F8F (zhu1)
4F90 (xu4)
4F91 (you4)
4F92 (an1)
4F93 (lu4)
4F94 (mou2)
4F95 (er2)
4F96 (lun2)
4F97 (dong4,tong2,tong3)
4F98 (cha4)
4F99 (chi4)
4F9A (xun4)
4F9B (gong1,gong4)
4F9C (zhou1)
4F9D (yi1)
4F9E (ru3)
4F9F (jian4)
4FA0 (xia2)
4FA1 (jia4,jie4)
4FA2 (zai4)
4FA3 (lu:3)
4FA4 (none0)
4FA5 (jiao3,yao2,jia3)
4FA6 (zhen1)
4FA7 (ce4,ze4,zhai1)
4FA8 (qiao2)
4FA9 (kuai4)
4FAA (chai2)
4FAB (ning4)
4FAC (nong2)
4FAD (jin3,jin4)
4FAE (wu3)
4FAF (hou4,hou2)
4FB0 (jiong3)
4FB1 (cheng3)
4FB2 (zhen4)
4FB3 (cuo4)
4FB4 (chou3)
4FB5 (qin1)
4FB6 (lu:3)
4FB7 (ju2)
4FB8 (shu4)
4FB9 (ting3)
4FBA (shen4)
4FBB (tuo1)
4FBC (bo2)
4FBD (nan2)
4FBE (hao1)
4FBF (bian4,pian2)
4FC0 (tui3)
4FC1 (yu3)
4FC2 (xi4)
4FC3 (cu4)
4FC4 (e2,e4)
4FC5 (qiu2)
4FC6 (xu2)
4FC7 (kuang3)
4FC8 (ku4)
4FC9 (wu2)
4FCA (jun4,zun4,juan4)
4FCB (yi4)
4FCC (fu3)
4FCD (lang2)
4FCE (zu3)
4FCF (qiao4)
4FD0 (li4)
4FD1 (yong3)
4FD2 (hun4)
4FD3 (jing4)
4FD4 (xian4)
4FD5 (san4)
4FD6 (pai3)
4FD7 (su2)
4FD8 (fu2)
4FD9 (xi1)
4FDA (li3)
4FDB (mian3)
4FDC (ping1)
4FDD (bao3)
4FDE (yu2,shu4)
4FDF (si4,qi2)
4FE0 (xia2)
4FE1 (xin4,shen1)
4FE2 (xiu1)
4FE3 (yu3)
4FE4 (ti4)
4FE5 (che1)
4FE6 (chou2)
4FE7 (none0)
4FE8 (yan3)
4FE9 (liang3,lia3)
4FEA (li4)
4FEB (lai2)
4FEC (si1)
4FED (jian3)
4FEE (xiu1)
4FEF (fu3)
4FF0 (he2)
4FF1 (ju4,ju1)
4FF2 (xiao4)
4FF3 (pai2)
4FF4 (jian4)
4FF5 (biao4,biao3)
4FF6 (ti4,chu4)
4FF7 (fei4)
4FF8 (feng4)
4FF9 (ya4)
4FFA (an3)
4FFB (bei4)
4FFC (yu4,zhou1)
4FFD (xin1)
4FFE (bi3,bei1,bi4)
4FFF (chi2)
5000 (chang1)
5001 (zhi1)
5002 (bing4)
5003 (zan2)
5004 (yao2)
5005 (cui4)
5006 (lia3,liang3)
5007 (wan3)
5008 (lai2)
5009 (cang1)
500A (zong3)
500B (ge4,ge5)
500C (guan1)
500D (bei4)
500E (tian1)
500F (shu1,shu4)
5010 (shu1)
5011 (men5,men2)
5012 (dao3,dao4)
5013 (tan2)
5014 (jue2,jue4)
5015 (chui2)
5016 (xing4)
5017 (peng2)
5018 (tang3,chang2)
5019 (hou4)
501A (yi3)
501B (qi1)
501C (ti4)
501D (gan4)
501E (jing4,liang4)
501F (jie4)
5020 (xu1)
5021 (chang4,chang1)
5022 (jie2)
5023 (fang3)
5024 (zhi2)
5025 (kong1,kong3)
5026 (juan4)
5027 (zong1)
5028 (ju4)
5029 (qian4)
502A (ni2)
502B (lun2)
502C (zhuo1,zhuo2)
502D (wo1)
502E (luo3)
502F (song1)
5030 (leng2)
5031 (hun4)
5032 (dong1)
5033 (zi4)
5034 (ben4)
5035 (wu3)
5036 (ju4,ju1)
5037 (nai4)
5038 (cai3)
5039 (jian3)
503A (zhai4)
503B (ye1)
503C (zhi2)
503D (sha4)
503E (qing1)
503F (none0)
5040 (ying1)
5041 (cheng1,cheng4)
5042 (qian2)
5043 (yan3)
5044 (nuan4)
5045 (zhong4)
5046 (chun3)
5047 (jia3,jia4)
5048 (jie2,ji4)
5049 (wei3)
504A (yu3)
504B (bing4)
504C (ruo4)
504D (ti2)
504E (wei1)
504F (pian1)
5050 (yan4)
5051 (feng1)
5052 (tang3)
5053 (wo4)
5054 (e4)
5055 (xie2,jie1)
5056 (che3)
5057 (sheng3)
5058 (kan3)
5059 (di4)
505A (zuo4)
505B (cha1)
505C (ting2)
505D (bei1)
505E (ye4)
505F (huang2)
5060 (yao3)
5061 (zhan4)
5062 (qiu1)
5063 (yan1)
5064 (you2)
5065 (jian4)
5066 (xu3)
5067 (zha1)
5068 (chai1)
5069 (fu4)
506A (bi1)
506B (zhi4)
506C (zong3)
506D (mian3)
506E (ji2)
506F (yi3)
5070 (xie4)
5071 (xun2)
5072 (si1,cai1)
5073 (duan1)
5074 (ce4,ze4)
5075 (zhen1)
5076 (ou3)
5077 (tou1)
5078 (tou1)
5079 (bei4)
507A (za2,zan2)
507B (lou2,lu:3)
507C (jie2)
507D (wei4)
507E (fen4)
507F (chang2)
5080 (kui3,gui1)
5081 (sou3)
5082 (chi3)
5083 (su4)
5084 (xia1)
5085 (fu4)
5086 (yuan4)
5087 (rong3)
5088 (li4)
5089 (ru4)
508A (yun3)
508B (gou4)
508C (ma4)
508D (bang4,bang1)
508E (dian1)
508F (tang2)
5090 (hao1)
5091 (jie2)
5092 (xi1)
5093 (shan1)
5094 (qian4)
5095 (jue2)
5096 (cang1)
5097 (chu4)
5098 (san3)
5099 (bei4)
509A (xiao4)
509B (yong2)
509C (yao2)
509D (ta4)
509E (suo1)
509F (wang1)
50A0 (fa2)
50A1 (bing4,bing1)
50A2 (jia1)
50A3 (dai3)
50A4 (zai4)
50A5 (tang3)
50A6 (none0)
50A7 (bin1)
50A8 (chu3)
50A9 (nuo2)
50AA (zan1)
50AB (lei3)
50AC (cui1)
50AD (yong1,yong4,yong2)
50AE (zao1)
50AF (zong3)
50B0 (peng2)
50B1 (song3)
50B2 (ao4)
50B3 (chuan2,zhuan4)
50B4 (yu3)
50B5 (zhai4)
50B6 (zu2)
50B7 (shang1)
50B8 (qiang3)
50B9 (qiang1)
50BA (chi4)
50BB (sha3)
50BC (han4)
50BD (zhang1)
50BE (qing1,qing2)
50BF (yan4)
50C0 (di4)
50C1 (xi1)
50C2 (lou2,lu:3)
50C3 (bei4)
50C4 (piao1)
50C5 (jin3,jin4)
50C6 (lian3)
50C7 (lu4)
50C8 (man4)
50C9 (qian1)
50CA (xian1)
50CB (qiu2)
50CC (ying2)
50CD (dong4)
50CE (zhuan4)
50CF (xiang4)
50D0 (shan3)
50D1 (qiao2)
50D2 (jiong3)
50D3 (tui2)
50D4 (zun3)
50D5 (pu2,pu1)
50D6 (xi1)
50D7 (lao4)
50D8 (chang3)
50D9 (guang1)
50DA (liao2)
50DB (qi1)
50DC (deng4)
50DD (chan2)
50DE (wei3)
50DF (zhang3)
50E0 (fan1)
50E1 (hui4)
50E2 (chuan3)
50E3 (tie3)
50E4 (dan4)
50E5 (jiao3,yao2)
50E6 (jiu4)
50E7 (seng1)
50E8 (fen4)
50E9 (xian4)
50EA (jue2)
50EB (e4)
50EC (jiao1)
50ED (jian4)
50EE (tong2,zhuang4)
50EF (lin2)
50F0 (bo2)
50F1 (gu4)
50F2 (xian1)
50F3 (su4)
50F4 (xian4)
50F5 (jiang1)
50F6 (min3)
50F7 (ye4)
50F8 (jin4)
50F9 (jia4)
50FA (qiao4)
50FB (pi4)
50FC (feng1)
50FD (zhou4)
50FE (ai4)
50FF (sai4)
5100 (yi2)
5101 (jun4,juan4)
5102 (nong2)
5103 (shan4)
5104 (yi4)
5105 (dang1)
5106 (jing3)
5107 (xuan1)
5108 (kuai4)
5109 (jian3)
510A (chu4)
510B (dan1)
510C (jiao3)
510D (sha3)
510E (zai4,zai3)
510F (none0)
5110 (bin4,bin1)
5111 (an4)
5112 (ru2)
5113 (tai2)
5114 (chou2)
5115 (chai2)
5116 (lan2)
5117 (ni3)
5118 (jin3,jin4)
5119 (qian1)
511A (meng2)
511B (wu3)
511C (neng2)
511D (qiong2)
511E (ni3)
511F (chang2)
5120 (lie4)
5121 (lei3)
5122 (lu:3)
5123 (kuang3)
5124 (bao4)
5125 (du2)
5126 (biao1)
5127 (zan3)
5128 (zhi2)
5129 (si4)
512A (you1)
512B (hao2)
512C (qin1)
512D (chen4)
512E (li4)
512F (teng2)
5130 (wei3)
5131 (long2)
5132 (chu3,chu2)
5133 (chan4)
5134 (rang2)
5135 (shu4)
5136 (hui4)
5137 (li4)
5138 (luo2)
5139 (zan3,zuan3)
513A (nuo2)
513B (tang3)
513C (yan3)
513D (lei4)
513E (nang4)
513F (er2,r2)
5140 (wu4,wu1)
5141 (yun3)
5142 (zan1)
5143 (yuan2)
5144 (xiong1)
5145 (chong1)
5146 (zhao4)
5147 (xiong1)
5148 (xian1)
5149 (guang1)
514A (dui4)
514B (ke4)
514C (dui4)
514D (mian3,wen4)
514E (tu4)
514F (chang2,zhang3)
5150 (er2)
5151 (dui4)
5152 (er2,er1)
5153 (jin1)
5154 (tu4)
5155 (si4)
5156 (yan3)
5157 (yan3)
5158 (shi3)
5159 (shi2,ke4)
515A (dang3)
515B (qian1)
515C (dou1)
515D (fen1)
515E (mao2)
515F (xin1)
5160 (dou1)
5161 (bai3,ke4)
5162 (jing1)
5163 (li3)
5164 (kuang4)
5165 (ru4)
5166 (wang2,wu2)
5167 (nei4)
5168 (quan2)
5169 (liang3)
516A (yu2,shu4)
516B (ba1,ba2)
516C (gong1)
516D (liu4,lu4)
516E (xi1)
516F (none0)
5170 (lan2)
5171 (gong4,gong1,gong3)
5172 (tian1)
5173 (guan1)
5174 (xing1,xing4)
5175 (bing1)
5176 (qi2,ji1)
5177 (ju4)
5178 (dian3)
5179 (zi1,ci2)
517A (none0)
517B (yang3)
517C (jian1)
517D (shou4)
517E (ji4)
517F (yi4)
5180 (ji4)
5181 (chan3)
5182 (jiong1)
5183 (mao4)
5184 (ran3)
5185 (nei4)
5186 (yuan2)
5187 (mao3,mou3)
5188 (gang1)
5189 (ran3)
518A (ce4)
518B (jiong1)
518C (ce4)
518D (zai4)
518E (gua3)
518F (jiong3)
5190 (mao4,mo4)
5191 (zhou4)
5192 (mao4,mo4)
5193 (gou4)
5194 (xu3)
5195 (mian3)
5196 (mi4)
5197 (rong3)
5198 (yin2)
5199 (xie3,xie4)
519A (kan3)
519B (jun1)
519C (nong2)
519D (yi2)
519E (mi2)
519F (shi4)
51A0 (guan1,guan4)
51A1 (meng2)
51A2 (zhong3)
51A3 (zui4)
51A4 (yuan1)
51A5 (ming2)
51A6 (kou4)
51A7 (none0)
51A8 (fu4)
51A9 (xie3)
51AA (mi4)
51AB (bing1)
51AC (dong1)
51AD (tai4)
51AE (gang1)
51AF (feng2,ping2)
51B0 (bing1)
51B1 (hu4)
51B2 (chong1,chong4)
51B3 (jue2)
51B4 (hu4)
51B5 (kuang4)
51B6 (ye3)
51B7 (leng3)
51B8 (pan4)
51B9 (fu3)
51BA (min3)
51BB (dong4)
51BC (xian3)
51BD (lie4)
51BE (xia2)
51BF (jian1)
51C0 (jing4)
51C1 (shu4)
51C2 (mei3)
51C3 (shang4)
51C4 (qi1)
51C5 (gu4)
51C6 (zhun3)
51C7 (song1)
51C8 (jing4)
51C9 (liang2,liang4)
51CA (qing4,jing4)
51CB (diao1)
51CC (ling2)
51CD (dong4)
51CE (gan4)
51CF (jian3)
51D0 (yin1,yin2)
51D1 (cou4)
51D2 (ai2)
51D3 (li4)
51D4 (cang1)
51D5 (ming3)
51D6 (zhun3)
51D7 (cui2)
51D8 (si1)
51D9 (duo2)
51DA (jin4)
51DB (lin3)
51DC (lin3)
51DD (ning2)
51DE (xi1)
51DF (du2)
51E0 (ji3,ji1)
51E1 (fan2)
51E2 (fan2)
51E3 (fan2)
51E4 (feng4)
51E5 (ju1)
51E6 (chu3,chu4)
51E7 (none0)
51E8 (feng1)
51E9 (none0)
51EA (none0)
51EB (fu2)
51EC (feng1)
51ED (ping2)
51EE (feng1)
51EF (kai3)
51F0 (huang2)
51F1 (kai3)
51F2 (gan1)
51F3 (deng4)
51F4 (ping2)
51F5 (qu1,kan3)
51F6 (xiong1)
51F7 (kuai4)
51F8 (tu1,tu2,gu3)
51F9 (ao1,wa1)
51FA (chu1)
51FB (ji1)
51FC (dang4)
51FD (han2)
51FE (han2)
51FF (zao2,zuo4)
5200 (dao1)
5201 (diao1)
5202 (dao1)
5203 (ren4)
5204 (ren4)
5205 (chuang1)
5206 (fen1,fen4)
5207 (qie4,qie1)
5208 (yi4)
5209 (ji4)
520A (kan1)
520B (qian4)
520C (cun3)
520D (chu2)
520E (wen3)
520F (ji1)
5210 (dan3)
5211 (xing2)
5212 (hua4,hua2,huai5)
5213 (wan2)
5214 (jue2)
5215 (li2)
5216 (yue4)
5217 (lie4)
5218 (liu2)
5219 (ze2)
521A (gang1)
521B (chuang4,chuang1)
521C (fu2)
521D (chu1)
521E (qu4)
521F (ju1)
5220 (shan1)
5221 (min3)
5222 (ling2)
5223 (zhong1)
5224 (pan4)
5225 (bie2)
5226 (jie2)
5227 (jie2)
5228 (bao4,pao2)
5229 (li4)
522A (shan1)
522B (bie2,bie4)
522C (chan3)
522D (jing3)
522E (gua1)
522F (gen1)
5230 (dao4)
5231 (chuang4)
5232 (kui1)
5233 (ku1)
5234 (duo4)
5235 (er4)
5236 (zhi4)
5237 (shua1,shua4)
5238 (quan4,xuan4)
5239 (cha4,sha1)
523A (ci4,ci1)
523B (ke4,ke1)
523C (jie2)
523D (gui4)
523E (ci4)
523F (gui4)
5240 (kai3)
5241 (duo4)
5242 (ji4)
5243 (ti4)
5244 (jing3)
5245 (lou2)
5246 (luo2)
5247 (ze2)
5248 (yuan1)
5249 (cuo4)
524A (xue1,xiao1,xue4)
524B (ke4)
524C (la4,la2)
524D (qian2)
524E (cha4)
524F (chuan4)
5250 (gua3)
5251 (jian4)
5252 (cuo4)
5253 (li2)
5254 (ti1)
5255 (fei4)
5256 (pou1,pou3,po3)
5257 (chan3)
5258 (qi2)
5259 (chuang4)
525A (zi4)
525B (gang1)
525C (wan1)
525D (bo1)
525E (ji1,ji3)
525F (duo1)
5260 (qing2)
5261 (yan3,shan4)
5262 (zhuo2)
5263 (jian4)
5264 (ji4)
5265 (bo1,bao1)
5266 (yan1)
5267 (ju4)
5268 (huo4)
5269 (sheng4)
526A (jian3)
526B (duo2)
526C (duan1)
526D (wu1)
526E (gua3)
526F (fu4)
5270 (sheng4)
5271 (jian4)
5272 (ge1)
5273 (zha2)
5274 (kai3)
5275 (chuang4,chuang1)
5276 (juan1)
5277 (chan3)
5278 (tuan2,zhuan1)
5279 (lu4)
527A (li2)
527B (fou2)
527C (shan1)
527D (piao1,piao4)
527E (kou1)
527F (jiao3,chao1,jia3)
5280 (gua1)
5281 (qiao1)
5282 (jue2)
5283 (hua4,hua2)
5284 (zha2)
5285 (zhuo2)
5286 (lian2)
5287 (ju4)
5288 (pi1,pi3)
5289 (liu2)
528A (gui4)
528B (jiao3)
528C (gui4)
528D (jian4)
528E (jian4)
528F (tang1)
5290 (huo1)
5291 (ji4)
5292 (jian4)
5293 (yi4)
5294 (jian4)
5295 (zhi4)
5296 (chan2)
5297 (cuan2)
5298 (mo2)
5299 (li2)
529A (zhu2)
529B (li4)
529C (ya4)
529D (quan4)
529E (ban4)
529F (gong1)
52A0 (jia1)
52A1 (wu4)
52A2 (mai4)
52A3 (lie4)
52A4 (jing4)
52A5 (keng1)
52A6 (xie2)
52A7 (zhi3)
52A8 (dong4)
52A9 (zhu4)
52AA (nu3,nao2)
52AB (jie2)
52AC (qu2)
52AD (shao4)
52AE (yi4)
52AF (zhu1)
52B0 (mo4)
52B1 (li4)
52B2 (jing4,jin4)
52B3 (lao2)
52B4 (lao2)
52B5 (juan4)
52B6 (kou3)
52B7 (yang2)
52B8 (wa1)
52B9 (xiao4)
52BA (mou2)
52BB (kuang1)
52BC (jie2)
52BD (lie4)
52BE (he2)
52BF (shi4)
52C0 (ke4)
52C1 (jing4,jin4)
52C2 (hao2)
52C3 (bo2)
52C4 (min3)
52C5 (chi4)
52C6 (lang2)
52C7 (yong3)
52C8 (yong3)
52C9 (mian3)
52CA (ke4)
52CB (xun1)
52CC (juan4)
52CD (qing2)
52CE (lu4)
52CF (bu4)
52D0 (meng3)
52D1 (lai4)
52D2 (le4,lei1)
52D3 (kai4)
52D4 (mian3)
52D5 (dong4)
52D6 (xu4)
52D7 (xu4)
52D8 (kan1,kan4)
52D9 (wu4)
52DA (yi4)
52DB (xun1)
52DC (weng3)
52DD (sheng4,sheng1)
52DE (lao2,lao4)
52DF (mu4)
52E0 (lu4)
52E1 (piao1)
52E2 (shi4)
52E3 (ji1)
52E4 (qin2)
52E5 (qiang3)
52E6 (jiao3,chao1)
52E7 (quan4)
52E8 (xiang4)
52E9 (yi4)
52EA (qiao1)
52EB (fan2)
52EC (juan1)
52ED (tong2)
52EE (ju4)
52EF (dan1)
52F0 (xie2)
52F1 (mai4)
52F2 (xun1)
52F3 (xun1)
52F4 (lu:4)
52F5 (li4)
52F6 (che4)
52F7 (rang2)
52F8 (quan4)
52F9 (bao1)
52FA (shao2,shuo4,biao1)
52FB (yun2)
52FC (jiu1)
52FD (bao4)
52FE (gou1,gou4)
52FF (wu4)
5300 (yun2)
5301 (none0)
5302 (none0)
5303 (gai4)
5304 (gai4)
5305 (bao1)
5306 (cong1)
5307 (none0)
5308 (xiong1)
5309 (peng1)
530A (ju2)
530B (tao2)
530C (ge2)
530D (pu2)
530E (an4)
530F (pao2)
5310 (fu2)
5311 (gong1)
5312 (da2)
5313 (jiu4)
5314 (qiong1)
5315 (bi3)
5316 (hua4,hua1)
5317 (bei3)
5318 (nao3)
5319 (chi2,shi5)
531A (fang1,xi3)
531B (jiu4)
531C (yi2)
531D (za1)
531E (jiang4)
531F (kang4)
5320 (jiang4)
5321 (kuang1)
5322 (hu1)
5323 (xia2)
5324 (qu1)
5325 (fan2)
5326 (gui3)
5327 (qie4)
5328 (cang2,zang4)
5329 (kuang1)
532A (fei3)
532B (hu1)
532C (yu3)
532D (gui3)
532E (kui4)
532F (hui4)
5330 (dan1)
5331 (kui4)
5332 (lian2)
5333 (lian2)
5334 (suan3)
5335 (du2)
5336 (jiu4)
5337 (qu2)
5338 (xi4)
5339 (pi3,pi1,ya3)
533A (qu1,ou1)
533B (yi1)
533C (an4)
533D (yan3)
533E (bian3)
533F (ni4)
5340 (qu1,ou1)
5341 (shi2)
5342 (xin4)
5343 (qian1)
5344 (nian4)
5345 (sa4)
5346 (zu2)
5347 (sheng1)
5348 (wu3)
5349 (hui4)
534A (ban4)
534B (shi4)
534C (xi4)
534D (wan4)
534E (hua2,hua4,hua1)
534F (xie2)
5350 (wan4)
5351 (bei1)
5352 (zu2,cu4)
5353 (zhuo2,zhuo1)
5354 (xie2)
5355 (dan1,chan2,shan4)
5356 (mai4)
5357 (nan2,na1)
5358 (dan1,chan2)
5359 (ji2)
535A (bo2)
535B (shuai4,lu:4)
535C (bu3,bo5)
535D (kuang4)
535E (bian4)
535F (bu3)
5360 (zhan4,zhan1)
5361 (ka3,qia3)
5362 (lu2)
5363 (you3)
5364 (lu3)
5365 (xi1)
5366 (gua4)
5367 (wo4)
5368 (xie4)
5369 (jie2)
536A (jie2)
536B (wei4)
536C (ang2,yang3)
536D (qiong2)
536E (zhi1)
536F (mao3)
5370 (yin4)
5371 (wei1,wei2)
5372 (shao4)
5373 (ji2)
5374 (que4)
5375 (luan3)
5376 (shi4)
5377 (juan3,juan4,quan2)
5378 (xie4)
5379 (xu4)
537A (jin3)
537B (que4)
537C (wu4)
537D (ji2)
537E (e4)
537F (qing1)
5380 (xi1)
5381 (none0)
5382 (chang3,han3,an1)
5383 (han3)
5384 (e4)
5385 (ting1)
5386 (li4)
5387 (zhe2)
5388 (an1,chang3)
5389 (li4)
538A (ya3)
538B (ya1,ya4)
538C (yan4)
538D (she4)
538E (zhi3)
538F (zha3)
5390 (pang2)
5391 (none0)
5392 (ke4)
5393 (ya2)
5394 (zhi4)
5395 (ce4,si5)
5396 (pang2)
5397 (ti2)
5398 (li2)
5399 (she4)
539A (hou4)
539B (ting1)
539C (zui1)
539D (cuo4)
539E (fei4)
539F (yuan2)
53A0 (ce4,si5)
53A1 (yuan2)
53A2 (xiang1)
53A3 (yan3)
53A4 (li4)
53A5 (jue2)
53A6 (sha4,xia4)
53A7 (dian1)
53A8 (chu2)
53A9 (jiu4)
53AA (qin2,jin3)
53AB (ao2)
53AC (gui3)
53AD (yan4,yan1)
53AE (si1)
53AF (li4)
53B0 (chang3,an1)
53B1 (lan2)
53B2 (li4)
53B3 (yan2)
53B4 (yan3)
53B5 (yuan2)
53B6 (si1)
53B7 (si1)
53B8 (lin2)
53B9 (qiu2)
53BA (qu4)
53BB (qu4)
53BC (none0)
53BD (lei3)
53BE (du1)
53BF (xian4)
53C0 (zhuan1)
53C1 (san1)
53C2 (can1,cen1,shen1)
53C3 (can1,cen1,shen1,san1)
53C4 (san1)
53C5 (can1,cen1,shen1)
53C6 (ai4)
53C7 (dai4)
53C8 (you4)
53C9 (cha1,cha2,cha3,cha4)
53CA (ji2)
53CB (you3)
53CC (shuang1)
53CD (fan3)
53CE (shou1)
53CF (guai4)
53D0 (ba2)
53D1 (fa1,fa4)
53D2 (ruo4)
53D3 (shi4)
53D4 (shu1,shu2)
53D5 (zhui4)
53D6 (qu3)
53D7 (shou4)
53D8 (bian4)
53D9 (xu4)
53DA (jia3)
53DB (pan4)
53DC (sou3)
53DD (ji2)
53DE (yu4)
53DF (sou3)
53E0 (die2)
53E1 (rui4)
53E2 (cong2)
53E3 (kou3)
53E4 (gu3)
53E5 (ju4,gou1)
53E6 (ling4)
53E7 (gua3)
53E8 (tao1,dao1,dao2)
53E9 (kou4)
53EA (zhi3,zhi1)
53EB (jiao4)
53EC (zhao4,shao4,zhao1)
53ED (ba1)
53EE (ding1)
53EF (ke3,ke4)
53F0 (tai2,tai1)
53F1 (chi4)
53F2 (shi3)
53F3 (you4)
53F4 (qiu2)
53F5 (po3)
53F6 (ye4,xie2)
53F7 (hao4,hao2)
53F8 (si1)
53F9 (tan4)
53FA (chi3)
53FB (le4)
53FC (diao1)
53FD (ji1)
53FE (none0)
53FF (hong1)
5400 (mie1)
5401 (yu4,xu1,yu1)
5402 (mang2)
5403 (chi1,ji2)
5404 (ge4,ge3)
5405 (xuan1)
5406 (yao1)
5407 (zi3)
5408 (he2,ge3)
5409 (ji2)
540A (diao4)
540B (cun4)
540C (tong2,tong4)
540D (ming2)
540E (hou4)
540F (li4)
5410 (tu3,tu4)
5411 (xiang4)
5412 (zha4,zha1)
5413 (he4,xia4)
5414 (ye3)
5415 (lu:3)
5416 (a1)
5417 (ma5,ma3,ma2)
5418 (ou3)
5419 (xue1)
541A (yi1)
541B (jun1)
541C (chou3)
541D (lin4)
541E (tun1)
541F (yin2)
5420 (fei4)
5421 (bi3,pi3)
5422 (qin4)
5423 (qin4)
5424 (jie4)
5425 (pou1)
5426 (fou3,pi3)
5427 (ba5,ba1)
5428 (dun1)
5429 (fen1)
542A (e2)
542B (han2)
542C (ting1,yin3)
542D (hang2,keng1)
542E (shun3)
542F (qi3)
5430 (hu1)
5431 (zhi1,zi1)
5432 (yin3)
5433 (wu2)
5434 (wu2)
5435 (chao3,chao1)
5436 (na4)
5437 (chuo4)
5438 (xi1)
5439 (chui1,chui4)
543A (dou1)
543B (wen3)
543C (hou3)
543D (ou2,hong1)
543E (wu2)
543F (gao4,gu4)
5440 (ya1,ya5)
5441 (jun4)
5442 (lu:3)
5443 (e4,e5)
5444 (ge2)
5445 (mei2)
5446 (dai1,ai2)
5447 (qi3)
5448 (cheng2)
5449 (wu2)
544A (gao4,gu4)
544B (fu1)
544C (jiao4)
544D (hong1)
544E (chi3)
544F (sheng1)
5450 (na4,na5,ne4,ne5)
5451 (tun1)
5452 (m2)
5453 (yi4)
5454 (dai1,tai3)
5455 (ou3,ou4)
5456 (li4)
5457 (bei5,bai4)
5458 (yuan2,yun2,yun4)
5459 (guo1)
545A (none0)
545B (qiang1,qiang4)
545C (wu1)
545D (e4)
545E (shi1)
545F (quan3)
5460 (pen3)
5461 (wen3)
5462 (ni2,ne5,na4,ne4)
5463 (mou2)
5464 (ling4)
5465 (ran3)
5466 (you1)
5467 (di3)
5468 (zhou1)
5469 (shi4)
546A (zhou4)
546B (zhan1)
546C (ling2)
546D (yi4)
546E (qi4)
546F (ping2)
5470 (zi3)
5471 (gua1,gu1,wa1,gua3)
5472 (ci1,zi1)
5473 (wei4)
5474 (xu1)
5475 (he1,ke1,a1,a2,a3,a4,a5)
5476 (nao2)
5477 (xia1,xia2)
5478 (pei1)
5479 (yi4)
547A (xiao1)
547B (shen1)
547C (hu1)
547D (ming4)
547E (da2)
547F (qu1)
5480 (ju3,zui3)
5481 (gan1)
5482 (za1)
5483 (tuo1)
5484 (duo1,duo4)
5485 (pou3)
5486 (pao2)
5487 (bie2)
5488 (fu2)
5489 (bi4,fu2)
548A (he2,he4,huo2,huo4,huo5)
548B (za3,ze2,zha1,zha4)
548C (he2,he4,huo2,huo4,huo5,hai1,he5,hu2)
548D (hai1)
548E (jiu4)
548F (yong3)
5490 (fu4,fu5)
5491 (da1)
5492 (zhou4)
5493 (wa3)
5494 (ka3,ka1)
5495 (gu1)
5496 (ka1,ga1)
5497 (zuo3)
5498 (bu4)
5499 (long2)
549A (dong1)
549B (ning2)
549C (zha4)
549D (si1)
549E (xian4)
549F (huo4)
54A0 (qi1)
54A1 (er4)
54A2 (e4)
54A3 (guang1)
54A4 (zha4)
54A5 (xi4,die2)
54A6 (yi2)
54A7 (lie3,lie1,lie5)
54A8 (zi1)
54A9 (mie1)
54AA (mi1)
54AB (zhi3)
54AC (yao3)
54AD (ji1)
54AE (zhou4)
54AF (ge1,ka3,lo5,luo4,ge2)
54B0 (shuai4)
54B1 (zan2,za2,zan5)
54B2 (xiao4)
54B3 (ke2,hai1,ka3,kai4)
54B4 (hui1)
54B5 (kua1)
54B6 (huai4)
54B7 (tao2)
54B8 (xian2)
54B9 (e4)
54BA (xuan3)
54BB (xiu1)
54BC (guo1,kuai1)
54BD (yan1,yan4,ye4)
54BE (lao3)
54BF (yi1)
54C0 (ai1)
54C1 (pin3)
54C2 (shen3)
54C3 (tong2)
54C4 (hong1,hong3,hong4)
54C5 (xiong1,hong1)
54C6 (duo1)
54C7 (wa1,wa5)
54C8 (ha1,ha3,ha4,ka1)
54C9 (zai1)
54CA (you4)
54CB (di4)
54CC (pai4)
54CD (xiang3)
54CE (ai1,ai3,ai4)
54CF (gen2)
54D0 (kuang1)
54D1 (ya1,ya3)
54D2 (da1)
54D3 (xiao1)
54D4 (bi4)
54D5 (hui4,yue3)
54D6 (none0)
54D7 (hua1,hua2,ye4)
54D8 (none0)
54D9 (kuai4)
54DA (duo3)
54DB (none0)
54DC (ji4)
54DD (nong2)
54DE (mou1)
54DF (yo5,yo1)
54E0 (hao4)
54E1 (yuan2,yun2,yun4)
54E2 (long4)
54E3 (pou3)
54E4 (mang2)
54E5 (ge1)
54E6 (e2,o2,o4,wo2,wo4)
54E7 (chi1)
54E8 (shao4)
54E9 (li1,li3,li5)
54EA (na3,nei3,na5,ne2,nai3)
54EB (zu2)
54EC (he1)
54ED (ku1)
54EE (xiao4,xiao1)
54EF (xian4)
54F0 (lao2)
54F1 (bei4)
54F2 (zhe2)
54F3 (zha1)
54F4 (liang4)
54F5 (ba1)
54F6 (mi3)
54F7 (le4)
54F8 (sui1)
54F9 (fou2)
54FA (bu3)
54FB (han4)
54FC (heng1,hng5)
54FD (geng3)
54FE (shuo1)
54FF (ge3)
5500 (you4)
5501 (yan4)
5502 (gu3)
5503 (gu3)
5504 (bai4,bei5)
5505 (han1)
5506 (suo1)
5507 (chun2)
5508 (yi4)
5509 (ai1,ai4)
550A (jia2)
550B (tu3)
550C (xian2)
550D (guan1,guan3)
550E (li4)
550F (xi1)
5510 (tang2)
5511 (zuo4)
5512 (miu1)
5513 (che1)
5514 (wu2,n2,n3,ng2,ng3)
5515 (zao4)
5516 (ya1)
5517 (dou3)
5518 (qi3)
5519 (di2)
551A (qin4)
551B (ma4)
551C (none0)
551D (gong4)
551E (dou3)
551F (none0)
5520 (lao2,lao4)
5521 (liang3)
5522 (suo3)
5523 (zao4)
5524 (huan4)
5525 (none0)
5526 (gou4)
5527 (ji1)
5528 (zuo3)
5529 (wo1)
552A (feng3)
552B (yin2)
552C (hu3,xia4)
552D (qi1)
552E (shou4)
552F (wei2,wei3)
5530 (shua1)
5531 (chang4)
5532 (er2)
5533 (li4)
5534 (qiang4)
5535 (an3)
5536 (jie4)
5537 (yo1)
5538 (nian4)
5539 (yu2)
553A (tian3)
553B (lai2)
553C (sha4)
553D (xi1)
553E (tuo4)
553F (hu1)
5540 (ai2)
5541 (zhou1,zhao1)
5542 (nou4)
5543 (ken3)
5544 (zhuo2)
5545 (zhuo2)
5546 (shang1)
5547 (di1)
5548 (heng4)
5549 (lin2)
554A (a5,a1,a2,a3,a4)
554B (xiao1)
554C (xiang1)
554D (tun1)
554E (wu3)
554F (wen4)
5550 (cui4)
5551 (jie1)
5552 (hu1)
5553 (qi3)
5554 (qi3)
5555 (tao2)
5556 (dan4)
5557 (dan4)
5558 (wan3)
5559 (zi3)
555A (bi3)
555B (cui4)
555C (chuo4,chuai4)
555D (he2)
555E (ya3,ya1)
555F (qi3)
5560 (zhe2)
5561 (fei1)
5562 (liang3)
5563 (xian2)
5564 (pi2)
5565 (sha2)
5566 (la5,la1)
5567 (ze2)
5568 (qing1)
5569 (gua4)
556A (pa1)
556B (zhe3)
556C (se4)
556D (zhuan4)
556E (nie4)
556F (guo1)
5570 (luo1)
5571 (yan1)
5572 (di4)
5573 (quan2)
5574 (tan1,chan3)
5575 (bo5)
5576 (ding4)
5577 (lang1)
5578 (xiao4)
5579 (none0)
557A (tang2)
557B (chi4)
557C (ti2)
557D (an2)
557E (jiu1)
557F (dan4)
5580 (ka1,ke4,ka4)
5581 (yong2)
5582 (wei4)
5583 (nan2)
5584 (shan4)
5585 (yu4)
5586 (zhe2)
5587 (la3,la1,la2)
5588 (jie1)
5589 (hou2)
558A (han3)
558B (die2,zha2)
558C (zhou1)
558D (chai2)
558E (kuai1)
558F (re3,nuo4)
5590 (yu4)
5591 (yin1)
5592 (zan3)
5593 (yao1)
5594 (wo1,o1)
5595 (mian3)
5596 (hu2)
5597 (yun3)
5598 (chuan3)
5599 (hui4)
559A (huan4)
559B (huan4)
559C (xi3)
559D (he1,he4)
559E (ji1)
559F (kui4)
55A0 (zhong3)
55A1 (wei3)
55A2 (sha4)
55A3 (xu3)
55A4 (huang2)
55A5 (du4)
55A6 (nie4)
55A7 (xuan1)
55A8 (liang4)
55A9 (yu4)
55AA (sang1,sang4)
55AB (chi1)
55AC (qiao2)
55AD (yan4)
55AE (dan1,chan2,shan4)
55AF (pen1)
55B0 (shi2,si4)
55B1 (li2)
55B2 (yo5,yo1)
55B3 (zha1,cha1)
55B4 (wei1)
55B5 (miao1)
55B6 (ying2)
55B7 (pen1,pen4,pen5)
55B8 (none0)
55B9 (kui2)
55BA (xi4)
55BB (yu4)
55BC (jie2)
55BD (lou5,lou2)
55BE (ku4)
55BF (cao1)
55C0 (huo4)
55C1 (ti2)
55C2 (yao2)
55C3 (he4)
55C4 (a2,sha4)
55C5 (xiu4)
55C6 (qiang1,qiang4)
55C7 (se4)
55C8 (yong1)
55C9 (su4)
55CA (hong3)
55CB (xie1)
55CC (ai4,yi4)
55CD (suo1)
55CE (ma5,ma3)
55CF (cha1)
55D0 (hai4)
55D1 (ke4,ke1)
55D2 (da1,ta4)
55D3 (sang3)
55D4 (chen1)
55D5 (ru4,nou4)
55D6 (sou1)
55D7 (gong1)
55D8 (ji1)
55D9 (pang3)
55DA (wu1)
55DB (qian4)
55DC (shi4)
55DD (ge2)
55DE (zi1)
55DF (jie1,jue1)
55E0 (luo4)
55E1 (weng1)
55E2 (wa4)
55E3 (si4)
55E4 (chi1)
55E5 (hao2)
55E6 (suo1)
55E7 (jia1,lun2)
55E8 (hai1,hei1)
55E9 (suo3)
55EA (qin2)
55EB (nie4)
55EC (he1)
55ED (none0)
55EE (sai4)
55EF (ng4,ng2,ng3,n2,n3,n4)
55F0 (ge4)
55F1 (na2)
55F2 (dia3)
55F3 (ai4,ai3)
55F4 (none0)
55F5 (tong1)
55F6 (bi4)
55F7 (ao2)
55F8 (ao2)
55F9 (lian2)
55FA (cui1)
55FB (zhe1)
55FC (mo4)
55FD (sou4)
55FE (sou3,zu2)
55FF (tan3)
5600 (di2,di1)
5601 (qi1)
5602 (jiao4)
5603 (chong1)
5604 (jiao1)
5605 (kai3)
5606 (tan4)
5607 (san1)
5608 (cao2)
5609 (jia1)
560A (none0)
560B (xiao1)
560C (piao4)
560D (lou5,lou2)
560E (ga1,ga3,ga2)
560F (gu3,jia3)
5610 (xiao1)
5611 (hu1)
5612 (hui4)
5613 (guo1)
5614 (ou1,ou3,ou4)
5615 (xian1)
5616 (ze2)
5617 (chang2)
5618 (xu1,shi1)
5619 (po2)
561A (de1,dei1)
561B (ma5,ma2)
561C (ma4,ma3,mo4)
561D (hu2)
561E (lei5)
561F (du1)
5620 (ga1)
5621 (tang1)
5622 (ye3)
5623 (beng1)
5624 (ying1)
5625 (none0)
5626 (jiao4)
5627 (mi4)
5628 (xiao4)
5629 (hua1,hua2,ye4)
562A (mai3)
562B (ran2)
562C (zuo1,chuai4,zhuai4)
562D (peng1)
562E (lao2,lao4)
562F (xiao4)
5630 (ji1)
5631 (zhu3)
5632 (chao2,zhao1)
5633 (kui4)
5634 (zui3)
5635 (xiao1)
5636 (si1)
5637 (hao2)
5638 (fu3,m2)
5639 (liao2)
563A (qiao2)
563B (xi1)
563C (xu4)
563D (chan3)
563E (dan4)
563F (hei1,mo4,hai1)
5640 (xun4)
5641 (wu4)
5642 (zun3)
5643 (pan2)
5644 (chi1)
5645 (kui1)
5646 (can3)
5647 (zan3)
5648 (cu4)
5649 (dan4)
564A (yu4)
564B (tun1)
564C (cheng1,ceng1)
564D (jiao4)
564E (ye1)
564F (xi1)
5650 (qi4)
5651 (hao2)
5652 (lian2)
5653 (xu1,shi1)
5654 (deng1)
5655 (hui1)
5656 (yin2)
5657 (pu1)
5658 (jue1)
5659 (qin2)
565A (xun2)
565B (nie4)
565C (lu1)
565D (si1)
565E (yan4)
565F (ying4)
5660 (da1)
5661 (zhan1)
5662 (o1)
5663 (zhou4)
5664 (jin4)
5665 (nong2)
5666 (hui4,yue1)
5667 (hui4)
5668 (qi4)
5669 (e4)
566A (zao4)
566B (yi1,yi4)
566C (shi4)
566D (jiao4)
566E (yuan4)
566F (ai4,ai3)
5670 (yong1)
5671 (xue2,jue2)
5672 (kuai4)
5673 (yu3)
5674 (pen1,pen4)
5675 (dao4)
5676 (ga2)
5677 (xin1)
5678 (dun1,dun4)
5679 (dang1)
567A (none0)
567B (sai1)
567C (pi1)
567D (pi3)
567E (yin1)
567F (zui3)
5680 (ning2)
5681 (di2)
5682 (han3)
5683 (ta4)
5684 (huo4,huo1,o3)
5685 (ru2)
5686 (hao1)
5687 (xia4,he4)
5688 (yan4)
5689 (duo1)
568A (pi4)
568B (chou2)
568C (ji4)
568D (jin4)
568E (hao2)
568F (ti4)
5690 (chang2)
5691 (none0)
5692 (none0)
5693 (ca1,cha1)
5694 (ti4)
5695 (lu1)
5696 (hui4)
5697 (bao4)
5698 (you1)
5699 (nie4)
569A (yin2)
569B (hu4)
569C (mo4)
569D (huang1)
569E (zhe2)
569F (li2)
56A0 (liu2)
56A1 (none0)
56A2 (nang2,nang1)
56A3 (xiao1,ao2)
56A4 (mo2)
56A5 (yan4)
56A6 (li4)
56A7 (lu2)
56A8 (long2)
56A9 (mo2)
56AA (dan1)
56AB (chen4)
56AC (pin2)
56AD (pi3)
56AE (xiang4)
56AF (huo4)
56B0 (mo2)
56B1 (xi1)
56B2 (duo3)
56B3 (ku4)
56B4 (yan2)
56B5 (chan2)
56B6 (ying1)
56B7 (rang3,rang1)
56B8 (dian3)
56B9 (la1)
56BA (ta4)
56BB (xiao1)
56BC (jiao2,jiao4,jue2)
56BD (chuo4)
56BE (huan4)
56BF (huo4)
56C0 (zhuan4,zhuan3)
56C1 (nie4)
56C2 (xiao1,ao2)
56C3 (ca4)
56C4 (li2)
56C5 (chan3)
56C6 (chai4)
56C7 (li4)
56C8 (yi4)
56C9 (luo1,luo2)
56CA (nang2,nang1)
56CB (zan4)
56CC (su1)
56CD (xi3)
56CE (none0)
56CF (jian1)
56D0 (za2)
56D1 (zhu3)
56D2 (lan2)
56D3 (nie4)
56D4 (nang1)
56D5 (none0)
56D6 (none0)
56D7 (wei2)
56D8 (hui2)
56D9 (yin1)
56DA (qiu2)
56DB (si4)
56DC (nin2)
56DD (jian3,nan1)
56DE (hui2)
56DF (xin4)
56E0 (yin1)
56E1 (nan1)
56E2 (tuan2)
56E3 (tuan2)
56E4 (dun4,tun2)
56E5 (kang4)
56E6 (yuan1)
56E7 (jiong3)
56E8 (pian1)
56E9 (yun4)
56EA (cong1,chuang1)
56EB (hu2)
56EC (hui2)
56ED (yuan2)
56EE (e2)
56EF (guo2)
56F0 (kun4)
56F1 (cong1)
56F2 (wei2)
56F3 (tu2)
56F4 (wei2)
56F5 (lun2)
56F6 (guo2)
56F7 (jun1)
56F8 (ri4)
56F9 (ling2)
56FA (gu4)
56FB (guo2)
56FC (tai1)
56FD (guo2)
56FE (tu2)
56FF (you4)
5700 (guo2)
5701 (yin2)
5702 (hun4)
5703 (pu3)
5704 (yu3)
5705 (han2)
5706 (yuan2)
5707 (lun2)
5708 (quan1,juan1,juan4,quan3)
5709 (yu3)
570A (qing1)
570B (guo2)
570C (chui2)
570D (wei2)
570E (yuan2)
570F (quan1,juan1,juan4)
5710 (ku1)
5711 (pu3)
5712 (yuan2)
5713 (yuan2)
5714 (e4)
5715 (tu2,shu1,guan3)
5716 (tu2)
5717 (tu2)
5718 (tuan2)
5719 (lu:e4)
571A (hui4)
571B (yi4)
571C (yuan2,huan2)
571D (luan2)
571E (luan2)
571F (tu3)
5720 (ya4)
5721 (tu3)
5722 (ting3)
5723 (sheng4)
5724 (yan2)
5725 (lu2)
5726 (none0)
5727 (ya1,ya4)
5728 (zai4)
5729 (wei2,xu1)
572A (ge1)
572B (yu4)
572C (wu1)
572D (gui1)
572E (pi3)
572F (yi2)
5730 (di4,de5)
5731 (qian1)
5732 (qian1)
5733 (zhen4)
5734 (zhuo2,shao2)
5735 (dang4)
5736 (qia4)
5737 (none0)
5738 (none0)
5739 (kuang4)
573A (chang3,chang2,chang5)
573B (qi2,yin2)
573C (nie4)
573D (mo4)
573E (ji1)
573F (jia2)
5740 (zhi3)
5741 (zhi3)
5742 (ban3)
5743 (xun1)
5744 (tou2)
5745 (qin3)
5746 (fen2)
5747 (jun1,yun4)
5748 (keng1)
5749 (dun4)
574A (fang1,fang2)
574B (fen4)
574C (ben4)
574D (tan1)
574E (kan3)
574F (huai4,pi1,pei1)
5750 (zuo4)
5751 (keng1)
5752 (bi4)
5753 (xing2)
5754 (di4)
5755 (jing1)
5756 (ji4)
5757 (kuai4)
5758 (di3)
5759 (jing1)
575A (jian1)
575B (tan2)
575C (li4)
575D (ba4)
575E (wu4)
575F (fen2)
5760 (zhui4)
5761 (po1)
5762 (pan3)
5763 (tang1)
5764 (kun1)
5765 (qu1)
5766 (tan3)
5767 (zhi2)
5768 (tuo2)
5769 (gan1)
576A (ping2)
576B (dian4)
576C (wa1)
576D (ni2)
576E (tai2,tai1)
576F (pi1)
5770 (jiong1)
5771 (yang1)
5772 (fo2)
5773 (ao4)
5774 (liu4)
5775 (qiu1)
5776 (mu4)
5777 (ke3,ke1)
5778 (gou4)
5779 (xue4)
577A (ba2)
577B (chi2,di3)
577C (che4)
577D (ling2)
577E (zhu4)
577F (fu4)
5780 (hu1)
5781 (zhi4)
5782 (chui2)
5783 (la1)
5784 (long3)
5785 (long3)
5786 (lu2)
5787 (ao4)
5788 (none0)
5789 (pao2)
578A (none0)
578B (xing2)
578C (tong2,dong4)
578D (ji4)
578E (ke4)
578F (lu4)
5790 (ci2)
5791 (chi3)
5792 (lei3)
5793 (gai1)
5794 (yin1)
5795 (hou4)
5796 (dui1)
5797 (zhao4)
5798 (fu2)
5799 (guang1)
579A (yao2)
579B (duo3,duo4)
579C (duo3,duo4)
579D (gui3)
579E (cha2)
579F (yang2)
57A0 (yin2)
57A1 (fa2)
57A2 (gou4)
57A3 (yuan2)
57A4 (die2)
57A5 (xie2)
57A6 (ken3)
57A7 (shang3)
57A8 (shou3)
57A9 (e4)
57AA (none0)
57AB (dian4)
57AC (hong2)
57AD (ya1,ya4)
57AE (kua3)
57AF (da5)
57B0 (none0)
57B1 (dang4)
57B2 (kai3)
57B3 (none0)
57B4 (nao3)
57B5 (an1)
57B6 (xing1)
57B7 (xian4)
57B8 (huan4,huan2,yuan4)
57B9 (bang1)
57BA (pei1)
57BB (ba4)
57BC (yi4)
57BD (yin4)
57BE (han4)
57BF (xu4)
57C0 (chui2)
57C1 (cen2)
57C2 (geng3)
57C3 (ai1)
57C4 (peng2)
57C5 (fang2)
57C6 (que4)
57C7 (yong3)
57C8 (jun4)
57C9 (jia2)
57CA (di4)
57CB (mai2,man2)
57CC (lang4)
57CD (xuan4)
57CE (cheng2)
57CF (shan1)
57D0 (jin1)
57D1 (zhe2)
57D2 (lie4,le4)
57D3 (lie4)
57D4 (pu3,bu4,bu3)
57D5 (cheng2)
57D6 (none0)
57D7 (bu4)
57D8 (shi2)
57D9 (xun1)
57DA (guo1)
57DB (jiong1)
57DC (ye3)
57DD (nian4)
57DE (di1)
57DF (yu4)
57E0 (bu4)
57E1 (wu4,ya1)
57E2 (juan3)
57E3 (sui4)
57E4 (pi2,bei1,bi4)
57E5 (cheng1)
57E6 (wan3)
57E7 (ju4)
57E8 (lun3)
57E9 (zheng1)
57EA (kong1)
57EB (zhong3)
57EC (dong1)
57ED (dai4)
57EE (tan4)
57EF (an3)
57F0 (cai4)
57F1 (shu2)
57F2 (beng3)
57F3 (kan3)
57F4 (zhi2)
57F5 (duo3)
57F6 (yi4)
57F7 (zhi2)
57F8 (yi4)
57F9 (pei2)
57FA (ji1)
57FB (zhun3)
57FC (qi2)
57FD (sao4)
57FE (ju4)
57FF (ni2,ni4)
5800 (ku1,jue2)
5801 (ke3)
5802 (tang2)
5803 (kun1)
5804 (ni4)
5805 (jian1)
5806 (dui1,zui1)
5807 (jin3)
5808 (gang1)
5809 (yu4)
580A (e4,wu4)
580B (peng2,beng4,peng4)
580C (gu4)
580D (tu4)
580E (leng4,ling2)
580F (none0)
5810 (ya2)
5811 (qian4)
5812 (none0)
5813 (an4)
5814 (chen1)
5815 (duo4,hui1)
5816 (nao3)
5817 (tu1)
5818 (cheng2)
5819 (yin1)
581A (hun2)
581B (bi4)
581C (lian4)
581D (guo1)
581E (die2)
581F (zhuan4)
5820 (hou4)
5821 (bao3,bu3,pu4,pu3)
5822 (bao3)
5823 (yu2)
5824 (di1,ti2)
5825 (mao2)
5826 (jie1)
5827 (ruan2)
5828 (e4,ai4)
5829 (geng4)
582A (kan1)
582B (zong1)
582C (yu2)
582D (huang2)
582E (e4)
582F (yao2)
5830 (yan4)
5831 (bao4)
5832 (ji2)
5833 (mei2)
5834 (chang2,chang3)
5835 (du3)
5836 (tuo1)
5837 (an3)
5838 (feng2)
5839 (zhong4)
583A (jie4)
583B (zhen1)
583C (heng4)
583D (gang1)
583E (chuan3)
583F (jian3)
5840 (none0)
5841 (lei3)
5842 (gang3)
5843 (huang1)
5844 (leng2)
5845 (duan4)
5846 (wan1)
5847 (xuan1)
5848 (ji4)
5849 (ji2)
584A (kuai4)
584B (ying2)
584C (ta1)
584D (cheng2)
584E (yong3)
584F (kai3)
5850 (su4)
5851 (su4)
5852 (shi2)
5853 (mi4)
5854 (ta3,da5)
5855 (weng3)
5856 (cheng2)
5857 (tu2)
5858 (tang2)
5859 (qiao1)
585A (zhong3)
585B (li4)
585C (peng2)
585D (bang4)
585E (sai4,se4,sai1)
585F (zang4)
5860 (dui1)
5861 (tian2)
5862 (wu4)
5863 (cheng3)
5864 (xun1,xuan1)
5865 (ge2)
5866 (zhen4)
5867 (ai4)
5868 (gong1)
5869 (yan2)
586A (kan3)
586B (tian2)
586C (yuan2)
586D (wen1)
586E (xie4)
586F (liu4)
5870 (none0)
5871 (lang3)
5872 (chang2,chang3)
5873 (peng2)
5874 (beng1)
5875 (chen2)
5876 (lu4)
5877 (lu3)
5878 (ou1)
5879 (qian4)
587A (mei2)
587B (mo4)
587C (zhuan1)
587D (shuang3)
587E (shu2)
587F (lou3)
5880 (chi2)
5881 (man4)
5882 (biao1)
5883 (jing4)
5884 (ce4)
5885 (shu4)
5886 (di4)
5887 (zhang4)
5888 (kan4)
5889 (yong1)
588A (dian4)
588B (chen3)
588C (zhi2)
588D (ji4)
588E (guo1)
588F (qiang3)
5890 (jin3)
5891 (di1)
5892 (shang1)
5893 (mu4)
5894 (cui1)
5895 (yan4)
5896 (ta3,da5)
5897 (zeng1)
5898 (qi2)
5899 (qiang2)
589A (liang2)
589B (none0)
589C (zhui4)
589D (qiao1)
589E (zeng1)
589F (xu1)
58A0 (shan4)
58A1 (shan4)
58A2 (ba2)
58A3 (pu2)
58A4 (kuai4)
58A5 (dong3)
58A6 (fan2)
58A7 (que4)
58A8 (mo4)
58A9 (dun1)
58AA (dun1)
58AB (zun1,zun3)
58AC (zui4)
58AD (sheng4)
58AE (duo4,hui1)
58AF (duo4)
58B0 (tan2)
58B1 (deng4,yan4)
58B2 (mu2)
58B3 (fen2)
58B4 (huang2)
58B5 (tan2)
58B6 (da5)
58B7 (ye4)
58B8 (chu2)
58B9 (none0)
58BA (ao4)
58BB (qiang2)
58BC (ji1)
58BD (qiao1)
58BE (ken3)
58BF (yi4)
58C0 (pi2)
58C1 (bi4)
58C2 (dian4)
58C3 (jiang1)
58C4 (ye3)
58C5 (yong1,yong3)
58C6 (xue2)
58C7 (tan2)
58C8 (lan3)
58C9 (ju4)
58CA (huai4,pi1)
58CB (dang4)
58CC (rang3)
58CD (qian4)
58CE (xuan1)
58CF (lan4)
58D0 (mi2)
58D1 (he4,huo4)
58D2 (kai4)
58D3 (ya1,ya4)
58D4 (dao3)
58D5 (hao2)
58D6 (ruan2)
58D7 (none0)
58D8 (lei3)
58D9 (kuang4)
58DA (lu2)
58DB (yan2)
58DC (tan2)
58DD (wei3)
58DE (huai4,pi1)
58DF (long3)
58E0 (long3)
58E1 (rui4)
58E2 (li4)
58E3 (lin2)
58E4 (rang3)
58E5 (chan2)
58E6 (xun1)
58E7 (yan2)
58E8 (lei2)
58E9 (ba4)
58EA (none0)
58EB (shi4)
58EC (ren2)
58ED (none0)
58EE (zhuang4)
58EF (zhuang4)
58F0 (sheng1)
58F1 (yi1)
58F2 (mai4)
58F3 (qiao4,ke2)
58F4 (zhu3)
58F5 (zhuang4)
58F6 (hu2)
58F7 (hu2)
58F8 (kun3)
58F9 (yi1)
58FA (hu2)
58FB (xu4)
58FC (kun3)
58FD (shou4)
58FE (mang3)
58FF (zun1)
5900 (shou4)
5901 (yi1)
5902 (zhi3)
5903 (gu1)
5904 (chu3,chu4)
5905 (xiang2)
5906 (feng2)
5907 (bei4)
5908 (none0)
5909 (bian4)
590A (sui1)
590B (qun1)
590C (ling2)
590D (fu4)
590E (zuo4)
590F (xia4,jia3)
5910 (xiong4)
5911 (none0)
5912 (nao2)
5913 (xia4)
5914 (kui2)
5915 (xi1,xi4)
5916 (wai4)
5917 (yuan4)
5918 (mao3)
5919 (su4)
591A (duo1)
591B (duo1)
591C (ye4)
591D (qing2)
591E (none0)
591F (gou4)
5920 (gou4)
5921 (qi4)
5922 (meng4)
5923 (meng4)
5924 (yin2)
5925 (huo3)
5926 (chen4)
5927 (da4,dai4)
5928 (ze4)
5929 (tian1)
592A (tai4)
592B (fu1,fu2)
592C (guai4)
592D (yao1,yao3)
592E (yang1)
592F (hang1,ben4)
5930 (gao3)
5931 (shi1)
5932 (ben3,tao1)
5933 (tai4)
5934 (tou2)
5935 (yan3)
5936 (bi3)
5937 (yi2)
5938 (kua1)
5939 (jia1,jia2,ga1)
593A (duo2)
593B (none0)
593C (kuang3)
593D (yun4)
593E (jia1,jia2)
593F (ba1)
5940 (en1,mang2)
5941 (lian2)
5942 (huan4)
5943 (di1)
5944 (yan3,yan1)
5945 (pao4)
5946 (juan4)
5947 (qi2,ji1)
5948 (nai4,nai3)
5949 (feng4)
594A (xie2)
594B (fen4)
594C (dian3)
594D (none0)
594E (kui2)
594F (zou4)
5950 (huan4)
5951 (qi4,xie4,qie4)
5952 (kai1)
5953 (she1)
5954 (ben1,ben4)
5955 (yi4)
5956 (jiang3)
5957 (tao4)
5958 (zhuang3,zang4)
5959 (ben3)
595A (xi1)
595B (huang3)
595C (fei3)
595D (diao1)
595E (sui1)
595F (beng1)
5960 (dian4)
5961 (ao4)
5962 (she1)
5963 (weng1)
5964 (pan3)
5965 (ao4)
5966 (wu4)
5967 (ao4)
5968 (jiang3)
5969 (lian2)
596A (duo2)
596B (yun1)
596C (jiang3)
596D (shi4)
596E (fen4)
596F (huo4)
5970 (bei4)
5971 (lian2)
5972 (che3)
5973 (nu:3,ru3)
5974 (nu2)
5975 (ding3)
5976 (nai3)
5977 (qian1)
5978 (jian1)
5979 (ta1)
597A (jiu3)
597B (nan2)
597C (cha4)
597D (hao3,hao4)
597E (xian1)
597F (fan4)
5980 (ji3)
5981 (shuo4)
5982 (ru2)
5983 (fei1)
5984 (wang4)
5985 (hong2)
5986 (zhuang1)
5987 (fu4)
5988 (ma1)
5989 (dan1)
598A (ren4)
598B (fu1)
598C (jing4)
598D (yan2)
598E (xie4)
598F (wen4)
5990 (zhong1)
5991 (pa1)
5992 (du4)
5993 (ji4)
5994 (keng1)
5995 (zhong4)
5996 (yao1)
5997 (jin4)
5998 (yun2)
5999 (miao4)
599A (pei1)
599B (chi1)
599C (yue4)
599D (zhuang1)
599E (niu1)
599F (yan4)
59A0 (na4)
59A1 (xin1,xin4)
59A2 (fen2)
59A3 (bi3)
59A4 (yu2)
59A5 (tuo3)
59A6 (feng1)
59A7 (yuan2)
59A8 (fang2,fang1)
59A9 (wu3)
59AA (yu4)
59AB (gui1)
59AC (du4)
59AD (ba2)
59AE (ni1)
59AF (zhou2)
59B0 (zhou2)
59B1 (zhao1)
59B2 (da2)
59B3 (nai3,ni3)
59B4 (yuan3)
59B5 (tou3)
59B6 (xuan2)
59B7 (zhi2)
59B8 (e1)
59B9 (mei4)
59BA (mo4)
59BB (qi1,qi4)
59BC (bi4)
59BD (shen1)
59BE (qie4)
59BF (e1)
59C0 (he2)
59C1 (xu3)
59C2 (fa2)
59C3 (zheng1)
59C4 (ni1)
59C5 (ban4)
59C6 (mu3)
59C7 (fu1,fu4)
59C8 (ling2)
59C9 (zi3)
59CA (zi3)
59CB (shi3)
59CC (ran3)
59CD (shan1)
59CE (yang1)
59CF (qian2)
59D0 (jie3)
59D1 (gu1)
59D2 (si4)
59D3 (xing4)
59D4 (wei3,wei1)
59D5 (zi1)
59D6 (ju4)
59D7 (shan1)
59D8 (pin1)
59D9 (ren4)
59DA (yao2)
59DB (tong3)
59DC (jiang1)
59DD (shu1)
59DE (ji2)
59DF (gai1)
59E0 (shang4)
59E1 (kuo4)
59E2 (juan1)
59E3 (jiao1)
59E4 (gou4)
59E5 (lao3,mu3)
59E6 (jian1)
59E7 (jian1)
59E8 (yi2)
59E9 (nian2)
59EA (zhi2)
59EB (ji1)
59EC (ji1)
59ED (xian4)
59EE (heng2)
59EF (guang1)
59F0 (jun1)
59F1 (kua1)
59F2 (yan4)
59F3 (ming3)
59F4 (lie4)
59F5 (pei4)
59F6 (yan3)
59F7 (you4)
59F8 (yan2)
59F9 (cha4)
59FA (xian3)
59FB (yin1)
59FC (chi3)
59FD (gui3)
59FE (quan2)
59FF (zi1)
5A00 (song1)
5A01 (wei1)
5A02 (hong2)
5A03 (wa2)
5A04 (lou2)
5A05 (ya4)
5A06 (rao3,rao2)
5A07 (jiao1)
5A08 (luan2)
5A09 (ping1)
5A0A (xian4)
5A0B (shao4)
5A0C (li3)
5A0D (cheng2)
5A0E (xie4)
5A0F (mang2)
5A10 (none0)
5A11 (suo1)
5A12 (mu3)
5A13 (wei3)
5A14 (ke4)
5A15 (lai4)
5A16 (chuo4)
5A17 (ding4)
5A18 (niang2)
5A19 (keng1)
5A1A (nan2)
5A1B (yu2)
5A1C (na4,nuo2)
5A1D (pei1)
5A1E (sui1)
5A1F (juan1)
5A20 (shen1,chen2,zhen4)
5A21 (zhi4)
5A22 (han2)
5A23 (di4)
5A24 (zhuang1)
5A25 (e2)
5A26 (pin2)
5A27 (tui4)
5A28 (xian4)
5A29 (mian3,wan3)
5A2A (wu2)
5A2B (yan2)
5A2C (wu3)
5A2D (xi1)
5A2E (yan2)
5A2F (yu2)
5A30 (si4)
5A31 (yu2)
5A32 (wa1)
5A33 (li4)
5A34 (xian2)
5A35 (ju1)
5A36 (qu3,qu4)
5A37 (chui2)
5A38 (qi1)
5A39 (xian2)
5A3A (zhui1)
5A3B (dong1)
5A3C (chang1)
5A3D (lu4)
5A3E (ai2)
5A3F (e1)
5A40 (e1)
5A41 (lou2,lu:3)
5A42 (mian2)
5A43 (cong2)
5A44 (pou3)
5A45 (ju2)
5A46 (po2)
5A47 (cai3)
5A48 (ling2)
5A49 (wan3)
5A4A (biao3)
5A4B (xiao1)
5A4C (shu3)
5A4D (qi3)
5A4E (hui1)
5A4F (fu4)
5A50 (wo3)
5A51 (rui2)
5A52 (tan2)
5A53 (fei1)
5A54 (none0)
5A55 (jie2)
5A56 (tian1)
5A57 (ni2)
5A58 (quan2)
5A59 (jing4)
5A5A (hun1)
5A5B (jing1)
5A5C (qian1)
5A5D (dian4)
5A5E (xing4)
5A5F (hu4)
5A60 (wan2)
5A61 (lai2)
5A62 (bi4)
5A63 (yin1)
5A64 (chou1,zhou1)
5A65 (chuo4)
5A66 (fu4)
5A67 (jing4)
5A68 (lun2)
5A69 (yan4,an4)
5A6A (lan2)
5A6B (kun1)
5A6C (yin2)
5A6D (ya4)
5A6E (none0)
5A6F (li4)
5A70 (dian3)
5A71 (xian2)
5A72 (none0)
5A73 (hua4)
5A74 (ying1)
5A75 (chan2)
5A76 (shen3)
5A77 (ting2)
5A78 (yang2)
5A79 (yao3)
5A7A (wu4)
5A7B (nan4)
5A7C (chuo4)
5A7D (jia3)
5A7E (tou1)
5A7F (xu4)
5A80 (yu2)
5A81 (wei1)
5A82 (ti2)
5A83 (rou2)
5A84 (mei3)
5A85 (dan1)
5A86 (ruan3)
5A87 (qin1)
5A88 (none0)
5A89 (wu1)
5A8A (qian2)
5A8B (chun1)
5A8C (mao2)
5A8D (fu4)
5A8E (jie3)
5A8F (duan1)
5A90 (xi1)
5A91 (zhong4)
5A92 (mei2)
5A93 (huang2)
5A94 (mian2)
5A95 (an1)
5A96 (ying2)
5A97 (xuan1)
5A98 (none0)
5A99 (wei1)
5A9A (mei4)
5A9B (yuan2,yuan4)
5A9C (zhen1)
5A9D (qiu1)
5A9E (ti2,shi4)
5A9F (xie4)
5AA0 (tuo3)
5AA1 (lian4)
5AA2 (mao4)
5AA3 (ran3)
5AA4 (si1)
5AA5 (pian1)
5AA6 (wei4)
5AA7 (wa1)
5AA8 (jiu4)
5AA9 (hu2)
5AAA (ao3)
5AAB (none0)
5AAC (bao3)
5AAD (xu1)
5AAE (tou1,tou3)
5AAF (gui1)
5AB0 (zou1)
5AB1 (yao2)
5AB2 (pi4)
5AB3 (xi2)
5AB4 (yuan2)
5AB5 (ying4)
5AB6 (rong2)
5AB7 (ru4)
5AB8 (chi1)
5AB9 (liu2)
5ABA (mei3)
5ABB (pan2)
5ABC (ao3)
5ABD (ma1)
5ABE (gou4)
5ABF (kui4)
5AC0 (qin2)
5AC1 (jia4)
5AC2 (sao3)
5AC3 (zhen1)
5AC4 (yuan2)
5AC5 (cha1)
5AC6 (yong2)
5AC7 (ming2)
5AC8 (ying1)
5AC9 (ji2)
5ACA (su4)
5ACB (niao3)
5ACC (xian2)
5ACD (tao1,yao3)
5ACE (pang2)
5ACF (lang2)
5AD0 (niao3)
5AD1 (bao2)
5AD2 (ai4)
5AD3 (pi4)
5AD4 (pin2)
5AD5 (yi4)
5AD6 (piao2)
5AD7 (yu4)
5AD8 (lei2)
5AD9 (xuan2)
5ADA (man4,man1)
5ADB (yi1)
5ADC (zhang1)
5ADD (kang1)
5ADE (yong2)
5ADF (ni4)
5AE0 (li2)
5AE1 (di2)
5AE2 (gui1)
5AE3 (yan1)
5AE4 (jin4)
5AE5 (zhuan1)
5AE6 (chang2)
5AE7 (ce4)
5AE8 (han1,ran3)
5AE9 (nen4)
5AEA (lao4)
5AEB (mo2)
5AEC (zhe1)
5AED (hu4)
5AEE (hu4)
5AEF (ao4)
5AF0 (nen4)
5AF1 (qiang2)
5AF2 (none0)
5AF3 (bi4)
5AF4 (gu1)
5AF5 (wu3)
5AF6 (qiao2)
5AF7 (tuo3)
5AF8 (zhan3)
5AF9 (mao2)
5AFA (xian2)
5AFB (xian2)
5AFC (mo4)
5AFD (liao2)
5AFE (lian2)
5AFF (hua4)
5B00 (gui1)
5B01 (deng1)
5B02 (zhi2)
5B03 (xu1)
5B04 (none0)
5B05 (hua4)
5B06 (xi1)
5B07 (hui4)
5B08 (rao3,rao2)
5B09 (xi1)
5B0A (yan4)
5B0B (chan2)
5B0C (jiao1)
5B0D (mei3)
5B0E (fan4)
5B0F (fan1)
5B10 (xian1)
5B11 (yi4)
5B12 (wei4)
5B13 (chan1)
5B14 (fan4)
5B15 (shi4)
5B16 (bi4)
5B17 (shan4)
5B18 (sui4)
5B19 (qiang2)
5B1A (lian2)
5B1B (huan2,qiong2,xuan1)
5B1C (none0)
5B1D (niao3)
5B1E (dong3)
5B1F (yi4)
5B20 (can2)
5B21 (ai4)
5B22 (niang2)
5B23 (ning2)
5B24 (ma1)
5B25 (tiao3)
5B26 (chou2)
5B27 (jin4)
5B28 (ci2)
5B29 (yu2)
5B2A (pin2)
5B2B (none0)
5B2C (xu1)
5B2D (nai3)
5B2E (yan1)
5B2F (tai2)
5B30 (ying1)
5B31 (can2)
5B32 (niao3)
5B33 (none0)
5B34 (ying2)
5B35 (mian2)
5B36 (none0)
5B37 (ma1)
5B38 (shen3)
5B39 (xing4)
5B3A (ni4)
5B3B (du2)
5B3C (liu2)
5B3D (yuan1)
5B3E (lan3)
5B3F (yan4)
5B40 (shuang1)
5B41 (ling2)
5B42 (jiao3)
5B43 (niang2)
5B44 (lan3)
5B45 (xian1)
5B46 (ying1)
5B47 (shuang1)
5B48 (shuai1)
5B49 (quan2)
5B4A (mi3)
5B4B (li2)
5B4C (luan2)
5B4D (yan2)
5B4E (zhu3)
5B4F (lan3)
5B50 (zi5,zi3,zi2)
5B51 (jie2)
5B52 (jue2)
5B53 (jue2)
5B54 (kong3)
5B55 (yun4)
5B56 (zi1)
5B57 (zi4)
5B58 (cun2)
5B59 (sun1)
5B5A (fu2)
5B5B (bei4,bo2)
5B5C (zi1)
5B5D (xiao4)
5B5E (xin4)
5B5F (meng4)
5B60 (si4)
5B61 (tai1)
5B62 (bao1)
5B63 (ji4)
5B64 (gu1)
5B65 (nu2)
5B66 (xue2)
5B67 (none0)
5B68 (chan2)
5B69 (hai2)
5B6A (luan2)
5B6B (sun1)
5B6C (nao1)
5B6D (mie1)
5B6E (cong2)
5B6F (jian1)
5B70 (shu2)
5B71 (chan2,can4)
5B72 (ya1)
5B73 (zi1,zi4)
5B74 (ni3)
5B75 (fu1)
5B76 (zi1)
5B77 (li2)
5B78 (xue2,xiao2)
5B79 (bo4)
5B7A (ru2,ru4)
5B7B (nai2)
5B7C (nie4)
5B7D (nie4)
5B7E (ying1)
5B7F (luan2)
5B80 (mian2)
5B81 (ning2,ning4)
5B82 (rong3)
5B83 (ta1)
5B84 (gui3)
5B85 (zhai2,zhe4)
5B86 (qiong2)
5B87 (yu3)
5B88 (shou3)
5B89 (an1)
5B8A (tu1)
5B8B (song4)
5B8C (wan2)
5B8D (rou4)
5B8E (yao3)
5B8F (hong2)
5B90 (yi2)
5B91 (jing3)
5B92 (zhun1)
5B93 (mi4)
5B94 (guai1)
5B95 (dang4)
5B96 (hong2)
5B97 (zong1)
5B98 (guan1)
5B99 (zhou4)
5B9A (ding4)
5B9B (wan3,yuan1)
5B9C (yi2)
5B9D (bao3)
5B9E (shi2)
5B9F (shi2)
5BA0 (chong3)
5BA1 (shen3)
5BA2 (ke4)
5BA3 (xuan1)
5BA4 (shi4)
5BA5 (you4)
5BA6 (huan4)
5BA7 (yi2)
5BA8 (tiao3)
5BA9 (shi3)
5BAA (xian4)
5BAB (gong1)
5BAC (cheng2)
5BAD (qun2)
5BAE (gong1)
5BAF (xiao1)
5BB0 (zai3)
5BB1 (zha1)
5BB2 (bao3)
5BB3 (hai4)
5BB4 (yan4)
5BB5 (xiao1)
5BB6 (jia1,gu1,jie5,jia5)
5BB7 (shen3)
5BB8 (chen2)
5BB9 (rong2)
5BBA (huang3)
5BBB (mi4)
5BBC (kou4)
5BBD (kuan1)
5BBE (bin1)
5BBF (su4,xiu3,xiu4)
5BC0 (cai3,shen3)
5BC1 (zan3)
5BC2 (ji4,ji2)
5BC3 (yuan1)
5BC4 (ji4)
5BC5 (yin2)
5BC6 (mi4)
5BC7 (kou4)
5BC8 (qing1)
5BC9 (he4)
5BCA (zhen1)
5BCB (jian3)
5BCC (fu4)
5BCD (ning2)
5BCE (bing4)
5BCF (huan2)
5BD0 (mei4)
5BD1 (qin3)
5BD2 (han2)
5BD3 (yu4)
5BD4 (shi2)
5BD5 (ning2)
5BD6 (jin4)
5BD7 (ning2)
5BD8 (zhi4)
5BD9 (yu3)
5BDA (bao3)
5BDB (kuan1)
5BDC (ning2)
5BDD (qin3)
5BDE (mo4)
5BDF (cha2)
5BE0 (ju4)
5BE1 (gua3)
5BE2 (qin3)
5BE3 (hu1)
5BE4 (wu4)
5BE5 (liao2)
5BE6 (shi2)
5BE7 (ning2,ning4)
5BE8 (zhai4)
5BE9 (shen3)
5BEA (wei3)
5BEB (xie3)
5BEC (kuan1)
5BED (hui4)
5BEE (liao2)
5BEF (jun4)
5BF0 (huan2)
5BF1 (yi4)
5BF2 (yi2)
5BF3 (bao3)
5BF4 (qin1)
5BF5 (chong3)
5BF6 (bao3)
5BF7 (feng1)
5BF8 (cun4)
5BF9 (dui4)
5BFA (si4)
5BFB (xun2,xin2)
5BFC (dao3)
5BFD (lu:3,luo1)
5BFE (dui4)
5BFF (shou4)
5C00 (po3)
5C01 (feng1)
5C02 (zhuan1)
5C03 (fu1)
5C04 (she4,shi2,ye4)
5C05 (ke4)
5C06 (jiang1,jiang4,qiang1)
5C07 (jiang1,jiang4,qiang1)
5C08 (zhuan1)
5C09 (wei4,yu4)
5C0A (zun1)
5C0B (xun2,xin2)
5C0C (shu4)
5C0D (dui4)
5C0E (dao3,dao4)
5C0F (xiao3)
5C10 (ji1)
5C11 (shao3,shao4)
5C12 (er3)
5C13 (er3)
5C14 (er3)
5C15 (ga3)
5C16 (jian1)
5C17 (shu1)
5C18 (chen2)
5C19 (shang4)
5C1A (shang4)
5C1B (yuan2)
5C1C (ga2)
5C1D (chang2)
5C1E (liao2,liao3)
5C1F (xian3)
5C20 (xian1)
5C21 (none0)
5C22 (wang1,you2)
5C23 (wang1,you2)
5C24 (you2)
5C25 (liao4)
5C26 (liao4)
5C27 (yao2)
5C28 (mang2,pang2)
5C29 (wang1)
5C2A (wang1)
5C2B (wang1)
5C2C (ga4)
5C2D (yao2)
5C2E (duo4)
5C2F (kui4)
5C30 (zhong3,zhong4)
5C31 (jiu4)
5C32 (gan1)
5C33 (gu3)
5C34 (gan1)
5C35 (gan1)
5C36 (gan1)
5C37 (gan1)
5C38 (shi1)
5C39 (yin3)
5C3A (chi3,che3)
5C3B (kao1)
5C3C (ni2)
5C3D (jin3,jin4)
5C3E (wei3,yi3)
5C3F (niao4,sui1,ni4)
5C40 (ju2)
5C41 (pi4)
5C42 (ceng2)
5C43 (xi4)
5C44 (bi1,bi3)
5C45 (ju1,ji1)
5C46 (jie4)
5C47 (tian1)
5C48 (qu1)
5C49 (ti4)
5C4A (jie4)
5C4B (wu1)
5C4C (diao3)
5C4D (shi1)
5C4E (shi3)
5C4F (ping2,bing3)
5C50 (ji1)
5C51 (xie4)
5C52 (chen2)
5C53 (xi4)
5C54 (ni2)
5C55 (zhan3)
5C56 (xi1)
5C57 (none0)
5C58 (man3)
5C59 (e1)
5C5A (lou4)
5C5B (ping2)
5C5C (ti4)
5C5D (fei4)
5C5E (shu3,zhu3)
5C5F (xie4)
5C60 (tu2)
5C61 (lu:3)
5C62 (lu:3)
5C63 (xi3)
5C64 (ceng2)
5C65 (lu:3)
5C66 (ju4)
5C67 (xie4)
5C68 (ju4)
5C69 (jue2)
5C6A (liao2)
5C6B (jue2)
5C6C (shu3,zhu3)
5C6D (xi4)
5C6E (che4)
5C6F (tun2,zhun1)
5C70 (ni4)
5C71 (shan1)
5C72 (wa1)
5C73 (xian1)
5C74 (li4)
5C75 (e4)
5C76 (none0)
5C77 (none0)
5C78 (long2)
5C79 (yi4,ge1)
5C7A (qi3)
5C7B (ren4)
5C7C (wu4)
5C7D (han4)
5C7E (shen1)
5C7F (yu3)
5C80 (chu1)
5C81 (sui4)
5C82 (qi3)
5C83 (none0)
5C84 (yue4)
5C85 (ban3)
5C86 (yao3)
5C87 (ang2)
5C88 (ya2)
5C89 (wu4)
5C8A (jie2)
5C8B (e4)
5C8C (ji2)
5C8D (qian1)
5C8E (fen1)
5C8F (wan2)
5C90 (qi2)
5C91 (cen2)
5C92 (qian2)
5C93 (qi2)
5C94 (cha4)
5C95 (jie4)
5C96 (qu1)
5C97 (gang3,gang1)
5C98 (xian4)
5C99 (ao4)
5C9A (lan2)
5C9B (dao3)
5C9C (ba1)
5C9D (zhai3)
5C9E (zuo4)
5C9F (yang3)
5CA0 (ju4)
5CA1 (gang1)
5CA2 (ke3)
5CA3 (gou3)
5CA4 (xue4)
5CA5 (bo1)
5CA6 (li4)
5CA7 (tiao2)
5CA8 (qu1)
5CA9 (yan2)
5CAA (fu2)
5CAB (xiu4)
5CAC (jia3)
5CAD (ling3)
5CAE (tuo2)
5CAF (pei1)
5CB0 (you3)
5CB1 (dai4)
5CB2 (kuang4)
5CB3 (yue4)
5CB4 (qu1)
5CB5 (hu4)
5CB6 (po4)
5CB7 (min2)
5CB8 (an4)
5CB9 (tiao2)
5CBA (ling3)
5CBB (chi2)
5CBC (none0)
5CBD (dong1)
5CBE (none0)
5CBF (kui1)
5CC0 (xiu4)
5CC1 (mao3)
5CC2 (tong2)
5CC3 (xue2)
5CC4 (yi4)
5CC5 (none0)
5CC6 (he1)
5CC7 (ke1)
5CC8 (luo4)
5CC9 (e1)
5CCA (fu4)
5CCB (xun2)
5CCC (die2)
5CCD (lu4)
5CCE (lang3)
5CCF (er3)
5CD0 (gai1)
5CD1 (quan2)
5CD2 (tong2,dong4)
5CD3 (yi2)
5CD4 (mu3)
5CD5 (shi2)
5CD6 (an1)
5CD7 (wei3)
5CD8 (hu1)
5CD9 (zhi4,shi4)
5CDA (mi4)
5CDB (li3)
5CDC (ji1)
5CDD (tong2)
5CDE (kui3)
5CDF (you4)
5CE0 (none0)
5CE1 (xia2)
5CE2 (li3)
5CE3 (yao2)
5CE4 (jiao4,qiao2,jiao2)
5CE5 (zheng1)
5CE6 (luan2)
5CE7 (jiao1)
5CE8 (e2)
5CE9 (e2)
5CEA (yu4)
5CEB (ye2)
5CEC (bu1)
5CED (qiao4)
5CEE (qun1)
5CEF (feng1)
5CF0 (feng1)
5CF1 (nao2,nao1)
5CF2 (li4)
5CF3 (you2)
5CF4 (xian4)
5CF5 (hong2)
5CF6 (dao3)
5CF7 (shen1)
5CF8 (cheng2)
5CF9 (tu2)
5CFA (geng3)
5CFB (jun4)
5CFC (hao4)
5CFD (xia2)
5CFE (yin1)
5CFF (wu2,yu1)
5D00 (lang4)
5D01 (kan3)
5D02 (lao2)
5D03 (lai2)
5D04 (xian3)
5D05 (que4)
5D06 (kong1)
5D07 (chong2)
5D08 (chong2)
5D09 (ta4)
5D0A (none0)
5D0B (hua2,hua4)
5D0C (ju1)
5D0D (lai2)
5D0E (qi2)
5D0F (min2)
5D10 (kun1)
5D11 (kun1)
5D12 (zu2)
5D13 (gu4)
5D14 (cui1)
5D15 (ya2)
5D16 (ya2,ai2)
5D17 (gang3,gang1)
5D18 (lun2)
5D19 (lun2)
5D1A (leng2)
5D1B (jue2)
5D1C (duo1)
5D1D (cheng1)
5D1E (guo1)
5D1F (yin2)
5D20 (dong1)
5D21 (han2)
5D22 (zheng1)
5D23 (wei3)
5D24 (yao2,xiao2)
5D25 (pi3)
5D26 (yan1)
5D27 (song1)
5D28 (jie2)
5D29 (beng1)
5D2A (zu2)
5D2B (jue2)
5D2C (dong1)
5D2D (zhan3)
5D2E (gu4)
5D2F (yin2)
5D30 (zi1)
5D31 (ze2)
5D32 (huang2)
5D33 (yu2)
5D34 (wei1,wai3)
5D35 (yang2)
5D36 (feng1)
5D37 (qiu2)
5D38 (dun4)
5D39 (ti2)
5D3A (yi3)
5D3B (zhi4)
5D3C (shi4)
5D3D (zai3)
5D3E (yao3)
5D3F (e4)
5D40 (zhu4)
5D41 (kan1)
5D42 (lu:4)
5D43 (yan3)
5D44 (mei3)
5D45 (gan1,gan4)
5D46 (ji1)
5D47 (ji1)
5D48 (huan4)
5D49 (ting2)
5D4A (sheng4)
5D4B (mei2)
5D4C (qian4,qian1,kan4)
5D4D (wu4)
5D4E (yu2)
5D4F (zong1)
5D50 (lan2)
5D51 (jie2,he2)
5D52 (yan2)
5D53 (yan2)
5D54 (wei3)
5D55 (zong1)
5D56 (cha2)
5D57 (sui4)
5D58 (rong2)
5D59 (ke1)
5D5A (qin1)
5D5B (yu2)
5D5C (qi2)
5D5D (lou3)
5D5E (tu2)
5D5F (dui1)
5D60 (xi1)
5D61 (weng1)
5D62 (cang1)
5D63 (dang1)
5D64 (rong2)
5D65 (jie2)
5D66 (ai2)
5D67 (liu2)
5D68 (wu3)
5D69 (song1)
5D6A (qiao1)
5D6B (zi1)
5D6C (wei2)
5D6D (beng1)
5D6E (dian1)
5D6F (cuo2)
5D70 (qian3)
5D71 (yong2)
5D72 (nie4)
5D73 (cuo2)
5D74 (ji2)
5D75 (none0)
5D76 (none0)
5D77 (song3)
5D78 (zong1)
5D79 (jiang4)
5D7A (liao2)
5D7B (none0)
5D7C (chan3)
5D7D (di4)
5D7E (cen1)
5D7F (ding3)
5D80 (tu1,die2)
5D81 (lou3)
5D82 (zhang4)
5D83 (zhan3)
5D84 (zhan3)
5D85 (ao2)
5D86 (cao2)
5D87 (qu1)
5D88 (qiang1)
5D89 (zui1)
5D8A (zui3)
5D8B (dao3)
5D8C (dao3)
5D8D (xi2)
5D8E (yu4)
5D8F (bo2)
5D90 (long2)
5D91 (xiang3)
5D92 (ceng2)
5D93 (bo1)
5D94 (qin1)
5D95 (jiao1)
5D96 (yan3)
5D97 (lao2)
5D98 (zhan4)
5D99 (lin2)
5D9A (liao2)
5D9B (liao2)
5D9C (jin1)
5D9D (deng4)
5D9E (duo4)
5D9F (zun1)
5DA0 (jiao4,qiao2)
5DA1 (gui4)
5DA2 (yao2)
5DA3 (qiao2)
5DA4 (yao2)
5DA5 (jue2)
5DA6 (zhan1)
5DA7 (yi4)
5DA8 (xue1)
5DA9 (nao2)
5DAA (ye4)
5DAB (ye4)
5DAC (yi1)
5DAD (e4)
5DAE (xian3)
5DAF (ji2)
5DB0 (xie4)
5DB1 (ke3)
5DB2 (sui3)
5DB3 (di4)
5DB4 (ao4)
5DB5 (zui4)
5DB6 (none0)
5DB7 (yi2)
5DB8 (rong2)
5DB9 (dao3)
5DBA (ling3)
5DBB (za2)
5DBC (yu3)
5DBD (yue4)
5DBE (yin3)
5DBF (none0)
5DC0 (jie2)
5DC1 (li4)
5DC2 (sui3,xi1)
5DC3 (long2)
5DC4 (long2)
5DC5 (dian1)
5DC6 (ying2)
5DC7 (xi1)
5DC8 (ju2)
5DC9 (chan2)
5DCA (ying3)
5DCB (kui1)
5DCC (yan2)
5DCD (wei1,wei2)
5DCE (nao2)
5DCF (quan2)
5DD0 (chao1)
5DD1 (cuan2)
5DD2 (luan2)
5DD3 (dian1)
5DD4 (dian1)
5DD5 (nie4)
5DD6 (yan2)
5DD7 (yan2)
5DD8 (yan3)
5DD9 (nao2)
5DDA (yan3)
5DDB (chuan1)
5DDC (gui4)
5DDD (chuan1)
5DDE (zhou1)
5DDF (huang1)
5DE0 (jing1)
5DE1 (xun2)
5DE2 (chao2)
5DE3 (chao2)
5DE4 (lie4)
5DE5 (gong1)
5DE6 (zuo3)
5DE7 (qiao3)
5DE8 (ju4)
5DE9 (gong3)
5DEA (none0)
5DEB (wu1,wu2)
5DEC (none0)
5DED (none0)
5DEE (cha1,cha4,chai1,ci1)
5DEF (qiu2)
5DF0 (qiu2)
5DF1 (ji3)
5DF2 (yi3)
5DF3 (si4)
5DF4 (ba1)
5DF5 (zhi1)
5DF6 (zhao1)
5DF7 (xiang4,hang4)
5DF8 (yi2)
5DF9 (jin3)
5DFA (xun4)
5DFB (juan4,juan3)
5DFC (none0)
5DFD (xun4)
5DFE (jin1)
5DFF (fu2)
5E00 (za1)
5E01 (bi4)
5E02 (shi4)
5E03 (bu4)
5E04 (ding1)
5E05 (shuai4)
5E06 (fan1,fan2)
5E07 (nie4)
5E08 (shi1)
5E09 (fen1)
5E0A (pa4)
5E0B (zhi3)
5E0C (xi1)
5E0D (hu4)
5E0E (dan4)
5E0F (wei2)
5E10 (zhang4)
5E11 (tang3)
5E12 (dai4)
5E13 (ma4)
5E14 (pei4)
5E15 (pa4)
5E16 (tie1,tie3,tie4)
5E17 (fu2)
5E18 (lian2)
5E19 (zhi4)
5E1A (zhou3)
5E1B (bo2)
5E1C (zhi4)
5E1D (di4)
5E1E (mo4)
5E1F (yi4)
5E20 (yi4)
5E21 (ping2)
5E22 (qia4)
5E23 (juan4)
5E24 (ru2)
5E25 (shuai4,shuo4)
5E26 (dai4)
5E27 (zhen1)
5E28 (shui4)
5E29 (qiao4)
5E2A (zhen1)
5E2B (shi1)
5E2C (qun2)
5E2D (xi2)
5E2E (bang1)
5E2F (dai4)
5E30 (gui1)
5E31 (chou2,dao4)
5E32 (ping2)
5E33 (zhang4)
5E34 (sha1)
5E35 (wan1)
5E36 (dai4)
5E37 (wei2)
5E38 (chang2)
5E39 (sha4)
5E3A (qi2)
5E3B (ze2)
5E3C (guo2)
5E3D (mao4)
5E3E (du3)
5E3F (hou2)
5E40 (zhen1,zheng4)
5E41 (xu1)
5E42 (mi4)
5E43 (wei2)
5E44 (wo4)
5E45 (fu2)
5E46 (yi4)
5E47 (bang1)
5E48 (ping2)
5E49 (none0)
5E4A (gong1)
5E4B (pan2)
5E4C (huang3)
5E4D (dao1,tao1)
5E4E (mi4)
5E4F (jia1)
5E50 (teng2)
5E51 (hui1)
5E52 (zhong1)
5E53 (sen1)
5E54 (man4)
5E55 (mu4)
5E56 (biao1)
5E57 (guo2)
5E58 (ze2)
5E59 (mu4)
5E5A (bang1)
5E5B (zhang4)
5E5C (jiong3)
5E5D (chan3)
5E5E (fu2)
5E5F (zhi4)
5E60 (hu1)
5E61 (fan1)
5E62 (chuang2,zhuang4)
5E63 (bi4)
5E64 (bi4)
5E65 (none0)
5E66 (mi4)
5E67 (qiao1)
5E68 (dan4)
5E69 (fen2)
5E6A (meng2)
5E6B (bang1)
5E6C (chou2,dao4)
5E6D (mie4)
5E6E (chu2)
5E6F (jie1)
5E70 (xian3)
5E71 (lan2)
5E72 (gan1,gan4)
5E73 (ping2)
5E74 (nian2)
5E75 (jian1)
5E76 (bing4,bing1)
5E77 (bing4)
5E78 (xing4)
5E79 (gan4,gan1)
5E7A (yao1)
5E7B (huan4)
5E7C (you4)
5E7D (you1)
5E7E (ji3,ji1)
5E7F (guang3,an1)
5E80 (pi3)
5E81 (ting1)
5E82 (ze4)
5E83 (guang3,an1)
5E84 (zhuang1)
5E85 (mo5)
5E86 (qing4)
5E87 (bi4)
5E88 (qin2)
5E89 (dun4)
5E8A (chuang2)
5E8B (gui3)
5E8C (ya3)
5E8D (bai4)
5E8E (jie4)
5E8F (xu4)
5E90 (lu2)
5E91 (wu3)
5E92 (none0)
5E93 (ku4)
5E94 (ying1,ying4)
5E95 (di3,de5)
5E96 (pao2)
5E97 (dian4)
5E98 (ya1)
5E99 (miao4)
5E9A (geng1)
5E9B (ci1)
5E9C (fu3)
5E9D (tong2)
5E9E (pang2)
5E9F (fei4)
5EA0 (xiang2)
5EA1 (yi3)
5EA2 (zhi4)
5EA3 (tiao1)
5EA4 (zhi4)
5EA5 (xiu1)
5EA6 (du4,duo2,duo4)
5EA7 (zuo4)
5EA8 (xiao1)
5EA9 (tu2)
5EAA (gui3)
5EAB (ku4)
5EAC (pang2,mang3)
5EAD (ting2)
5EAE (you3)
5EAF (bu1)
5EB0 (bing3)
5EB1 (cheng3)
5EB2 (lai2)
5EB3 (bi4,bei1)
5EB4 (ji2)
5EB5 (an1)
5EB6 (shu4)
5EB7 (kang1)
5EB8 (yong1)
5EB9 (tuo3)
5EBA (song1)
5EBB (shu4)
5EBC (qing3)
5EBD (yu4)
5EBE (yu3)
5EBF (miao4)
5EC0 (sou1)
5EC1 (ce4,ci4)
5EC2 (xiang1)
5EC3 (fei4)
5EC4 (jiu4)
5EC5 (he2)
5EC6 (hui4)
5EC7 (liu4)
5EC8 (sha4,xia4)
5EC9 (lian2)
5ECA (lang2)
5ECB (sou1)
5ECC (jian1)
5ECD (pou3)
5ECE (qing3)
5ECF (jiu4)
5ED0 (jiu4)
5ED1 (qin2,jin3)
5ED2 (ao2)
5ED3 (kuo4)
5ED4 (lou2)
5ED5 (yin4)
5ED6 (liao4)
5ED7 (dai4)
5ED8 (lu4)
5ED9 (yi4)
5EDA (chu2)
5EDB (chan2)
5EDC (tu2)
5EDD (si1)
5EDE (xin1)
5EDF (miao4)
5EE0 (chang3,an1)
5EE1 (wu3)
5EE2 (fei4)
5EE3 (guang3,an1)
5EE4 (none0)
5EE5 (guai4)
5EE6 (bi4)
5EE7 (qiang2)
5EE8 (xie4)
5EE9 (lin3)
5EEA (lin3)
5EEB (liao2)
5EEC (lu2)
5EED (none0)
5EEE (ying2)
5EEF (xian1)
5EF0 (ting1)
5EF1 (yong1)
5EF2 (li2)
5EF3 (ting1)
5EF4 (yin3)
5EF5 (xun2)
5EF6 (yan2)
5EF7 (ting2)
5EF8 (di2)
5EF9 (po4)
5EFA (jian4)
5EFB (hui2)
5EFC (nai3)
5EFD (hui2)
5EFE (gong3)
5EFF (nian4)
5F00 (kai1)
5F01 (bian4)
5F02 (yi4)
5F03 (qi4)
5F04 (nong4,long4)
5F05 (fen2)
5F06 (ju3)
5F07 (yan3)
5F08 (yi4)
5F09 (zang4,zhuang3)
5F0A (bi4)
5F0B (yi4)
5F0C (yi1)
5F0D (er4)
5F0E (san1)
5F0F (shi4)
5F10 (er4)
5F11 (shi4)
5F12 (shi4)
5F13 (gong1)
5F14 (diao4)
5F15 (yin3)
5F16 (hu4)
5F17 (fu2)
5F18 (hong2)
5F19 (wu1)
5F1A (tui2)
5F1B (chi2)
5F1C (qiang2,qiang3)
5F1D (ba4)
5F1E (shen3)
5F1F (di4)
5F20 (zhang1)
5F21 (jue2)
5F22 (tao1)
5F23 (fu3)
5F24 (di3)
5F25 (mi2)
5F26 (xian2)
5F27 (hu2)
5F28 (chao1)
5F29 (nu3)
5F2A (jing4)
5F2B (zhen3)
5F2C (yi2)
5F2D (mi3)
5F2E (quan1)
5F2F (wan1)
5F30 (shao1)
5F31 (ruo4)
5F32 (xuan1)
5F33 (jing4)
5F34 (diao1)
5F35 (zhang1)
5F36 (jiang4)
5F37 (qiang2,jiang4,qiang3)
5F38 (beng1)
5F39 (dan4,tan2)
5F3A (qiang2,qiang3,jiang4)
5F3B (bi4)
5F3C (bi4)
5F3D (she4)
5F3E (dan4,tan2)
5F3F (jian3)
5F40 (gou4)
5F41 (none0)
5F42 (fa1)
5F43 (bi4)
5F44 (kou1)
5F45 (none0)
5F46 (bie4)
5F47 (xiao1)
5F48 (dan4,tan2)
5F49 (kuang4)
5F4A (qiang2,jiang4)
5F4B (hong2)
5F4C (mi2)
5F4D (kuo4)
5F4E (wan1)
5F4F (jue2)
5F50 (ji4)
5F51 (ji4)
5F52 (gui1)
5F53 (dang1,dang4)
5F54 (lu4)
5F55 (lu4)
5F56 (tuan4)
5F57 (hui4)
5F58 (zhi4)
5F59 (hui4)
5F5A (hui4)
5F5B (yi2)
5F5C (yi2)
5F5D (yi2)
5F5E (yi2)
5F5F (huo4)
5F60 (huo4)
5F61 (shan1)
5F62 (xing2)
5F63 (zhang1)
5F64 (tong2)
5F65 (yan4)
5F66 (yan4)
5F67 (yu4)
5F68 (chi1)
5F69 (cai3)
5F6A (biao1)
5F6B (diao1)
5F6C (bin1)
5F6D (peng2)
5F6E (yong3)
5F6F (piao4)
5F70 (zhang1)
5F71 (ying3)
5F72 (chi1)
5F73 (chi4)
5F74 (zhuo2)
5F75 (tuo3)
5F76 (ji2)
5F77 (pang2,fang3)
5F78 (zhong1)
5F79 (yi4)
5F7A (wang2)
5F7B (che4)
5F7C (bi3)
5F7D (di1)
5F7E (ling3)
5F7F (fu2)
5F80 (wang3,wang4)
5F81 (zheng1)
5F82 (cu2)
5F83 (wang3,wang4)
5F84 (jing4)
5F85 (dai4,dai1)
5F86 (xi1)
5F87 (xun4,xun2)
5F88 (hen3)
5F89 (yang2)
5F8A (huai2,hui2)
5F8B (lu:4)
5F8C (hou4)
5F8D (wang3)
5F8E (cheng3)
5F8F (zhi4)
5F90 (xu2)
5F91 (jing4)
5F92 (tu2)
5F93 (cong2)
5F94 (none0)
5F95 (lai2)
5F96 (cong2)
5F97 (de2,de5,dei3)
5F98 (pai2)
5F99 (xi3)
5F9A (none0)
5F9B (qi1)
5F9C (chang2)
5F9D (zhi4)
5F9E (cong2,cong1,zong4)
5F9F (zhou1)
5FA0 (lai2)
5FA1 (yu4)
5FA2 (xie4)
5FA3 (jie4)
5FA4 (jian4)
5FA5 (chi2,shi4)
5FA6 (jia3)
5FA7 (bian4)
5FA8 (huang2)
5FA9 (fu4)
5FAA (xun2)
5FAB (wei3)
5FAC (pang2)
5FAD (yao2)
5FAE (wei1,wei2)
5FAF (xi1)
5FB0 (zheng1)
5FB1 (piao4)
5FB2 (chi2)
5FB3 (de2)
5FB4 (zheng1)
5FB5 (zhi3,zheng1)
5FB6 (bie2)
5FB7 (de2)
5FB8 (chong1)
5FB9 (che4)
5FBA (jiao3)
5FBB (wei4)
5FBC (jiao4,jiao3,jia3)
5FBD (hui1)
5FBE (mei2)
5FBF (long4)
5FC0 (xiang1)
5FC1 (bao4)
5FC2 (qu2)
5FC3 (xin1)
5FC4 (xin1)
5FC5 (bi4)
5FC6 (yi4)
5FC7 (le4)
5FC8 (ren2)
5FC9 (dao1)
5FCA (ding4)
5FCB (gai3)
5FCC (ji4)
5FCD (ren3)
5FCE (ren2)
5FCF (chan4)
5FD0 (tan3)
5FD1 (te4)
5FD2 (te4,tui1,tei1)
5FD3 (gan1)
5FD4 (qi4)
5FD5 (dai4)
5FD6 (cun3)
5FD7 (zhi4)
5FD8 (wang4,wang2)
5FD9 (mang2)
5FDA (xi1)
5FDB (fan2)
5FDC (ying1,ying4)
5FDD (tian3)
5FDE (min2)
5FDF (min2)
5FE0 (zhong1)
5FE1 (chong1)
5FE2 (wu4)
5FE3 (ji2)
5FE4 (wu3)
5FE5 (xi4)
5FE6 (ye4)
5FE7 (you1)
5FE8 (wan4)
5FE9 (zong3)
5FEA (zhong1,song1)
5FEB (kuai4)
5FEC (yu4)
5FED (bian4)
5FEE (zhi4)
5FEF (chi2)
5FF0 (cui4)
5FF1 (chen2)
5FF2 (tai4)
5FF3 (tun2)
5FF4 (qian2)
5FF5 (nian4)
5FF6 (hun2)
5FF7 (xiong1)
5FF8 (niu3,nu:4)
5FF9 (wang3)
5FFA (xian1)
5FFB (xin1)
5FFC (kang1)
5FFD (hu1)
5FFE (kai4)
5FFF (fen4)
6000 (huai2)
6001 (tai4)
6002 (song3)
6003 (wu3)
6004 (ou4)
6005 (chang4)
6006 (chuang4)
6007 (ju4)
6008 (yi4)
6009 (bao3)
600A (chao1)
600B (min2)
600C (pi1)
600D (zuo4)
600E (zen3,ze3)
600F (yang4)
6010 (kou4)
6011 (ban4)
6012 (nu4)
6013 (nao2)
6014 (zheng1,zheng4)
6015 (pa4)
6016 (bu4)
6017 (tie1)
6018 (hu4)
6019 (hu4)
601A (ju4)
601B (da2)
601C (lian2,ling2)
601D (si1,sai1)
601E (zhou4)
601F (di4)
6020 (dai4)
6021 (yi2)
6022 (tu2)
6023 (you2)
6024 (fu1)
6025 (ji2)
6026 (peng1)
6027 (xing4)
6028 (yuan4)
6029 (ni2)
602A (guai4)
602B (fu2,fei4)
602C (xi4)
602D (bi4)
602E (you1)
602F (qie4,que4)
6030 (xuan4)
6031 (zong1)
6032 (bing3)
6033 (huang3)
6034 (xu4)
6035 (chu4)
6036 (pi1)
6037 (xi1)
6038 (xi1)
6039 (tan1)
603A (none0)
603B (zong3)
603C (dui4)
603D (none0)
603E (none0)
603F (yi4)
6040 (chi3)
6041 (nen4,ren4,nin2)
6042 (xun2)
6043 (shi4)
6044 (xi4)
6045 (lao3)
6046 (heng2)
6047 (kuang1)
6048 (mou2,mu4)
6049 (zhi3)
604A (xie2)
604B (lian4)
604C (tiao1)
604D (huang3)
604E (die2)
604F (hao3)
6050 (kong3)
6051 (gui3)
6052 (heng2)
6053 (xi1)
6054 (xiao4)
6055 (shu4)
6056 (sai1,si1)
6057 (hu1)
6058 (qiu1)
6059 (yang4)
605A (hui4)
605B (hui2)
605C (chi4)
605D (jia2)
605E (yi2)
605F (xiong1)
6060 (guai4)
6061 (lin4)
6062 (hui1)
6063 (zi4)
6064 (xu4)
6065 (chi3)
6066 (xiang4)
6067 (nu:4)
6068 (hen4)
6069 (en1)
606A (ke4,que4)
606B (dong4,tong1)
606C (tian2)
606D (gong1)
606E (quan2)
606F (xi1,xi2)
6070 (qia4)
6071 (yue4)
6072 (peng1)
6073 (ken3)
6074 (de2)
6075 (hui4)
6076 (e4,e3,wu4,wu1)
6077 (none0)
6078 (tong4)
6079 (yan1)
607A (kai3)
607B (ce4)
607C (nao3)
607D (yun4)
607E (mang2)
607F (yong3)
6080 (yong3)
6081 (juan4)
6082 (mang2)
6083 (kun3)
6084 (qiao3,qiao1)
6085 (yue4)
6086 (yu4)
6087 (yu4)
6088 (jie4)
6089 (xi1)
608A (zhe2,qi1)
608B (lin4)
608C (ti4)
608D (han4)
608E (hao4)
608F (qie4)
6090 (ti4)
6091 (bu4)
6092 (yi4)
6093 (qian4)
6094 (hui3)
6095 (xi1)
6096 (bei4)
6097 (man2)
6098 (yi2)
6099 (heng1)
609A (song3)
609B (quan1)
609C (cheng3)
609D (kui1,li3)
609E (wu4)
609F (wu4)
60A0 (you1)
60A1 (li2)
60A2 (liang4)
60A3 (huan4)
60A4 (cong1)
60A5 (yi4)
60A6 (yue4)
60A7 (li4)
60A8 (nin2)
60A9 (nao3)
60AA (e4,e3,wu4)
60AB (que4)
60AC (xuan2)
60AD (qian1)
60AE (wu4)
60AF (min3)
60B0 (cong2)
60B1 (fei3)
60B2 (bei1)
60B3 (de2)
60B4 (cui4)
60B5 (chang4)
60B6 (men4,men1)
60B7 (li4)
60B8 (ji4)
60B9 (guan4)
60BA (guan4)
60BB (xing4)
60BC (dao4)
60BD (qi1)
60BE (kong1)
60BF (tian3)
60C0 (lun2)
60C1 (xi1)
60C2 (kan3)
60C3 (kun1)
60C4 (ni4)
60C5 (qing2,qing5)
60C6 (chou2)
60C7 (dun1)
60C8 (guo3)
60C9 (chan1)
60CA (jing1)
60CB (wan3)
60CC (yuan1)
60CD (jin1)
60CE (ji4)
60CF (lin2)
60D0 (yu4)
60D1 (huo4)
60D2 (he2)
60D3 (quan1)
60D4 (yan3)
60D5 (ti4)
60D6 (ti4)
60D7 (nie1)
60D8 (wang3)
60D9 (chuo4)
60DA (hu1)
60DB (hun1)
60DC (xi1,xi2)
60DD (chang3)
60DE (xin1)
60DF (wei2)
60E0 (hui4)
60E1 (e4,e3,wu4,wu1)
60E2 (rui3)
60E3 (zong3)
60E4 (jian1)
60E5 (yong3)
60E6 (dian4)
60E7 (ju4)
60E8 (can3,can4)
60E9 (cheng2)
60EA (de2)
60EB (bei4)
60EC (qie4)
60ED (can2)
60EE (dan4)
60EF (guan4)
60F0 (duo4)
60F1 (nao3)
60F2 (yun4)
60F3 (xiang3)
60F4 (zhui4)
60F5 (die2)
60F6 (huang2)
60F7 (chun3)
60F8 (qiong2)
60F9 (re3)
60FA (xing1)
60FB (ce4)
60FC (bian3)
60FD (hun1)
60FE (zong1)
60FF (ti2)
6100 (qiao3)
6101 (chou2)
6102 (bei4)
6103 (xuan1)
6104 (wei1)
6105 (ge2)
6106 (qian1)
6107 (wei3)
6108 (yu4)
6109 (yu2)
610A (bi4)
610B (xuan1)
610C (huan4)
610D (min3)
610E (bi4)
610F (yi4)
6110 (mian3)
6111 (yong3)
6112 (kai4,qi4)
6113 (dang4)
6114 (yin1)
6115 (e4)
6116 (chen2)
6117 (mou4)
6118 (qia4)
6119 (ke4)
611A (yu2)
611B (ai4)
611C (qie4)
611D (yan3)
611E (nuo4)
611F (gan3)
6120 (yun4)
6121 (zong3)
6122 (sai1)
6123 (leng4)
6124 (fen4)
6125 (none0)
6126 (kui4)
6127 (kui4)
6128 (que4)
6129 (gong1)
612A (yun2)
612B (su4)
612C (su4)
612D (qi2)
612E (yao2)
612F (song3)
6130 (huang4)
6131 (none0)
6132 (gu3)
6133 (ju4)
6134 (chuang4)
6135 (ta1)
6136 (xie2)
6137 (kai3)
6138 (zheng3)
6139 (yong3)
613A (cao3)
613B (sun4)
613C (shen4)
613D (bo2)
613E (kai4)
613F (yuan4)
6140 (xie2)
6141 (hun4)
6142 (yong3)
6143 (yang3)
6144 (li4)
6145 (sao1)
6146 (tao1)
6147 (yin1)
6148 (ci2)
6149 (xu4)
614A (qian4,qie4)
614B (tai4)
614C (huang1,huang5)
614D (yun4)
614E (shen4)
614F (ming3)
6150 (none0)
6151 (she4)
6152 (cong2)
6153 (piao1)
6154 (mo4)
6155 (mu4)
6156 (guo2)
6157 (chi4)
6158 (can3,can4)
6159 (can2)
615A (can2)
615B (cui2)
615C (min3)
615D (ni4,te4)
615E (zhang1)
615F (tong4)
6160 (ao4)
6161 (shuang3)
6162 (man4)
6163 (guan4)
6164 (que4)
6165 (zao4)
6166 (jiu4)
6167 (hui4)
6168 (kai3,kai4)
6169 (lian2)
616A (ou4,ou1)
616B (song3)
616C (jin3)
616D (yin4)
616E (lu:4)
616F (shang1)
6170 (wei4)
6171 (tuan2)
6172 (man2)
6173 (qian1)
6174 (zhe2)
6175 (yong1)
6176 (qing4)
6177 (kang1,kang3)
6178 (di4)
6179 (zhi2)
617A (lu:2)
617B (juan4)
617C (qi1)
617D (qi1)
617E (yu4)
617F (ping2)
6180 (liao2)
6181 (zong3)
6182 (you1)
6183 (chuang1)
6184 (zhi4)
6185 (tong4)
6186 (cheng1)
6187 (qi4)
6188 (qu1)
6189 (peng2)
618A (bei4)
618B (bie1)
618C (chun2)
618D (jiao1)
618E (zeng1)
618F (chi4)
6190 (lian2)
6191 (ping2)
6192 (kui4)
6193 (hui4)
6194 (qiao2)
6195 (cheng2)
6196 (yin4)
6197 (yin4)
6198 (xi3)
6199 (xi3)
619A (dan4)
619B (tan2)
619C (duo4)
619D (dui4)
619E (dui4)
619F (su4)
61A0 (jue4)
61A1 (ce4)
61A2 (xiao1)
61A3 (fan2)
61A4 (fen4)
61A5 (lao2)
61A6 (lao4)
61A7 (chong1)
61A8 (han1)
61A9 (qi4)
61AA (xian2)
61AB (min3)
61AC (jing3)
61AD (liao3)
61AE (wu3)
61AF (can3)
61B0 (jue2)
61B1 (chou4)
61B2 (xian4)
61B3 (tan3)
61B4 (sheng2)
61B5 (pi1)
61B6 (yi4)
61B7 (chu4)
61B8 (xian1)
61B9 (nao2)
61BA (dan4)
61BB (tan3)
61BC (jing3)
61BD (song1)
61BE (han4)
61BF (jiao1)
61C0 (wei4)
61C1 (huan2)
61C2 (dong3)
61C3 (qin2)
61C4 (qin2)
61C5 (qu2)
61C6 (cao3)
61C7 (ken3)
61C8 (xie4)
61C9 (ying4,ying1)
61CA (ao4)
61CB (mao4)
61CC (yi4)
61CD (lin3)
61CE (se4)
61CF (jun4)
61D0 (huai2)
61D1 (men4)
61D2 (lan3)
61D3 (ai4)
61D4 (lin3)
61D5 (yan1)
61D6 (gua1)
61D7 (xia4)
61D8 (chi4)
61D9 (yu3)
61DA (yin4)
61DB (dai1)
61DC (meng3)
61DD (ai4)
61DE (meng3)
61DF (dui4)
61E0 (qi2)
61E1 (mo3)
61E2 (lan2)
61E3 (men4)
61E4 (chou2)
61E5 (zhi4)
61E6 (nuo4)
61E7 (nuo4)
61E8 (yan1,yan4)
61E9 (yang3)
61EA (bo2)
61EB (zhi2)
61EC (xing4)
61ED (kuang4)
61EE (you1)
61EF (fu2)
61F0 (liu2)
61F1 (mie4)
61F2 (cheng2)
61F3 (none0)
61F4 (chan4)
61F5 (meng3)
61F6 (lan3)
61F7 (huai2)
61F8 (xuan2)
61F9 (rang4)
61FA (chan4)
61FB (ji4)
61FC (ju4)
61FD (huan1)
61FE (she4,zhe2)
61FF (yi4)
6200 (lian4)
6201 (nan3)
6202 (mi2)
6203 (tang3)
6204 (jue2)
6205 (gang4)
6206 (gang4,zhuang4)
6207 (zhuang4)
6208 (ge1)
6209 (yue4)
620A (wu4)
620B (jian1)
620C (xu1,qu5)
620D (shu4)
620E (rong2)
620F (xi4,hu1)
6210 (cheng2)
6211 (wo3)
6212 (jie4)
6213 (ge1)
6214 (jian1)
6215 (qiang1)
6216 (huo4)
6217 (qiang1,qiang4)
6218 (zhan4)
6219 (dong4)
621A (qi1)
621B (jia2)
621C (die2)
621D (cai2)
621E (jia2)
621F (ji3)
6220 (shi4,chi4)
6221 (kan1)
6222 (ji2)
6223 (kui2)
6224 (gai4)
6225 (deng3)
6226 (zhan4)
6227 (chuang1,qiang1,qiang4)
6228 (ge1)
6229 (jian3)
622A (jie2)
622B (yu4)
622C (jian3)
622D (yan3)
622E (lu4)
622F (xi4,hu1)
6230 (zhan4)
6231 (xi4)
6232 (xi4,hu1)
6233 (chuo1)
6234 (dai4)
6235 (qu2)
6236 (hu4)
6237 (hu4)
6238 (hu4)
6239 (e4)
623A (shi4)
623B (li4)
623C (mao3)
623D (hu4)
623E (li4)
623F (fang2)
6240 (suo3)
6241 (bian3,pian1)
6242 (dian4)
6243 (jiong1)
6244 (shang3)
6245 (yi2)
6246 (yi3)
6247 (shan4,shan1)
6248 (hu4)
6249 (fei1)
624A (yan3)
624B (shou3)
624C (shou3)
624D (cai2)
624E (zha1,za1,zha2)
624F (qiu2)
6250 (le4)
6251 (pu1)
6252 (ba1,pa2,pa1)
6253 (da3,da2)
6254 (reng1)
6255 (fu2,bi4)
6256 (none0)
6257 (zai4)
6258 (tuo1)
6259 (zhang4)
625A (diao1)
625B (kang2,gang1)
625C (yu1)
625D (ku1)
625E (han4)
625F (shen1)
6260 (cha1)
6261 (chi3)
6262 (gu3)
6263 (kou4)
6264 (wu4)
6265 (tuo1)
6266 (qian1)
6267 (zhi2)
6268 (cha1)
6269 (kuo4)
626A (men2)
626B (sao3,sao4)
626C (yang2)
626D (niu3)
626E (ban4)
626F (che3)
6270 (rao3)
6271 (xi1)
6272 (qian2)
6273 (ban1,pan1)
6274 (jia2)
6275 (yu2)
6276 (fu2)
6277 (ao4)
6278 (xi1)
6279 (pi1)
627A (zhi3)
627B (zi4)
627C (e4)
627D (dun4)
627E (zhao3)
627F (cheng2)
6280 (ji4)
6281 (yan3)
6282 (kuang2)
6283 (bian4)
6284 (chao1)
6285 (ju1)
6286 (wen4)
6287 (hu2)
6288 (yue4)
6289 (jue2)
628A (ba3,ba4)
628B (qin4)
628C (zhen3)
628D (zheng3)
628E (yun3)
628F (wan2)
6290 (na4)
6291 (yi4)
6292 (shu1)
6293 (zhua1)
6294 (pou2)
6295 (tou2)
6296 (dou3)
6297 (kang4)
6298 (zhe2,she2,zhe1)
6299 (pou2)
629A (fu3)
629B (pao1)
629C (ba2)
629D (ao3)
629E (ze2,zhai2)
629F (tuan2)
62A0 (kou1)
62A1 (lun2,lun1)
62A2 (qiang3,qiang1)
62A3 (none0)
62A4 (hu4)
62A5 (bao4)
62A6 (bing3)
62A7 (zhi3)
62A8 (peng1)
62A9 (tan1)
62AA (pu1)
62AB (pi1)
62AC (tai2)
62AD (yao3)
62AE (zhen3)
62AF (zha1)
62B0 (yang3)
62B1 (bao4)
62B2 (he1)
62B3 (ni3)
62B4 (yi4)
62B5 (di3)
62B6 (chi4)
62B7 (pi1)
62B8 (za1)
62B9 (mo3,ma1,mo4)
62BA (mo3)
62BB (chen1,shen4)
62BC (ya1,ya2)
62BD (chou1)
62BE (qu1)
62BF (min3)
62C0 (chu4)
62C1 (jia1)
62C2 (fu2,bi4)
62C3 (zha3)
62C4 (zhu3)
62C5 (dan1,dan4,dan3)
62C6 (chai1,ca1)
62C7 (mu3)
62C8 (nian1,nian3)
62C9 (la1,la2,la3,la4)
62CA (fu3)
62CB (pao1)
62CC (ban4)
62CD (pai1)
62CE (lin1)
62CF (na2)
62D0 (guai3)
62D1 (qian2)
62D2 (ju4)
62D3 (tuo4,ta4)
62D4 (ba2)
62D5 (tuo1)
62D6 (tuo1)
62D7 (ao4,niu4,yao4,ao3)
62D8 (ju1)
62D9 (zhuo1,zhuo2)
62DA (pan4,pin1)
62DB (zhao1)
62DC (bai4)
62DD (bai4)
62DE (di3)
62DF (ni3)
62E0 (ju4,ju1)
62E1 (kuo4)
62E2 (long3)
62E3 (jian3)
62E4 (qia2)
62E5 (yong1)
62E6 (lan2)
62E7 (ning3,ning2,ning4)
62E8 (bo1)
62E9 (ze2,zhai2)
62EA (qian1)
62EB (hen2)
62EC (kuo4,gua1)
62ED (shi4)
62EE (jie2)
62EF (zheng3)
62F0 (nin3)
62F1 (gong3)
62F2 (gong3)
62F3 (quan2)
62F4 (shuan1)
62F5 (tun2)
62F6 (zan3,za1)
62F7 (kao3)
62F8 (chi3)
62F9 (xie2)
62FA (ce4)
62FB (hui1)
62FC (pin1)
62FD (zhuai4,ye4,zhuai1)
62FE (shi2,she4)
62FF (na2)
6300 (bo4)
6301 (chi2)
6302 (gua4)
6303 (zhi4)
6304 (kuo4)
6305 (duo3)
6306 (duo3)
6307 (zhi3,zhi1,zhi2)
6308 (qie4)
6309 (an4)
630A (nong4,long4)
630B (zhen4)
630C (ge2)
630D (jiao4)
630E (kua4)
630F (dong4)
6310 (ru2,na2)
6311 (tiao3,tiao1)
6312 (lie4)
6313 (zha1)
6314 (lu:3)
6315 (die2)
6316 (wa1)
6317 (jue2)
6318 (none0)
6319 (ju3)
631A (zhi4)
631B (luan2)
631C (ya4)
631D (wo1,zhua1)
631E (ta4)
631F (xie2,jia1)
6320 (nao2)
6321 (dang3,dang4)
6322 (jiao3,jia3)
6323 (zheng1,zheng4)
6324 (ji3)
6325 (hui1)
6326 (xian2)
6327 (none0)
6328 (ai1,ai2)
6329 (tuo1)
632A (nuo2)
632B (cuo4)
632C (bo2)
632D (geng3)
632E (ti3)
632F (zhen4)
6330 (cheng2)
6331 (suo1)
6332 (suo1,sa1,sha1)
6333 (keng1,keng3)
6334 (mei3)
6335 (long4,nong4)
6336 (ju2)
6337 (peng2)
6338 (jian3)
6339 (yi4)
633A (ting3)
633B (shan1)
633C (nuo4)
633D (wan3)
633E (xie2,jia2,xia2)
633F (cha1)
6340 (feng1)
6341 (jiao3,jia3)
6342 (wu3,wu2)
6343 (jun4)
6344 (jiu4)
6345 (tong3)
6346 (kun3)
6347 (huo4)
6348 (tu2)
6349 (zhuo1)
634A (pou2)
634B (lu:3,luo1)
634C (ba1)
634D (han4)
634E (shao1,shao4)
634F (nie1)
6350 (juan1)
6351 (she4)
6352 (shu4)
6353 (ye2)
6354 (jue2)
6355 (bu3)
6356 (huan2)
6357 (bu4)
6358 (jun4)
6359 (yi4)
635A (zhai1)
635B (lu:3)
635C (sou1)
635D (tuo1)
635E (lao1)
635F (sun3)
6360 (bang1)
6361 (jian3)
6362 (huan4)
6363 (dao3)
6364 (none0)
6365 (wan4)
6366 (qin2)
6367 (peng3)
6368 (she3,she4)
6369 (lie4)
636A (min2)
636B (men2)
636C (fu3)
636D (bai3)
636E (ju4,ju1)
636F (dao2)
6370 (wo3)
6371 (ai2,ai1)
6372 (juan3)
6373 (yue4)
6374 (zong3)
6375 (chen3)
6376 (chui2)
6377 (jie2)
6378 (tu1)
6379 (ben4)
637A (na4)
637B (nian3)
637C (nuo2)
637D (zu2)
637E (wo4)
637F (xi1,qi1)
6380 (xian1)
6381 (cheng2)
6382 (dian1)
6383 (sao3,sao4)
6384 (lun2,lun1)
6385 (qing4)
6386 (gang1)
6387 (duo1,duo5)
6388 (shou4)
6389 (diao4)
638A (pou2,pou3)
638B (di3)
638C (zhang3)
638D (gun3)
638E (ji3)
638F (tao1)
6390 (qia1)
6391 (qi2)
6392 (pai2,pai3)
6393 (shu2)
6394 (qian1)
6395 (ling2)
6396 (ye4,ye1,yi4)
6397 (ya3)
6398 (jue2)
6399 (zheng1,zheng4)
639A (liang3)
639B (gua4)
639C (yi3)
639D (huo4)
639E (shan4)
639F (ding4)
63A0 (lu:e4,lu:e3)
63A1 (cai3)
63A2 (tan4,tan1)
63A3 (che4)
63A4 (bing1)
63A5 (jie1)
63A6 (ti1)
63A7 (kong4)
63A8 (tui1)
63A9 (yan3)
63AA (cuo4)
63AB (zou1)
63AC (ju1,ju2)
63AD (tian4)
63AE (qian2)
63AF (ken4)
63B0 (bai1,bo4)
63B1 (shou3,pa2)
63B2 (jie1)
63B3 (lu3)
63B4 (guai1,guo2)
63B5 (none0)
63B6 (none0)
63B7 (zhi4,zhi1)
63B8 (dan3,shan4,shan3)
63B9 (none0)
63BA (chan1,shan3,can4)
63BB (sao1)
63BC (guan4)
63BD (peng4)
63BE (yuan4)
63BF (nuo4)
63C0 (jian3)
63C1 (zheng1)
63C2 (jiu1)
63C3 (jian1)
63C4 (yu2)
63C5 (yan2)
63C6 (kui2)
63C7 (nan3)
63C8 (hong1)
63C9 (rou2)
63CA (pi4)
63CB (wei1)
63CC (sai1)
63CD (zou4)
63CE (xuan1)
63CF (miao2)
63D0 (ti2,di1,shi2)
63D1 (nie1)
63D2 (cha1)
63D3 (shi4)
63D4 (zong3)
63D5 (zhen4)
63D6 (yi1)
63D7 (shun3)
63D8 (heng2)
63D9 (bian4)
63DA (yang2)
63DB (huan4)
63DC (yan3)
63DD (zan3)
63DE (an3)
63DF (xu1,ju1)
63E0 (ya4)
63E1 (wo4)
63E2 (ke4)
63E3 (chuai3,chuai1,chuai4)
63E4 (ji2,jie2)
63E5 (ti4)
63E6 (la2)
63E7 (la4)
63E8 (cheng2)
63E9 (kai1)
63EA (jiu1)
63EB (jiu1)
63EC (tu2)
63ED (jie1)
63EE (hui1)
63EF (geng1)
63F0 (chong4)
63F1 (shuo4)
63F2 (she2,die2)
63F3 (xie1)
63F4 (yuan2)
63F5 (qian2)
63F6 (ye2)
63F7 (cha1)
63F8 (zha1)
63F9 (bei1)
63FA (yao2)
63FB (none0)
63FC (none0)
63FD (lan3)
63FE (wen4)
63FF (qin4)
6400 (chan1)
6401 (ge1,ge2)
6402 (lou3,lou1)
6403 (zong3)
6404 (geng1)
6405 (jiao3,jia3)
6406 (gou4)
6407 (qin4)
6408 (yong3)
6409 (que4)
640A (chou1)
640B (chuai1)
640C (zhan3)
640D (sun3)
640E (sun1)
640F (bo2)
6410 (chu4)
6411 (rong3)
6412 (bang4,peng2)
6413 (cuo1)
6414 (sao1)
6415 (ke4)
6416 (yao2)
6417 (dao3)
6418 (zhi1)
6419 (nu4)
641A (xie2)
641B (jian1)
641C (sou1)
641D (qiu3)
641E (gao3)
641F (xian3)
6420 (shuo4)
6421 (sang3)
6422 (jin4)
6423 (mie4)
6424 (e4)
6425 (chui2)
6426 (nuo4)
6427 (shan1)
6428 (ta4)
6429 (jie2)
642A (tang2)
642B (pan2)
642C (ban1)
642D (da1)
642E (li4)
642F (tao1)
6430 (hu2)
6431 (zhi4)
6432 (wa1)
6433 (xia2)
6434 (qian1)
6435 (wen4)
6436 (qiang3,chuang3,qiang1)
6437 (chen1)
6438 (zhen1)
6439 (e4)
643A (xie2)
643B (nuo4)
643C (quan2)
643D (cha2)
643E (zha4)
643F (ge2)
6440 (wu3)
6441 (en4)
6442 (she4)
6443 (gong4)
6444 (she4)
6445 (shu1)
6446 (bai3)
6447 (yao2)
6448 (bin4)
6449 (sou1)
644A (tan1)
644B (sha1)
644C (chan3)
644D (suo1)
644E (liao2)
644F (chong1)
6450 (chuang1)
6451 (guo2,guai1)
6452 (bing4)
6453 (feng2)
6454 (shuai1)
6455 (di4)
6456 (qi4)
6457 (none0)
6458 (zhai1,zhe2)
6459 (lian3)
645A (cheng1)
645B (chi1)
645C (guan4)
645D (lu4)
645E (luo4)
645F (lou3,lou1)
6460 (zong3)
6461 (gai4,xi4)
6462 (hu4)
6463 (zha1)
6464 (chuang3)
6465 (tang4)
6466 (hua4)
6467 (cui1)
6468 (nai2)
6469 (mo2,ma1)
646A (jiang1)
646B (gui1)
646C (ying4)
646D (zhi2)
646E (ao2)
646F (zhi4)
6470 (chi4)
6471 (man2)
6472 (shan4)
6473 (kou1)
6474 (shu1)
6475 (suo3)
6476 (tuan2)
6477 (zhao1)
6478 (mo1,mo2)
6479 (mo2)
647A (zhe2)
647B (chan1,shan3)
647C (keng1)
647D (biao1,biao4)
647E (jiang4)
647F (yin1)
6480 (gou4)
6481 (qian1)
6482 (liao4,liao1,liao2)
6483 (ji1)
6484 (ying1)
6485 (jue1)
6486 (pie1)
6487 (pie3,pie1)
6488 (lao1)
6489 (dun1)
648A (xian4)
648B (ruan2)
648C (kui4)
648D (zan3)
648E (yi4)
648F (xian2)
6490 (cheng1)
6491 (cheng1)
6492 (sa1,sa3)
6493 (nao2)
6494 (heng4)
6495 (si1)
6496 (han4)
6497 (huang2)
6498 (da1)
6499 (zun3)
649A (nian3)
649B (lin3)
649C (zheng3)
649D (hui1)
649E (zhuang4,chuang2)
649F (jiao3,jia3)
64A0 (ji3)
64A1 (cao1)
64A2 (dan3)
64A3 (dan3,shan3,shan4)
64A4 (che4)
64A5 (bo1)
64A6 (che3)
64A7 (jue2)
64A8 (xiao1)
64A9 (liao2,liao1,liao4)
64AA (ben4)
64AB (fu3)
64AC (qiao4)
64AD (bo1,bo4)
64AE (cuo1,zuo3,cuo4,cuo3)
64AF (zhuo2)
64B0 (zhuan4)
64B1 (tuo3)
64B2 (pu1)
64B3 (qin4)
64B4 (dun1)
64B5 (nian3)
64B6 (none0)
64B7 (xie2)
64B8 (lu1)
64B9 (jiao3,jia3)
64BA (cuan1)
64BB (ta4)
64BC (han4)
64BD (qiao4)
64BE (zhua1,wo1)
64BF (jian3)
64C0 (gan3)
64C1 (yong3,yong1)
64C2 (lei2,lei4,lei1)
64C3 (kuo3)
64C4 (lu3)
64C5 (shan4)
64C6 (zhuo2)
64C7 (ze2,zhai2)
64C8 (pu1)
64C9 (chuo4)
64CA (ji2,ji1)
64CB (dang3,dang4)
64CC (se4)
64CD (cao1,cao4)
64CE (qing2)
64CF (jing4)
64D0 (huan4)
64D1 (jie1)
64D2 (qin2)
64D3 (kuai3)
64D4 (dan1,dan3,dan4)
64D5 (xie2)
64D6 (ge3)
64D7 (pi3)
64D8 (bo4,bai1)
64D9 (ao4)
64DA (ju4,ju1)
64DB (ye4)
64DC (none0)
64DD (none0)
64DE (sou3,sou4)
64DF (mi2)
64E0 (ji3)
64E1 (tai2)
64E2 (zhuo2)
64E3 (dao3)
64E4 (xing3)
64E5 (lan3)
64E6 (ca1)
64E7 (ju3)
64E8 (ye2)
64E9 (ru3)
64EA (ye4)
64EB (ye4)
64EC (ni3)
64ED (huo4)
64EE (ji2)
64EF (bin4)
64F0 (ning3,ning2)
64F1 (ge1,ge2)
64F2 (zhi4,zhi2)
64F3 (jie2)
64F4 (kuo4)
64F5 (mo2,ma1)
64F6 (jian4)
64F7 (xie2)
64F8 (lie4)
64F9 (tan1)
64FA (bai3)
64FB (sou3,sou4)
64FC (lu1)
64FD (lu:e4)
64FE (rao3)
64FF (zhi2)
6500 (pan1)
6501 (yang3)
6502 (lei4)
6503 (sa4)
6504 (shu1)
6505 (zan3,cuan2)
6506 (nian3)
6507 (xian3)
6508 (jun4)
6509 (huo1)
650A (lu:e4)
650B (la4)
650C (han4)
650D (ying2)
650E (lu2)
650F (long3)
6510 (qian1)
6511 (qian1)
6512 (zan3,cuan2)
6513 (qian1)
6514 (lan2)
6515 (san1)
6516 (ying1)
6517 (mei2)
6518 (rang3,rang2)
6519 (chan1)
651A (none0)
651B (cuan1)
651C (xie2,xi1)
651D (she4)
651E (luo1)
651F (jun4)
6520 (mi2)
6521 (li2)
6522 (zan3,cuan2)
6523 (luan2)
6524 (tan1)
6525 (zuan4)
6526 (li4)
6527 (dian1)
6528 (wa1)
6529 (dang3)
652A (jiao3,gao3,jia3)
652B (jue2)
652C (lan3)
652D (li4)
652E (nang3)
652F (zhi1)
6530 (gui4)
6531 (gui3)
6532 (qi1)
6533 (xin2)
6534 (po1)
6535 (po1)
6536 (shou1)
6537 (kao3)
6538 (you1)
6539 (gai3)
653A (gai3)
653B (gong1)
653C (gan1)
653D (ban1)
653E (fang4)
653F (zheng4)
6540 (bo2)
6541 (dian1)
6542 (kou4)
6543 (min3)
6544 (wu4)
6545 (gu4)
6546 (ge2)
6547 (ce4)
6548 (xiao4)
6549 (mi3)
654A (chu4)
654B (ge2)
654C (di2)
654D (xu4)
654E (jiao4)
654F (min3)
6550 (chen2)
6551 (jiu4)
6552 (shen1)
6553 (duo2)
6554 (yu3)
6555 (chi4)
6556 (ao2)
6557 (bai4)
6558 (xu4)
6559 (jiao4,jiao1)
655A (duo2)
655B (lian3)
655C (nie4)
655D (bi4)
655E (chang3,tang3)
655F (dian4)
6560 (duo2)
6561 (yi4)
6562 (gan3)
6563 (san4,san3,san5)
6564 (ke3)
6565 (yan4)
6566 (dun1,dui4)
6567 (qi3)
6568 (dou3)
6569 (xiao4)
656A (duo2)
656B (jiao3,jia3)
656C (jing4)
656D (yang2)
656E (xia2)
656F (hun1,min3)
6570 (shu4,shu3,shuo4)
6571 (ai2)
6572 (qiao1)
6573 (ai2)
6574 (zheng3)
6575 (di2)
6576 (zhen4)
6577 (fu1)
6578 (shu4,shu3,shuo4)
6579 (liao2)
657A (qu1)
657B (xiong4)
657C (xi3)
657D (jiao3)
657E (none0)
657F (qiao2)
6580 (zhuo2)
6581 (yi4,du4)
6582 (lian4,lian3)
6583 (bi4)
6584 (li4)
6585 (xue2)
6586 (xiao4)
6587 (wen2,wen4)
6588 (xue2)
6589 (qi2,ji4,qi4)
658A (qi2,ji4,qi4)
658B (zhai1)
658C (bin1)
658D (jue2)
658E (zhai1)
658F (lang3)
6590 (fei3)
6591 (ban1)
6592 (ban1)
6593 (lan2)
6594 (yu3)
6595 (lan2)
6596 (wei3)
6597 (dou4,dou3)
6598 (sheng1)
6599 (liao4)
659A (jia3)
659B (hu2)
659C (xie2,xia2)
659D (jia3)
659E (yu3)
659F (zhen1)
65A0 (jiao4)
65A1 (wo4)
65A2 (tiao3,tou4)
65A3 (dou4)
65A4 (jin1,jin5)
65A5 (chi4)
65A6 (yin2)
65A7 (fu3)
65A8 (qiang1)
65A9 (zhan3)
65AA (qu2,ju1)
65AB (zhuo2)
65AC (zhan3)
65AD (duan4)
65AE (zhuo2)
65AF (si1)
65B0 (xin1)
65B1 (zhuo2)
65B2 (zhuo2)
65B3 (qin2)
65B4 (lin2)
65B5 (zhuo2)
65B6 (chu4)
65B7 (duan4)
65B8 (zhu3)
65B9 (fang1)
65BA (xie4)
65BB (hang2)
65BC (wu1,yu1,yu2)
65BD (shi1)
65BE (pei4)
65BF (you2)
65C0 (none0)
65C1 (pang2,bang4)
65C2 (qi2)
65C3 (zhan1)
65C4 (mao2,mao4)
65C5 (lu:3)
65C6 (pei4)
65C7 (pi1)
65C8 (liu2)
65C9 (fu1)
65CA (fang3)
65CB (xuan2,xuan4)
65CC (jing1)
65CD (jing1)
65CE (ni3)
65CF (zu2)
65D0 (zhao4)
65D1 (yi3)
65D2 (liu2)
65D3 (shao1)
65D4 (jian4)
65D5 (none0)
65D6 (yi3)
65D7 (qi2)
65D8 (zhi4)
65D9 (fan1)
65DA (piao1)
65DB (fan1)
65DC (zhan1)
65DD (guai4)
65DE (sui4)
65DF (yu2)
65E0 (wu2,mo2)
65E1 (ji4)
65E2 (ji4)
65E3 (ji4)
65E4 (huo4)
65E5 (ri4)
65E6 (dan4)
65E7 (jiu4)
65E8 (zhi3)
65E9 (zao3)
65EA (xie2)
65EB (tiao1)
65EC (xun2)
65ED (xu4)
65EE (ga1)
65EF (la2)
65F0 (gan4)
65F1 (han4)
65F2 (tai2)
65F3 (di4)
65F4 (xu1)
65F5 (chan3)
65F6 (shi2)
65F7 (kuang4)
65F8 (yang2)
65F9 (shi2)
65FA (wang4)
65FB (min2)
65FC (min2)
65FD (tun1)
65FE (chun1)
65FF (wu4)
6600 (yun2)
6601 (bei4)
6602 (ang2)
6603 (ze4)
6604 (ban3)
6605 (jie2)
6606 (kun1)
6607 (sheng1)
6608 (hu4)
6609 (fang3)
660A (hao4)
660B (gui4)
660C (chang1)
660D (xuan1)
660E (ming2)
660F (hun1)
6610 (fen1)
6611 (qin3)
6612 (hu1)
6613 (yi4)
6614 (xi1,xi2)
6615 (xin1)
6616 (yan2)
6617 (ze4)
6618 (fang3)
6619 (tan2)
661A (shen4)
661B (ju4)
661C (yang2)
661D (zan3)
661E (bing3)
661F (xing1)
6620 (ying4)
6621 (xuan4)
6622 (pei3)
6623 (zhen3)
6624 (ling2)
6625 (chun1)
6626 (hao4)
6627 (mei4)
6628 (zuo2)
6629 (mo4)
662A (bian4)
662B (xu4)
662C (hun1)
662D (zhao1)
662E (zong4)
662F (shi4)
6630 (shi4)
6631 (yu4)
6632 (fei4,fu2)
6633 (die2)
6634 (mao3)
6635 (ni4,ni3)
6636 (chang3)
6637 (wen1)
6638 (dong1)
6639 (ai3)
663A (bing3)
663B (ang2)
663C (zhou4)
663D (long2)
663E (xian3)
663F (kuang4)
6640 (tiao3)
6641 (chao2,zhao1,zhao4)
6642 (shi2)
6643 (huang3,huang4)
6644 (huang3,huang4)
6645 (xuan1)
6646 (kui2)
6647 (xu1,kua1)
6648 (jiao3)
6649 (jin4)
664A (zhi3)
664B (jin4)
664C (shang3)
664D (tong2)
664E (hong3)
664F (yan4)
6650 (gai1)
6651 (xiang3)
6652 (shai4)
6653 (xiao3)
6654 (ye4)
6655 (yun1,yun4)
6656 (hui1)
6657 (han2)
6658 (han4)
6659 (jun4)
665A (wan3)
665B (xian4)
665C (kun1)
665D (zhou4)
665E (xi1)
665F (sheng4,cheng2)
6660 (sheng4)
6661 (bu1)
6662 (zhe2,zhe1,zhe5)
6663 (zhe1)
6664 (wu4)
6665 (han4)
6666 (hui4)
6667 (hao4)
6668 (chen2)
6669 (wan3)
666A (tian3)
666B (zhuo1)
666C (zui4)
666D (zhou3)
666E (pu3)
666F (jing3,ying3)
6670 (xi1)
6671 (shan3)
6672 (yi3)
6673 (xi1)
6674 (qing2)
6675 (qi3)
6676 (jing1)
6677 (gui3)
6678 (zhen3)
6679 (yi4)
667A (zhi4)
667B (an3)
667C (wan3)
667D (lin2)
667E (liang4)
667F (chang1)
6680 (wang3)
6681 (xiao3)
6682 (zan4)
6683 (none0)
6684 (xuan1)
6685 (geng4)
6686 (yi2)
6687 (xia2,xia4)
6688 (yun1,yun4)
6689 (hui1)
668A (fu3)
668B (min3,min2)
668C (kui2)
668D (he4)
668E (ying4)
668F (du3)
6690 (wei3)
6691 (shu3)
6692 (qing2)
6693 (mao4)
6694 (nan2)
6695 (jian3)
6696 (nuan3)
6697 (an4)
6698 (yang2)
6699 (chun1)
669A (yao2)
669B (suo3)
669C (pu3)
669D (ming2,ming4)
669E (jiao3)
669F (kai3)
66A0 (gao3)
66A1 (weng3)
66A2 (chang4)
66A3 (qi4)
66A4 (hao4)
66A5 (yan4)
66A6 (li4)
66A7 (ai4)
66A8 (ji4)
66A9 (gui4)
66AA (men3)
66AB (zan4,zhan4)
66AC (xie4)
66AD (hao4)
66AE (mu4)
66AF (mo4)
66B0 (cong1)
66B1 (ni4)
66B2 (zhang1)
66B3 (hui4)
66B4 (bao4,pu4)
66B5 (han4)
66B6 (xuan2)
66B7 (chuan2)
66B8 (liao3)
66B9 (xian1)
66BA (dan4)
66BB (jing3)
66BC (pie1)
66BD (lin2)
66BE (tun1)
66BF (xi3)
66C0 (yi4)
66C1 (ji4)
66C2 (kuang4)
66C3 (dai4)
66C4 (ye4)
66C5 (ye4)
66C6 (li4)
66C7 (tan2)
66C8 (tong2)
66C9 (xiao3)
66CA (fei4)
66CB (qin3)
66CC (zhao4)
66CD (hao4)
66CE (yi4)
66CF (xiang4)
66D0 (xing1)
66D1 (sen1)
66D2 (jiao3)
66D3 (bao4)
66D4 (jing4)
66D5 (none0)
66D6 (ai4)
66D7 (ye4)
66D8 (ru2)
66D9 (shu3,shu4)
66DA (meng2)
66DB (xun1)
66DC (yao4,yue4)
66DD (pu4,bao4)
66DE (li4)
66DF (chen2)
66E0 (kuang4)
66E1 (die2)
66E2 (none0)
66E3 (yan4)
66E4 (huo4)
66E5 (lu2)
66E6 (xi1)
66E7 (rong2)
66E8 (long2)
66E9 (nang3)
66EA (luo3)
66EB (luan2)
66EC (shai4)
66ED (tang3)
66EE (yan3)
66EF (chu2)
66F0 (yue1)
66F1 (yue1)
66F2 (qu3,qu1)
66F3 (ye4,zhuai4,yi4)
66F4 (geng4,geng1)
66F5 (zhuai4)
66F6 (hu1)
66F7 (he2)
66F8 (shu1)
66F9 (cao2)
66FA (cao2)
66FB (sheng1)
66FC (man4)
66FD (ceng2,zeng1)
66FE (ceng2,zeng1)
66FF (ti4)
6700 (zui4)
6701 (can3)
6702 (xu4)
6703 (hui4,hui3,kuai4)
6704 (yin4)
6705 (qie4)
6706 (fen1)
6707 (pi2,bi4)
6708 (yue4)
6709 (you3,you4)
670A (ruan3)
670B (peng2)
670C (ban1)
670D (fu2,fu4)
670E (ling2)
670F (fei3)
6710 (qu2)
6711 (none0)
6712 (nu:4)
6713 (tiao4,tiao3)
6714 (shuo4)
6715 (zhen4)
6716 (lang3)
6717 (lang3)
6718 (juan1,zui1)
6719 (ming2)
671A (huang1)
671B (wang4)
671C (tun1)
671D (chao2,zhao1)
671E (ji1,qi1)
671F (qi1,ji1,qi2)
6720 (ying1)
6721 (zong3)
6722 (wang4)
6723 (tong2)
6724 (lang3)
6725 (none0)
6726 (meng2)
6727 (long2)
6728 (mu4)
6729 (deng3)
672A (wei4)
672B (mo4)
672C (ben3)
672D (zha2)
672E (zhu2)
672F (shu4,zhu2)
6730 (none0)
6731 (zhu1)
6732 (ren2)
6733 (ba1)
6734 (po4,piao2,pu3,po1,pu2)
6735 (duo3)
6736 (duo3)
6737 (dao1)
6738 (li4)
6739 (qiu2)
673A (ji1)
673B (jiu1)
673C (bi3)
673D (xiu3)
673E (ting2)
673F (ci4)
6740 (sha1)
6741 (none0)
6742 (za2)
6743 (quan2)
6744 (qian1)
6745 (yu2)
6746 (gan1,gan3)
6747 (wu1)
6748 (cha1,cha4)
6749 (shan1,sha1)
674A (xun2)
674B (fan2)
674C (wu4)
674D (zi3)
674E (li3)
674F (xing4)
6750 (cai2)
6751 (cun1)
6752 (ren4)
6753 (shao2,biao1)
6754 (zhe2)
6755 (di4)
6756 (zhang4)
6757 (mang2)
6758 (chi4)
6759 (yi4)
675A (gu3)
675B (gong1)
675C (du4)
675D (yi2)
675E (qi3)
675F (shu4)
6760 (gang1,gang4)
6761 (tiao2)
6762 (none0)
6763 (none0)
6764 (none0)
6765 (lai2)
6766 (shan1)
6767 (mang2)
6768 (yang2)
6769 (ma4)
676A (miao3)
676B (si4)
676C (yuan2)
676D (hang2)
676E (fei4)
676F (bei1)
6770 (jie2)
6771 (dong1)
6772 (gao3)
6773 (yao3,miao3)
6774 (xian1)
6775 (chu3)
6776 (chun1)
6777 (pa2,ba5)
6778 (shu1)
6779 (hua4)
677A (xin2)
677B (chou3,niu3)
677C (zhu4)
677D (chou3)
677E (song1)
677F (ban3)
6780 (song1)
6781 (ji2)
6782 (yue4)
6783 (yun2)
6784 (gou4)
6785 (ji1)
6786 (mao2)
6787 (pi2)
6788 (bi4)
6789 (wang3)
678A (ang4)
678B (fang1)
678C (fen2)
678D (yi4)
678E (fu2)
678F (nan2)
6790 (xi1)
6791 (hu4)
6792 (ya2)
6793 (dou3)
6794 (xun2)
6795 (zhen3,zhen4)
6796 (yao3)
6797 (lin2)
6798 (rui4)
6799 (e4)
679A (mei2)
679B (zhao4)
679C (guo3)
679D (zhi1,qi2)
679E (zong1,cong1)
679F (yun4)
67A0 (none0)
67A1 (dou3)
67A2 (shu1)
67A3 (zao3)
67A4 (none0)
67A5 (li4)
67A6 (lu2)
67A7 (jian3)
67A8 (cheng2)
67A9 (song1)
67AA (qiang1)
67AB (feng1)
67AC (nan2)
67AD (xiao1)
67AE (xian1)
67AF (ku1)
67B0 (ping2)
67B1 (tai2)
67B2 (xi3)
67B3 (zhi3,zhi1)
67B4 (guai3)
67B5 (xiao1)
67B6 (jia4)
67B7 (jia1)
67B8 (gou3,gou1,ju3)
67B9 (bao1,fu2)
67BA (mo4)
67BB (yi4)
67BC (ye4)
67BD (sang1)
67BE (shi4)
67BF (nie4)
67C0 (bi3)
67C1 (tuo2,duo4,duo1)
67C2 (yi2)
67C3 (ling2)
67C4 (bing3,bing4)
67C5 (ni3)
67C6 (la1)
67C7 (he2)
67C8 (ban4)
67C9 (fan2,bian1)
67CA (zhong1)
67CB (dai4)
67CC (ci2)
67CD (yang1)
67CE (fu1)
67CF (bo2,bai3,bo4)
67D0 (mou3)
67D1 (gan1)
67D2 (qi1)
67D3 (ran3)
67D4 (rou2)
67D5 (mao4)
67D6 (zhao1)
67D7 (song1)
67D8 (zhe4)
67D9 (xia2)
67DA (you4,you2)
67DB (shen1)
67DC (ju3,gui4)
67DD (tuo4)
67DE (zuo4,zha4)
67DF (nan2)
67E0 (ning2)
67E1 (yong3)
67E2 (di3)
67E3 (zhi2)
67E4 (zha1)
67E5 (cha2,zha1)
67E6 (dan4)
67E7 (gu1)
67E8 (none0)
67E9 (jiu4)
67EA (ao1)
67EB (fu2,bi4)
67EC (jian3)
67ED (bo1)
67EE (duo4)
67EF (ke1)
67F0 (nai4)
67F1 (zhu4)
67F2 (bi4)
67F3 (liu3)
67F4 (chai2)
67F5 (zha4)
67F6 (si4)
67F7 (zhu4)
67F8 (pei1)
67F9 (shi4)
67FA (guai3)
67FB (cha2,zha1)
67FC (yao2)
67FD (cheng1)
67FE (jiu4)
67FF (shi4)
6800 (zhi1)
6801 (liu3)
6802 (mei2)
6803 (none0)
6804 (rong2)
6805 (zha4,shan1)
6806 (none0)
6807 (biao1)
6808 (zhan4)
6809 (zhi4)
680A (long2)
680B (dong4)
680C (lu2)
680D (none0)
680E (li4,yue4)
680F (lan2)
6810 (yong3)
6811 (shu4)
6812 (xun2)
6813 (shuan1)
6814 (qi4)
6815 (zhen1)
6816 (qi1,xi1)
6817 (li4)
6818 (chi2,yi2)
6819 (xiang2)
681A (zhen4)
681B (li4)
681C (su4)
681D (gua1,kuo4)
681E (kan1)
681F (bing1,ben1)
6820 (ren3)
6821 (xiao4,jiao4)
6822 (bo2,bai3)
6823 (ren3)
6824 (bing4)
6825 (zi1)
6826 (chou2)
6827 (yi4)
6828 (ci4)
6829 (xu3)
682A (zhu1)
682B (jian4)
682C (zui4)
682D (er2)
682E (er3)
682F (yu4)
6830 (fa2)
6831 (gong3)
6832 (kao3)
6833 (lao3)
6834 (zhan1)
6835 (li4)
6836 (none0)
6837 (yang4)
6838 (he2,hu2)
6839 (gen1)
683A (zhi3)
683B (chi4)
683C (ge2)
683D (zai1)
683E (luan2)
683F (fa2)
6840 (jie2)
6841 (heng2,hang2)
6842 (gui4)
6843 (tao2)
6844 (guang4,guang1)
6845 (wei2)
6846 (kuang4,kuang1)
6847 (ru2)
6848 (an4)
6849 (an1)
684A (juan4)
684B (yi2)
684C (zhuo1)
684D (ku1)
684E (zhi4,zhi2)
684F (qiong2)
6850 (tong2)
6851 (sang1)
6852 (sang1)
6853 (huan2)
6854 (jie2,ju2)
6855 (jiu4)
6856 (xue4)
6857 (duo4)
6858 (zhui1)
6859 (yu2)
685A (zan3)
685B (none0)
685C (ying1)
685D (none0)
685E (none0)
685F (zhan4)
6860 (ya1)
6861 (rao2)
6862 (zhen1)
6863 (dang4)
6864 (qi1)
6865 (qiao2)
6866 (hua4)
6867 (gui4,hui4)
6868 (jiang3)
6869 (zhuang1)
686A (xun2)
686B (suo1)
686C (suo1)
686D (zhen4)
686E (bei1)
686F (ting1)
6870 (kuo4)
6871 (jing4)
6872 (bo2)
6873 (ben4)
6874 (fu2)
6875 (rui3)
6876 (tong3)
6877 (jue2)
6878 (xi1)
6879 (lang2)
687A (liu3)
687B (feng1)
687C (qi1)
687D (wen3)
687E (jun1)
687F (gan3)
6880 (cu4)
6881 (liang2)
6882 (qiu2)
6883 (ting3,ting4)
6884 (you3)
6885 (mei2)
6886 (bang1)
6887 (long4)
6888 (peng1)
6889 (zhuang1)
688A (di4)
688B (xuan1)
688C (tu2)
688D (zao4)
688E (ao1)
688F (gu4)
6890 (bi4)
6891 (di2)
6892 (han2)
6893 (zi3)
6894 (zhi1)
6895 (ren4)
6896 (bei4)
6897 (geng3)
6898 (jian3)
6899 (huan4)
689A (wan3)
689B (nuo2)
689C (jia2)
689D (tiao2)
689E (ji4)
689F (xiao1)
68A0 (lu:3)
68A1 (kuan3)
68A2 (shao1,sao4)
68A3 (cen2)
68A4 (fen1)
68A5 (song1)
68A6 (meng4)
68A7 (wu2)
68A8 (li2)
68A9 (li2)
68AA (dou4)
68AB (cen1)
68AC (ying3)
68AD (suo1)
68AE (ju2)
68AF (ti1)
68B0 (xie4)
68B1 (kun3)
68B2 (zhuo2)
68B3 (shu1)
68B4 (chan1)
68B5 (fan4)
68B6 (wei3)
68B7 (jing4)
68B8 (li2)
68B9 (bing1,bin1)
68BA (none0)
68BB (none0)
68BC (tao2)
68BD (zhi4)
68BE (lai2)
68BF (lian2)
68C0 (jian3)
68C1 (zhuo1)
68C2 (ling2)
68C3 (li2)
68C4 (qi4)
68C5 (bing3)
68C6 (lun2)
68C7 (cong1)
68C8 (qian4)
68C9 (mian2)
68CA (qi2)
68CB (qi2)
68CC (cai3)
68CD (gun4)
68CE (chan2)
68CF (de2)
68D0 (fei3)
68D1 (pai2)
68D2 (bang4)
68D3 (pou3,bang4)
68D4 (hun1)
68D5 (zong1)
68D6 (cheng2)
68D7 (zao3)
68D8 (ji2)
68D9 (li4)
68DA (peng2)
68DB (yu4)
68DC (yu4)
68DD (gu4)
68DE (hun2)
68DF (dong4)
68E0 (tang2)
68E1 (gang1)
68E2 (wang3)
68E3 (di4)
68E4 (xi2)
68E5 (fan2)
68E6 (cheng1)
68E7 (zhan4)
68E8 (qi3)
68E9 (yuan1)
68EA (yan3)
68EB (yu4)
68EC (quan1)
68ED (yi4)
68EE (sen1)
68EF (ren3)
68F0 (chui2)
68F1 (leng2,ling2,leng1)
68F2 (qi1,xi1)
68F3 (zhuo2)
68F4 (fu2)
68F5 (ke1)
68F6 (lai2)
68F7 (zou1)
68F8 (zou1)
68F9 (zhao4,zhuo1)
68FA (guan1)
68FB (fen1)
68FC (fen2)
68FD (chen1)
68FE (qiong2)
68FF (nie4)
6900 (wan3)
6901 (guo3)
6902 (lu4)
6903 (hao2)
6904 (jie1)
6905 (yi3,yi1)
6906 (chou2)
6907 (ju3)
6908 (ju2)
6909 (cheng2,sheng4)
690A (zuo2)
690B (liang2)
690C (qiang1)
690D (zhi2)
690E (zhui1,chui2)
690F (ya1)
6910 (ju1)
6911 (bei1,pi2)
6912 (jiao1)
6913 (zhuo2)
6914 (zi1)
6915 (bin1)
6916 (peng2)
6917 (ding4)
6918 (chu3)
6919 (shan1)
691A (none0)
691B (none0)
691C (jian3)
691D (gui1)
691E (xi4)
691F (du2)
6920 (qian4)
6921 (none0)
6922 (kui4)
6923 (none0)
6924 (luo2)
6925 (zhi1)
6926 (none0)
6927 (none0)
6928 (none0)
6929 (none0)
692A (peng4)
692B (shan4)
692C (none0)
692D (tuo3)
692E (sen1)
692F (duo2)
6930 (ye1,ye2)
6931 (fu4)
6932 (wei3)
6933 (wei1)
6934 (duan4)
6935 (jia3)
6936 (zong1)
6937 (jian1)
6938 (yi2)
6939 (shen4,zhen1,zhen4)
693A (xi2)
693B (yan4)
693C (yan3)
693D (chuan2)
693E (zhan4)
693F (chun1)
6940 (yu3,ju3)
6941 (he2)
6942 (zha1,cha2)
6943 (wo4)
6944 (bian1)
6945 (bi4)
6946 (yao1)
6947 (huo4)
6948 (xu1)
6949 (ruo4)
694A (yang2)
694B (la4)
694C (yan2)
694D (ben3)
694E (hun2)
694F (kui2)
6950 (jie4)
6951 (kui2)
6952 (si1)
6953 (feng1)
6954 (xie1,xie4)
6955 (tuo3)
6956 (ji2)
6957 (jian4)
6958 (mu4)
6959 (mao4)
695A (chu3)
695B (hu4,ku3)
695C (hu2)
695D (lian4)
695E (leng2,leng4)
695F (ting2)
6960 (nan2)
6961 (yu2)
6962 (you2)
6963 (mei2)
6964 (song3)
6965 (xuan4)
6966 (xuan4)
6967 (ying1)
6968 (zhen1)
6969 (pian2)
696A (die2)
696B (ji2)
696C (jie2)
696D (ye4)
696E (chu3)
696F (shun3,dun4)
6970 (yu2)
6971 (cou4)
6972 (wei1)
6973 (mei2)
6974 (di4)
6975 (ji2)
6976 (jie2)
6977 (kai3,jie1)
6978 (qiu1)
6979 (ying2)
697A (rou2)
697B (heng2)
697C (lou2)
697D (le4,yue4)
697E (none0)
697F (gui4)
6980 (pin3)
6981 (none0)
6982 (gai4)
6983 (tan2)
6984 (lan3)
6985 (yun2)
6986 (yu2)
6987 (chen4)
6988 (lu:2)
6989 (ju3)
698A (none0)
698B (none0)
698C (none0)
698D (xie4)
698E (jia3)
698F (yi4)
6990 (zhan3)
6991 (fu4)
6992 (nuo4)
6993 (mi4)
6994 (lang2)
6995 (rong2)
6996 (gu3)
6997 (jian4)
6998 (ju4)
6999 (ta3)
699A (yao3)
699B (zhen1)
699C (bang3)
699D (sha1)
699E (yuan2)
699F (zi3)
69A0 (ming2)
69A1 (su4)
69A2 (jia4)
69A3 (yao2)
69A4 (jie2)
69A5 (huang3)
69A6 (gan4,han2)
69A7 (fei3)
69A8 (zha4)
69A9 (qian2)
69AA (ma4)
69AB (sun3)
69AC (yuan2)
69AD (xie4)
69AE (rong2)
69AF (shi2)
69B0 (zhi1)
69B1 (cui1)
69B2 (yun2)
69B3 (ting2)
69B4 (liu2)
69B5 (rong2)
69B6 (tang2)
69B7 (que4)
69B8 (zhai1)
69B9 (si1)
69BA (sheng4)
69BB (ta4)
69BC (ke4,ke2)
69BD (xi1)
69BE (gu4)
69BF (qi1)
69C0 (kao3)
69C1 (gao3)
69C2 (sun1)
69C3 (pan2)
69C4 (tao1)
69C5 (ge2)
69C6 (xun2)
69C7 (dian1,zhen3)
69C8 (nou4)
69C9 (ji2)
69CA (shuo4)
69CB (gou4)
69CC (chui2)
69CD (qiang1)
69CE (cha2)
69CF (qian3)
69D0 (huai2)
69D1 (mei2)
69D2 (xu4)
69D3 (gang4)
69D4 (gao1)
69D5 (zhuo2)
69D6 (tuo2)
69D7 (qiao2)
69D8 (yang4)
69D9 (dian1)
69DA (jia3)
69DB (jian4,kan3)
69DC (zui4)
69DD (none0)
69DE (long2)
69DF (bin1,bing1)
69E0 (zhu1)
69E1 (none0)
69E2 (xi2)
69E3 (qi3)
69E4 (lian2)
69E5 (hui4)
69E6 (yong2)
69E7 (qian4)
69E8 (guo3)
69E9 (gai4)
69EA (gai4)
69EB (tuan2)
69EC (hua4)
69ED (qi1,cu4,qi4)
69EE (sen1)
69EF (cui1)
69F0 (beng4)
69F1 (you3)
69F2 (hu2)
69F3 (jiang3)
69F4 (hu4)
69F5 (huan4)
69F6 (kui4)
69F7 (yi4)
69F8 (yi4)
69F9 (gao1)
69FA (kang1)
69FB (gui1)
69FC (gui1)
69FD (cao2)
69FE (man2,man4)
69FF (jin3)
6A00 (di4)
6A01 (zhuang1)
6A02 (le4,yue4)
6A03 (lang3)
6A04 (chen2)
6A05 (cong1,zong1)
6A06 (li2)
6A07 (xiu1)
6A08 (qing2)
6A09 (shuang3)
6A0A (fan2)
6A0B (tong1)
6A0C (guan4)
6A0D (ji1)
6A0E (suo1)
6A0F (lei3)
6A10 (lu3)
6A11 (liang2)
6A12 (mi4)
6A13 (lou2)
6A14 (chao2)
6A15 (su4)
6A16 (ke1)
6A17 (chu1,shu1)
6A18 (tang2)
6A19 (biao1)
6A1A (lu4)
6A1B (jiu1)
6A1C (shu4)
6A1D (zha1)
6A1E (shu1)
6A1F (zhang1)
6A20 (men2)
6A21 (mo2,mu2)
6A22 (niao3)
6A23 (yang4)
6A24 (tiao2)
6A25 (peng2)
6A26 (zhu4)
6A27 (sha1)
6A28 (xi1)
6A29 (quan2)
6A2A (heng2,heng4)
6A2B (jian1)
6A2C (cong1)
6A2D (none0)
6A2E (none0)
6A2F (qiang2)
6A30 (none0)
6A31 (ying1)
6A32 (er4)
6A33 (xin2)
6A34 (zhi2)
6A35 (qiao2)
6A36 (zui1)
6A37 (cong2)
6A38 (pu2,po4,pu3)
6A39 (shu4)
6A3A (hua4,hua2)
6A3B (kui4)
6A3C (zhen1)
6A3D (zun1)
6A3E (yue4)
6A3F (zhan3)
6A40 (xi1)
6A41 (xun2)
6A42 (dian4)
6A43 (fa1)
6A44 (gan3)
6A45 (mo2,mu2)
6A46 (wu3)
6A47 (qiao1,cui4)
6A48 (rao2,nao2)
6A49 (lin4)
6A4A (liu2)
6A4B (qiao2)
6A4C (xian4)
6A4D (run4)
6A4E (fan2)
6A4F (zhan3)
6A50 (tuo2)
6A51 (lao3)
6A52 (yun2)
6A53 (shun4)
6A54 (tui2)
6A55 (cheng1)
6A56 (tang2)
6A57 (meng2)
6A58 (ju2)
6A59 (cheng2,chen2)
6A5A (su4)
6A5B (jue2)
6A5C (jue2)
6A5D (tan2)
6A5E (hui4)
6A5F (ji1)
6A60 (nuo3)
6A61 (xiang4)
6A62 (tuo3)
6A63 (ning3)
6A64 (rui3)
6A65 (zhu1)
6A66 (tong2,chuang2)
6A67 (zeng1)
6A68 (fen4)
6A69 (qiong2)
6A6A (ran3)
6A6B (heng2,heng4)
6A6C (cen2)
6A6D (gu1,ku1)
6A6E (liu3)
6A6F (lao4)
6A70 (gao1)
6A71 (chu2)
6A72 (none0)
6A73 (none0)
6A74 (none0)
6A75 (none0)
6A76 (ji2)
6A77 (dou1)
6A78 (none0)
6A79 (lu3)
6A7A (none0)
6A7B (none0)
6A7C (yuan2)
6A7D (ta4)
6A7E (shu1)
6A7F (jiang1)
6A80 (tan2)
6A81 (lin3)
6A82 (nong2)
6A83 (yin3)
6A84 (xi2)
6A85 (sui4)
6A86 (shan1)
6A87 (zui4)
6A88 (xuan2)
6A89 (cheng1)
6A8A (gan4)
6A8B (ju4)
6A8C (zui4)
6A8D (yi4)
6A8E (qin2)
6A8F (pu3)
6A90 (yan2,yin2)
6A91 (lei2)
6A92 (feng1)
6A93 (hui3)
6A94 (dang3)
6A95 (ji4)
6A96 (sui4)
6A97 (bo4,bo2)
6A98 (bi4)
6A99 (ding3)
6A9A (chu3)
6A9B (zhua1)
6A9C (gui4,hui4,kuai4)
6A9D (ji4)
6A9E (jia3)
6A9F (jia3)
6AA0 (qing2)
6AA1 (zhe4)
6AA2 (jian3)
6AA3 (qiang2)
6AA4 (dao4)
6AA5 (yi3)
6AA6 (biao3)
6AA7 (song1)
6AA8 (she1)
6AA9 (lin3)
6AAA (li4,yue4)
6AAB (cha2)
6AAC (meng2)
6AAD (yin2)
6AAE (tao2)
6AAF (tai2)
6AB0 (mian2)
6AB1 (qi2)
6AB2 (none0)
6AB3 (bin1,bing1)
6AB4 (huo4)
6AB5 (ji4)
6AB6 (qian1)
6AB7 (mi2,ni3)
6AB8 (ning2)
6AB9 (yi1)
6ABA (gao3)
6ABB (jian4,kan3)
6ABC (yin4)
6ABD (er2)
6ABE (qing3)
6ABF (yan3)
6AC0 (qi2)
6AC1 (mi4)
6AC2 (zhao4)
6AC3 (gui4,ju3)
6AC4 (chun1)
6AC5 (ji1)
6AC6 (kui2)
6AC7 (po2)
6AC8 (deng4)
6AC9 (chu2)
6ACA (none0)
6ACB (mian2)
6ACC (you1)
6ACD (zhi4)
6ACE (guang4)
6ACF (qian1)
6AD0 (lei3)
6AD1 (lei2,lei3)
6AD2 (sa4)
6AD3 (lu3)
6AD4 (none0)
6AD5 (cuan2)
6AD6 (lu:2)
6AD7 (mie4)
6AD8 (hui4)
6AD9 (ou1)
6ADA (lu:2)
6ADB (zhi4,jie2)
6ADC (gao1)
6ADD (du2)
6ADE (yuan2)
6ADF (li4,yue4)
6AE0 (fei4)
6AE1 (zhu4)
6AE2 (sou3)
6AE3 (lian2)
6AE4 (none0)
6AE5 (chu2)
6AE6 (none0)
6AE7 (zhu1)
6AE8 (lu2)
6AE9 (yan2)
6AEA (li4)
6AEB (zhu1)
6AEC (chen4)
6AED (jie2)
6AEE (e4)
6AEF (su1)
6AF0 (huai2)
6AF1 (nie4)
6AF2 (yu4)
6AF3 (long2)
6AF4 (lai4)
6AF5 (none0)
6AF6 (xian3)
6AF7 (none0)
6AF8 (ju3)
6AF9 (xiao1)
6AFA (ling2)
6AFB (ying1)
6AFC (jian1)
6AFD (yin3)
6AFE (you2)
6AFF (ying2)
6B00 (xiang1)
6B01 (nong2)
6B02 (bo2)
6B03 (chan1)
6B04 (lan2)
6B05 (ju3)
6B06 (shuang1)
6B07 (she4)
6B08 (wei2)
6B09 (cong4)
6B0A (quan2)
6B0B (qu2)
6B0C (none0)
6B0D (none0)
6B0E (yu4)
6B0F (luo2)
6B10 (li4)
6B11 (zan4)
6B12 (luan2)
6B13 (dang3)
6B14 (jue2)
6B15 (none0)
6B16 (lan3)
6B17 (lan2)
6B18 (zhu3)
6B19 (lei2)
6B1A (li3,ji1)
6B1B (ba4,ba3)
6B1C (nang2)
6B1D (yu4)
6B1E (ling2)
6B1F (none0)
6B20 (qian4,qian5)
6B21 (ci4)
6B22 (huan1)
6B23 (xin1)
6B24 (yu2)
6B25 (yu4)
6B26 (qian1)
6B27 (ou1)
6B28 (xu1)
6B29 (chao1)
6B2A (chu4)
6B2B (qi4)
6B2C (kai4)
6B2D (yi4)
6B2E (jue2)
6B2F (xi2)
6B30 (xu1)
6B31 (xia4)
6B32 (yu4)
6B33 (kuai4)
6B34 (lang2)
6B35 (kuan3)
6B36 (shuo4)
6B37 (xi1)
6B38 (e^1,e^2,e^3,e^4,ai3,ai4)
6B39 (yi1,qi1)
6B3A (qi1)
6B3B (hu1)
6B3C (chi3)
6B3D (qin1)
6B3E (kuan3)
6B3F (kan3)
6B40 (kuan3)
6B41 (kan3)
6B42 (chuan2)
6B43 (sha4)
6B44 (none0)
6B45 (yin1)
6B46 (xin1)
6B47 (xie1)
6B48 (yu2)
6B49 (qian4)
6B4A (xiao1)
6B4B (yi2)
6B4C (ge1)
6B4D (wu1)
6B4E (tan4)
6B4F (jin4)
6B50 (ou1)
6B51 (hu1)
6B52 (ti4)
6B53 (huan1)
6B54 (xu1)
6B55 (pen1)
6B56 (xi1)
6B57 (xiao4)
6B58 (hu1)
6B59 (she4,xi1,xi4)
6B5A (none0)
6B5B (lian4)
6B5C (chu4)
6B5D (yi4)
6B5E (kan3)
6B5F (yu2)
6B60 (chuo4)
6B61 (huan1)
6B62 (zhi3)
6B63 (zheng4,zheng1)
6B64 (ci3)
6B65 (bu4)
6B66 (wu3)
6B67 (qi2)
6B68 (bu4)
6B69 (bu4)
6B6A (wai1)
6B6B (ju4)
6B6C (qian2)
6B6D (chi2)
6B6E (se4)
6B6F (chi3)
6B70 (se4)
6B71 (zhong3)
6B72 (sui4)
6B73 (sui4)
6B74 (li4)
6B75 (cuo4)
6B76 (yu2)
6B77 (li4)
6B78 (gui1)
6B79 (dai3)
6B7A (dai3)
6B7B (si3)
6B7C (jian1)
6B7D (zhe2)
6B7E (mo4)
6B7F (mo4)
6B80 (yao3)
6B81 (mo4)
6B82 (cu2)
6B83 (yang1)
6B84 (tian3)
6B85 (sheng1)
6B86 (dai4)
6B87 (shang1)
6B88 (xu1)
6B89 (xun4)
6B8A (shu1)
6B8B (can2)
6B8C (jue2)
6B8D (piao3)
6B8E (qia4)
6B8F (qiu2)
6B90 (su4)
6B91 (qing2)
6B92 (yun3)
6B93 (lian4)
6B94 (yi4)
6B95 (fou3)
6B96 (zhi2,shi5)
6B97 (ye4)
6B98 (can2)
6B99 (hun1)
6B9A (dan1)
6B9B (ji2)
6B9C (ye4)
6B9D (none0)
6B9E (yun3)
6B9F (wen1)
6BA0 (chou4,xiu4)
6BA1 (bin4)
6BA2 (ti4)
6BA3 (jin4)
6BA4 (shang1)
6BA5 (yin2)
6BA6 (diao1)
6BA7 (cu4)
6BA8 (hui4)
6BA9 (cuan4)
6BAA (yi4)
6BAB (dan1,dan4)
6BAC (du4)
6BAD (jiang1)
6BAE (lian4)
6BAF (bin4)
6BB0 (du2)
6BB1 (jian1)
6BB2 (jian1)
6BB3 (shu1)
6BB4 (ou1)
6BB5 (duan4)
6BB6 (zhu4)
6BB7 (yin1,yan1,yin3)
6BB8 (qing4)
6BB9 (yi1)
6BBA (sha1,shai4)
6BBB (ke2,qiao4)
6BBC (ke2,qiao4,que4)
6BBD (yao2)
6BBE (xun4)
6BBF (dian4)
6BC0 (hui3)
6BC1 (hui3)
6BC2 (gu3,gu1)
6BC3 (que4)
6BC4 (ji1)
6BC5 (yi4)
6BC6 (ou1)
6BC7 (hui3)
6BC8 (duan4)
6BC9 (yi1)
6BCA (xiao1)
6BCB (wu2)
6BCC (guan4)
6BCD (mu3)
6BCE (mei3)
6BCF (mei3)
6BD0 (ai3)
6BD1 (zuo3)
6BD2 (du2)
6BD3 (yu4)
6BD4 (bi3,bi4)
6BD5 (bi4)
6BD6 (bi4)
6BD7 (pi2)
6BD8 (pi2)
6BD9 (bi4)
6BDA (chan2)
6BDB (mao2)
6BDC (none0)
6BDD (none0)
6BDE (pi2)
6BDF (none0)
6BE0 (jia1)
6BE1 (zhan1)
6BE2 (sai1)
6BE3 (mu4)
6BE4 (tuo4)
6BE5 (xun2)
6BE6 (er4)
6BE7 (rong2)
6BE8 (xian3)
6BE9 (ju2)
6BEA (mu2)
6BEB (hao2)
6BEC (qiu2)
6BED (dou4)
6BEE (none0)
6BEF (tan3)
6BF0 (pei2)
6BF1 (ju1)
6BF2 (duo2)
6BF3 (cui4)
6BF4 (bi1)
6BF5 (san1)
6BF6 (none0)
6BF7 (mao4)
6BF8 (sui1)
6BF9 (shu1)
6BFA (yu1)
6BFB (tuo4)
6BFC (he2)
6BFD (jian4)
6BFE (ta4)
6BFF (san1)
6C00 (lu:2)
6C01 (mu2)
6C02 (li2)
6C03 (tong2)
6C04 (rong3)
6C05 (chang3)
6C06 (pu3)
6C07 (lu3,lu5)
6C08 (zhan1)
6C09 (sao4)
6C0A (zhan1)
6C0B (meng2)
6C0C (lu3)
6C0D (qu2)
6C0E (die2)
6C0F (shi4,zhi1)
6C10 (di3,di1)
6C11 (min2)
6C12 (jue2)
6C13 (mang2,meng2)
6C14 (qi4)
6C15 (pie1)
6C16 (nai3)
6C17 (qi4)
6C18 (dao1)
6C19 (xian1)
6C1A (chuan1)
6C1B (fen1)
6C1C (ri4)
6C1D (nei4,nai3)
6C1E (none0)
6C1F (fu2)
6C20 (shen1)
6C21 (dong1)
6C22 (qing1)
6C23 (qi4)
6C24 (yin1)
6C25 (xi1)
6C26 (hai4)
6C27 (yang3)
6C28 (an1)
6C29 (ya4)
6C2A (ke4)
6C2B (qing1)
6C2C (ya4)
6C2D (dong1)
6C2E (dan4)
6C2F (lu:4)
6C30 (qing2)
6C31 (yang3)
6C32 (yun1)
6C33 (yun1)
6C34 (shui3)
6C35 (shui3)
6C36 (zheng3)
6C37 (bing1)
6C38 (yong3)
6C39 (dang4)
6C3A (shui3)
6C3B (le4)
6C3C (ni4)
6C3D (tun3)
6C3E (fan4)
6C3F (gui3)
6C40 (ting1)
6C41 (zhi1)
6C42 (qiu2)
6C43 (bin1)
6C44 (ze4)
6C45 (mian3)
6C46 (cuan1)
6C47 (hui4)
6C48 (diao1)
6C49 (han4)
6C4A (cha4)
6C4B (zhuo2)
6C4C (chuan4)
6C4D (wan2)
6C4E (fan4)
6C4F (dai4)
6C50 (xi1,xi4)
6C51 (tuo1)
6C52 (mang3)
6C53 (qiu2)
6C54 (qi4)
6C55 (shan4)
6C56 (pai4)
6C57 (han4,han2)
6C58 (qian1)
6C59 (wu1)
6C5A (wu1)
6C5B (xun4)
6C5C (si4)
6C5D (ru3)
6C5E (gong3,hong4)
6C5F (jiang1)
6C60 (chi2)
6C61 (wu1)
6C62 (none0)
6C63 (none0)
6C64 (tang1,shang1)
6C65 (zhi1)
6C66 (chi2)
6C67 (qian1)
6C68 (mi4)
6C69 (gu3)
6C6A (wang1)
6C6B (qing4)
6C6C (jing3)
6C6D (rui4)
6C6E (jun1)
6C6F (hong2)
6C70 (tai4)
6C71 (quan3)
6C72 (ji2)
6C73 (bian4)
6C74 (bian4)
6C75 (gan4)
6C76 (wen4)
6C77 (zhong1)
6C78 (fang1)
6C79 (xiong1)
6C7A (jue2)
6C7B (hu3)
6C7C (none0)
6C7D (qi4)
6C7E (fen2)
6C7F (xu4)
6C80 (xu4)
6C81 (qin4,shen4)
6C82 (yi2)
6C83 (wo4)
6C84 (yun2)
6C85 (yuan2)
6C86 (hang4)
6C87 (yan3)
6C88 (shen3,chen2)
6C89 (chen2)
6C8A (dan4)
6C8B (you2)
6C8C (dun4,zhuan4)
6C8D (hu4)
6C8E (huo4)
6C8F (qi1)
6C90 (mu4)
6C91 (rou2)
6C92 (mei2,mo4)
6C93 (ta4,da2,ta5)
6C94 (mian3)
6C95 (wu4)
6C96 (chong1)
6C97 (tian1)
6C98 (bi3)
6C99 (sha1,sha4)
6C9A (zhi3)
6C9B (pei4)
6C9C (pan4)
6C9D (zhui3)
6C9E (za1)
6C9F (gou1)
6CA0 (liu2)
6CA1 (mei2,mo4)
6CA2 (ze2)
6CA3 (feng1)
6CA4 (ou4,ou1)
6CA5 (li4)
6CA6 (lun2)
6CA7 (cang1)
6CA8 (feng1)
6CA9 (wei2)
6CAA (hu4)
6CAB (mo4)
6CAC (mei4)
6CAD (shu4)
6CAE (ju3,ju4,ju1)
6CAF (zan3)
6CB0 (tuo1)
6CB1 (tuo2)
6CB2 (duo4)
6CB3 (he2)
6CB4 (li4)
6CB5 (mi3)
6CB6 (yi2)
6CB7 (fu2)
6CB8 (fei4)
6CB9 (you2)
6CBA (tian2)
6CBB (zhi4)
6CBC (zhao3)
6CBD (gu1)
6CBE (zhan1)
6CBF (yan2,yan4)
6CC0 (si1)
6CC1 (kuang4)
6CC2 (jiong3)
6CC3 (ju1)
6CC4 (xie4)
6CC5 (qiu2)
6CC6 (yi4)
6CC7 (jia1)
6CC8 (zhong1)
6CC9 (quan2)
6CCA (bo2,po1,po4)
6CCB (hui4)
6CCC (mi4,bi4)
6CCD (ben1)
6CCE (zhuo2)
6CCF (chu4)
6CD0 (le4)
6CD1 (you3)
6CD2 (gu1)
6CD3 (hong2)
6CD4 (gan1)
6CD5 (fa3)
6CD6 (mao3)
6CD7 (si4)
6CD8 (hu1)
6CD9 (ping2)
6CDA (ci3)
6CDB (fan4,fan2)
6CDC (zhi1)
6CDD (su4)
6CDE (ning4)
6CDF (cheng1)
6CE0 (ling2)
6CE1 (pao4,pao1)
6CE2 (bo1,po1)
6CE3 (qi4,xie4)
6CE4 (si4)
6CE5 (ni2,ni4)
6CE6 (ju2)
6CE7 (yue4)
6CE8 (zhu4)
6CE9 (sheng1)
6CEA (lei4)
6CEB (xuan4)
6CEC (xue4)
6CED (fu1)
6CEE (pan4)
6CEF (min3)
6CF0 (tai4)
6CF1 (yang1)
6CF2 (ji3)
6CF3 (yong3)
6CF4 (guan4)
6CF5 (beng4)
6CF6 (xue2)
6CF7 (long2,shuang1)
6CF8 (lu2)
6CF9 (dan4)
6CFA (luo4,po1)
6CFB (xie4)
6CFC (po1)
6CFD (ze2)
6CFE (jing1)
6CFF (yin2)
6D00 (zhou1)
6D01 (jie2)
6D02 (yi4)
6D03 (hui1)
6D04 (hui2)
6D05 (zui3)
6D06 (cheng2)
6D07 (yin1)
6D08 (wei2)
6D09 (hou4)
6D0A (jian4)
6D0B (yang2)
6D0C (lie4)
6D0D (si4)
6D0E (ji4)
6D0F (er2)
6D10 (xing2)
6D11 (fu2,fu4)
6D12 (sa3)
6D13 (zi4)
6D14 (zhi3)
6D15 (yin1)
6D16 (wu2)
6D17 (xi3,xian3)
6D18 (kao3)
6D19 (zhu1)
6D1A (jiang4)
6D1B (luo4)
6D1C (none0)
6D1D (an4)
6D1E (dong4)
6D1F (yi2)
6D20 (mou2)
6D21 (lei3)
6D22 (yi1)
6D23 (mi3)
6D24 (quan2)
6D25 (jin1)
6D26 (po4)
6D27 (wei3)
6D28 (xiao2)
6D29 (xie4)
6D2A (hong2)
6D2B (xu4)
6D2C (su4)
6D2D (kuang1)
6D2E (tao2)
6D2F (qie4,jie2)
6D30 (ju4)
6D31 (er3)
6D32 (zhou1)
6D33 (ru4)
6D34 (ping2)
6D35 (xun2)
6D36 (xiong1)
6D37 (zhi4)
6D38 (guang1,huang3)
6D39 (huan2)
6D3A (ming2)
6D3B (huo2)
6D3C (wa1)
6D3D (qia4,xia2)
6D3E (pai4,pa1)
6D3F (wu1)
6D40 (qu3)
6D41 (liu2)
6D42 (yi4)
6D43 (jia1)
6D44 (jing4)
6D45 (qian3,jian1)
6D46 (jiang1,jiang4)
6D47 (jiao1)
6D48 (zhen1)
6D49 (shi1)
6D4A (zhuo2)
6D4B (ce4)
6D4C (none0)
6D4D (hui4,kuai4)
6D4E (ji4,ji3)
6D4F (liu2)
6D50 (chan3)
6D51 (hun2)
6D52 (hu3,xu3)
6D53 (nong2)
6D54 (xun2)
6D55 (jin4)
6D56 (lie4)
6D57 (qiu2)
6D58 (wei3)
6D59 (zhe4)
6D5A (jun4,xun4)
6D5B (han2)
6D5C (bang1)
6D5D (mang2)
6D5E (zhuo2)
6D5F (you2)
6D60 (xi1)
6D61 (bo2)
6D62 (dou4)
6D63 (huan4,wan3)
6D64 (hong2)
6D65 (yi4)
6D66 (pu3)
6D67 (ying3)
6D68 (lan3)
6D69 (hao4)
6D6A (lang4)
6D6B (han3)
6D6C (li3)
6D6D (geng1)
6D6E (fu2)
6D6F (wu2)
6D70 (li4)
6D71 (chun2)
6D72 (feng2)
6D73 (yi4)
6D74 (yu4)
6D75 (tong2)
6D76 (lao2)
6D77 (hai3)
6D78 (jin4,jin1)
6D79 (jia2,jia1)
6D7A (chong1)
6D7B (weng3)
6D7C (mei3)
6D7D (sui1)
6D7E (cheng1)
6D7F (pei4)
6D80 (xian4)
6D81 (shen4)
6D82 (tu2)
6D83 (kun4)
6D84 (pin1)
6D85 (nie4)
6D86 (han4)
6D87 (jing1)
6D88 (xiao1)
6D89 (she4)
6D8A (nian3)
6D8B (tu1)
6D8C (yong3,chong1)
6D8D (xiao1)
6D8E (xian2)
6D8F (ting3)
6D90 (e2)
6D91 (su4)
6D92 (tun1)
6D93 (juan1)
6D94 (cen2)
6D95 (ti4)
6D96 (li4)
6D97 (shui4)
6D98 (si4)
6D99 (lei4)
6D9A (shui4)
6D9B (tao1)
6D9C (du2)
6D9D (lao4)
6D9E (lai2)
6D9F (lian2)
6DA0 (wei2)
6DA1 (wo1,guo1)
6DA2 (yun2)
6DA3 (huan4)
6DA4 (di2)
6DA5 (none0)
6DA6 (run4)
6DA7 (jian4)
6DA8 (zhang3,zhang4)
6DA9 (se4)
6DAA (fu2)
6DAB (guan4)
6DAC (xing4)
6DAD (shou4)
6DAE (shuan4)
6DAF (ya2)
6DB0 (chuo4)
6DB1 (zhang4)
6DB2 (ye4,yi4)
6DB3 (kong1)
6DB4 (wan3)
6DB5 (han2)
6DB6 (tuo1)
6DB7 (dong1)
6DB8 (he2,hao4)
6DB9 (wo1)
6DBA (ju1)
6DBB (gan4)
6DBC (liang2,liang4)
6DBD (hun1)
6DBE (ta4)
6DBF (zhuo1)
6DC0 (dian4)
6DC1 (qie4)
6DC2 (de2)
6DC3 (juan4)
6DC4 (zi1)
6DC5 (xi1)
6DC6 (xiao2,yao2)
6DC7 (qi2)
6DC8 (gu3)
6DC9 (guo3)
6DCA (han4)
6DCB (lin2,lin4)
6DCC (tang3)
6DCD (zhou1)
6DCE (peng3)
6DCF (hao4)
6DD0 (chang1)
6DD1 (shu1,shu2)
6DD2 (qi1)
6DD3 (fang1)
6DD4 (chi4)
6DD5 (lu4)
6DD6 (nao4)
6DD7 (ju2)
6DD8 (tao2)
6DD9 (cong2)
6DDA (lei4)
6DDB (zhi4)
6DDC (peng2)
6DDD (fei2)
6DDE (song1)
6DDF (tian3)
6DE0 (pi4)
6DE1 (dan4)
6DE2 (yu4)
6DE3 (ni2)
6DE4 (yu1)
6DE5 (lu4)
6DE6 (gan4)
6DE7 (mi4)
6DE8 (jing4)
6DE9 (ling2)
6DEA (lun2)
6DEB (yin2)
6DEC (cui4)
6DED (qu2)
6DEE (huai2)
6DEF (yu4)
6DF0 (nian4)
6DF1 (shen1)
6DF2 (piao2,hu1)
6DF3 (chun2)
6DF4 (hu1)
6DF5 (yuan1)
6DF6 (lai2)
6DF7 (hun4,hun2,hun3)
6DF8 (qing1)
6DF9 (yan1,yan4)
6DFA (qian3,jian1)
6DFB (tian1)
6DFC (miao3)
6DFD (zhi3)
6DFE (yin3)
6DFF (mi4)
6E00 (ben1)
6E01 (yuan1)
6E02 (wen4)
6E03 (re4)
6E04 (fei1)
6E05 (qing1)
6E06 (yuan1)
6E07 (ke3)
6E08 (ji4)
6E09 (she4)
6E0A (yuan1)
6E0B (se4)
6E0C (lu4)
6E0D (zi4)
6E0E (du2)
6E0F (none0)
6E10 (jian4,jian1)
6E11 (mian3,sheng2)
6E12 (pi4)
6E13 (xi1)
6E14 (yu2)
6E15 (yuan1)
6E16 (shen3)
6E17 (shen4)
6E18 (rou2)
6E19 (huan4)
6E1A (zhu3)
6E1B (jian3)
6E1C (nuan3)
6E1D (yu2)
6E1E (qiu2)
6E1F (ting2)
6E20 (qu2)
6E21 (du4)
6E22 (feng2)
6E23 (zha1,zha3)
6E24 (bo2)
6E25 (wo4)
6E26 (wo1,guo1)
6E27 (di4)
6E28 (wei1)
6E29 (wen1)
6E2A (ru2)
6E2B (xie4)
6E2C (ce4)
6E2D (wei4)
6E2E (ge1)
6E2F (gang3)
6E30 (yan3)
6E31 (hong2)
6E32 (xuan4)
6E33 (mi3)
6E34 (ke3)
6E35 (mao2)
6E36 (ying1)
6E37 (yan3)
6E38 (you2)
6E39 (hong1)
6E3A (miao3)
6E3B (xing3)
6E3C (mei3)
6E3D (zai1)
6E3E (hun2,hun4)
6E3F (nai4)
6E40 (kui2)
6E41 (shi2)
6E42 (e4)
6E43 (pai4)
6E44 (mei2)
6E45 (lian4)
6E46 (qi4)
6E47 (qi4)
6E48 (mei2)
6E49 (tian2)
6E4A (cou4)
6E4B (wei2)
6E4C (can1)
6E4D (tuan1)
6E4E (mian3)
6E4F (xu1)
6E50 (mo4)
6E51 (xu3)
6E52 (ji2)
6E53 (pen2)
6E54 (jian1)
6E55 (jian3)
6E56 (hu2)
6E57 (feng4)
6E58 (xiang1)
6E59 (yi4)
6E5A (yin4)
6E5B (zhan4)
6E5C (shi2)
6E5D (jie1)
6E5E (zhen1)
6E5F (huang2)
6E60 (tan4)
6E61 (yu2)
6E62 (bi4)
6E63 (min3)
6E64 (shi1)
6E65 (tu2)
6E66 (sheng1)
6E67 (yong3,chong1)
6E68 (ju2)
6E69 (zhong4)
6E6A (none0)
6E6B (qiu1,jia3,jiao3,jiu1)
6E6C (jiao3)
6E6D (none0)
6E6E (yin1,yan1)
6E6F (tang1,shang1)
6E70 (long2)
6E71 (huo4)
6E72 (yuan2)
6E73 (nan3)
6E74 (ban4)
6E75 (you3)
6E76 (quan2)
6E77 (chui2)
6E78 (liang4)
6E79 (chan2)
6E7A (yan2)
6E7B (chun2)
6E7C (nie4)
6E7D (zi1)
6E7E (wan1)
6E7F (shi1)
6E80 (man3)
6E81 (ying2)
6E82 (la4)
6E83 (kui4,hui4)
6E84 (none0)
6E85 (jian4,jian1)
6E86 (xu4)
6E87 (lou2)
6E88 (gui1)
6E89 (gai4)
6E8A (none0)
6E8B (none0)
6E8C (po1)
6E8D (jin4)
6E8E (gui4)
6E8F (tang2)
6E90 (yuan2)
6E91 (suo3)
6E92 (yuan2)
6E93 (lian2)
6E94 (yao3)
6E95 (meng4)
6E96 (zhun3)
6E97 (sheng2)
6E98 (ke4)
6E99 (tai4)
6E9A (ta3)
6E9B (wa1)
6E9C (liu1,liu4)
6E9D (gou1)
6E9E (sao1)
6E9F (ming2)
6EA0 (zha4)
6EA1 (shi2)
6EA2 (yi4)
6EA3 (lun4)
6EA4 (ma3)
6EA5 (pu3)
6EA6 (wei1)
6EA7 (li4)
6EA8 (cai2)
6EA9 (wu4)
6EAA (xi1,qi1)
6EAB (wen1)
6EAC (qiang1)
6EAD (ce4)
6EAE (shi1)
6EAF (su4)
6EB0 (yi1)
6EB1 (zhen1,qin2)
6EB2 (sou1)
6EB3 (yun2)
6EB4 (xiu4)
6EB5 (yin1)
6EB6 (rong2)
6EB7 (hun4)
6EB8 (su4)
6EB9 (su4)
6EBA (ni4,niao4)
6EBB (ta4,ta1)
6EBC (shi1)
6EBD (ru4)
6EBE (wei1)
6EBF (pan4)
6EC0 (chu4)
6EC1 (chu2)
6EC2 (pang1)
6EC3 (weng1)
6EC4 (cang1)
6EC5 (mie4)
6EC6 (he2)
6EC7 (dian1)
6EC8 (hao4)
6EC9 (huang3)
6ECA (xi4)
6ECB (zi1)
6ECC (di2)
6ECD (zhi4)
6ECE (ying2,xing2)
6ECF (fu3)
6ED0 (jie2)
6ED1 (hua2,gu3)
6ED2 (ge1)
6ED3 (zi3)
6ED4 (tao1)
6ED5 (teng2)
6ED6 (sui1)
6ED7 (bi4)
6ED8 (jiao4)
6ED9 (hui4)
6EDA (gun3)
6EDB (yin2)
6EDC (gao1)
6EDD (long2,shuang1)
6EDE (zhi4)
6EDF (yan4)
6EE0 (she4)
6EE1 (man3)
6EE2 (ying2)
6EE3 (chun2)
6EE4 (lu:4)
6EE5 (lan4)
6EE6 (luan2)
6EE7 (xiao4)
6EE8 (bin1)
6EE9 (tan1)
6EEA (yu4)
6EEB (xiu3)
6EEC (hu4)
6EED (bi4)
6EEE (biao1)
6EEF (zhi4)
6EF0 (jiang3)
6EF1 (kou4)
6EF2 (shen4)
6EF3 (shang1)
6EF4 (di1)
6EF5 (mi4)
6EF6 (ao2)
6EF7 (lu3)
6EF8 (hu3,xu3)
6EF9 (hu1)
6EFA (you2)
6EFB (chan3)
6EFC (fan4)
6EFD (yong1)
6EFE (gun3)
6EFF (man3)
6F00 (qing4)
6F01 (yu2)
6F02 (piao1,piao3,piao4)
6F03 (ji2)
6F04 (ya2)
6F05 (jiao3)
6F06 (qi1,qu4,xi1)
6F07 (xi3)
6F08 (ji4)
6F09 (lu4)
6F0A (lu:3,lou2)
6F0B (long2)
6F0C (jin3)
6F0D (guo2)
6F0E (cong2)
6F0F (lou4)
6F10 (zhi2)
6F11 (gai4)
6F12 (qiang2)
6F13 (li2)
6F14 (yan3)
6F15 (cao2)
6F16 (jiao4)
6F17 (cong1)
6F18 (chun2)
6F19 (tuan2)
6F1A (ou4,ou1)
6F1B (teng2)
6F1C (ye3)
6F1D (xi2)
6F1E (mi4)
6F1F (tang2)
6F20 (mo4)
6F21 (shang1)
6F22 (han4)
6F23 (lian2)
6F24 (lan3)
6F25 (wa1)
6F26 (li2)
6F27 (qian2)
6F28 (feng2)
6F29 (xuan2)
6F2A (yi1)
6F2B (man4,man2)
6F2C (zi4)
6F2D (mang3)
6F2E (kang1)
6F2F (luo4,ta4)
6F30 (peng1)
6F31 (shu4)
6F32 (zhang3,zhang4)
6F33 (zhang1)
6F34 (chong2)
6F35 (xu4)
6F36 (huan4)
6F37 (kuo4,huo3)
6F38 (jian4,jian1)
6F39 (yan1)
6F3A (chuang3,shuang3)
6F3B (liao2)
6F3C (cui3)
6F3D (ti2)
6F3E (yang4)
6F3F (jiang1,jiang4)
6F40 (cong2)
6F41 (ying3)
6F42 (hong2)
6F43 (xiu1)
6F44 (shu4)
6F45 (guan4)
6F46 (ying2)
6F47 (xiao1)
6F48 (none0)
6F49 (none0)
6F4A (xu4)
6F4B (lian4)
6F4C (zhi4)
6F4D (wei2)
6F4E (pi4)
6F4F (yu4)
6F50 (jiao4)
6F51 (po1)
6F52 (xiang4)
6F53 (hui4)
6F54 (jie2)
6F55 (wu3)
6F56 (pa2)
6F57 (ji2)
6F58 (pan1)
6F59 (wei2)
6F5A (xiao1,su4)
6F5B (qian2)
6F5C (qian2)
6F5D (xi1)
6F5E (lu4)
6F5F (xi4)
6F60 (sun4)
6F61 (dun4)
6F62 (huang2)
6F63 (min3)
6F64 (run4)
6F65 (su4)
6F66 (liao3,liao2,lao3)
6F67 (zhen1)
6F68 (zhong1)
6F69 (yi4)
6F6A (di2)
6F6B (wan1)
6F6C (dan4)
6F6D (tan2)
6F6E (chao2)
6F6F (xun2)
6F70 (kui4,hui4)
6F71 (none0)
6F72 (shao4)
6F73 (tu2)
6F74 (zhu1)
6F75 (sa3)
6F76 (hei1)
6F77 (bi3,bi4)
6F78 (shan1)
6F79 (chan2)
6F7A (chan2)
6F7B (shu3)
6F7C (tong2)
6F7D (pu1)
6F7E (lin2)
6F7F (wei2)
6F80 (se4)
6F81 (se4)
6F82 (cheng2,deng4)
6F83 (jiong3)
6F84 (cheng2,deng4)
6F85 (hua4)
6F86 (jiao1)
6F87 (lao4,lao2)
6F88 (che4)
6F89 (gan3)
6F8A (cun1)
6F8B (heng4)
6F8C (si1)
6F8D (shu4)
6F8E (peng2,peng1)
6F8F (han4)
6F90 (yun2)
6F91 (liu4,liu1)
6F92 (hong4)
6F93 (fu2)
6F94 (hao4)
6F95 (he2)
6F96 (xian1)
6F97 (jian4)
6F98 (shan1)
6F99 (xi4)
6F9A (ao4)
6F9B (lu3)
6F9C (lan2)
6F9D (none0)
6F9E (yu2)
6F9F (lin3)
6FA0 (min3,mian3,sheng2)
6FA1 (zao3)
6FA2 (dang1)
6FA3 (huan3)
6FA4 (ze2)
6FA5 (xie4)
6FA6 (yu4)
6FA7 (li3)
6FA8 (shi4)
6FA9 (xue2)
6FAA (ling2)
6FAB (man4)
6FAC (zi1)
6FAD (yong1)
6FAE (kuai4,hui4)
6FAF (can4)
6FB0 (lian4)
6FB1 (dian4)
6FB2 (ye4)
6FB3 (ao4)
6FB4 (huan2)
6FB5 (lian4)
6FB6 (chan2)
6FB7 (man4)
6FB8 (dan3)
6FB9 (dan4,tan2)
6FBA (yi4)
6FBB (sui4)
6FBC (pi4)
6FBD (ju4)
6FBE (ta4)
6FBF (qin2)
6FC0 (ji1)
6FC1 (zhuo2)
6FC2 (lian2)
6FC3 (nong2)
6FC4 (guo1)
6FC5 (jin4)
6FC6 (fen2)
6FC7 (se4)
6FC8 (ji2)
6FC9 (sui1)
6FCA (hui4)
6FCB (chu3)
6FCC (ta4)
6FCD (song1)
6FCE (ding3)
6FCF (se4)
6FD0 (zhu3)
6FD1 (lai4)
6FD2 (bin1)
6FD3 (lian2)
6FD4 (mi3)
6FD5 (shi1)
6FD6 (shu4)
6FD7 (mi4)
6FD8 (ning4,neng4)
6FD9 (ying2)
6FDA (ying2,xing2)
6FDB (meng2)
6FDC (jin4)
6FDD (qi2)
6FDE (bi4)
6FDF (ji4,ji3)
6FE0 (hao2)
6FE1 (ru2)
6FE2 (zui3,cui4)
6FE3 (wo4)
6FE4 (tao1,tao2)
6FE5 (yin4)
6FE6 (yin3)
6FE7 (dui4)
6FE8 (ci2)
6FE9 (huo4)
6FEA (jing4)
6FEB (lan4)
6FEC (jun4)
6FED (ai4)
6FEE (pu2)
6FEF (zhuo2)
6FF0 (wei2)
6FF1 (bin1)
6FF2 (gu3)
6FF3 (qian2)
6FF4 (xing2)
6FF5 (bin1)
6FF6 (kuo4)
6FF7 (fei4)
6FF8 (none0)
6FF9 (bin1)
6FFA (jian4,jian1)
6FFB (dui4,wei2)
6FFC (luo4)
6FFD (luo4)
6FFE (lu:4)
6FFF (li4)
7000 (you1)
7001 (yang4)
7002 (lu3)
7003 (si4)
7004 (jie2)
7005 (ying4,ying2)
7006 (du2)
7007 (wang3)
7008 (hui1)
7009 (xie4)
700A (pan2)
700B (shen3)
700C (biao1)
700D (chan2)
700E (mie4)
700F (liu2)
7010 (jian1)
7011 (pu4,bao4)
7012 (se4)
7013 (cheng2)
7014 (gu3)
7015 (bin1,pin2)
7016 (huo4)
7017 (xian4)
7018 (lu2)
7019 (qin1)
701A (han4)
701B (ying2)
701C (rong2)
701D (li4)
701E (jing4)
701F (xiao1)
7020 (ying2)
7021 (sui3)
7022 (wei2)
7023 (xie4)
7024 (huai2)
7025 (hao4)
7026 (zhu1)
7027 (long2,shuang1)
7028 (lai4)
7029 (dui4)
702A (fan2)
702B (hu2)
702C (lai4)
702D (none0)
702E (none0)
702F (ying2)
7030 (mi2)
7031 (ji4)
7032 (lian4)
7033 (jian4)
7034 (ying3)
7035 (fen4)
7036 (lin2)
7037 (yi4)
7038 (jian1)
7039 (yue4)
703A (chan2)
703B (dai4)
703C (rang2,rang4)
703D (jian3)
703E (lan2)
703F (fan2)
7040 (shuang4)
7041 (yuan1)
7042 (zhuo2)
7043 (feng1)
7044 (she4)
7045 (lei3)
7046 (lan2)
7047 (cong2)
7048 (qu2)
7049 (yong1)
704A (qian2)
704B (fa3)
704C (guan4)
704D (que4)
704E (yan4)
704F (hao4)
7050 (none0)
7051 (sa3)
7052 (zan4)
7053 (luan2)
7054 (yan4)
7055 (li2)
7056 (mi3)
7057 (dan4)
7058 (tan1)
7059 (dang3)
705A (jiao3)
705B (chan3)
705C (none0)
705D (hao4)
705E (ba4)
705F (zhu2)
7060 (lan3)
7061 (lan2)
7062 (nang3)
7063 (wan1)
7064 (luan2)
7065 (quan2)
7066 (xian1)
7067 (yan4)
7068 (gan4)
7069 (yan4)
706A (yu4)
706B (huo3)
706C (biao1)
706D (mie4)
706E (guang1)
706F (deng1)
7070 (hui1)
7071 (xiao1)
7072 (xiao1)
7073 (none0)
7074 (hong2)
7075 (ling2)
7076 (zao4)
7077 (zhuan4)
7078 (jiu3)
7079 (zha4)
707A (xie4)
707B (chi4)
707C (zhuo2)
707D (zai1)
707E (zai1)
707F (can4)
7080 (yang2)
7081 (qi4)
7082 (zhong1)
7083 (fen2)
7084 (niu3)
7085 (gui4,jiong3)
7086 (wen2)
7087 (po4)
7088 (yi4)
7089 (lu2)
708A (chui1,chui4)
708B (pi1)
708C (kai4)
708D (pan4)
708E (yan2)
708F (kai4)
7090 (pang4)
7091 (mu4)
7092 (chao3)
7093 (liao4)
7094 (gui4,que1)
7095 (kang4)
7096 (dun4)
7097 (guang1)
7098 (xin1)
7099 (zhi4)
709A (guang1)
709B (xin1)
709C (wei3)
709D (qiang4)
709E (bian4)
709F (da2)
70A0 (xia2)
70A1 (zheng1)
70A2 (zhu2)
70A3 (ke3)
70A4 (zhao4)
70A5 (fu2)
70A6 (ba2)
70A7 (duo4)
70A8 (duo4)
70A9 (ling4)
70AA (zhuo2)
70AB (xuan4)
70AC (ju4)
70AD (tan4)
70AE (pao4,bao1,pao2,pao1)
70AF (jiong3)
70B0 (pao2)
70B1 (tai2)
70B2 (tai2)
70B3 (bing3)
70B4 (yang3)
70B5 (tong1,dong1)
70B6 (han1)
70B7 (zhu4)
70B8 (zha4,zha2)
70B9 (dian3,dian5)
70BA (wei4,wei2)
70BB (shi2)
70BC (lian4)
70BD (chi4)
70BE (ping2)
70BF (none0)
70C0 (hu1)
70C1 (shuo4)
70C2 (lan4)
70C3 (ting1)
70C4 (jiao3)
70C5 (xu4)
70C6 (xing2)
70C7 (quan4)
70C8 (lie4)
70C9 (huan4)
70CA (yang2,yang4)
70CB (xiao1)
70CC (xiu1)
70CD (xian3)
70CE (yin2)
70CF (wu1,wu4)
70D0 (zhou1)
70D1 (yao2)
70D2 (shi4)
70D3 (wei1)
70D4 (tong2)
70D5 (tong2)
70D6 (zai1)
70D7 (kai4)
70D8 (hong1)
70D9 (luo4,lao4)
70DA (xia2)
70DB (zhu2)
70DC (xuan3)
70DD (zheng1)
70DE (po4)
70DF (yan1,yin1)
70E0 (hui3)
70E1 (guang1)
70E2 (zhe4)
70E3 (hui1)
70E4 (kao3)
70E5 (none0)
70E6 (fan2)
70E7 (shao1)
70E8 (ye4)
70E9 (hui4)
70EA (none0)
70EB (tang4)
70EC (jin4)
70ED (re4)
70EE (none0)
70EF (xi1)
70F0 (fu2)
70F1 (jiong3)
70F2 (che4)
70F3 (pu3)
70F4 (jing3,ting1)
70F5 (zhuo2)
70F6 (ting3)
70F7 (wan2)
70F8 (hai3)
70F9 (peng1)
70FA (lang3)
70FB (shan1)
70FC (hu1)
70FD (feng1)
70FE (chi4)
70FF (rong2)
7100 (hu2)
7101 (none0)
7102 (shu2)
7103 (lang3)
7104 (xun1)
7105 (xun1)
7106 (jue2)
7107 (xiao1)
7108 (xi1)
7109 (yan1)
710A (han4)
710B (zhuang4)
710C (qu1,jun4)
710D (di4,ti1)
710E (xie4)
710F (qi4)
7110 (wu4)
7111 (none0)
7112 (none0)
7113 (han2)
7114 (yan4)
7115 (huan4)
7116 (men4)
7117 (ju2)
7118 (dao4,tao1)
7119 (bei4)
711A (fen2)
711B (lin4)
711C (kun1)
711D (hun4)
711E (chun1)
711F (xi2)
7120 (cui4)
7121 (wu2,mo2)
7122 (hong1)
7123 (ju4)
7124 (fu3)
7125 (yue1)
7126 (jiao1)
7127 (cong1)
7128 (feng4)
7129 (ping1)
712A (qiong1)
712B (cui4)
712C (xi2)
712D (qiong2)
712E (xin4)
712F (zhuo2,chao1,zhuo1)
7130 (yan4)
7131 (yan4)
7132 (yi4)
7133 (jue2)
7134 (yu4)
7135 (gang4)
7136 (ran2)
7137 (pi2)
7138 (yan4)
7139 (none0)
713A (sheng1)
713B (chang4)
713C (shao1)
713D (none0)
713E (none0)
713F (none0)
7140 (none0)
7141 (chen2)
7142 (he4)
7143 (kui3)
7144 (zhong1)
7145 (duan4)
7146 (ya1)
7147 (hui1)
7148 (feng4)
7149 (lian4)
714A (xuan1)
714B (xing1)
714C (huang2)
714D (jiao3)
714E (jian1)
714F (bi4)
7150 (ying1)
7151 (zhu3)
7152 (wei3)
7153 (tuan1)
7154 (tian4)
7155 (xi1)
7156 (nuan3,xuan1)
7157 (nuan3)
7158 (chan2)
7159 (yan1)
715A (jiong3)
715B (jiong3)
715C (yu4)
715D (mei4)
715E (sha4,sha1)
715F (wu4)
7160 (ye4)
7161 (xin4)
7162 (qiong2)
7163 (rou3)
7164 (mei2)
7165 (huan4)
7166 (xu4,xu3)
7167 (zhao4)
7168 (wei1)
7169 (fan2)
716A (qiu2)
716B (sui4)
716C (yang2,yang4)
716D (lie4)
716E (zhu3)
716F (none0)
7170 (gao4)
7171 (gua1)
7172 (bao1)
7173 (hu2)
7174 (yun1)
7175 (xia1)
7176 (none0)
7177 (none0)
7178 (bian1)
7179 (wei1)
717A (tui4)
717B (tang2)
717C (chao3)
717D (shan1,shan4)
717E (yun1)
717F (bo2)
7180 (huang3)
7181 (xie2)
7182 (xi4)
7183 (wu4)
7184 (xi1,xi2)
7185 (yun2)
7186 (he2)
7187 (he4)
7188 (xi1)
7189 (yun1)
718A (xiong2)
718B (nai2)
718C (kao3)
718D (none0)
718E (yao4)
718F (xun1,xun4)
7190 (ming2)
7191 (lian2)
7192 (ying2)
7193 (wen4)
7194 (rong2)
7195 (none0)
7196 (none0)
7197 (qiang4)
7198 (liu4,liu1)
7199 (xi1)
719A (bi4)
719B (biao1)
719C (cong1)
719D (lu4)
719E (jian1)
719F (shu2,shou2)
71A0 (yi4)
71A1 (lou2)
71A2 (feng1)
71A3 (sui1)
71A4 (yi4)
71A5 (teng1)
71A6 (jue2)
71A7 (zong1)
71A8 (yun4,yu4)
71A9 (hu4)
71AA (yi2)
71AB (zhi4)
71AC (ao2,ao1)
71AD (wei4)
71AE (liao2)
71AF (han4)
71B0 (ou1)
71B1 (re4)
71B2 (jiong3)
71B3 (man4)
71B4 (none0)
71B5 (shang1)
71B6 (cuan4)
71B7 (zeng1)
71B8 (jian1)
71B9 (xi1)
71BA (xi1)
71BB (xi1)
71BC (yi4)
71BD (xiao4)
71BE (chi4)
71BF (huang2)
71C0 (chan3)
71C1 (ye4)
71C2 (qian2)
71C3 (ran2)
71C4 (yan4)
71C5 (xian2)
71C6 (qiao2)
71C7 (zun1)
71C8 (deng1)
71C9 (dun4)
71CA (shen1)
71CB (jiao1)
71CC (fen2)
71CD (si1)
71CE (liao2,liao3,liao4)
71CF (yu4)
71D0 (lin2)
71D1 (tong2)
71D2 (shao1)
71D3 (fen2)
71D4 (fan2)
71D5 (yan4,yan1)
71D6 (xun2)
71D7 (lan4)
71D8 (mei3)
71D9 (tang4)
71DA (yi1)
71DB (jing3)
71DC (men4)
71DD (none0)
71DE (none0)
71DF (ying2)
71E0 (yu4)
71E1 (yi4)
71E2 (xue2)
71E3 (lan2)
71E4 (tai4)
71E5 (zao4)
71E6 (can4)
71E7 (sui4)
71E8 (xi1)
71E9 (que4)
71EA (cong1)
71EB (lian2)
71EC (hui3)
71ED (zhu2)
71EE (xie4)
71EF (ling2)
71F0 (wei1)
71F1 (yi4)
71F2 (xie2)
71F3 (zhao4)
71F4 (hui4)
71F5 (none0)
71F6 (none0)
71F7 (lan2)
71F8 (ru2)
71F9 (xian3)
71FA (kao3)
71FB (xun1)
71FC (jin4)
71FD (chou2)
71FE (dao4,tao1,tao2)
71FF (yao4)
7200 (he4)
7201 (lan4)
7202 (biao1)
7203 (rong2)
7204 (li4)
7205 (mo4)
7206 (bao4)
7207 (ruo4)
7208 (di4)
7209 (lu:4)
720A (ao2)
720B (xun4)
720C (kuang4)
720D (shuo4)
720E (none0)
720F (li4)
7210 (lu2)
7211 (jue2)
7212 (liao4)
7213 (yan4)
7214 (xi1)
7215 (xie4)
7216 (long2)
7217 (yan4)
7218 (none0)
7219 (rang3,shang4)
721A (yue4)
721B (lan4)
721C (cong2)
721D (jue2,jiao4)
721E (tong2)
721F (guan4)
7220 (none0)
7221 (che4)
7222 (mi2)
7223 (tang3)
7224 (lan4)
7225 (zhu2)
7226 (lan3)
7227 (ling2)
7228 (cuan4)
7229 (yu4)
722A (zhua3,zhao3)
722B (lan4)
722C (pa2)
722D (zheng1)
722E (pao2)
722F (zhao3)
7230 (yuan2)
7231 (ai4)
7232 (wei4,wei2)
7233 (none0)
7234 (jue2)
7235 (jue2)
7236 (fu4,fu3)
7237 (ye2)
7238 (ba4)
7239 (die1)
723A (ye2)
723B (yao2)
723C (zu3)
723D (shuang3)
723E (er3)
723F (pan2,qiang2,ban4)
7240 (chuan2)
7241 (ke1)
7242 (zang1)
7243 (zang1)
7244 (qiang1)
7245 (die2)
7246 (qiang2)
7247 (pian4,pian1)
7248 (ban3)
7249 (pan4)
724A (shao2)
724B (jian1)
724C (pai2)
724D (du2)
724E (yong1)
724F (tou2)
7250 (tou2)
7251 (bian1)
7252 (die2)
7253 (bang3)
7254 (bo2)
7255 (bang3)
7256 (you3)
7257 (none0)
7258 (du2)
7259 (ya2)
725A (cheng4,cheng1)
725B (niu2)
725C (cheng1)
725D (pin4)
725E (jiu1)
725F (mou2,mu4)
7260 (ta1)
7261 (mu3)
7262 (lao2)
7263 (ren4)
7264 (mang2)
7265 (fang1)
7266 (mao2)
7267 (mu4)
7268 (ren4)
7269 (wu4)
726A (yan4)
726B (fa2)
726C (bei4)
726D (si4)
726E (jian4)
726F (gu3)
7270 (you4)
7271 (gu3)
7272 (sheng1)
7273 (mu3)
7274 (di3)
7275 (qian1)
7276 (quan4)
7277 (quan2)
7278 (zi4)
7279 (te4)
727A (xi1)
727B (mang2)
727C (keng1)
727D (qian1)
727E (wu3,wu2)
727F (gu4)
7280 (xi1)
7281 (li2)
7282 (li2)
7283 (pou3)
7284 (ji1)
7285 (gang1)
7286 (zhi2)
7287 (ben1,ben4)
7288 (quan2)
7289 (run1)
728A (du2)
728B (ju4)
728C (jia1)
728D (jian1,qian2)
728E (feng1)
728F (pian1)
7290 (ke1)
7291 (ju2)
7292 (kao4,di2)
7293 (chu2)
7294 (xi4)
7295 (bei4)
7296 (luo4)
7297 (jie4)
7298 (ma2)
7299 (san1)
729A (wei4)
729B (li2)
729C (dun1)
729D (tong2)
729E (se4)
729F (jiang4)
72A0 (xi1)
72A1 (li4)
72A2 (du2)
72A3 (lie4)
72A4 (pi2)
72A5 (piao3)
72A6 (bao4)
72A7 (xi1)
72A8 (chou1)
72A9 (wei4)
72AA (kui2)
72AB (chou1)
72AC (quan3,quan2)
72AD (quan3)
72AE (ba2)
72AF (fan4)
72B0 (qiu2)
72B1 (bo2)
72B2 (chai2)
72B3 (chuo2)
72B4 (an4,han1)
72B5 (jie2)
72B6 (zhuang4)
72B7 (guang3)
72B8 (ma3)
72B9 (you2)
72BA (kang4)
72BB (bo2)
72BC (hou3)
72BD (ya2)
72BE (han4)
72BF (huan1)
72C0 (zhuang4)
72C1 (yun3)
72C2 (kuang2)
72C3 (niu3)
72C4 (di2)
72C5 (qing1)
72C6 (zhong4)
72C7 (yun3)
72C8 (bei4)
72C9 (pi1)
72CA (ju2)
72CB (ni2)
72CC (sheng1)
72CD (pao2)
72CE (xia2)
72CF (tuo2)
72D0 (hu2)
72D1 (ling2)
72D2 (fei4)
72D3 (pi1)
72D4 (ni2)
72D5 (sheng1)
72D6 (you4)
72D7 (gou3)
72D8 (yue4)
72D9 (ju1)
72DA (dan4)
72DB (bo4)
72DC (gu3)
72DD (xian3)
72DE (ning2)
72DF (huan2)
72E0 (hen3)
72E1 (jiao3,jia3)
72E2 (he2,hao2,mo4)
72E3 (zhao4)
72E4 (ji2)
72E5 (huan2)
72E6 (shan1)
72E7 (ta4)
72E8 (rong2)
72E9 (shou4)
72EA (tong1)
72EB (lao3)
72EC (du2)
72ED (xia2)
72EE (shi1)
72EF (kuai4)
72F0 (zheng1)
72F1 (yu4)
72F2 (sun1)
72F3 (yu2)
72F4 (bi4)
72F5 (mang2)
72F6 (xi3)
72F7 (juan4)
72F8 (li2)
72F9 (xia2)
72FA (yin2)
72FB (suan1)
72FC (lang2)
72FD (bei4)
72FE (zhi4)
72FF (yan2)
7300 (sha1)
7301 (li4)
7302 (zhi4)
7303 (xian3)
7304 (jing1)
7305 (han4)
7306 (fei3)
7307 (yao2)
7308 (ba4,pi2)
7309 (qi2)
730A (ni2)
730B (biao1)
730C (yin4)
730D (li2)
730E (lie4)
730F (jian1)
7310 (qiang1)
7311 (kun1)
7312 (yan1)
7313 (guo3)
7314 (zong4)
7315 (mi2)
7316 (chang1)
7317 (yi1)
7318 (zhi4)
7319 (zheng1)
731A (ya2)
731B (meng3)
731C (cai1)
731D (cu4)
731E (she1)
731F (lie4)
7320 (none0)
7321 (luo2)
7322 (hu2)
7323 (zong1)
7324 (hu2)
7325 (wei3)
7326 (feng1)
7327 (wo1)
7328 (yuan2)
7329 (xing1)
732A (zhu1)
732B (mao1,mao2)
732C (wei4)
732D (yuan2)
732E (xian4)
732F (tuan1)
7330 (ya4)
7331 (nao2)
7332 (xie1,he4)
7333 (jia1)
7334 (hou2)
7335 (bian1)
7336 (you2)
7337 (you2)
7338 (mei2)
7339 (cha2)
733A (yao2)
733B (sun1)
733C (bo2)
733D (ming2)
733E (hua2)
733F (yuan2)
7340 (sou1)
7341 (ma3)
7342 (yuan2)
7343 (dai1)
7344 (yu4)
7345 (shi1)
7346 (hao2)
7347 (none0)
7348 (yi4)
7349 (zhen1)
734A (chuang4)
734B (hao2)
734C (man4)
734D (jing4)
734E (jiang3)
734F (mo4)
7350 (zhang1)
7351 (chan2)
7352 (ao2)
7353 (ao2)
7354 (hao2)
7355 (cui1)
7356 (ben4)
7357 (jue2)
7358 (bi4)
7359 (bi4)
735A (huang2)
735B (bu3)
735C (lin2)
735D (yu4)
735E (tong2)
735F (yao4)
7360 (liao2)
7361 (shuo4)
7362 (xiao1)
7363 (shou4)
7364 (none0)
7365 (xi2)
7366 (ge2)
7367 (juan4)
7368 (du2)
7369 (hui4)
736A (kuai4)
736B (xian3)
736C (xie4)
736D (ta3)
736E (xian3)
736F (xun1)
7370 (ning2)
7371 (bian1)
7372 (huo4)
7373 (nou2)
7374 (meng3)
7375 (lie4)
7376 (nao2)
7377 (guang3)
7378 (shou4)
7379 (lu2)
737A (ta4,ta3)
737B (xian4)
737C (mi2)
737D (rang2)
737E (huan1)
737F (nao2)
7380 (luo2)
7381 (xian3)
7382 (qi2)
7383 (qu2)
7384 (xuan2)
7385 (miao4)
7386 (zi1)
7387 (lu:4,shuai4,shuo4)
7388 (lu2)
7389 (yu4)
738A (su4)
738B (wang2,wang4)
738C (qiu2)
738D (ga3)
738E (ding1)
738F (le4)
7390 (ba1)
7391 (ji1)
7392 (hong2)
7393 (di4)
7394 (chuan4)
7395 (gan1)
7396 (jiu3)
7397 (yu2)
7398 (qi3)
7399 (yu2)
739A (yang2,chang4)
739B (ma3)
739C (hong2)
739D (wu3)
739E (fu1)
739F (min2,wen2)
73A0 (jie4)
73A1 (ya2)
73A2 (bin1,fen1)
73A3 (bian4)
73A4 (beng3)
73A5 (yue4)
73A6 (jue2)
73A7 (yun3)
73A8 (jue2)
73A9 (wan2,wan4)
73AA (jian1)
73AB (mei2)
73AC (dan3)
73AD (pi2)
73AE (wei3)
73AF (huan2)
73B0 (xian4)
73B1 (qiang1)
73B2 (ling2)
73B3 (dai4)
73B4 (yi4)
73B5 (an2)
73B6 (ping2)
73B7 (dian4)
73B8 (fu2)
73B9 (xuan2)
73BA (xi3)
73BB (bo1)
73BC (ci3)
73BD (gou3)
73BE (jia3)
73BF (shao2)
73C0 (po4)
73C1 (ci2)
73C2 (ke1)
73C3 (ran3)
73C4 (sheng1)
73C5 (shen1)
73C6 (yi2)
73C7 (zu3)
73C8 (jia1)
73C9 (min2)
73CA (shan1)
73CB (liu3)
73CC (bi4)
73CD (zhen1)
73CE (zhen1)
73CF (jue2)
73D0 (fa3,fa4)
73D1 (long2)
73D2 (jin1)
73D3 (jiao4)
73D4 (jian4)
73D5 (li4)
73D6 (guang1)
73D7 (xian1)
73D8 (zhou1)
73D9 (gong3)
73DA (yan1)
73DB (xiu4)
73DC (yang2)
73DD (xu3)
73DE (luo4)
73DF (su4)
73E0 (zhu1)
73E1 (qin2)
73E2 (ken4)
73E3 (xun2)
73E4 (bao3)
73E5 (er3)
73E6 (xiang2)
73E7 (yao2)
73E8 (xia2)
73E9 (heng2,hang2)
73EA (gui1)
73EB (chong1)
73EC (xu4)
73ED (ban1)
73EE (pei4)
73EF (none0)
73F0 (dang1)
73F1 (ying1)
73F2 (hun2,hui1)
73F3 (wen2)
73F4 (e2)
73F5 (cheng2)
73F6 (ti2,di4)
73F7 (wu3)
73F8 (wu2)
73F9 (cheng2)
73FA (jun4)
73FB (mei2)
73FC (bei4)
73FD (ting3)
73FE (xian4)
73FF (chuo4)
7400 (han2)
7401 (xuan2)
7402 (yan2)
7403 (qiu2)
7404 (quan3)
7405 (lang2)
7406 (li3)
7407 (xiu4)
7408 (fu2)
7409 (liu2)
740A (ya2,ye2)
740B (xi1)
740C (ling2)
740D (li4)
740E (jin1)
740F (lian3)
7410 (suo3)
7411 (suo3)
7412 (none0)
7413 (wan2)
7414 (dian4)
7415 (bing3)
7416 (zhan3)
7417 (cui4)
7418 (min2)
7419 (yu4)
741A (ju1)
741B (chen1)
741C (lai2)
741D (wen2)
741E (sheng4)
741F (wei2)
7420 (dian3)
7421 (chu4)
7422 (zhuo2,zuo2)
7423 (pei3)
7424 (cheng1)
7425 (hu3)
7426 (qi2)
7427 (e4)
7428 (kun1)
7429 (chang1)
742A (qi2)
742B (beng3)
742C (wan3)
742D (lu4)
742E (cong2)
742F (guan3)
7430 (yan3)
7431 (diao1)
7432 (bei4)
7433 (lin2)
7434 (qin2)
7435 (pi2)
7436 (pa2,ba5)
7437 (qiang1)
7438 (zhuo2)
7439 (qin2)
743A (fa4)
743B (none0)
743C (qiong2)
743D (du3)
743E (jie4)
743F (hun2,hui1)
7440 (yu3)
7441 (mao4,mei4)
7442 (mei2)
7443 (chun1)
7444 (xuan1)
7445 (ti2)
7446 (xing1)
7447 (dai4)
7448 (rou2)
7449 (min2)
744A (zhen1)
744B (wei3)
744C (ruan3)
744D (huan4)
744E (xie2)
744F (chuan1)
7450 (jian3)
7451 (zhuan4)
7452 (yang2)
7453 (lian4)
7454 (quan2)
7455 (xia2)
7456 (duan4)
7457 (yuan4)
7458 (ye2)
7459 (nao3)
745A (hu2)
745B (ying1)
745C (yu2)
745D (huang2)
745E (rui4)
745F (se4)
7460 (liu2)
7461 (none0)
7462 (rong2)
7463 (suo3)
7464 (yao2)
7465 (wen1)
7466 (wu3)
7467 (jin1)
7468 (jin4)
7469 (ying2)
746A (ma3)
746B (tao1)
746C (liu2)
746D (tang2)
746E (li4)
746F (lang2)
7470 (gui1)
7471 (tian4)
7472 (qiang1)
7473 (cuo3)
7474 (jue2)
7475 (zhao3)
7476 (yao2)
7477 (ai4)
7478 (bin1)
7479 (tu2)
747A (chang2)
747B (kun1)
747C (zhuan1)
747D (cong1)
747E (jin3)
747F (yi1)
7480 (cui3)
7481 (cong1)
7482 (qi2)
7483 (li2,li5)
7484 (ying3)
7485 (suo3)
7486 (qiu2)
7487 (xuan2)
7488 (ao2)
7489 (lian2,lian3)
748A (man2)
748B (zhang1)
748C (yin2)
748D (none0)
748E (ying1)
748F (wei4)
7490 (lu4)
7491 (wu2)
7492 (deng1)
7493 (none0)
7494 (zeng1)
7495 (xun2)
7496 (qu2)
7497 (dang4)
7498 (lin2)
7499 (liao2)
749A (qiong2)
749B (su4)
749C (huang2)
749D (gui1)
749E (pu2)
749F (jing3)
74A0 (fan2)
74A1 (jin4)
74A2 (liu2)
74A3 (ji1)
74A4 (none0)
74A5 (jing3)
74A6 (ai4)
74A7 (bi4)
74A8 (can4)
74A9 (qu2)
74AA (zao3)
74AB (dang1)
74AC (jiao3)
74AD (gun4)
74AE (tan3)
74AF (hui4)
74B0 (huan2)
74B1 (se4)
74B2 (sui4)
74B3 (tian2)
74B4 (none0)
74B5 (yu2)
74B6 (jin4)
74B7 (fu1)
74B8 (bin1)
74B9 (shu2)
74BA (wen4,wen2)
74BB (zui3)
74BC (lan2)
74BD (xi3)
74BE (ji4)
74BF (xuan2)
74C0 (ruan3)
74C1 (huo4)
74C2 (gai4)
74C3 (lei2)
74C4 (du2)
74C5 (li4)
74C6 (zhi2)
74C7 (rou2)
74C8 (li2)
74C9 (zan4)
74CA (qiong2)
74CB (zhe2)
74CC (gui1)
74CD (sui4)
74CE (la4)
74CF (long2)
74D0 (lu2)
74D1 (li4)
74D2 (zan4)
74D3 (lan4)
74D4 (ying1)
74D5 (mi2)
74D6 (xiang1)
74D7 (xi1)
74D8 (guan4)
74D9 (dao4)
74DA (zan4)
74DB (huan2)
74DC (gua1)
74DD (bao2)
74DE (die2)
74DF (pao2)
74E0 (hu4)
74E1 (zhi2)
74E2 (piao2)
74E3 (ban4)
74E4 (rang2)
74E5 (li4)
74E6 (wa3,wa4)
74E7 (none0)
74E8 (jiang1,hong2)
74E9 (qian2,wa3)
74EA (ban3)
74EB (pen2)
74EC (fang3)
74ED (dan3)
74EE (weng4)
74EF (ou1)
74F0 (none0)
74F1 (none0)
74F2 (none0)
74F3 (hu2)
74F4 (ling2)
74F5 (yi2)
74F6 (ping2)
74F7 (ci2)
74F8 (none0)
74F9 (juan4)
74FA (chang2)
74FB (chi1)
74FC (none0)
74FD (dang4)
74FE (meng3)
74FF (bu4)
7500 (chui2)
7501 (ping2)
7502 (bian1)
7503 (zhou4)
7504 (zhen1)
7505 (none0)
7506 (ci2)
7507 (ying1)
7508 (qi4)
7509 (xian2)
750A (lou3)
750B (di4)
750C (ou1)
750D (meng2)
750E (zhuan1)
750F (beng4)
7510 (lin2)
7511 (zeng4)
7512 (wu3)
7513 (pi4)
7514 (dan1)
7515 (weng4)
7516 (ying1)
7517 (yan3)
7518 (gan1)
7519 (dai4)
751A (shen4,shen2,she2)
751B (tian2)
751C (tian2)
751D (han1)
751E (chang2)
751F (sheng1)
7520 (qing2)
7521 (shen1)
7522 (chan3)
7523 (chan3)
7524 (rui2)
7525 (sheng1)
7526 (su1)
7527 (shen1)
7528 (yong4)
7529 (shuai3)
752A (lu4)
752B (fu3)
752C (yong3)
752D (beng2)
752E (none0)
752F (ning2)
7530 (tian2)
7531 (you2)
7532 (jia3)
7533 (shen1)
7534 (zha2)
7535 (dian4)
7536 (fu2)
7537 (nan2)
7538 (dian4)
7539 (ping2)
753A (ding1,ting3)
753B (hua4)
753C (ting3,ding1)
753D (quan3)
753E (zai1)
753F (meng2)
7540 (bi4)
7541 (qi2)
7542 (liu4)
7543 (xun2)
7544 (liu2)
7545 (chang4)
7546 (mu3)
7547 (yun2)
7548 (fan4)
7549 (fu2)
754A (geng1)
754B (tian2)
754C (jie4)
754D (jie4)
754E (quan3)
754F (wei4)
7550 (fu4)
7551 (tian2)
7552 (mu3)
7553 (none0)
7554 (pan4)
7555 (jiang1)
7556 (wa1)
7557 (da2)
7558 (nan2)
7559 (liu2)
755A (ben3)
755B (zhen3)
755C (chu4,xu4)
755D (mu3)
755E (mu3)
755F (ce4)
7560 (none0)
7561 (gai1)
7562 (bi4)
7563 (da2)
7564 (zhi4)
7565 (lu:e4)
7566 (qi2,xi1)
7567 (lu:e4)
7568 (pan1)
7569 (none0)
756A (fan1,pan1)
756B (hua4)
756C (yu2)
756D (yu2)
756E (mu3)
756F (jun4)
7570 (yi4)
7571 (liu2)
7572 (she1)
7573 (die2)
7574 (chou2)
7575 (hua4)
7576 (dang1,dang4)
7577 (chuo4)
7578 (ji1)
7579 (wan3)
757A (jiang1)
757B (cheng2)
757C (chang4)
757D (tun3)
757E (lei2)
757F (ji1)
7580 (cha1)
7581 (liu2)
7582 (die2)
7583 (tuan3)
7584 (lin2)
7585 (jiang1)
7586 (jiang1)
7587 (chou2)
7588 (bo4)
7589 (die2)
758A (die2)
758B (pi3,shu1,ya3)
758C (nie4)
758D (dan4)
758E (shu1)
758F (shu1,shu4)
7590 (zhi4)
7591 (yi2)
7592 (chuang2)
7593 (nai3)
7594 (ding1)
7595 (bi3)
7596 (jie1)
7597 (liao2)
7598 (gong1,gang1)
7599 (ge1)
759A (jiu4)
759B (zhou3)
759C (xia4)
759D (shan4)
759E (xu1)
759F (nu:e4,yao4)
75A0 (li4)
75A1 (yang2)
75A2 (chen4)
75A3 (you2)
75A4 (ba1)
75A5 (jie4)
75A6 (jue2)
75A7 (xi1)
75A8 (xia1)
75A9 (cui4)
75AA (bi4)
75AB (yi4)
75AC (li4)
75AD (zong4)
75AE (chuang1)
75AF (feng1)
75B0 (zhu4)
75B1 (pao4)
75B2 (pi2)
75B3 (gan1)
75B4 (ke1)
75B5 (ci1,ci2)
75B6 (xie4)
75B7 (qi2)
75B8 (dan3,da5)
75B9 (zhen3)
75BA (fa2)
75BB (zhi3)
75BC (teng2)
75BD (ju1)
75BE (ji2)
75BF (fei4)
75C0 (ju1)
75C1 (dian4)
75C2 (jia1)
75C3 (xuan2,xian2)
75C4 (zha4)
75C5 (bing4)
75C6 (nie4)
75C7 (zheng4,zheng1)
75C8 (yong1)
75C9 (jing4)
75CA (quan2)
75CB (chong2)
75CC (tong1)
75CD (yi2)
75CE (jie4)
75CF (wei3)
75D0 (hui2)
75D1 (duo3)
75D2 (yang3)
75D3 (chi4)
75D4 (zhi4)
75D5 (hen2)
75D6 (ya3)
75D7 (mei4)
75D8 (dou4)
75D9 (jing4)
75DA (xiao1)
75DB (tong4)
75DC (tu1)
75DD (mang2)
75DE (pi3)
75DF (xiao1)
75E0 (suan1)
75E1 (pu1)
75E2 (li4)
75E3 (zhi4)
75E4 (cuo2)
75E5 (duo2)
75E6 (wu4)
75E7 (sha1)
75E8 (lao2)
75E9 (shou4)
75EA (huan4)
75EB (xian2)
75EC (yi4)
75ED (peng2)
75EE (zhang4)
75EF (guan3)
75F0 (tan2)
75F1 (fei4)
75F2 (ma2)
75F3 (lin2)
75F4 (chi1)
75F5 (ji4)
75F6 (tian3)
75F7 (an1)
75F8 (chi4)
75F9 (bi4)
75FA (bi4)
75FB (min2)
75FC (gu4,gu1)
75FD (dui1)
75FE (e1)
75FF (wei3)
7600 (yu1)
7601 (cui4)
7602 (ya3)
7603 (zhu2)
7604 (xi1)
7605 (dan4,dan1,dan3)
7606 (shen4)
7607 (zhong3)
7608 (ji4,zhi4)
7609 (yu4)
760A (hou2)
760B (feng1)
760C (la4)
760D (yang2)
760E (shen4)
760F (tu2)
7610 (yu3)
7611 (gua1)
7612 (wen2)
7613 (huan4)
7614 (ku4)
7615 (jia3,xia2)
7616 (yin1)
7617 (yi4)
7618 (lou4)
7619 (sao4)
761A (jue2)
761B (chi4)
761C (xi2)
761D (guan1)
761E (yi4)
761F (wen1)
7620 (ji2)
7621 (chuang1)
7622 (ban1)
7623 (lei3)
7624 (liu2)
7625 (chai4,cuo2)
7626 (shou4)
7627 (nu:e4,yao4)
7628 (dian1)
7629 (da2,da5)
762A (bie1,bie3)
762B (tan1)
762C (zhang4)
762D (biao1)
762E (shen4)
762F (cu4)
7630 (luo3)
7631 (yi4)
7632 (zong4)
7633 (chou1)
7634 (zhang4)
7635 (zhai4)
7636 (sou4)
7637 (suo3)
7638 (que2)
7639 (diao4)
763A (lou4)
763B (lou4)
763C (mo4)
763D (jin4)
763E (yin3)
763F (ying3)
7640 (huang2)
7641 (fu2)
7642 (liao2)
7643 (long2)
7644 (qiao2)
7645 (liu2)
7646 (lao2)
7647 (xian2)
7648 (fei4)
7649 (dan4,dan1,dan3)
764A (yin4)
764B (he4)
764C (ai2,yan2)
764D (ban1)
764E (xian2)
764F (guan1)
7650 (guai4)
7651 (nong2)
7652 (yu4)
7653 (wei2)
7654 (yi4)
7655 (yong1)
7656 (pi3,pi4)
7657 (lei3)
7658 (li4,ji1)
7659 (shu3)
765A (dan4)
765B (lin3)
765C (dian4)
765D (lin3)
765E (lai4)
765F (bie1,bie3)
7660 (ji4)
7661 (chi1)
7662 (yang3)
7663 (xuan3)
7664 (jie1)
7665 (zheng1,zheng4)
7666 (none0)
7667 (li4)
7668 (huo4)
7669 (lai4)
766A (ji1)
766B (dian1)
766C (xian3,xuan3)
766D (ying3)
766E (yin3)
766F (qu2)
7670 (yong1)
7671 (tan1)
7672 (dian1)
7673 (luo3)
7674 (luan2)
7675 (luan2)
7676 (bo1)
7677 (none0)
7678 (gui3)
7679 (po1)
767A (fa1)
767B (deng1)
767C (fa1)
767D (bai2)
767E (bai3,bo2)
767F (qie2)
7680 (bi1)
7681 (zao4)
7682 (zao4)
7683 (mao4)
7684 (de5,di4,di2)
7685 (pa1)
7686 (jie1)
7687 (huang2)
7688 (gui1)
7689 (ci3)
768A (ling2)
768B (gao1)
768C (mo4)
768D (ji4)
768E (jiao3,jia3)
768F (peng3)
7690 (gao1)
7691 (ai2)
7692 (e2)
7693 (hao4)
7694 (han4)
7695 (bi4)
7696 (wan3,huan3)
7697 (chou2)
7698 (qian4)
7699 (xi1)
769A (ai2)
769B (jiong3)
769C (hao4)
769D (huang3)
769E (hao4)
769F (ze2)
76A0 (cui2)
76A1 (hao4)
76A2 (xiao3)
76A3 (ye4)
76A4 (po2)
76A5 (hao4)
76A6 (jiao3)
76A7 (ai4)
76A8 (xing1)
76A9 (huang4)
76AA (li4)
76AB (piao3)
76AC (he4)
76AD (jiao4)
76AE (pi2)
76AF (gan3)
76B0 (pao4)
76B1 (zhou4)
76B2 (jun1)
76B3 (qiu2)
76B4 (cun1)
76B5 (que4)
76B6 (zha1)
76B7 (gu3)
76B8 (jun1)
76B9 (jun1)
76BA (zhou4)
76BB (zha1)
76BC (gu3)
76BD (zhan3)
76BE (du2)
76BF (min3)
76C0 (qi3)
76C1 (ying2)
76C2 (yu2)
76C3 (bei1)
76C4 (zhao1)
76C5 (zhong1)
76C6 (pen2)
76C7 (he2)
76C8 (ying2)
76C9 (he2)
76CA (yi4)
76CB (bo1)
76CC (wan3)
76CD (he2)
76CE (ang4)
76CF (zhan3)
76D0 (yan2)
76D1 (jian1,jian4)
76D2 (he2)
76D3 (yu1)
76D4 (kui1)
76D5 (fan4)
76D6 (gai4,ge3)
76D7 (dao4)
76D8 (pan2)
76D9 (fu3)
76DA (qiu2)
76DB (sheng4,cheng2)
76DC (dao4)
76DD (lu4)
76DE (zhan3)
76DF (meng2,ming2)
76E0 (lu4)
76E1 (jin4,jin3)
76E2 (xu4)
76E3 (jian1,jian4)
76E4 (pan2)
76E5 (guan4)
76E6 (an1)
76E7 (lu2)
76E8 (xu3)
76E9 (zhou1)
76EA (dang4)
76EB (an1)
76EC (gu3)
76ED (li4)
76EE (mu4)
76EF (ding1)
76F0 (gan3)
76F1 (xu1)
76F2 (mang2)
76F3 (mang2)
76F4 (zhi2)
76F5 (qi4)
76F6 (wan3)
76F7 (tian2)
76F8 (xiang1,xiang4)
76F9 (dun3)
76FA (xin1)
76FB (xi1)
76FC (pan4)
76FD (feng1)
76FE (dun4,shun3)
76FF (min2)
7700 (ming2)
7701 (sheng3,xing3)
7702 (shi4)
7703 (yun2)
7704 (mian3,mian4)
7705 (pan1)
7706 (fang3)
7707 (miao3)
7708 (dan1)
7709 (mei2)
770A (mao4)
770B (kan4,kan1)
770C (xian4)
770D (kou1)
770E (shi4)
770F (yang1)
7710 (zheng1)
7711 (yao3)
7712 (shen1)
7713 (huo4)
7714 (da4)
7715 (zhen3)
7716 (kuang4)
7717 (ju1)
7718 (shen4)
7719 (yi2)
771A (sheng3)
771B (mei4)
771C (mo4)
771D (zhu3)
771E (zhen1)
771F (zhen1)
7720 (mian2)
7721 (di1)
7722 (yuan1)
7723 (die2)
7724 (yi2)
7725 (zi4)
7726 (zi4)
7727 (chao3)
7728 (zha3)
7729 (xuan4)
772A (bing3)
772B (mi3)
772C (long2)
772D (sui1)
772E (tong2)
772F (mi1,mi2)
7730 (die2)
7731 (yi2)
7732 (er4)
7733 (ming3)
7734 (xuan4)
7735 (chi1)
7736 (kuang4)
7737 (juan4)
7738 (mou2)
7739 (zhen4)
773A (tiao4)
773B (yang2)
773C (yan3)
773D (mo4)
773E (zhong4)
773F (mai4)
7740 (zhe5,zhuo2,zhao2,zhao1)
7741 (zheng1)
7742 (mei2)
7743 (suo1)
7744 (shao4)
7745 (han4)
7746 (huan3)
7747 (di4)
7748 (cheng3)
7749 (cuo1)
774A (juan4)
774B (e2)
774C (wan3)
774D (xian4)
774E (xi1)
774F (kun4)
7750 (lai4)
7751 (jian3)
7752 (shan3)
7753 (tian3)
7754 (hun3)
7755 (wan3)
7756 (ling2)
7757 (shi4)
7758 (qiong2)
7759 (lie4)
775A (ya2,ai2)
775B (jing1)
775C (zheng1)
775D (li2)
775E (lai4)
775F (sui4)
7760 (juan4)
7761 (shui4)
7762 (sui1)
7763 (du1)
7764 (pi4)
7765 (pi4,bi4)
7766 (mu4)
7767 (hun1)
7768 (ni4)
7769 (lu4)
776A (gao1)
776B (jie2)
776C (cai3)
776D (zhou3)
776E (yu2)
776F (hun1)
7770 (ma4)
7771 (xia4)
7772 (xing3)
7773 (hui1)
7774 (gun4)
7775 (none0)
7776 (chun3)
7777 (jian1)
7778 (mei4)
7779 (du3)
777A (hou2)
777B (xuan1)
777C (ti2)
777D (kui2)
777E (gao1)
777F (rui4)
7780 (mao4)
7781 (xu4)
7782 (fa1)
7783 (wen1)
7784 (miao2)
7785 (chou3)
7786 (kui4)
7787 (mi1)
7788 (weng3)
7789 (kou4)
778A (dang4)
778B (chen1)
778C (ke1)
778D (sou3)
778E (xia1)
778F (qiong2)
7790 (mao4)
7791 (ming2)
7792 (man2)
7793 (shui4)
7794 (ze2)
7795 (zhang4)
7796 (yi4)
7797 (diao1)
7798 (kou1)
7799 (mo4)
779A (shun4)
779B (cong1)
779C (lou2)
779D (chi1)
779E (man2)
779F (piao3)
77A0 (cheng1)
77A1 (ji4)
77A2 (meng2)
77A3 (huan4)
77A4 (run2)
77A5 (pie1)
77A6 (xi1)
77A7 (qiao2,ya3)
77A8 (pu1)
77A9 (zhu3)
77AA (deng4)
77AB (shen3)
77AC (shun4)
77AD (liao4,liao3)
77AE (che4)
77AF (xian2)
77B0 (kan4)
77B1 (ye4)
77B2 (xu4)
77B3 (tong2)
77B4 (wu2)
77B5 (lin2)
77B6 (kui4)
77B7 (jian4)
77B8 (ye4)
77B9 (ai4)
77BA (hui4)
77BB (zhan1)
77BC (jian3)
77BD (gu3)
77BE (zhao4)
77BF (ju4,qu2,qu1)
77C0 (wei2)
77C1 (chou3)
77C2 (ji4)
77C3 (ning3)
77C4 (xun1)
77C5 (yao4)
77C6 (huo4)
77C7 (meng2)
77C8 (mian2)
77C9 (bin1,pin2)
77CA (mian2)
77CB (li4)
77CC (guang4)
77CD (jue2)
77CE (xuan1)
77CF (mian2)
77D0 (huo4)
77D1 (lu2)
77D2 (meng2)
77D3 (long2)
77D4 (guan4)
77D5 (man3)
77D6 (xi3)
77D7 (chu4)
77D8 (tang3)
77D9 (kan4)
77DA (zhu3)
77DB (mao2)
77DC (jin1,qin2,guan1)
77DD (lin2)
77DE (yu4)
77DF (shuo4)
77E0 (ce4)
77E1 (jue2)
77E2 (shi3)
77E3 (yi3)
77E4 (shen3)
77E5 (zhi1,zhi4)
77E6 (hou2,hou4)
77E7 (shen3)
77E8 (ying3)
77E9 (ju3,ju5)
77EA (zhou1)
77EB (jiao3,jia3,jiao2)
77EC (cuo2)
77ED (duan3)
77EE (ai3)
77EF (jiao3,jia3,jiao2)
77F0 (zeng1)
77F1 (huo4)
77F2 (bai3,bai4,pai3)
77F3 (shi2,dan4)
77F4 (ding4)
77F5 (qi4)
77F6 (ji1)
77F7 (zi3)
77F8 (gan1)
77F9 (wu4)
77FA (tuo1)
77FB (ku1)
77FC (qiang1)
77FD (xi1)
77FE (fan2)
77FF (kuang4)
7800 (dang4)
7801 (ma3)
7802 (sha1)
7803 (dan1)
7804 (jue2)
7805 (li4)
7806 (fu1)
7807 (min2)
7808 (nuo3)
7809 (hua1,xu1)
780A (kang4)
780B (zhi3)
780C (qi4,qie4)
780D (kan3)
780E (jie4)
780F (fen1)
7810 (e4)
7811 (ya4)
7812 (pi1)
7813 (zhe2)
7814 (yan2,yan4)
7815 (sui4)
7816 (zhuan1)
7817 (che1)
7818 (dun4)
7819 (pan1)
781A (yan4)
781B (none0)
781C (feng1)
781D (fa3)
781E (mo4)
781F (zha3,zuo4)
7820 (qu1)
7821 (yu4)
7822 (ke1)
7823 (tuo2)
7824 (tuo2)
7825 (di3)
7826 (zhai4)
7827 (zhen1)
7828 (e4)
7829 (fu2,fei4)
782A (mu3)
782B (zhu3)
782C (la2,li4)
782D (bian1)
782E (nu3)
782F (ping1)
7830 (peng1)
7831 (ling2)
7832 (pao4)
7833 (le4)
7834 (po4)
7835 (bo1)
7836 (po4)
7837 (shen1)
7838 (za2)
7839 (ai4)
783A (li4)
783B (long2)
783C (tong2)
783D (none0)
783E (li4)
783F (kuang4)
7840 (chu3)
7841 (keng1)
7842 (quan2)
7843 (zhu1)
7844 (kuang1)
7845 (gui1,huo4)
7846 (e4)
7847 (nao2)
7848 (jia2)
7849 (lu4)
784A (wei3,kui4)
784B (ai4)
784C (luo4,ge4)
784D (ken4)
784E (xing2)
784F (yan2)
7850 (dong4,dong3)
7851 (peng1)
7852 (xi1)
7853 (none0)
7854 (hong2)
7855 (shuo4)
7856 (xia2)
7857 (qiao1)
7858 (none0)
7859 (wei4)
785A (qiao2)
785B (none0)
785C (keng1)
785D (xiao1)
785E (que4)
785F (chan4)
7860 (lang3)
7861 (hong1)
7862 (yu2)
7863 (xiao1)
7864 (xia2)
7865 (mang3)
7866 (long4)
7867 (none0)
7868 (che1)
7869 (che4)
786A (wo4)
786B (liu2)
786C (ying4)
786D (mang2)
786E (que4)
786F (yan4)
7870 (cuo3)
7871 (kun3)
7872 (yu4)
7873 (none0)
7874 (none0)
7875 (lu3)
7876 (chen3)
7877 (jian3)
7878 (none0)
7879 (song1)
787A (zhuo2)
787B (keng1)
787C (peng2)
787D (yan3)
787E (zhui4)
787F (kong1)
7880 (ceng2)
7881 (qi2)
7882 (zong4)
7883 (qing4)
7884 (lin2)
7885 (jun1)
7886 (bo1)
7887 (ding4)
7888 (min2)
7889 (diao1)
788A (jian1)
788B (he4)
788C (liu4,lu4)
788D (ai4)
788E (sui4)
788F (que4)
7890 (ling2)
7891 (bei1)
7892 (yin2)
7893 (dui4)
7894 (wu3)
7895 (qi2)
7896 (lun2)
7897 (wan3)
7898 (dian3)
7899 (gang1)
789A (bei4)
789B (qi4)
789C (chen3)
789D (ruan3)
789E (yan2)
789F (die2)
78A0 (ding4)
78A1 (zhou5,zhou2)
78A2 (tuo2)
78A3 (jie2)
78A4 (ying1)
78A5 (bian3)
78A6 (ke4)
78A7 (bi4)
78A8 (wei1)
78A9 (shuo4,shi2)
78AA (zhen1)
78AB (duan4)
78AC (xia2)
78AD (dang4)
78AE (ti2)
78AF (nao3)
78B0 (peng4)
78B1 (jian3)
78B2 (di4)
78B3 (tan4)
78B4 (cha2,cha1)
78B5 (none0)
78B6 (qi4)
78B7 (none0)
78B8 (feng1)
78B9 (xuan4)
78BA (que4)
78BB (que4)
78BC (ma3)
78BD (gong1)
78BE (nian3)
78BF (su4)
78C0 (e2)
78C1 (ci2)
78C2 (liu4)
78C3 (si1)
78C4 (tang2)
78C5 (bang4,pang2,pang1)
78C6 (hua2)
78C7 (pi1)
78C8 (wei3)
78C9 (sang3)
78CA (lei3)
78CB (cuo1)
78CC (tian2)
78CD (xia2)
78CE (xi1)
78CF (lian2)
78D0 (pan2)
78D1 (wei4)
78D2 (yun3)
78D3 (dui1)
78D4 (zhe2)
78D5 (ke1)
78D6 (la2)
78D7 (none0)
78D8 (qing4)
78D9 (gun3)
78DA (zhuan1)
78DB (chan2)
78DC (qi4)
78DD (ao2)
78DE (peng1)
78DF (lu4)
78E0 (lu3)
78E1 (kan4)
78E2 (qiang3)
78E3 (chen3)
78E4 (yin3)
78E5 (lei3)
78E6 (biao1)
78E7 (qi4)
78E8 (mo2,mo4)
78E9 (qi1)
78EA (cui1)
78EB (zong1)
78EC (qing4)
78ED (chuo4)
78EE (none0)
78EF (ji1)
78F0 (shan4)
78F1 (lao2)
78F2 (qu2)
78F3 (zeng1)
78F4 (deng4)
78F5 (jian4)
78F6 (xi4)
78F7 (lin2)
78F8 (ding4)
78F9 (dian4)
78FA (huang2)
78FB (pan2)
78FC (za2)
78FD (qiao1)
78FE (di1)
78FF (li4)
7900 (jian4)
7901 (jiao1)
7902 (xi1)
7903 (zhang3)
7904 (qiao2)
7905 (dun1)
7906 (jian3)
7907 (yu4)
7908 (zhui4)
7909 (he2)
790A (huo4)
790B (zhai2)
790C (lei2)
790D (ke3)
790E (chu3)
790F (ji2)
7910 (que4)
7911 (dang4)
7912 (wo4,yi3)
7913 (jiang1)
7914 (pi4)
7915 (pi1)
7916 (yu4)
7917 (pin1)
7918 (qi4)
7919 (ai4)
791A (ke1)
791B (jian1)
791C (yu4)
791D (ruan3)
791E (meng2)
791F (pao4)
7920 (zi1)
7921 (bo2)
7922 (none0)
7923 (mie4)
7924 (ca3)
7925 (xian2)
7926 (kuang4,gong3)
7927 (lei3)
7928 (lei3)
7929 (zhi4)
792A (li4)
792B (li4)
792C (fan2)
792D (que4)
792E (pao4)
792F (ying1)
7930 (li4)
7931 (long2)
7932 (long2)
7933 (mo4)
7934 (bo2)
7935 (shuang1)
7936 (guan4)
7937 (lan2)
7938 (zan3)
7939 (yan2)
793A (shi4)
793B (shi4)
793C (li3)
793D (reng2)
793E (she4)
793F (yue4)
7940 (si4)
7941 (qi2)
7942 (ta1)
7943 (ma4)
7944 (xie4)
7945 (yao1)
7946 (xian1)
7947 (zhi3,qi2,zhi1)
7948 (qi2)
7949 (zhi3)
794A (beng1)
794B (shu1)
794C (chong1)
794D (none0)
794E (yi1)
794F (shi2)
7950 (you4)
7951 (zhi4)
7952 (tiao2)
7953 (fu2)
7954 (fu4)
7955 (mi4)
7956 (zu3)
7957 (zhi1)
7958 (suan4)
7959 (mei4)
795A (zuo4)
795B (qu1)
795C (hu4)
795D (zhu4)
795E (shen2)
795F (sui4)
7960 (ci2)
7961 (chai2)
7962 (mi2,ni3)
7963 (lu:3)
7964 (yu3)
7965 (xiang2)
7966 (wu2)
7967 (tiao1)
7968 (piao4)
7969 (zhu1)
796A (gui3)
796B (xia2)
796C (zhi1)
796D (ji4,zhai4)
796E (gao4)
796F (zhen1)
7970 (gao4)
7971 (shui4)
7972 (jin4)
7973 (zhen3)
7974 (gai1,jie4)
7975 (kun3)
7976 (di4)
7977 (dao3)
7978 (huo4)
7979 (tao2)
797A (qi2)
797B (gu4)
797C (guan4)
797D (zui4)
797E (ling2)
797F (lu4)
7980 (bing3)
7981 (jin4,jin1)
7982 (dao3)
7983 (zhi2)
7984 (lu4)
7985 (shan4,chan2)
7986 (bei1)
7987 (zhe3)
7988 (hui1)
7989 (you3)
798A (xi4)
798B (yin1)
798C (zi1)
798D (huo4)
798E (zhen1)
798F (fu2)
7990 (yuan4)
7991 (wu2)
7992 (xian3)
7993 (yang2)
7994 (ti2)
7995 (yi1)
7996 (mei2)
7997 (si1)
7998 (di4)
7999 (none0)
799A (zhuo2)
799B (zhen1)
799C (yong3)
799D (ji4)
799E (gao4)
799F (tang2)
79A0 (chi3)
79A1 (ma4)
79A2 (ta1)
79A3 (none0)
79A4 (xuan1)
79A5 (qi2)
79A6 (yu4)
79A7 (xi3)
79A8 (ji1)
79A9 (si4)
79AA (chan2,shan4)
79AB (xuan1)
79AC (hui4)
79AD (sui4)
79AE (li3)
79AF (nong2)
79B0 (ni3,mi2)
79B1 (dao3)
79B2 (li4)
79B3 (rang2,rang3)
79B4 (yue4)
79B5 (ti2)
79B6 (zan3)
79B7 (lei4)
79B8 (rou2)
79B9 (yu3)
79BA (yu2,yu4)
79BB (li2)
79BC (xie4)
79BD (qin2)
79BE (he2)
79BF (tu1)
79C0 (xiu4)
79C1 (si1)
79C2 (ren2)
79C3 (tu1)
79C4 (zi3)
79C5 (cha2)
79C6 (gan3)
79C7 (yi4)
79C8 (xian1)
79C9 (bing3)
79CA (nian2)
79CB (qiu1)
79CC (qiu1)
79CD (zhong3,chong2,zhong4)
79CE (fen4)
79CF (hao4)
79D0 (yun2)
79D1 (ke1)
79D2 (miao3)
79D3 (zhi1)
79D4 (jing1)
79D5 (bi3)
79D6 (zhi1)
79D7 (yu4)
79D8 (mi4,bi4,lin2)
79D9 (ku4)
79DA (ban4)
79DB (pi1)
79DC (ni2)
79DD (li4)
79DE (you2)
79DF (zu1)
79E0 (pi1)
79E1 (ba2)
79E2 (ling2)
79E3 (mo4)
79E4 (cheng4,chen4,cheng1)
79E5 (nian2)
79E6 (qin2)
79E7 (yang1)
79E8 (zuo2)
79E9 (zhi4)
79EA (zhi1)
79EB (shu2)
79EC (ju4)
79ED (zi3)
79EE (tai2)
79EF (ji1)
79F0 (cheng1,chen4,cheng4)
79F1 (tong2)
79F2 (zhi4)
79F3 (huo2)
79F4 (he2)
79F5 (yin1)
79F6 (zi1)
79F7 (zhi2)
79F8 (jie1)
79F9 (ren3)
79FA (du4)
79FB (yi2)
79FC (zhu4)
79FD (hui4)
79FE (nong2)
79FF (fu3)
7A00 (xi1)
7A01 (kao3)
7A02 (lang2)
7A03 (fu1,fu2)
7A04 (ze4)
7A05 (shui4)
7A06 (lu:3)
7A07 (kun3)
7A08 (gan3)
7A09 (jing1)
7A0A (ti2)
7A0B (cheng2)
7A0C (tu2)
7A0D (shao1,shao4)
7A0E (shui4)
7A0F (ya4)
7A10 (lun3)
7A11 (lu4)
7A12 (gu4)
7A13 (zuo2)
7A14 (ren3)
7A15 (zhun4)
7A16 (bang4)
7A17 (bai4,bi4)
7A18 (ji1,qi2)
7A19 (zhi2)
7A1A (zhi4)
7A1B (kun3)
7A1C (leng2)
7A1D (peng2)
7A1E (ke1)
7A1F (bing3)
7A20 (chou2)
7A21 (zui4)
7A22 (yu4)
7A23 (su1)
7A24 (none0)
7A25 (none0)
7A26 (yi1)
7A27 (xi4)
7A28 (bian1)
7A29 (ji4)
7A2A (fu4)
7A2B (bi1)
7A2C (nuo4)
7A2D (jie1)
7A2E (zhong3,chong2,zhong4)
7A2F (zong1)
7A30 (xu1)
7A31 (cheng1,chen4,cheng4)
7A32 (dao4)
7A33 (wen3)
7A34 (lian2)
7A35 (zi1)
7A36 (yu4)
7A37 (ji4)
7A38 (xu4)
7A39 (zhen3)
7A3A (zhi4)
7A3B (dao4)
7A3C (jia4)
7A3D (ji1,qi3)
7A3E (gao3)
7A3F (gao3)
7A40 (gu3)
7A41 (rong2)
7A42 (sui4)
7A43 (none0)
7A44 (ji4)
7A45 (kang1)
7A46 (mu4)
7A47 (shan1)
7A48 (men2)
7A49 (zhi4)
7A4A (ji4)
7A4B (lu4)
7A4C (su1,wei4)
7A4D (ji1)
7A4E (ying3)
7A4F (wen3)
7A50 (qiu1)
7A51 (se4)
7A52 (none0)
7A53 (yi4)
7A54 (huang2)
7A55 (qie4)
7A56 (ji3)
7A57 (sui4)
7A58 (xiao1)
7A59 (pu2)
7A5A (jiao1)
7A5B (zhuo1)
7A5C (tong2)
7A5D (none0)
7A5E (lu:3)
7A5F (sui4)
7A60 (nong2)
7A61 (se4)
7A62 (hui4)
7A63 (rang2)
7A64 (nuo4)
7A65 (yu4)
7A66 (none0)
7A67 (ji4)
7A68 (tui2)
7A69 (wen3)
7A6A (cheng1,chen4,cheng4)
7A6B (huo4)
7A6C (gong3)
7A6D (lu:3)
7A6E (biao1)
7A6F (none0)
7A70 (rang2)
7A71 (jue2)
7A72 (li2)
7A73 (zan4)
7A74 (xue2,xue4)
7A75 (wa1)
7A76 (jiu1,jiu4)
7A77 (qiong2)
7A78 (xi1)
7A79 (qiong2,qiong1)
7A7A (kong1,kong4)
7A7B (yu1)
7A7C (sen1)
7A7D (jing3)
7A7E (yao4)
7A7F (chuan1)
7A80 (zhun1)
7A81 (tu1,tu2)
7A82 (lao2)
7A83 (qie4)
7A84 (zhai3,ze2)
7A85 (yao3)
7A86 (bian3)
7A87 (bao2)
7A88 (yao3)
7A89 (bing3)
7A8A (yu3)
7A8B (zhu2)
7A8C (jiao4)
7A8D (qiao4)
7A8E (diao4)
7A8F (wu1)
7A90 (gui1)
7A91 (yao2)
7A92 (zhi4)
7A93 (chuan1)
7A94 (yao3)
7A95 (tiao3)
7A96 (jiao4)
7A97 (chuang1)
7A98 (jiong3,jun3)
7A99 (xiao1)
7A9A (cheng2)
7A9B (kou4)
7A9C (cuan4)
7A9D (wo1)
7A9E (dan4)
7A9F (ku1)
7AA0 (ke1)
7AA1 (zhui4)
7AA2 (xu4)
7AA3 (su1)
7AA4 (none0)
7AA5 (kui1)
7AA6 (dou4)
7AA7 (none0)
7AA8 (yin4,xun1)
7AA9 (wo1)
7AAA (wa1)
7AAB (ya4)
7AAC (yu2)
7AAD (ju4)
7AAE (qiong2)
7AAF (yao2)
7AB0 (yao2)
7AB1 (tiao4)
7AB2 (liao4)
7AB3 (yu3)
7AB4 (tian2)
7AB5 (diao4)
7AB6 (ju4)
7AB7 (liao2)
7AB8 (xi1)
7AB9 (wu4)
7ABA (kui1)
7ABB (chuang1)
7ABC (ju3)
7ABD (none0)
7ABE (kuan3)
7ABF (long2)
7AC0 (cheng1)
7AC1 (cui4)
7AC2 (piao2)
7AC3 (zao4)
7AC4 (cuan4)
7AC5 (qiao4)
7AC6 (qiong2)
7AC7 (dou4)
7AC8 (zao4)
7AC9 (zao4)
7ACA (qie4)
7ACB (li4)
7ACC (chu4)
7ACD (shi2,gong1,sheng1)
7ACE (fu4)
7ACF (qian1,gong1,sheng1)
7AD0 (chu4)
7AD1 (hong2)
7AD2 (qi2,ji1)
7AD3 (qian1,fen1,zhi1,yi1,gong1,sheng1)
7AD4 (gong1,sheng1)
7AD5 (shi2,fen1,zhi1,yi1,gong1,sheng1)
7AD6 (shu4)
7AD7 (miao4)
7AD8 (ju3)
7AD9 (zhan4)
7ADA (zhu4)
7ADB (ling2)
7ADC (long2)
7ADD (bing4,bing1)
7ADE (jing4)
7ADF (jing4)
7AE0 (zhang1)
7AE1 (yi1,gong1,sheng1,bai3,bei4,si4)
7AE2 (si4,qi2)
7AE3 (jun4)
7AE4 (hong2)
7AE5 (tong2)
7AE6 (song3)
7AE7 (jing4)
7AE8 (diao4)
7AE9 (yi4)
7AEA (shu4)
7AEB (jing4)
7AEC (qu3)
7AED (jie2)
7AEE (ping2)
7AEF (duan1)
7AF0 (shao2)
7AF1 (zhuan3)
7AF2 (ceng2)
7AF3 (deng1)
7AF4 (cun1)
7AF5 (huai1)
7AF6 (jing4)
7AF7 (kan4)
7AF8 (jing4)
7AF9 (zhu2)
7AFA (zhu2)
7AFB (le4)
7AFC (peng2)
7AFD (yu2)
7AFE (chi2)
7AFF (gan1)
7B00 (mang2)
7B01 (zhu2)
7B02 (none0)
7B03 (du3)
7B04 (ji1)
7B05 (xiao2)
7B06 (ba1)
7B07 (suan4)
7B08 (ji2)
7B09 (zhen3)
7B0A (zhao4)
7B0B (sun3)
7B0C (ya2)
7B0D (zhui4)
7B0E (yuan2)
7B0F (hu4)
7B10 (gang1)
7B11 (xiao4)
7B12 (cen2)
7B13 (pi2)
7B14 (bi3)
7B15 (jian3)
7B16 (yi3)
7B17 (dong1)
7B18 (shan1)
7B19 (sheng1)
7B1A (xia2)
7B1B (di2)
7B1C (zhu2)
7B1D (na4)
7B1E (chi1)
7B1F (gu1)
7B20 (li4)
7B21 (qie4)
7B22 (min3)
7B23 (bao1)
7B24 (tiao2)
7B25 (si4)
7B26 (fu2)
7B27 (ce4)
7B28 (ben4)
7B29 (fa2)
7B2A (da2)
7B2B (zi3)
7B2C (di4)
7B2D (ling2)
7B2E (ze2,zuo2)
7B2F (nu2)
7B30 (fu2)
7B31 (gou3)
7B32 (fan2)
7B33 (jia1)
7B34 (ge3)
7B35 (fan4)
7B36 (shi3)
7B37 (mao3)
7B38 (po3)
7B39 (none0)
7B3A (jian1)
7B3B (qiong2)
7B3C (long3,long2)
7B3D (none0)
7B3E (bian1)
7B3F (luo4)
7B40 (gui4)
7B41 (qu3,qu1)
7B42 (chi2)
7B43 (yin1)
7B44 (yao4)
7B45 (xian3)
7B46 (bi3)
7B47 (qiong2)
7B48 (gua1)
7B49 (deng3)
7B4A (jiao3)
7B4B (jin1)
7B4C (quan2)
7B4D (sun3)
7B4E (ru2)
7B4F (fa2)
7B50 (kuang1)
7B51 (zhu4,zhu2)
7B52 (tong3)
7B53 (ji1)
7B54 (da2,da1)
7B55 (hang2)
7B56 (ce4)
7B57 (zhong4)
7B58 (kou4)
7B59 (lai2)
7B5A (bi4)
7B5B (shai1)
7B5C (dang1)
7B5D (zheng1)
7B5E (ce4)
7B5F (fu1)
7B60 (yun2,jun1)
7B61 (tu2)
7B62 (pa2)
7B63 (li4)
7B64 (lang2)
7B65 (ju3)
7B66 (guan3)
7B67 (jian3)
7B68 (han2)
7B69 (tong3)
7B6A (xia2)
7B6B (zhi4)
7B6C (cheng2)
7B6D (suan4)
7B6E (shi4)
7B6F (zhu4)
7B70 (zuo2)
7B71 (xiao3)
7B72 (shao1)
7B73 (ting2)
7B74 (jia2,ce4)
7B75 (yan2)
7B76 (gao3)
7B77 (kuai4)
7B78 (gan1)
7B79 (chou2)
7B7A (kuang1)
7B7B (gang4)
7B7C (yun2)
7B7D (none0)
7B7E (qian1)
7B7F (xiao3)
7B80 (jian3)
7B81 (pu2)
7B82 (lai2)
7B83 (zou1)
7B84 (bi4)
7B85 (bi4)
7B86 (bi4)
7B87 (ge4)
7B88 (chi2)
7B89 (guai3)
7B8A (yu1)
7B8B (jian1)
7B8C (zhao4)
7B8D (gu1)
7B8E (chi2)
7B8F (zheng1)
7B90 (qing4)
7B91 (sha4)
7B92 (zhou3)
7B93 (lu4)
7B94 (bo2)
7B95 (ji1,ji5)
7B96 (lin2)
7B97 (suan4)
7B98 (jun4)
7B99 (fu1)
7B9A (zha2)
7B9B (gu1)
7B9C (kong1)
7B9D (qian2)
7B9E (qian1)
7B9F (jun4,jun1)
7BA0 (chui2)
7BA1 (guan3)
7BA2 (yuan1)
7BA3 (ce4)
7BA4 (ju2)
7BA5 (bo3)
7BA6 (ze2)
7BA7 (qie4)
7BA8 (tuo4)
7BA9 (luo2)
7BAA (dan1)
7BAB (xiao1)
7BAC (ruo4)
7BAD (jian4)
7BAE (none0)
7BAF (bian1)
7BB0 (sun3)
7BB1 (xiang1)
7BB2 (xian3)
7BB3 (ping2)
7BB4 (zhen1)
7BB5 (sheng3)
7BB6 (hu2)
7BB7 (shi1,yi2)
7BB8 (zhu4)
7BB9 (yue1)
7BBA (chun1)
7BBB (fu1)
7BBC (wu1)
7BBD (dong3)
7BBE (shuo4)
7BBF (ji2)
7BC0 (jie2,jie1)
7BC1 (huang2)
7BC2 (xing1)
7BC3 (mei2)
7BC4 (fan4)
7BC5 (chuan2)
7BC6 (zhuan4)
7BC7 (pian1)
7BC8 (feng1)
7BC9 (zhu2,zhu4)
7BCA (hong2)
7BCB (qie4)
7BCC (hou2)
7BCD (qiu1)
7BCE (miao3)
7BCF (qian4)
7BD0 (none0)
7BD1 (kui4)
7BD2 (none0)
7BD3 (lou3)
7BD4 (yun2)
7BD5 (he2)
7BD6 (tang2)
7BD7 (yue4)
7BD8 (chou1)
7BD9 (gao1)
7BDA (fei3)
7BDB (ruo4)
7BDC (zheng1)
7BDD (gou1)
7BDE (nie4)
7BDF (qian4)
7BE0 (xiao3)
7BE1 (cuan4)
7BE2 (gong1)
7BE3 (pang2)
7BE4 (du3)
7BE5 (li4)
7BE6 (bi4)
7BE7 (zhuo2)
7BE8 (chu2)
7BE9 (shai1)
7BEA (chi2)
7BEB (zhu2)
7BEC (qiang1)
7BED (long2,long3)
7BEE (lan2)
7BEF (jian1)
7BF0 (bu4)
7BF1 (li2)
7BF2 (hui4)
7BF3 (bi4)
7BF4 (di2)
7BF5 (cong1)
7BF6 (yan1)
7BF7 (peng2)
7BF8 (sen1)
7BF9 (cuan4)
7BFA (pai2)
7BFB (piao4)
7BFC (dou1)
7BFD (yu3)
7BFE (mie4)
7BFF (zhuan1)
7C00 (ze2,kui4)
7C01 (xi3)
7C02 (guo2)
7C03 (yi2)
7C04 (hu4)
7C05 (chan3)
7C06 (kou4)
7C07 (cu4)
7C08 (ping2)
7C09 (zao4)
7C0A (ji1)
7C0B (gui3)
7C0C (su4)
7C0D (lou3)
7C0E (zha4)
7C0F (lu4)
7C10 (nian3)
7C11 (suo1)
7C12 (cuan4)
7C13 (none0)
7C14 (suo1)
7C15 (le4)
7C16 (duan4)
7C17 (liang2)
7C18 (xiao1)
7C19 (bo2)
7C1A (mi4)
7C1B (shai1)
7C1C (dang4)
7C1D (liao2)
7C1E (dan1)
7C1F (dian4)
7C20 (fu3)
7C21 (jian3)
7C22 (min3)
7C23 (kui4)
7C24 (dai4)
7C25 (qiao2)
7C26 (deng1)
7C27 (huang2)
7C28 (sun3)
7C29 (lao2)
7C2A (zan1)
7C2B (xiao1)
7C2C (lu4)
7C2D (shi4)
7C2E (zan1)
7C2F (none0)
7C30 (pai2)
7C31 (qi2)
7C32 (pai2)
7C33 (gan4)
7C34 (ju4)
7C35 (du4)
7C36 (lu4)
7C37 (yan2)
7C38 (bo4,bo3)
7C39 (dang1)
7C3A (sai4)
7C3B (ke1)
7C3C (gou4)
7C3D (qian1)
7C3E (lian2)
7C3F (bu4)
7C40 (zhou4)
7C41 (lai4)
7C42 (none0)
7C43 (lan2)
7C44 (kui4)
7C45 (yu2)
7C46 (yue4)
7C47 (hao2)
7C48 (zhen1)
7C49 (tai2)
7C4A (ti4)
7C4B (mi2)
7C4C (chou2)
7C4D (ji2)
7C4E (none0)
7C4F (qi2)
7C50 (teng2)
7C51 (zhuan4)
7C52 (zhou4)
7C53 (fan1)
7C54 (sou3)
7C55 (zhou4)
7C56 (qian1)
7C57 (kuo4)
7C58 (teng2)
7C59 (lu4)
7C5A (lu2)
7C5B (jian1)
7C5C (tuo4)
7C5D (ying2)
7C5E (yu4)
7C5F (lai4)
7C60 (long2,long3)
7C61 (none0)
7C62 (lian2)
7C63 (lan2)
7C64 (qian1)
7C65 (yue4)
7C66 (zhong1)
7C67 (qu2)
7C68 (lian2)
7C69 (bian1)
7C6A (duan4)
7C6B (zuan3)
7C6C (li2)
7C6D (shai1)
7C6E (luo2)
7C6F (ying2)
7C70 (yue4)
7C71 (zhuo2)
7C72 (xu1,yu1,yu4)
7C73 (mi3)
7C74 (di2)
7C75 (fan2)
7C76 (shen1)
7C77 (zhe2)
7C78 (shen1)
7C79 (nu:3)
7C7A (xie2)
7C7B (lei4)
7C7C (xian1)
7C7D (zi3)
7C7E (ni2)
7C7F (cun4)
7C80 (zhang4)
7C81 (qian1)
7C82 (none0)
7C83 (bi3)
7C84 (ban3)
7C85 (wu4)
7C86 (sha1)
7C87 (kang1)
7C88 (rou3)
7C89 (fen3)
7C8A (bi4)
7C8B (cui4,sui4)
7C8C (yin3)
7C8D (li2)
7C8E (chi3)
7C8F (tai4)
7C90 (none0)
7C91 (ba1)
7C92 (li4)
7C93 (gan1)
7C94 (ju4)
7C95 (po4)
7C96 (mo4)
7C97 (cu1)
7C98 (zhan1,nian2)
7C99 (zhou4)
7C9A (li2)
7C9B (su4)
7C9C (tiao4)
7C9D (li4)
7C9E (xi1)
7C9F (su4)
7CA0 (hong2)
7CA1 (tong2)
7CA2 (zi1,ci2)
7CA3 (ce4)
7CA4 (yue4)
7CA5 (zhou1,yu4)
7CA6 (lin2)
7CA7 (zhuang1)
7CA8 (bai3)
7CA9 (none0)
7CAA (fen4)
7CAB (mian4)
7CAC (qu1)
7CAD (none0)
7CAE (liang2)
7CAF (xian4)
7CB0 (fu1)
7CB1 (liang2)
7CB2 (can4)
7CB3 (jing1,geng1)
7CB4 (li3)
7CB5 (yue4)
7CB6 (lu4)
7CB7 (ju2)
7CB8 (qi2)
7CB9 (cui4)
7CBA (bai4)
7CBB (chang2)
7CBC (lin2)
7CBD (zong4)
7CBE (jing1)
7CBF (guo3)
7CC0 (none0)
7CC1 (san3,shen1)
7CC2 (san3,shen1)
7CC3 (tang2)
7CC4 (bian3)
7CC5 (rou2,rou3)
7CC6 (mian4)
7CC7 (hou2)
7CC8 (xu3)
7CC9 (zong4)
7CCA (hu2,hu1,hu4)
7CCB (jian4)
7CCC (zan1)
7CCD (ci2)
7CCE (li2)
7CCF (xie4)
7CD0 (fu1)
7CD1 (nuo4)
7CD2 (bei4)
7CD3 (gu3,yu4)
7CD4 (xiu3)
7CD5 (gao1)
7CD6 (tang2)
7CD7 (qiu3)
7CD8 (none0)
7CD9 (cao1)
7CDA (zhuang1)
7CDB (tang2)
7CDC (mi2,mei2)
7CDD (san3,shen1)
7CDE (fen4)
7CDF (zao1)
7CE0 (kang1)
7CE1 (jiang4)
7CE2 (mo2)
7CE3 (san3)
7CE4 (san3)
7CE5 (nuo4)
7CE6 (chi4)
7CE7 (liang2)
7CE8 (jiang4)
7CE9 (kuai1)
7CEA (bo2)
7CEB (huan2)
7CEC (shu3)
7CED (zong4)
7CEE (jian4)
7CEF (nuo4)
7CF0 (tuan2)
7CF1 (nie4)
7CF2 (li4)
7CF3 (zuo4)
7CF4 (di2)
7CF5 (nie4)
7CF6 (tiao4)
7CF7 (lan2)
7CF8 (mi4)
7CF9 (mi4)
7CFA (jiu1)
7CFB (xi4,ji4)
7CFC (gong1)
7CFD (zheng3)
7CFE (jiu1,jiu3)
7CFF (you4)
7D00 (ji4)
7D01 (cha4)
7D02 (zhou4)
7D03 (xun2)
7D04 (yue1,yao1)
7D05 (hong2,gong1)
7D06 (yu1)
7D07 (he2,ge1)
7D08 (wan2)
7D09 (ren4)
7D0A (wen3,wen4)
7D0B (wen2,wen4)
7D0C (qiu2)
7D0D (na4)
7D0E (zi1)
7D0F (tou3)
7D10 (niu3)
7D11 (fou2)
7D12 (jie4)
7D13 (shu1)
7D14 (chun2)
7D15 (pi2,pi1)
7D16 (yin3)
7D17 (sha1)
7D18 (hong2)
7D19 (zhi3)
7D1A (ji2)
7D1B (fen1)
7D1C (yun2)
7D1D (ren2)
7D1E (dan3)
7D1F (jin1)
7D20 (su4)
7D21 (fang3)
7D22 (suo3)
7D23 (cui4)
7D24 (jiu3)
7D25 (zha2)
7D26 (ba1)
7D27 (jin3)
7D28 (fu1)
7D29 (zhi4)
7D2A (qi1)
7D2B (zi3)
7D2C (chou2)
7D2D (hong2)
7D2E (zha2,za1)
7D2F (lei3,lei4,lei2)
7D30 (xi4)
7D31 (fu2)
7D32 (xie4)
7D33 (shen1)
7D34 (bei4)
7D35 (zhu4)
7D36 (qu3,qu1)
7D37 (ling2)
7D38 (zhu4)
7D39 (shao4)
7D3A (gan4)
7D3B (yang1)
7D3C (fu2)
7D3D (tuo2)
7D3E (zhen3)
7D3F (dai4)
7D40 (chu4)
7D41 (shi1)
7D42 (zhong1)
7D43 (xian2)
7D44 (zu3)
7D45 (jiong3)
7D46 (ban4)
7D47 (ju4)
7D48 (pa4)
7D49 (shu4)
7D4A (zui4)
7D4B (kuang4)
7D4C (jing1,jing4)
7D4D (ren4)
7D4E (heng4,hang2)
7D4F (xie4)
7D50 (jie2,jie1)
7D51 (zhu1)
7D52 (chou2)
7D53 (gua4)
7D54 (bai3)
7D55 (jue2)
7D56 (kuang4)
7D57 (hu2)
7D58 (ci4)
7D59 (geng1)
7D5A (geng1)
7D5B (tao1)
7D5C (xie2,jie2)
7D5D (ku4)
7D5E (jiao3,jia3)
7D5F (quan1)
7D60 (gai3)
7D61 (luo4,lao4)
7D62 (xuan4)
7D63 (beng1,ping3)
7D64 (xian4)
7D65 (fu2)
7D66 (gei3,ji3)
7D67 (tong2)
7D68 (rong2)
7D69 (tiao4)
7D6A (yin1)
7D6B (lei3)
7D6C (xie4)
7D6D (quan4)
7D6E (xu4)
7D6F (hai4)
7D70 (die2)
7D71 (tong3)
7D72 (si1)
7D73 (jiang4)
7D74 (xiang2)
7D75 (hui4)
7D76 (jue2)
7D77 (zhi2)
7D78 (jian3)
7D79 (juan4)
7D7A (chi1)
7D7B (mian3)
7D7C (zhen3)
7D7D (lu:3)
7D7E (cheng2)
7D7F (qiu2)
7D80 (shu1)
7D81 (bang3)
7D82 (tong3)
7D83 (xiao1)
7D84 (wan4)
7D85 (qin1)
7D86 (geng3)
7D87 (xiu3)
7D88 (ti2,di4,ti4)
7D89 (xiu4)
7D8A (xie2)
7D8B (hong2)
7D8C (xi4)
7D8D (fu2)
7D8E (ting2)
7D8F (sui1,sui2)
7D90 (dui4)
7D91 (kun3)
7D92 (fu1)
7D93 (jing1,jing4)
7D94 (hu4)
7D95 (zhi1)
7D96 (yan2)
7D97 (jiong3)
7D98 (feng2)
7D99 (ji4)
7D9A (xu4)
7D9B (none0)
7D9C (zong4,zeng4,zong1)
7D9D (lin3)
7D9E (duo3)
7D9F (li4)
7DA0 (lu:4)
7DA1 (liang2)
7DA2 (chou2)
7DA3 (quan3)
7DA4 (shao4)
7DA5 (qi4)
7DA6 (qi2)
7DA7 (zhun3)
7DA8 (qi2)
7DA9 (wan3)
7DAA (qian4)
7DAB (xian4)
7DAC (shou4)
7DAD (wei2)
7DAE (qi3,qing4,qing3)
7DAF (tao2)
7DB0 (wan3)
7DB1 (gang1)
7DB2 (wang3)
7DB3 (beng1,beng3,beng4)
7DB4 (zhui4)
7DB5 (cai3)
7DB6 (guo3)
7DB7 (cui4)
7DB8 (lun2,guan1)
7DB9 (liu3)
7DBA (qi3)
7DBB (zhan4)
7DBC (bei1)
7DBD (chuo4)
7DBE (ling2)
7DBF (mian2)
7DC0 (qi1)
7DC1 (jie2)
7DC2 (tan1)
7DC3 (zong1)
7DC4 (gun3)
7DC5 (zou1)
7DC6 (yi4)
7DC7 (zi1)
7DC8 (xing4)
7DC9 (liang3)
7DCA (jin3)
7DCB (fei1)
7DCC (rui2)
7DCD (min2)
7DCE (yu4)
7DCF (zong3)
7DD0 (fan2)
7DD1 (lu:4)
7DD2 (xu4)
7DD3 (none0)
7DD4 (shang4)
7DD5 (none0)
7DD6 (xu4)
7DD7 (xiang1)
7DD8 (jian1)
7DD9 (ke4)
7DDA (xian4)
7DDB (ruan3)
7DDC (mian2)
7DDD (ji1,qi1,qi4)
7DDE (duan4)
7DDF (zhong4)
7DE0 (di4)
7DE1 (min2)
7DE2 (miao2)
7DE3 (yuan2)
7DE4 (xie4)
7DE5 (bao3)
7DE6 (si1)
7DE7 (qiu1)
7DE8 (bian1)
7DE9 (huan3)
7DEA (geng1)
7DEB (zong3)
7DEC (mian3)
7DED (wei4)
7DEE (fu4)
7DEF (wei3)
7DF0 (yu2)
7DF1 (gou1)
7DF2 (miao3)
7DF3 (jie2)
7DF4 (lian4)
7DF5 (zong1)
7DF6 (bian4,pian2)
7DF7 (yun4)
7DF8 (yin1)
7DF9 (ti2)
7DFA (gua1)
7DFB (zhi4)
7DFC (yun1)
7DFD (cheng1)
7DFE (chan2)
7DFF (dai4)
7E00 (jia1)
7E01 (yuan2)
7E02 (zong3)
7E03 (xu1)
7E04 (sheng2)
7E05 (none0)
7E06 (geng1)
7E07 (none0)
7E08 (ying2)
7E09 (jin4)
7E0A (yi4)
7E0B (zhui4)
7E0C (ni4)
7E0D (bang1)
7E0E (gu3)
7E0F (pan2)
7E10 (zhou4)
7E11 (jian1)
7E12 (cuo3)
7E13 (quan2)
7E14 (shuang3)
7E15 (yun1)
7E16 (xia2)
7E17 (shuai1)
7E18 (xi1)
7E19 (rong2)
7E1A (tao1)
7E1B (fu2)
7E1C (yun2)
7E1D (zhen3)
7E1E (gao3)
7E1F (ru4)
7E20 (hu2)
7E21 (zai3)
7E22 (teng2)
7E23 (xian4,xuan2)
7E24 (su4)
7E25 (zhen3)
7E26 (zong4)
7E27 (tao1)
7E28 (huang3)
7E29 (cai4)
7E2A (bi4,bie4)
7E2B (feng2,feng4)
7E2C (cu4)
7E2D (li2)
7E2E (suo1,su4)
7E2F (yin3)
7E30 (xi3)
7E31 (zong4,zong1)
7E32 (lei2)
7E33 (zhuan4)
7E34 (qian4)
7E35 (man4)
7E36 (zhi2)
7E37 (lu:3)
7E38 (mo4)
7E39 (piao3,piao1)
7E3A (lian2)
7E3B (mi2)
7E3C (xuan4)
7E3D (zong3)
7E3E (ji1)
7E3F (shan1)
7E40 (sui4)
7E41 (fan2,po2)
7E42 (shuai4)
7E43 (beng1)
7E44 (yi1)
7E45 (sao1)
7E46 (mou2,miao4,miu4)
7E47 (zhou4,yao2,you2)
7E48 (qiang3)
7E49 (hun2)
7E4A (xian1)
7E4B (xi4,ji4)
7E4C (none0)
7E4D (xiu4)
7E4E (ran2)
7E4F (xuan4)
7E50 (hui4)
7E51 (qiao1)
7E52 (zeng1,zeng4)
7E53 (zuo3)
7E54 (zhi1)
7E55 (shan4)
7E56 (san3)
7E57 (lin2)
7E58 (yu4)
7E59 (fan1)
7E5A (liao2)
7E5B (chuo4)
7E5C (zun1)
7E5D (jian4)
7E5E (rao4,rao3)
7E5F (chan3)
7E60 (rui3)
7E61 (xiu4)
7E62 (hui4)
7E63 (hua4)
7E64 (zuan3)
7E65 (xi1)
7E66 (qiang3)
7E67 (none0)
7E68 (da2)
7E69 (sheng2)
7E6A (hui4)
7E6B (xi4,ji4)
7E6C (se4)
7E6D (jian3)
7E6E (jiang1)
7E6F (huan2)
7E70 (qiao1,zao3)
7E71 (cong1)
7E72 (jie4)
7E73 (jiao3,jia3,zhuo2)
7E74 (bo4)
7E75 (chan2)
7E76 (yi4)
7E77 (nao2)
7E78 (sui4)
7E79 (yi4)
7E7A (shai3)
7E7B (xu1)
7E7C (ji4)
7E7D (bin1)
7E7E (qian3)
7E7F (jian4,kan3)
7E80 (pu2)
7E81 (xun1)
7E82 (zuan3)
7E83 (qi2)
7E84 (peng2)
7E85 (li4)
7E86 (mo4)
7E87 (lei4)
7E88 (xie2)
7E89 (zuan3)
7E8A (kuang4)
7E8B (you1)
7E8C (xu4)
7E8D (lei2)
7E8E (xian1)
7E8F (chan2)
7E90 (none0)
7E91 (lu2)
7E92 (chan2)
7E93 (ying1)
7E94 (cai2)
7E95 (xiang1)
7E96 (xian1)
7E97 (zui1)
7E98 (zuan3)
7E99 (luo4)
7E9A (xi3)
7E9B (dao4,du2)
7E9C (lan4,lan3)
7E9D (lei2)
7E9E (lian4)
7E9F (mi4)
7EA0 (jiu1)
7EA1 (yu1)
7EA2 (hong2,gong1)
7EA3 (zhou4)
7EA4 (xian1,qian4)
7EA5 (he2,ge1)
7EA6 (yue1,yao1)
7EA7 (ji2)
7EA8 (wan2)
7EA9 (kuang4)
7EAA (ji4,ji3)
7EAB (ren4)
7EAC (wei3)
7EAD (yun2)
7EAE (hong2)
7EAF (chun2)
7EB0 (pi1)
7EB1 (sha1)
7EB2 (gang1)
7EB3 (na4)
7EB4 (ren4)
7EB5 (zong4)
7EB6 (lun2,guan1)
7EB7 (fen1)
7EB8 (zhi3)
7EB9 (wen2,wen4)
7EBA (fang3)
7EBB (zhu4)
7EBC (zhen4)
7EBD (niu3)
7EBE (shu1)
7EBF (xian4)
7EC0 (gan4)
7EC1 (xie4)
7EC2 (fu2)
7EC3 (lian4)
7EC4 (zu3)
7EC5 (shen1)
7EC6 (xi4)
7EC7 (zhi1)
7EC8 (zhong1)
7EC9 (zhou4)
7ECA (ban4)
7ECB (fu2)
7ECC (chu4)
7ECD (shao4)
7ECE (yi4)
7ECF (jing1,jing4)
7ED0 (dai4)
7ED1 (bang3)
7ED2 (rong2)
7ED3 (jie2,jie1)
7ED4 (ku4)
7ED5 (rao3,rao4,rao5)
7ED6 (die2)
7ED7 (hang2)
7ED8 (hui4)
7ED9 (ji3,gei3)
7EDA (xuan4)
7EDB (jiang4)
7EDC (luo4,lao4)
7EDD (jue2)
7EDE (jiao3,jia3)
7EDF (tong3)
7EE0 (geng3)
7EE1 (xiao1)
7EE2 (juan4)
7EE3 (xiu4)
7EE4 (xi4)
7EE5 (sui2)
7EE6 (tao1)
7EE7 (ji4)
7EE8 (ti2,ti4,di4)
7EE9 (ji4,ji1)
7EEA (xu4)
7EEB (ling2)
7EEC (yin1)
7EED (xu4)
7EEE (qi3)
7EEF (fei1)
7EF0 (chuo4,chao1,chuo5)
7EF1 (shang4)
7EF2 (gun3)
7EF3 (sheng2)
7EF4 (wei2)
7EF5 (mian2)
7EF6 (shou4)
7EF7 (beng1,beng3,beng4)
7EF8 (chou2)
7EF9 (tao2)
7EFA (liu3)
7EFB (quan3)
7EFC (zong1,zeng4)
7EFD (zhan4)
7EFE (wan3)
7EFF (lu:4,lu4)
7F00 (zhui4)
7F01 (zi1)
7F02 (ke4)
7F03 (xiang1)
7F04 (jian1)
7F05 (mian3)
7F06 (lan3)
7F07 (ti2)
7F08 (miao3)
7F09 (ji1,qi1)
7F0A (yun4)
7F0B (hui4)
7F0C (si1)
7F0D (duo3)
7F0E (duan4)
7F0F (bian4,pian2)
7F10 (xian4)
7F11 (gou1)
7F12 (zhui4)
7F13 (huan3)
7F14 (di4)
7F15 (lu:3)
7F16 (bian1)
7F17 (min2)
7F18 (yuan2)
7F19 (jin4)
7F1A (fu4)
7F1B (ru4)
7F1C (zhen3)
7F1D (feng2,feng4)
7F1E (cui1)
7F1F (gao3)
7F20 (chan2)
7F21 (li2)
7F22 (yi4)
7F23 (jian1)
7F24 (bin1)
7F25 (piao1,piao3)
7F26 (man4)
7F27 (lei2)
7F28 (ying1)
7F29 (suo1,su4)
7F2A (mou2,miao4,miu4)
7F2B (sao1)
7F2C (xie2)
7F2D (liao2)
7F2E (shan4)
7F2F (zeng1,zeng4)
7F30 (jiang1)
7F31 (qian3)
7F32 (qiao1,sao1,zao3)
7F33 (huan2)
7F34 (jiao3,zhuo2,jia3)
7F35 (zuan3)
7F36 (fou3)
7F37 (xie4)
7F38 (gang1)
7F39 (fou3)
7F3A (que1)
7F3B (fou3)
7F3C (que1)
7F3D (bo1)
7F3E (ping2)
7F3F (hou4)
7F40 (none0)
7F41 (gang1)
7F42 (ying1)
7F43 (ying1)
7F44 (qing4)
7F45 (xia4)
7F46 (guan4)
7F47 (zun1)
7F48 (tan2)
7F49 (none0)
7F4A (qing4)
7F4B (weng4)
7F4C (ying1)
7F4D (lei2)
7F4E (tan2)
7F4F (lu2)
7F50 (guan4)
7F51 (wang3)
7F52 (gang1)
7F53 (wang3)
7F54 (wang3)
7F55 (han3)
7F56 (none0)
7F57 (luo2,luo1,luo5)
7F58 (fu2,fou2)
7F59 (mi2)
7F5A (fa2)
7F5B (gu1)
7F5C (zhu3)
7F5D (ju1)
7F5E (mao2)
7F5F (gu3)
7F60 (min2)
7F61 (gang1)
7F62 (ba4,ba5)
7F63 (gua4)
7F64 (ti2)
7F65 (juan4)
7F66 (fu1)
7F67 (lin2,sen1)
7F68 (yan3)
7F69 (zhao4)
7F6A (zui4)
7F6B (gua4)
7F6C (zhuo2)
7F6D (yu4)
7F6E (zhi4)
7F6F (an3)
7F70 (fa2)
7F71 (lan3)
7F72 (shu3,shu4)
7F73 (si1)
7F74 (pi2)
7F75 (ma4)
7F76 (liu3)
7F77 (ba4,ba5,pi2)
7F78 (fa2)
7F79 (li2)
7F7A (chao1)
7F7B (wei4)
7F7C (bi4)
7F7D (ji4)
7F7E (zeng1)
7F7F (tong2)
7F80 (liu3)
7F81 (ji1)
7F82 (juan4)
7F83 (mi4)
7F84 (zhao4)
7F85 (luo2,luo1)
7F86 (pi2,biao1)
7F87 (ji1)
7F88 (ji1)
7F89 (luan2)
7F8A (yang2)
7F8B (mie1)
7F8C (qiang1)
7F8D (ta4)
7F8E (mei3)
7F8F (yang3)
7F90 (you3)
7F91 (you3)
7F92 (fen2)
7F93 (ba1)
7F94 (gao1)
7F95 (yang4)
7F96 (gu3)
7F97 (qiang1)
7F98 (zang1)
7F99 (gao1)
7F9A (ling2)
7F9B (yi4)
7F9C (zhu4)
7F9D (di1)
7F9E (xiu1)
7F9F (qiang3)
7FA0 (yi2)
7FA1 (xian4)
7FA2 (rong2)
7FA3 (qun2)
7FA4 (qun2)
7FA5 (qian1,qiang3)
7FA6 (huan2)
7FA7 (suo1)
7FA8 (xian4)
7FA9 (yi4)
7FAA (yang3)
7FAB (qiang1)
7FAC (xian2)
7FAD (yu2)
7FAE (geng1)
7FAF (jie2)
7FB0 (tang1)
7FB1 (yuan2)
7FB2 (xi1)
7FB3 (fan2)
7FB4 (shan1)
7FB5 (fen4)
7FB6 (shan1)
7FB7 (lian3)
7FB8 (lei2)
7FB9 (geng1)
7FBA (nou2)
7FBB (qiang4)
7FBC (chan4)
7FBD (yu3)
7FBE (gong4)
7FBF (yi4)
7FC0 (chong2,chong1)
7FC1 (weng1)
7FC2 (fen1)
7FC3 (hong2)
7FC4 (chi4)
7FC5 (chi4)
7FC6 (cui2)
7FC7 (fu2,pei4)
7FC8 (xia2)
7FC9 (pen3)
7FCA (yi4)
7FCB (la1)
7FCC (yi4)
7FCD (pi1,po1)
7FCE (ling2)
7FCF (liu4)
7FD0 (zhi4)
7FD1 (qu2)
7FD2 (xi2)
7FD3 (xie2)
7FD4 (xiang2)
7FD5 (xi1,xi4)
7FD6 (xi4)
7FD7 (qi2)
7FD8 (qiao2,qiao4)
7FD9 (hui4)
7FDA (hui1)
7FDB (shu4)
7FDC (se4)
7FDD (hong2)
7FDE (jiang1)
7FDF (zhai2,di2)
7FE0 (cui4)
7FE1 (fei3)
7FE2 (tao1)
7FE3 (sha4)
7FE4 (chi4)
7FE5 (zhu4)
7FE6 (jian3)
7FE7 (xuan1)
7FE8 (shi4)
7FE9 (pian1)
7FEA (zong1)
7FEB (wan4)
7FEC (hui1)
7FED (hou2)
7FEE (he2)
7FEF (he4)
7FF0 (han4)
7FF1 (ao2)
7FF2 (piao1)
7FF3 (yi4)
7FF4 (lian2)
7FF5 (qu2)
7FF6 (none0)
7FF7 (lin2)
7FF8 (pen3)
7FF9 (qiao2,qiao4)
7FFA (ao2)
7FFB (fan1)
7FFC (yi4)
7FFD (hui4)
7FFE (xuan1)
7FFF (dao4)
8000 (yao4,yue4)
8001 (lao3)
8002 (none0)
8003 (kao3)
8004 (mao4)
8005 (zhe3)
8006 (qi2)
8007 (gou3)
8008 (gou2)
8009 (gou3)
800A (die2)
800B (die2)
800C (er2)
800D (shua3)
800E (ruan3)
800F (er2)
8010 (nai4)
8011 (zhuan1,duan1)
8012 (lei3)
8013 (ting1)
8014 (zi3)
8015 (geng1)
8016 (chao4)
8017 (hao4)
8018 (yun2)
8019 (pa2,ba4)
801A (pi1)
801B (chi2)
801C (si4)
801D (qu4)
801E (jia1)
801F (ju4)
8020 (huo1)
8021 (chu2)
8022 (lao4)
8023 (lun3)
8024 (ji2)
8025 (tang1,tang3)
8026 (ou3)
8027 (lou2)
8028 (nou4)
8029 (jiang3)
802A (pang3)
802B (ze2)
802C (lou2)
802D (ji1)
802E (lao4)
802F (huo4)
8030 (you1)
8031 (mo4)
8032 (huai2)
8033 (er3)
8034 (zhe2)
8035 (ding1)
8036 (ye1,ye2)
8037 (da1)
8038 (song3)
8039 (qin2)
803A (yun2)
803B (chi3)
803C (dan1)
803D (dan1)
803E (hong2)
803F (geng3)
8040 (zhi2)
8041 (none0)
8042 (nie4)
8043 (dan1)
8044 (zhen3)
8045 (che4)
8046 (ling2)
8047 (zheng1)
8048 (you3)
8049 (wa1)
804A (liao2)
804B (long2)
804C (zhi2)
804D (ning2)
804E (tiao1)
804F (er2,er4)
8050 (ya4)
8051 (die2)
8052 (guo1,gua1)
8053 (none0)
8054 (lian2)
8055 (hao4)
8056 (sheng4)
8057 (lie4)
8058 (pin4)
8059 (jing1)
805A (ju4)
805B (bi4)
805C (di3)
805D (guo2)
805E (wen2,wen4)
805F (xu4)
8060 (ping1)
8061 (cong1)
8062 (none0)
8063 (none0)
8064 (ting2)
8065 (yu3)
8066 (cong1)
8067 (kui2)
8068 (lian2)
8069 (kui4)
806A (cong1)
806B (lian2)
806C (weng3)
806D (kui4)
806E (lian2)
806F (lian2)
8070 (cong1)
8071 (ao2)
8072 (sheng1)
8073 (song3)
8074 (ting1)
8075 (kui4)
8076 (nie4)
8077 (zhi2)
8078 (dan1)
8079 (ning2)
807A (none0)
807B (ji1)
807C (ting1)
807D (ting1,ting4)
807E (long2)
807F (yu4)
8080 (yu4)
8081 (zhao4)
8082 (si4)
8083 (su4)
8084 (yi4)
8085 (su4)
8086 (si4)
8087 (zhao4)
8088 (zhao4)
8089 (rou4)
808A (yi4)
808B (lei4,le4,le1)
808C (ji1)
808D (qiu2)
808E (ken3)
808F (cao4)
8090 (ge1)
8091 (di4)
8092 (huan2)
8093 (huang1)
8094 (yi3)
8095 (ren4)
8096 (xiao4,xiao1)
8097 (ru3)
8098 (zhou3)
8099 (yuan1)
809A (du4,du3)
809B (gang1)
809C (rong2)
809D (gan1)
809E (cha1)
809F (wo4)
80A0 (chang2)
80A1 (gu3)
80A2 (zhi1)
80A3 (qin2)
80A4 (fu1)
80A5 (fei2)
80A6 (ban1)
80A7 (pei1)
80A8 (pang4)
80A9 (jian1)
80AA (fang2)
80AB (zhun1)
80AC (you2)
80AD (na4)
80AE (ang1)
80AF (ken3)
80B0 (ran2)
80B1 (gong1)
80B2 (yu4,yo1)
80B3 (wen3)
80B4 (yao2)
80B5 (jin4)
80B6 (pi2)
80B7 (qian3)
80B8 (xi4)
80B9 (xi4)
80BA (fei4)
80BB (ken3)
80BC (jing3)
80BD (tai4)
80BE (shen4)
80BF (zhong3)
80C0 (zhang4)
80C1 (xie2)
80C2 (shen4)
80C3 (wei4)
80C4 (zhou4)
80C5 (die2)
80C6 (dan3)
80C7 (fei4)
80C8 (ba2)
80C9 (bo2)
80CA (qu2)
80CB (tian2)
80CC (bei4,bei1)
80CD (gua1)
80CE (tai1)
80CF (zi3)
80D0 (ku1)
80D1 (zhi1)
80D2 (ni4)
80D3 (ping2)
80D4 (zi4)
80D5 (fu4)
80D6 (pang4,pan2)
80D7 (zhen1)
80D8 (xian2)
80D9 (zuo4)
80DA (pei1)
80DB (jia3)
80DC (sheng4,sheng1)
80DD (zhi1)
80DE (bao1)
80DF (mu3)
80E0 (qu1)
80E1 (hu2)
80E2 (ke1)
80E3 (yi3)
80E4 (yin4)
80E5 (xu1)
80E6 (yang1)
80E7 (long2)
80E8 (dong4)
80E9 (ka3)
80EA (lu2)
80EB (jing4)
80EC (nu3)
80ED (yan1)
80EE (pang1)
80EF (kua4)
80F0 (yi2)
80F1 (guang1)
80F2 (hai3,gai3)
80F3 (ge1,ga1,ge2)
80F4 (dong4)
80F5 (zhi4)
80F6 (jiao1)
80F7 (xiong1)
80F8 (xiong1)
80F9 (er2)
80FA (an4)
80FB (xing2)
80FC (pian2)
80FD (neng2)
80FE (zi4)
80FF (none0)
8100 (cheng2)
8101 (tiao4)
8102 (zhi1)
8103 (cui4)
8104 (mei2)
8105 (xie2)
8106 (cui4)
8107 (xie2)
8108 (mo4,mai4)
8109 (mai4,mo4)
810A (ji3,ji2)
810B (xie2)
810C (none0)
810D (kuai4)
810E (sa4)
810F (zang4,zang1)
8110 (qi2)
8111 (nao3)
8112 (mi3)
8113 (nong2)
8114 (luan2)
8115 (wan3)
8116 (bo2)
8117 (wen3)
8118 (wan3)
8119 (qiu2)
811A (jiao3,jue2,jia3)
811B (jing4)
811C (you3)
811D (heng1)
811E (cuo3)
811F (lie4)
8120 (shan1)
8121 (ting3)
8122 (mei2)
8123 (chun2)
8124 (shen4)
8125 (xie2)
8126 (none0)
8127 (juan1)
8128 (cu4)
8129 (xiu1)
812A (xin4)
812B (tuo1)
812C (pao1)
812D (cheng2)
812E (nei3)
812F (fu3,pu2)
8130 (dou4)
8131 (tuo1)
8132 (niao4)
8133 (nao3)
8134 (pi3)
8135 (gu3)
8136 (luo2)
8137 (li4)
8138 (lian3)
8139 (zhang4)
813A (cui4)
813B (jie2)
813C (liang3)
813D (shui2)
813E (pi2)
813F (biao1)
8140 (lun2)
8141 (pian2)
8142 (guo4)
8143 (juan4)
8144 (chui2,zhui1)
8145 (dan4)
8146 (tian3)
8147 (nei3)
8148 (jing1)
8149 (jie1)
814A (la4,xi1)
814B (ye4,yi4)
814C (a1,yan1)
814D (ren3)
814E (shen4)
814F (chuo4,duo2)
8150 (fu3)
8151 (fu3)
8152 (ju1)
8153 (fei2)
8154 (qiang1)
8155 (wan4)
8156 (dong4)
8157 (pi2)
8158 (guo2)
8159 (zong1)
815A (ding4)
815B (wu1)
815C (mei2)
815D (ruan3)
815E (zhuan4,dun4)
815F (zhi4)
8160 (cou4)
8161 (gua1,luo2)
8162 (ou3)
8163 (di4)
8164 (an1)
8165 (xing1)
8166 (nao3)
8167 (shu4)
8168 (shuan4)
8169 (nan3)
816A (yun4)
816B (zhong3)
816C (rou2)
816D (e4)
816E (sai1)
816F (tu2)
8170 (yao1)
8171 (jian4)
8172 (wei3)
8173 (jiao3)
8174 (yu2)
8175 (jia1)
8176 (duan4)
8177 (bi4)
8178 (chang2)
8179 (fu4)
817A (xian4)
817B (ni4)
817C (mian3)
817D (wa4)
817E (teng2)
817F (tui3)
8180 (bang3,pang1,pang2,bang4)
8181 (qian3)
8182 (lu:3)
8183 (wa4)
8184 (shou4)
8185 (tang2)
8186 (su4)
8187 (zhui4)
8188 (ge2)
8189 (yi4)
818A (bo2,bo5)
818B (liao2)
818C (ji2)
818D (pi2)
818E (xie2)
818F (gao1,gao4)
8190 (lu:3)
8191 (bin4)
8192 (none0)
8193 (chang2)
8194 (lu4)
8195 (guo2)
8196 (pang1)
8197 (chuai2)
8198 (biao1)
8199 (jiang3)
819A (fu1)
819B (tang2)
819C (mo2,mo4)
819D (xi1)
819E (zhuan1)
819F (lu:4)
81A0 (jiao1)
81A1 (ying4)
81A2 (lu:2)
81A3 (zhi4)
81A4 (xue3)
81A5 (chun1)
81A6 (lin4)
81A7 (tong2)
81A8 (peng2)
81A9 (ni4)
81AA (chuai4)
81AB (liao2)
81AC (cui4)
81AD (gui1)
81AE (xiao1)
81AF (teng1)
81B0 (fan2)
81B1 (zhi2)
81B2 (jiao1)
81B3 (shan4)
81B4 (hu1)
81B5 (cui4)
81B6 (run4)
81B7 (xin4)
81B8 (sui3)
81B9 (fen4)
81BA (ying1)
81BB (shan1)
81BC (gua1)
81BD (dan3)
81BE (kuai4)
81BF (nong2)
81C0 (tun2)
81C1 (lian2)
81C2 (bei5,bi4,bei4)
81C3 (yong1)
81C4 (jue2)
81C5 (chu4)
81C6 (yi4)
81C7 (juan3)
81C8 (la4,xi1)
81C9 (lian3)
81CA (sao1,sao4)
81CB (tun2)
81CC (gu3)
81CD (qi2)
81CE (cui4)
81CF (bin4)
81D0 (xun1)
81D1 (nao4,ru2)
81D2 (huo4)
81D3 (zang4)
81D4 (xian4)
81D5 (biao1)
81D6 (xing4)
81D7 (kuan1)
81D8 (la4,xi1)
81D9 (yan1)
81DA (lu2)
81DB (hu4)
81DC (za1)
81DD (luo3)
81DE (qu2)
81DF (zang4)
81E0 (luan2)
81E1 (ni2)
81E2 (za1)
81E3 (chen2)
81E4 (qian1)
81E5 (wo4)
81E6 (guang4,wang3)
81E7 (zang1)
81E8 (lin2)
81E9 (guang4)
81EA (zi4)
81EB (jiao3)
81EC (nie4)
81ED (chou4,xiu4)
81EE (ji4)
81EF (gao1)
81F0 (chou4,xiu4)
81F1 (mian2)
81F2 (nie4)
81F3 (zhi4)
81F4 (zhi4)
81F5 (ge2)
81F6 (jian4)
81F7 (die2)
81F8 (zhi4)
81F9 (xiu1)
81FA (tai2,tai1)
81FB (zhen1)
81FC (jiu4)
81FD (xian4)
81FE (yu2)
81FF (cha2)
8200 (yao3)
8201 (yu2)
8202 (chong1)
8203 (xi4)
8204 (xi4)
8205 (jiu4)
8206 (yu2)
8207 (yu3,yu4)
8208 (xing1,xing4)
8209 (ju3)
820A (jiu4)
820B (xin4)
820C (she2)
820D (she4,she3)
820E (she3,she4)
820F (jiu3)
8210 (shi4)
8211 (tan1)
8212 (shu1)
8213 (shi4)
8214 (tian3)
8215 (dan4)
8216 (pu4)
8217 (pu4,pu1)
8218 (guan3)
8219 (hua4)
821A (tian4)
821B (chuan3)
821C (shun4)
821D (xia2)
821E (wu3)
821F (zhou1)
8220 (dao1)
8221 (chuan2)
8222 (shan1)
8223 (yi3)
8224 (none0)
8225 (pa1)
8226 (tai4)
8227 (fan2)
8228 (ban3)
8229 (chuan2)
822A (hang2)
822B (fang3)
822C (ban1,bo1,pan2)
822D (bi3)
822E (lu2)
822F (zhong1)
8230 (jian4)
8231 (cang1)
8232 (ling2)
8233 (zhu2)
8234 (ze2)
8235 (duo4,tuo2)
8236 (bo2)
8237 (xian2)
8238 (ge3)
8239 (chuan2)
823A (jia2,xia2)
823B (lu2)
823C (hong2)
823D (pang2)
823E (xi1)
823F (none0)
8240 (fu2)
8241 (zao4)
8242 (feng2)
8243 (li2)
8244 (shao1)
8245 (yu2)
8246 (lang2)
8247 (ting3)
8248 (none0)
8249 (wei3)
824A (bo2)
824B (meng3)
824C (nian4)
824D (ju1)
824E (huang2)
824F (shou3)
8250 (zong1)
8251 (bian4)
8252 (mao4)
8253 (die2)
8254 (none0)
8255 (bang4)
8256 (cha1)
8257 (yi4)
8258 (sou1,sao1)
8259 (cang1)
825A (cao2)
825B (lou2)
825C (dai4)
825D (none0)
825E (yao4)
825F (chong1,tong2)
8260 (none0)
8261 (dang1)
8262 (qiang2)
8263 (lu3)
8264 (yi3)
8265 (jie4)
8266 (jian4)
8267 (huo4)
8268 (meng2)
8269 (qi2)
826A (lu3)
826B (lu2)
826C (chan2)
826D (shuang1)
826E (gen4,gen3)
826F (liang2)
8270 (jian1)
8271 (jian1)
8272 (se4,shai3)
8273 (yan4)
8274 (fu2)
8275 (ping2)
8276 (yan4)
8277 (yan4)
8278 (cao3)
8279 (cao3)
827A (yi4)
827B (le4)
827C (ting1)
827D (jiao1)
827E (ai4,yi4)
827F (nai3)
8280 (tiao2)
8281 (jiao1)
8282 (jie2,jie1)
8283 (peng2)
8284 (wan2)
8285 (yi4)
8286 (chai1)
8287 (mian2)
8288 (mi3)
8289 (gan4)
828A (qian1)
828B (yu4)
828C (yu4)
828D (shao2)
828E (xiong1)
828F (du4)
8290 (xia4)
8291 (qi3)
8292 (mang2,wang2)
8293 (zi3)
8294 (hui4)
8295 (sui1)
8296 (zhi4)
8297 (xiang1)
8298 (bi4,pi2)
8299 (fu2)
829A (tun2)
829B (wei3)
829C (wu2)
829D (zhi1)
829E (qi3)
829F (shan1)
82A0 (wen2)
82A1 (qian4)
82A2 (ren2)
82A3 (fou2)
82A4 (kou1)
82A5 (jie4,gai4)
82A6 (lu2,lu3)
82A7 (zhu4)
82A8 (ji1)
82A9 (qin2)
82AA (qi2)
82AB (yan2,yuan2)
82AC (fen1)
82AD (ba1)
82AE (rui4)
82AF (xin1,xin4)
82B0 (ji4)
82B1 (hua1)
82B2 (hua1)
82B3 (fang1)
82B4 (wu4)
82B5 (jue2)
82B6 (gou1)
82B7 (zhi3)
82B8 (yun2)
82B9 (qin2)
82BA (ao3)
82BB (chu2)
82BC (mao4)
82BD (ya2,di2)
82BE (fei4,fu2)
82BF (reng4)
82C0 (hang2)
82C1 (cong1)
82C2 (yin2)
82C3 (you3)
82C4 (bian4)
82C5 (yi4)
82C6 (none0)
82C7 (wei3)
82C8 (li4)
82C9 (pi3)
82CA (e4)
82CB (xian4)
82CC (chang2)
82CD (cang1)
82CE (zhu4,ning2)
82CF (su1)
82D0 (yi2,ti2)
82D1 (yuan4)
82D2 (ran3)
82D3 (ling2)
82D4 (tai2,tai1)
82D5 (tiao2,shao2)
82D6 (di2)
82D7 (miao2)
82D8 (qing3)
82D9 (li4)
82DA (rao2)
82DB (ke1)
82DC (mu4)
82DD (pei4)
82DE (bao1)
82DF (gou3)
82E0 (min2)
82E1 (yi3)
82E2 (yi3)
82E3 (ju4,qu3)
82E4 (pie3)
82E5 (ruo4,re3)
82E6 (ku3)
82E7 (zhu4,ning2)
82E8 (ni3)
82E9 (bo2)
82EA (bing3)
82EB (shan1,shan4)
82EC (qiu2)
82ED (yao3)
82EE (xian1)
82EF (ben3)
82F0 (hong2)
82F1 (ying1)
82F2 (zha3)
82F3 (dong1)
82F4 (ju1)
82F5 (die2)
82F6 (nie2)
82F7 (gan1)
82F8 (hu1)
82F9 (ping2,pin2)
82FA (mei2)
82FB (fu2)
82FC (sheng1)
82FD (gu1)
82FE (bi4)
82FF (wei4)
8300 (fu2)
8301 (zhuo2)
8302 (mao4)
8303 (fan4)
8304 (qie2,jia1)
8305 (mao2)
8306 (mao2,mao3)
8307 (ba2)
8308 (zi3,ci2)
8309 (mo4)
830A (zi1)
830B (di3)
830C (chi2)
830D (gou3)
830E (jing1)
830F (long2)
8310 (none0)
8311 (niao3)
8312 (none0)
8313 (xue2)
8314 (ying2)
8315 (qiong2)
8316 (ge2)
8317 (ming2)
8318 (li4)
8319 (rong2)
831A (yin4)
831B (gen4)
831C (qian4,xi1)
831D (chai3)
831E (chen2)
831F (yu4)
8320 (xiu1)
8321 (zi4)
8322 (lie4)
8323 (wu2)
8324 (duo1)
8325 (kui1)
8326 (ce4)
8327 (jian3)
8328 (ci2)
8329 (gou3)
832A (guang1)
832B (mang2)
832C (cha2,zha1)
832D (jiao1)
832E (jiao1)
832F (fu2)
8330 (yu2)
8331 (zhu1)
8332 (zi1)
8333 (jiang1)
8334 (hui2)
8335 (yin1)
8336 (cha2)
8337 (fa2)
8338 (rong2,rong3)
8339 (ru2,ru4)
833A (chong1)
833B (mang3)
833C (tong2)
833D (zhong4)
833E (none0)
833F (zhu2)
8340 (xun2)
8341 (huan2)
8342 (kua1)
8343 (quan2)
8344 (gai1)
8345 (da2)
8346 (jing1)
8347 (xing4)
8348 (chuan3)
8349 (cao3)
834A (jing1)
834B (er2)
834C (an4)
834D (shou1)
834E (chi2)
834F (ren3)
8350 (jian4)
8351 (ti2,yi2)
8352 (huang1,huang5)
8353 (ping2)
8354 (li4)
8355 (jin1)
8356 (lao3,pei2)
8357 (rong2)
8358 (zhuang1)
8359 (da2)
835A (jia2)
835B (rao2)
835C (bi4)
835D (ce4)
835E (qiao2)
835F (hui4)
8360 (ji4,qi2)
8361 (dang4)
8362 (none0)
8363 (rong2)
8364 (hun1,xun1)
8365 (ying2,xing2)
8366 (luo4)
8367 (ying2)
8368 (qian2,xun2)
8369 (jin4)
836A (sun1)
836B (yin4,yin1)
836C (mai3)
836D (hong2)
836E (zhou4)
836F (yao4)
8370 (du4)
8371 (wei3)
8372 (chu4)
8373 (dou4)
8374 (fu1)
8375 (ren3)
8376 (yin2)
8377 (he2,he4)
8378 (bi2)
8379 (bu4)
837A (yun2)
837B (di2)
837C (tu2)
837D (sui1)
837E (sui1)
837F (cheng2)
8380 (chen2)
8381 (wu2)
8382 (bie2)
8383 (xi1)
8384 (geng3)
8385 (li4)
8386 (pu2)
8387 (zhu4)
8388 (mo4)
8389 (li4)
838A (zhuang1)
838B (ji2)
838C (duo2)
838D (qiu2)
838E (sha1,suo1)
838F (suo1)
8390 (chen2)
8391 (feng1)
8392 (ju3)
8393 (mei2)
8394 (meng2)
8395 (xing4)
8396 (jing1)
8397 (che1)
8398 (xin1,shen1)
8399 (jun1)
839A (yan2,yan4)
839B (ting2)
839C (you2)
839D (cuo4)
839E (guan1,guan3,wan3,wan1)
839F (han4)
83A0 (you3)
83A1 (cuo4)
83A2 (jia2)
83A3 (wang4)
83A4 (you2)
83A5 (niu3,chou3)
83A6 (shao1)
83A7 (xian4)
83A8 (lang4,liang2,lang2)
83A9 (fu2,piao3)
83AA (e2)
83AB (mo4)
83AC (wen4)
83AD (jie2)
83AE (nan2)
83AF (mu4)
83B0 (kan3)
83B1 (lai2)
83B2 (lian2)
83B3 (shi4,shi2)
83B4 (wo1,zhua1)
83B5 (tu2,tu4)
83B6 (xian1)
83B7 (huo4)
83B8 (you2)
83B9 (ying2)
83BA (ying1)
83BB (none0)
83BC (chun2)
83BD (mang3)
83BE (mang3)
83BF (ci4)
83C0 (yu4,wan3)
83C1 (jing1)
83C2 (di4)
83C3 (qu2)
83C4 (dong1)
83C5 (jian1)
83C6 (zou1)
83C7 (gu1)
83C8 (la1)
83C9 (lu4,lu:4)
83CA (ju2)
83CB (wei4)
83CC (jun1,jun4)
83CD (nie4)
83CE (kun1)
83CF (he2)
83D0 (pu2)
83D1 (zai1)
83D2 (gao3)
83D3 (guo3)
83D4 (fu2)
83D5 (lun2)
83D6 (chang1)
83D7 (chou2)
83D8 (song1)
83D9 (chui2)
83DA (zhan4)
83DB (men2)
83DC (cai4)
83DD (ba2)
83DE (li2)
83DF (tu4,tu2)
83E0 (bo1)
83E1 (han4)
83E2 (bao4)
83E3 (qin4)
83E4 (juan3)
83E5 (xi1)
83E6 (qin2)
83E7 (di3)
83E8 (jie1)
83E9 (pu2)
83EA (dang4)
83EB (jin3)
83EC (zhao3)
83ED (tai2)
83EE (geng1)
83EF (hua2,hua4,hua1)
83F0 (gu1)
83F1 (ling2)
83F2 (fei1,fei3)
83F3 (jin1)
83F4 (an4)
83F5 (wang3)
83F6 (beng3)
83F7 (zhou3)
83F8 (yan1)
83F9 (zu1)
83FA (jian1)
83FB (lin3)
83FC (tan3)
83FD (shu1,shu2)
83FE (tian2)
83FF (dao4)
8400 (hu3)
8401 (ji1,qi2)
8402 (he2)
8403 (cui4)
8404 (tao2)
8405 (chun1)
8406 (bei1,bi4)
8407 (chang2)
8408 (huan2)
8409 (fei2)
840A (lai2)
840B (qi1)
840C (meng2)
840D (ping2)
840E (wei3,wei1)
840F (dan4)
8410 (sha4)
8411 (huan2)
8412 (yan3)
8413 (yi2)
8414 (tiao2)
8415 (qi2,ji4)
8416 (wan3)
8417 (ce4)
8418 (nai4)
8419 (none0)
841A (tuo4)
841B (jiu1)
841C (tie1)
841D (luo2)
841E (none0)
841F (none0)
8420 (meng2)
8421 (none0)
8422 (none0)
8423 (ding4)
8424 (ying2)
8425 (ying2)
8426 (ying2)
8427 (xiao1)
8428 (sa4)
8429 (qiu1)
842A (ke1)
842B (xiang4)
842C (wan4,mo4)
842D (yu3)
842E (yu4)
842F (fu4)
8430 (lian4)
8431 (xuan1)
8432 (xuan1)
8433 (nan2)
8434 (ze2)
8435 (wo1)
8436 (chun3)
8437 (xiao1)
8438 (yu2)
8439 (pian1,bian3)
843A (mao4)
843B (an1)
843C (e4)
843D (luo4,la4,lao4,luo1)
843E (ying2)
843F (huo2)
8440 (gua1)
8441 (jiang1)
8442 (wan3)
8443 (zuo2)
8444 (zuo4)
8445 (ju1)
8446 (bao3)
8447 (rou2)
8448 (xi3)
8449 (xie2,ye4,she4)
844A (an1)
844B (qu2)
844C (jian1)
844D (fu2)
844E (lu:4)
844F (lu:4)
8450 (pen2)
8451 (feng1,feng4)
8452 (hong2)
8453 (hong2)
8454 (hou2)
8455 (yan2)
8456 (tu1)
8457 (zhu4,zhe5,zhao1,zhao2,zhu3,zi1,zhuo2)
8458 (zi1)
8459 (xiang1)
845A (shen4,ren4)
845B (ge3,ge2)
845C (qia1)
845D (jing4)
845E (mi3)
845F (huang2)
8460 (shen1)
8461 (pu2)
8462 (ge3)
8463 (dong3)
8464 (zhou4)
8465 (qian2)
8466 (wei3)
8467 (bo2)
8468 (wei1)
8469 (pa1)
846A (ji4)
846B (hu2)
846C (zang4)
846D (jia1)
846E (duan4)
846F (yao4)
8470 (jun4)
8471 (cong1)
8472 (quan2)
8473 (wei1)
8474 (xian2)
8475 (kui2)
8476 (ting2)
8477 (hun1,xun1)
8478 (xi3)
8479 (shi1)
847A (qi4)
847B (lan2)
847C (zong1)
847D (yao1)
847E (yuan1)
847F (mei2)
8480 (yun1)
8481 (shu4)
8482 (di4)
8483 (zhuan4)
8484 (guan1)
8485 (none0)
8486 (qiong2)
8487 (chan3)
8488 (kai3)
8489 (kui4)
848A (none0)
848B (jiang3)
848C (lou2)
848D (wei3)
848E (pai4)
848F (none0)
8490 (sou1)
8491 (yin1)
8492 (shi1)
8493 (chun2)
8494 (shi4,shi2)
8495 (yun1)
8496 (zhen1)
8497 (lang4)
8498 (nu2)
8499 (meng3,meng2,meng1)
849A (he2)
849B (que1)
849C (suan4)
849D (yuan2)
849E (li4)
849F (ju3)
84A0 (xi2)
84A1 (bang4,pang2)
84A2 (chu2)
84A3 (xu2)
84A4 (tu2)
84A5 (liu2)
84A6 (huo4)
84A7 (zhen1)
84A8 (qian4)
84A9 (zu1)
84AA (po4)
84AB (cuo1)
84AC (yuan1)
84AD (chu2)
84AE (yu4)
84AF (kuai3)
84B0 (pan2)
84B1 (pu2)
84B2 (pu2)
84B3 (na4)
84B4 (shuo4)
84B5 (xi1)
84B6 (fen2)
84B7 (yun2)
84B8 (zheng1)
84B9 (jian1)
84BA (ji2)
84BB (ruo4)
84BC (cang1)
84BD (en1)
84BE (mi2)
84BF (hao1)
84C0 (sun1)
84C1 (zhen1)
84C2 (ming2)
84C3 (none0)
84C4 (xu4)
84C5 (liu2)
84C6 (xi2)
84C7 (gu1)
84C8 (lang2)
84C9 (rong2)
84CA (weng3)
84CB (gai4,ge3,he2)
84CC (cuo4)
84CD (shi1)
84CE (tang2)
84CF (luo3)
84D0 (ru4)
84D1 (suo1)
84D2 (xian1)
84D3 (bei4)
84D4 (yao3)
84D5 (gui4)
84D6 (bi4)
84D7 (zong3)
84D8 (gun3)
84D9 (none0)
84DA (xiu1)
84DB (ce4)
84DC (none0)
84DD (lan2,lan5,la5)
84DE (none0)
84DF (ji4)
84E0 (li2)
84E1 (can1)
84E2 (lang2)
84E3 (yu4)
84E4 (none0)
84E5 (ying2)
84E6 (mo4)
84E7 (diao4)
84E8 (xiu1)
84E9 (wu4)
84EA (tong1)
84EB (zhu2)
84EC (peng2)
84ED (an1)
84EE (lian2)
84EF (cong1)
84F0 (xi3)
84F1 (ping2)
84F2 (qiu1,ou1)
84F3 (jin4)
84F4 (chun2)
84F5 (jie2)
84F6 (wei3)
84F7 (tui1)
84F8 (cao2)
84F9 (yu4)
84FA (yi4)
84FB (ji2)
84FC (liao3,lu4)
84FD (bi4)
84FE (lu3)
84FF (xu5,su4)
8500 (bu4)
8501 (zhang1)
8502 (luo2)
8503 (qiang2)
8504 (man4)
8505 (yan2)
8506 (leng2)
8507 (ji4)
8508 (biao1,piao4)
8509 (gun3)
850A (han3)
850B (di2)
850C (su4)
850D (lu4)
850E (she4)
850F (shang1)
8510 (di2)
8511 (mie4)
8512 (xun1)
8513 (man4,wan4,man2)
8514 (bo5,bu3,bo2)
8515 (di4)
8516 (cuo2)
8517 (zhe4)
8518 (sen1)
8519 (xuan4)
851A (yu4,wei4)
851B (hu2)
851C (ao2)
851D (mi3)
851E (lou2)
851F (cu4)
8520 (zhong1)
8521 (cai4)
8522 (po2)
8523 (jiang3)
8524 (mi4)
8525 (cong1)
8526 (niao3)
8527 (hui4)
8528 (jun4)
8529 (yin2)
852A (jian4)
852B (nian1)
852C (shu1)
852D (yin4,yin1)
852E (kui4)
852F (chen2)
8530 (hu4)
8531 (sha1)
8532 (kou4)
8533 (qian4)
8534 (ma2,ma1)
8535 (cang2,zang4)
8536 (ze2)
8537 (qiang2)
8538 (dou1)
8539 (lian3)
853A (lin4)
853B (kou4)
853C (ai3)
853D (bi4)
853E (li2)
853F (wei3)
8540 (ji2)
8541 (qian2,xun2)
8542 (sheng4)
8543 (fan2,fan1,bo1)
8544 (meng2)
8545 (ou3)
8546 (chan3)
8547 (dian3)
8548 (xun4,jun4)
8549 (jiao1,qiao2)
854A (rui3)
854B (rui3)
854C (lei3)
854D (yu2)
854E (qiao2)
854F (chu2)
8550 (hua2,hua1,hua4)
8551 (jian1)
8552 (mai3)
8553 (yun2)
8554 (bao1)
8555 (you2)
8556 (qu2)
8557 (lu4)
8558 (rao2)
8559 (hui4)
855A (e4)
855B (ti2)
855C (fei3)
855D (jue2)
855E (zui4)
855F (fa4)
8560 (ru2)
8561 (fen2)
8562 (kui4)
8563 (shun4)
8564 (rui2)
8565 (ya3)
8566 (xu1)
8567 (fu4)
8568 (jue2)
8569 (dang4)
856A (wu2)
856B (tong2)
856C (si1)
856D (xiao1)
856E (xi4)
856F (yong1)
8570 (wen1)
8571 (shao1)
8572 (qi2)
8573 (jian1)
8574 (yun4)
8575 (sun1)
8576 (ling2)
8577 (yu4)
8578 (xia2)
8579 (weng4)
857A (ji2)
857B (hong2,hong4)
857C (si4)
857D (deng1)
857E (lei3)
857F (xuan1)
8580 (yun4)
8581 (yu4)
8582 (xi2)
8583 (hao4)
8584 (bo2,bao2,bo4)
8585 (hao1)
8586 (ai4)
8587 (wei1,wei2)
8588 (hui4)
8589 (wei4)
858A (ji4)
858B (ci2)
858C (xiang1)
858D (luan4)
858E (mie4)
858F (yi4)
8590 (leng2)
8591 (jiang1)
8592 (can4)
8593 (shen1,can1,cen1)
8594 (qiang2)
8595 (lian2)
8596 (ke1)
8597 (yuan2)
8598 (da2)
8599 (ti4)
859A (tang2)
859B (xue1)
859C (bi4,bo4)
859D (zhan1)
859E (sun1)
859F (lian4,xian1)
85A0 (fan2)
85A1 (ding3)
85A2 (xiao4)
85A3 (gu3)
85A4 (xie4)
85A5 (shu3)
85A6 (jian4)
85A7 (kao3)
85A8 (hong1)
85A9 (sa4)
85AA (xin1)
85AB (xun1)
85AC (yao4)
85AD (bai4)
85AE (sou3)
85AF (shu3)
85B0 (xun1)
85B1 (dui4)
85B2 (pin2)
85B3 (wei3)
85B4 (neng2)
85B5 (chou2)
85B6 (mai2)
85B7 (ru2)
85B8 (piao1)
85B9 (tai2)
85BA (qi2,ji4)
85BB (zao3)
85BC (chen2)
85BD (zhen1)
85BE (er3)
85BF (ni3)
85C0 (ying2)
85C1 (gao3)
85C2 (cong4)
85C3 (xiao1)
85C4 (qi2)
85C5 (fa2)
85C6 (jian3)
85C7 (xu4)
85C8 (kui1)
85C9 (jie4,ji2)
85CA (bian3)
85CB (di2)
85CC (mi4)
85CD (lan2,la5)
85CE (jin4)
85CF (zang4,cang2)
85D0 (miao3)
85D1 (qiong2)
85D2 (qie4)
85D3 (xian3,li4)
85D4 (none0)
85D5 (ou3)
85D6 (xian2)
85D7 (su4)
85D8 (lu:2)
85D9 (yi4)
85DA (xu4)
85DB (xie3)
85DC (li2)
85DD (yi4)
85DE (la3)
85DF (lei3)
85E0 (jiao4)
85E1 (di2)
85E2 (zhi3)
85E3 (pi2)
85E4 (teng2)
85E5 (yao4,yue4)
85E6 (mo4,mo2)
85E7 (huan3)
85E8 (biao1)
85E9 (fan1,fan2)
85EA (sou3)
85EB (tan2)
85EC (tui1)
85ED (qiong2)
85EE (qiao2)
85EF (wei4)
85F0 (liu2)
85F1 (hui2)
85F2 (shu1)
85F3 (gao3)
85F4 (yun4)
85F5 (none0)
85F6 (li4)
85F7 (zhu1,shu3)
85F8 (zhu1)
85F9 (ai3)
85FA (lin4)
85FB (zao3)
85FC (xuan1)
85FD (chen4)
85FE (lai4)
85FF (huo4)
8600 (tuo4)
8601 (wu4,e4)
8602 (rui3)
8603 (rui3)
8604 (qi2)
8605 (heng2)
8606 (lu2,lu3)
8607 (su1)
8608 (tui2)
8609 (mang2)
860A (yun4)
860B (pin2,ping2)
860C (yu3)
860D (xun1)
860E (ji4)
860F (jiong1)
8610 (xuan1)
8611 (mo2)
8612 (none0)
8613 (su1)
8614 (jiong1)
8615 (none0)
8616 (nie4)
8617 (bo4,nie4)
8618 (rang2)
8619 (yi4)
861A (xian3,li4)
861B (yu2)
861C (ju2)
861D (lian4)
861E (lian4,lian3)
861F (yin3)
8620 (qiang2)
8621 (ying1)
8622 (long2)
8623 (tou3)
8624 (wei3)
8625 (yue4)
8626 (ling2)
8627 (qu2)
8628 (yao2)
8629 (fan2)
862A (mi2)
862B (lan2)
862C (kui1)
862D (lan2)
862E (ji4)
862F (dang4)
8630 (none0)
8631 (lei4)
8632 (lei3)
8633 (tong4)
8634 (feng1)
8635 (zhi2)
8636 (wei4)
8637 (kui2)
8638 (zhan4)
8639 (huai4)
863A (li2)
863B (ji4)
863C (mi2)
863D (lei3)
863E (huai4)
863F (luo2)
8640 (ji1)
8641 (nao2)
8642 (lu4)
8643 (jian1)
8644 (none0)
8645 (none0)
8646 (lei3)
8647 (quan3)
8648 (xiao1)
8649 (yi4)
864A (luan2)
864B (men2)
864C (bie1)
864D (hu1)
864E (hu3,hu4)
864F (lu3)
8650 (nu:e4)
8651 (lu:4)
8652 (zhi4)
8653 (xiao1)
8654 (qian2)
8655 (chu4,chu3)
8656 (hu1)
8657 (xu1)
8658 (cuo2)
8659 (fu2)
865A (xu1)
865B (xu1)
865C (lu3)
865D (hu3,hu4)
865E (yu2)
865F (hao4,hao2)
8660 (jiao1)
8661 (ju4)
8662 (guo2)
8663 (bao4)
8664 (yan2)
8665 (zhan4)
8666 (zhan4)
8667 (kui1)
8668 (ban1)
8669 (xi4)
866A (shu2)
866B (chong2,hui3)
866C (qiu2)
866D (diao1)
866E (ji3)
866F (qiu2)
8670 (ding1)
8671 (shi1)
8672 (none0)
8673 (di4)
8674 (zhe2)
8675 (she2,yi2)
8676 (yu1)
8677 (gan1)
8678 (zi3)
8679 (hong2,jiang4)
867A (hui3,hui1)
867B (meng2)
867C (ge4)
867D (sui1)
867E (xia1,ha2)
867F (chai4)
8680 (shi2)
8681 (yi3)
8682 (ma3,ma1,ma4)
8683 (xiang4)
8684 (fang1)
8685 (e4)
8686 (pa1)
8687 (chi3)
8688 (qian1)
8689 (wen2)
868A (wen2)
868B (rui4)
868C (bang4,beng4)
868D (pi2)
868E (yue4)
868F (yue4)
8690 (jun1)
8691 (qi2)
8692 (ran2)
8693 (yin3)
8694 (qi2,chi2)
8695 (can2,tian3)
8696 (yuan2)
8697 (jue2)
8698 (hui2)
8699 (qian2)
869A (qi2)
869B (zhong4)
869C (ya2)
869D (hao2)
869E (mu4)
869F (wang2)
86A0 (fen2)
86A1 (fen2)
86A2 (hang2)
86A3 (gong1)
86A4 (zao3)
86A5 (fu3)
86A6 (ran2)
86A7 (jie4)
86A8 (fu2)
86A9 (chi1)
86AA (dou3)
86AB (bao4)
86AC (xian3)
86AD (ni3)
86AE (te4)
86AF (qiu1)
86B0 (you2)
86B1 (zha4)
86B2 (ping2)
86B3 (chi2)
86B4 (you4)
86B5 (he2,ke4)
86B6 (han1)
86B7 (ju4)
86B8 (li4)
86B9 (fu4)
86BA (ran2)
86BB (zha2)
86BC (gou3)
86BD (pi2)
86BE (bo3)
86BF (xian2)
86C0 (zhu4)
86C1 (diao1)
86C2 (bie3)
86C3 (bing3)
86C4 (gu1,gu3)
86C5 (ran2)
86C6 (qu1,ju1)
86C7 (she2,yi2)
86C8 (tie4)
86C9 (ling2)
86CA (gu3)
86CB (dan4)
86CC (gu3)
86CD (ying2)
86CE (li4)
86CF (cheng1)
86D0 (qu1)
86D1 (mou2)
86D2 (ge2)
86D3 (ci4)
86D4 (hui2)
86D5 (hui2)
86D6 (mang2)
86D7 (fu4)
86D8 (yang2)
86D9 (wa1)
86DA (lie4)
86DB (zhu1)
86DC (yi1)
86DD (xian2)
86DE (kuo4)
86DF (jiao1)
86E0 (li4)
86E1 (yi4)
86E2 (ping2)
86E3 (ji1)
86E4 (ha2,ge2)
86E5 (she2)
86E6 (yi2)
86E7 (wang3)
86E8 (mo4)
86E9 (qiong2)
86EA (qie4)
86EB (gui3)
86EC (gong3)
86ED (zhi4)
86EE (man2)
86EF (none0)
86F0 (zhe2)
86F1 (jia2)
86F2 (nao2)
86F3 (si1)
86F4 (qi2)
86F5 (xing1)
86F6 (lie4)
86F7 (qiu2)
86F8 (shao1,xiao1)
86F9 (yong3)
86FA (jia2)
86FB (tui4,shui4)
86FC (che1)
86FD (bai4)
86FE (e2,yi3)
86FF (han4)
8700 (shu3)
8701 (xuan2)
8702 (feng1)
8703 (shen4)
8704 (zhen4)
8705 (fu3)
8706 (xian4,xian3)
8707 (zhe2,zhe1)
8708 (wu2)
8709 (fu2)
870A (li2)
870B (lang2)
870C (bi4)
870D (chu2)
870E (yuan1)
870F (you3)
8710 (jie2)
8711 (dan4)
8712 (yan2)
8713 (ting2)
8714 (dian4)
8715 (tui4)
8716 (hui2)
8717 (wo1)
8718 (zhi1)
8719 (song1)
871A (fei1,fei3)
871B (ju1)
871C (mi4)
871D (qi2)
871E (qi2)
871F (yu4)
8720 (jun3)
8721 (la4,zha4)
8722 (meng3)
8723 (qiang1)
8724 (si1)
8725 (xi1)
8726 (lun2)
8727 (li4)
8728 (die2)
8729 (tiao2)
872A (tao1)
872B (kun1)
872C (gan1)
872D (han4)
872E (yu4)
872F (bang4,beng4)
8730 (fei2)
8731 (pi2)
8732 (wei3)
8733 (dun1)
8734 (yi4)
8735 (yuan1)
8736 (su4)
8737 (quan2)
8738 (qian3)
8739 (rui4)
873A (ni2)
873B (qing1)
873C (wei4)
873D (liang3)
873E (guo3)
873F (wan1,wan3)
8740 (dong1)
8741 (e4)
8742 (ban3)
8743 (zhuo2)
8744 (wang3)
8745 (can2)
8746 (yang3)
8747 (ying2)
8748 (guo1)
8749 (chan2)
874A (none0)
874B (la4,zha4)
874C (ke1)
874D (ji2)
874E (xie1,he2)
874F (ting2)
8750 (mai4)
8751 (xu1)
8752 (mian2)
8753 (yu2)
8754 (jie1)
8755 (shi2)
8756 (xuan1)
8757 (huang2)
8758 (yan3)
8759 (bian1)
875A (rou2)
875B (wei1)
875C (fu4)
875D (yuan2)
875E (mei4)
875F (wei4)
8760 (fu2)
8761 (ruan3)
8762 (xie2)
8763 (you2)
8764 (you2,qiu2)
8765 (mao2)
8766 (xia1,ha2)
8767 (ying1)
8768 (shi1)
8769 (chong2)
876A (tang1)
876B (zhu1)
876C (zong1)
876D (ti2)
876E (fu4)
876F (yuan2)
8770 (kui2)
8771 (meng2)
8772 (la4)
8773 (du2)
8774 (hu2)
8775 (qiu1)
8776 (die2)
8777 (li4,xi2)
8778 (gua1,wo1)
8779 (yun1)
877A (ju3)
877B (nan3)
877C (lou2)
877D (chun1)
877E (rong2)
877F (ying2)
8780 (jiang1)
8781 (tun4)
8782 (lang2)
8783 (pang2)
8784 (si1,shi1)
8785 (xi1)
8786 (xi1)
8787 (xi1)
8788 (yuan2)
8789 (weng1)
878A (lian2)
878B (sou1)
878C (ban1)
878D (rong2)
878E (rong2)
878F (ji2)
8790 (wu1)
8791 (xiu4)
8792 (han4)
8793 (qin2)
8794 (yi2)
8795 (bi1)
8796 (hua2)
8797 (tang2)
8798 (yi3)
8799 (du4)
879A (nai4)
879B (he2)
879C (hu2)
879D (xi1)
879E (ma3,ma1,ma4)
879F (ming2)
87A0 (yi4)
87A1 (wen2)
87A2 (ying2)
87A3 (teng2,te4)
87A4 (yu3)
87A5 (cang1)
87A6 (none0)
87A7 (none0)
87A8 (man3)
87A9 (none0)
87AA (shang1)
87AB (shi4,zhe1)
87AC (cao2)
87AD (chi1)
87AE (di4)
87AF (ao2)
87B0 (lu4)
87B1 (wei4)
87B2 (zhi4)
87B3 (tang2)
87B4 (chen2)
87B5 (piao1)
87B6 (qu2)
87B7 (pi2)
87B8 (yu2)
87B9 (jian4)
87BA (luo2)
87BB (lou2)
87BC (qin3)
87BD (zhong1)
87BE (yin3)
87BF (jiang1)
87C0 (shuai4,shuo4)
87C1 (wen2)
87C2 (jiao1)
87C3 (wan4)
87C4 (zhe2,zhi2)
87C5 (zhe4)
87C6 (ma2,ma5)
87C7 (ma2)
87C8 (guo1)
87C9 (liao4)
87CA (mao2)
87CB (xi1)
87CC (cong1)
87CD (li2)
87CE (man3)
87CF (xiao1)
87D0 (none0)
87D1 (zhang1)
87D2 (mang3)
87D3 (xiang4)
87D4 (mo4)
87D5 (zi1)
87D6 (si1)
87D7 (qiu1)
87D8 (te4)
87D9 (zhi2)
87DA (peng2)
87DB (peng2)
87DC (jiao3)
87DD (qu2)
87DE (bie2)
87DF (liao3)
87E0 (pan2)
87E1 (gui3)
87E2 (xi3)
87E3 (ji3)
87E4 (zhuan1)
87E5 (huang2)
87E6 (fei4)
87E7 (lao2)
87E8 (jue2)
87E9 (jue2)
87EA (hui4)
87EB (yin2)
87EC (chan2)
87ED (jiao1)
87EE (shan4)
87EF (rao2,nao2)
87F0 (xiao1)
87F1 (wu2)
87F2 (chong2)
87F3 (xun2)
87F4 (si1)
87F5 (none0)
87F6 (cheng1)
87F7 (dang1)
87F8 (li3,li2)
87F9 (xie4)
87FA (shan4)
87FB (yi3)
87FC (jing3)
87FD (da2)
87FE (chan2)
87FF (qi4)
8800 (zi1)
8801 (xiang4)
8802 (she4)
8803 (luo3)
8804 (qin2)
8805 (ying2)
8806 (chai4)
8807 (li4)
8808 (ze2)
8809 (xuan1)
880A (lian2)
880B (zhu2)
880C (ze2)
880D (xie1)
880E (mang3)
880F (xie4,xie3)
8810 (qi2)
8811 (rong2)
8812 (jian3)
8813 (meng3)
8814 (hao2)
8815 (ru2,ruan3)
8816 (huo4)
8817 (zhuo2)
8818 (jie2)
8819 (bin1)
881A (he4)
881B (mie4)
881C (fan2)
881D (lei2)
881E (jie2)
881F (la4,zha4)
8820 (mi4)
8821 (li3,li2)
8822 (chun3)
8823 (li4)
8824 (qiu1)
8825 (nie4)
8826 (lu2)
8827 (du4)
8828 (xiao1)
8829 (zhu1)
882A (long2)
882B (li4)
882C (long2)
882D (feng1)
882E (ye1)
882F (pi2)
8830 (rang2)
8831 (gu3)
8832 (juan1)
8833 (ying1)
8834 (none0)
8835 (xi1)
8836 (can2)
8837 (qu2)
8838 (quan2)
8839 (du4)
883A (can2)
883B (man2)
883C (qu2)
883D (jie2)
883E (zhu2)
883F (zha2)
8840 (xue4,xie3)
8841 (huang1)
8842 (nu:4)
8843 (pei1)
8844 (nu:4)
8845 (xin4)
8846 (zhong4)
8847 (mo4)
8848 (er4)
8849 (mie4)
884A (mie4)
884B (shi4)
884C (xing2,hang2,hang4,xing4,heng2)
884D (yan3)
884E (kan4)
884F (yuan4)
8850 (none0)
8851 (ling2)
8852 (xuan4)
8853 (shu4,zhu2)
8854 (xian2)
8855 (tong4)
8856 (long4)
8857 (jie1)
8858 (xian2)
8859 (ya2)
885A (hu2)
885B (wei4)
885C (dao4)
885D (chong1,chong4)
885E (wei4)
885F (dao4)
8860 (zhun1)
8861 (heng2)
8862 (qu2)
8863 (yi1,yi4,yi3)
8864 (yi1)
8865 (bu3)
8866 (gan3)
8867 (yu2)
8868 (biao3)
8869 (cha4,cha3)
886A (yi2)
886B (shan1)
886C (chen4)
886D (fu1)
886E (gun3)
886F (fen1)
8870 (shuai1,cui1)
8871 (jie2,ji2)
8872 (na4)
8873 (zhong1)
8874 (dan3)
8875 (ri4)
8876 (zhong4)
8877 (zhong1)
8878 (xie4)
8879 (qi2,zhi1)
887A (xie2)
887B (ran2)
887C (zhi1)
887D (ren4)
887E (qin1)
887F (jin1)
8880 (jun1)
8881 (yuan2)
8882 (mei4)
8883 (chai4)
8884 (ao3)
8885 (niao3)
8886 (hui1)
8887 (ran2)
8888 (jia1)
8889 (tuo2)
888A (ling3)
888B (dai4)
888C (bao4)
888D (pao2)
888E (yao4)
888F (zuo4)
8890 (bi4)
8891 (shao4)
8892 (tan3)
8893 (ju3)
8894 (he4)
8895 (xue4)
8896 (xiu4)
8897 (zhen3)
8898 (yi2)
8899 (pa4)
889A (bo1,fu2)
889B (di1)
889C (wa4)
889D (fu4)
889E (gun3)
889F (zhi4)
88A0 (zhi4)
88A1 (ran2)
88A2 (pan4)
88A3 (yi4)
88A4 (mao4)
88A5 (none0)
88A6 (na4)
88A7 (kou1)
88A8 (xuan4)
88A9 (chan1)
88AA (qu1)
88AB (bei4,pi1)
88AC (yu4)
88AD (xi2)
88AE (none0)
88AF (bo2)
88B0 (none0)
88B1 (fu2)
88B2 (yi2)
88B3 (chi3)
88B4 (ku4)
88B5 (ren4)
88B6 (jiang4)
88B7 (jia2,qia1)
88B8 (cun2)
88B9 (mo4)
88BA (jie2)
88BB (er2)
88BC (ge1)
88BD (ru2)
88BE (zhu1)
88BF (gui1)
88C0 (yin1)
88C1 (cai2)
88C2 (lie4,lie3)
88C3 (none0)
88C4 (none0)
88C5 (zhuang1)
88C6 (dang1)
88C7 (none0)
88C8 (kun1)
88C9 (ken4)
88CA (niao3)
88CB (shu4)
88CC (jia2)
88CD (kun3)
88CE (cheng2,cheng3)
88CF (li3)
88D0 (juan1)
88D1 (shen1)
88D2 (pou2)
88D3 (ge2)
88D4 (yi4)
88D5 (yu4)
88D6 (chen3)
88D7 (liu2)
88D8 (qiu2)
88D9 (qun2)
88DA (ji4)
88DB (yi4)
88DC (bu3)
88DD (zhuang1)
88DE (shui4)
88DF (sha1)
88E0 (qun2)
88E1 (li3)
88E2 (lian2)
88E3 (lian3)
88E4 (ku4)
88E5 (jian3)
88E6 (fou2)
88E7 (tan3)
88E8 (bi4,pi2,bei1)
88E9 (gun1)
88EA (tao2)
88EB (yuan1)
88EC (ling2)
88ED (chi3)
88EE (chang1)
88EF (chou2)
88F0 (duo1)
88F1 (biao3)
88F2 (liang3)
88F3 (shang5,chang2)
88F4 (pei2)
88F5 (pei2)
88F6 (fei1)
88F7 (yuan1)
88F8 (luo3)
88F9 (guo3)
88FA (yan3)
88FB (du3)
88FC (ti4,xi1,xi2)
88FD (zhi4)
88FE (ju1)
88FF (qi3)
8900 (ji4)
8901 (zhi2)
8902 (gua4)
8903 (ken4)
8904 (none0)
8905 (ti4)
8906 (shi4)
8907 (fu4)
8908 (chong2)
8909 (xie1)
890A (bian3)
890B (die2)
890C (kun1,hui1)
890D (duan1)
890E (xiu4)
890F (xiu4)
8910 (he4,he2)
8911 (yuan4)
8912 (bao1)
8913 (bao3)
8914 (fu4)
8915 (yu2)
8916 (tuan4)
8917 (yan3)
8918 (hui1)
8919 (bei4)
891A (chu3,zhu3)
891B (lu:3)
891C (none0)
891D (none0)
891E (yun3)
891F (ta1)
8920 (gou1)
8921 (da1)
8922 (huai2)
8923 (rong2)
8924 (yuan4)
8925 (ru4)
8926 (nai4)
8927 (jiong3)
8928 (suo3)
8929 (ban1)
892A (tun4,tui4)
892B (chi3)
892C (sang3)
892D (niao3)
892E (ying1)
892F (jie4)
8930 (qian1)
8931 (huai2)
8932 (ku4)
8933 (lian2)
8934 (lan2)
8935 (li2)
8936 (zhe3,zhe2,xi2)
8937 (shi1)
8938 (lu:3)
8939 (yi4)
893A (die1)
893B (xie4)
893C (xian1)
893D (wei4)
893E (biao3)
893F (cao2)
8940 (ji1)
8941 (qiang3)
8942 (sen1)
8943 (bao1)
8944 (xiang1)
8945 (none0)
8946 (pu2)
8947 (jian3)
8948 (zhuan4)
8949 (jian4)
894A (zui4)
894B (ji2)
894C (dan1)
894D (za2)
894E (fan2)
894F (bo1)
8950 (xiang4)
8951 (xin2)
8952 (bie2,bi4)
8953 (rao2)
8954 (man3)
8955 (lan2)
8956 (ao3)
8957 (duo2)
8958 (hui4)
8959 (cao4)
895A (sui4)
895B (nong2)
895C (chan1)
895D (lian4,lian3)
895E (bi4)
895F (jin1)
8960 (dang1)
8961 (shu2)
8962 (tan3)
8963 (bi4)
8964 (lan2)
8965 (pu2)
8966 (ru2)
8967 (zhi3)
8968 (none0)
8969 (shu3)
896A (wa4)
896B (shi4)
896C (bai3)
896D (xie2)
896E (bo2)
896F (chen4)
8970 (lai3)
8971 (long2)
8972 (xi2)
8973 (xian1)
8974 (lan2)
8975 (zhe2)
8976 (dai4)
8977 (none0)
8978 (zan4)
8979 (shi1)
897A (jian3)
897B (pan4)
897C (yi4)
897D (none0)
897E (ya4)
897F (xi1)
8980 (xi1)
8981 (yao4,yao1)
8982 (feng3)
8983 (tan2,qin2)
8984 (none0)
8985 (none0)
8986 (fu4)
8987 (ba4)
8988 (he2)
8989 (ji1)
898A (ji1)
898B (jian4,xian4)
898C (guan1)
898D (bian4)
898E (yan4)
898F (gui1)
8990 (jue2,jiao4)
8991 (pian3)
8992 (mao2)
8993 (mi4)
8994 (mi4)
8995 (mie4)
8996 (shi4)
8997 (si1)
8998 (zhan1,chan1)
8999 (luo2)
899A (jue2,jiao4)
899B (mo4)
899C (tiao4)
899D (lian2)
899E (yao4)
899F (zhi4)
89A0 (jun1)
89A1 (xi2)
89A2 (shan3)
89A3 (wei1)
89A4 (xi4)
89A5 (tian3)
89A6 (yu2)
89A7 (lan3)
89A8 (e4)
89A9 (du3)
89AA (qin1,qing4)
89AB (pang3)
89AC (ji4)
89AD (ming2)
89AE (ping1)
89AF (gou4)
89B0 (qu4,qu1)
89B1 (zhan4)
89B2 (jin3,jin4)
89B3 (guan1,guan4)
89B4 (deng1)
89B5 (jian4)
89B6 (luo2)
89B7 (qu4,qu1)
89B8 (jian4)
89B9 (wei2)
89BA (jue2,jiao4)
89BB (qu4)
89BC (luo2)
89BD (lan3)
89BE (shen3)
89BF (di2)
89C0 (guan1,guan4)
89C1 (jian4,xian4)
89C2 (guan1,guan4)
89C3 (yan4)
89C4 (gui1)
89C5 (mi4)
89C6 (shi4)
89C7 (chan1)
89C8 (lan3)
89C9 (jue2,jiao4)
89CA (ji4)
89CB (xi2)
89CC (di2)
89CD (tian3)
89CE (yu2)
89CF (gou4)
89D0 (jin4)
89D1 (qu4,qu1)
89D2 (jiao3,jue2,jia3)
89D3 (jiu1)
89D4 (jin1)
89D5 (cu1)
89D6 (jue2)
89D7 (zhi4)
89D8 (chao4)
89D9 (ji2)
89DA (gu1)
89DB (dan4)
89DC (zui3,zi1)
89DD (di3)
89DE (shang1)
89DF (hua4)
89E0 (quan2)
89E1 (ge2)
89E2 (zhi4)
89E3 (jie3,jie4,xie4)
89E4 (gui3)
89E5 (gong1)
89E6 (chu4)
89E7 (jie3,jie4,xie4)
89E8 (huan4)
89E9 (qiu2)
89EA (xing1)
89EB (su4)
89EC (ni2)
89ED (ji1)
89EE (lu4)
89EF (zhi4)
89F0 (zhu1)
89F1 (bi4)
89F2 (xing1)
89F3 (hu2)
89F4 (shang1)
89F5 (gong1)
89F6 (zhi4)
89F7 (xue2)
89F8 (chu4)
89F9 (xi1)
89FA (yi2)
89FB (li4)
89FC (jue2)
89FD (xi1)
89FE (yan4)
89FF (xi1)
8A00 (yan2)
8A01 (yan2)
8A02 (ding4)
8A03 (fu4)
8A04 (qiu2)
8A05 (qiu2)
8A06 (jiao4)
8A07 (hong1)
8A08 (ji4)
8A09 (fan4)
8A0A (xun4)
8A0B (diao4)
8A0C (hong2,hong4)
8A0D (cha4)
8A0E (tao3)
8A0F (xu1)
8A10 (jie2)
8A11 (yi2)
8A12 (ren4)
8A13 (xun4)
8A14 (yin2)
8A15 (shan4)
8A16 (qi4)
8A17 (tuo1)
8A18 (ji4)
8A19 (xun4)
8A1A (yin2)
8A1B (e2)
8A1C (fen1)
8A1D (ya4)
8A1E (yao1)
8A1F (song4)
8A20 (shen3)
8A21 (yin2)
8A22 (xin1)
8A23 (jue2)
8A24 (xiao2)
8A25 (ne4,na4)
8A26 (chen2)
8A27 (you2)
8A28 (zhi3)
8A29 (xiong1)
8A2A (fang3)
8A2B (xin4)
8A2C (chao1)
8A2D (she4)
8A2E (xian1)
8A2F (sa3)
8A30 (zhun1)
8A31 (xu3,hu3)
8A32 (yi4)
8A33 (yi4)
8A34 (su4)
8A35 (chi1)
8A36 (he1)
8A37 (shen1)
8A38 (he2)
8A39 (xu4)
8A3A (zhen3,zhen1)
8A3B (zhu4)
8A3C (zheng4)
8A3D (gou4)
8A3E (zi3,zi1)
8A3F (zi3)
8A40 (zhan1)
8A41 (gu3)
8A42 (fu4)
8A43 (jian3)
8A44 (die2)
8A45 (ling2)
8A46 (di3)
8A47 (yang4)
8A48 (li4)
8A49 (nao2)
8A4A (pan4)
8A4B (zhou4)
8A4C (gan4)
8A4D (shi4)
8A4E (ju4)
8A4F (ao4)
8A50 (zha4)
8A51 (tuo1)
8A52 (yi2)
8A53 (qu3)
8A54 (zhao4)
8A55 (ping2)
8A56 (bi4)
8A57 (xiong4)
8A58 (chu4,qu1)
8A59 (ba2)
8A5A (da2)
8A5B (zu3)
8A5C (tao1)
8A5D (zhu3)
8A5E (ci2)
8A5F (zhe2)
8A60 (yong3)
8A61 (xu3)
8A62 (xun2)
8A63 (yi4)
8A64 (huang3)
8A65 (he2)
8A66 (shi4)
8A67 (cha2)
8A68 (jiao1)
8A69 (shi1)
8A6A (hen3)
8A6B (cha4)
8A6C (gou4)
8A6D (gui3)
8A6E (quan2)
8A6F (hui4)
8A70 (jie2)
8A71 (hua4)
8A72 (gai1)
8A73 (xiang2)
8A74 (hui4)
8A75 (shen1)
8A76 (chou2)
8A77 (tong2)
8A78 (mi2)
8A79 (zhan1)
8A7A (ming2)
8A7B (e4)
8A7C (hui1)
8A7D (yan2)
8A7E (xiong1)
8A7F (gua4)
8A80 (er4)
8A81 (beng3)
8A82 (tiao3,diao4)
8A83 (chi3)
8A84 (lei3)
8A85 (zhu1)
8A86 (kuang1)
8A87 (kua1)
8A88 (wu2)
8A89 (yu4)
8A8A (teng2)
8A8B (ji4)
8A8C (zhi4)
8A8D (ren4)
8A8E (su4)
8A8F (lang3)
8A90 (e2)
8A91 (kuang2)
8A92 (e^1,e^2,e^3,e^4)
8A93 (shi4)
8A94 (ting3)
8A95 (dan4)
8A96 (bei4)
8A97 (chan2)
8A98 (you4)
8A99 (heng2)
8A9A (qiao4)
8A9B (qin1)
8A9C (shua4)
8A9D (an1)
8A9E (yu3,yu4)
8A9F (xiao4)
8AA0 (cheng2)
8AA1 (jie4)
8AA2 (xian4)
8AA3 (wu1,wu2)
8AA4 (wu4)
8AA5 (gao4)
8AA6 (song4)
8AA7 (pu3)
8AA8 (hui4,hui3)
8AA9 (jing4)
8AAA (shuo1,shui4,yue4)
8AAB (zhen4)
8AAC (shuo1,shui4,yue4)
8AAD (du2,dou4)
8AAE (none0)
8AAF (chang4)
8AB0 (shui2,shei2)
8AB1 (jie2)
8AB2 (ke4)
8AB3 (qu1)
8AB4 (cong2)
8AB5 (xiao2)
8AB6 (sui4)
8AB7 (wang3)
8AB8 (xuan2)
8AB9 (fei3)
8ABA (chi1)
8ABB (ta4)
8ABC (yi2,yi4)
8ABD (na2)
8ABE (yin2)
8ABF (diao4,tiao2)
8AC0 (pi3)
8AC1 (chuo4)
8AC2 (chan3)
8AC3 (chen1)
8AC4 (zhun1)
8AC5 (ji1)
8AC6 (qi1)
8AC7 (tan2)
8AC8 (chui4)
8AC9 (wei3)
8ACA (ju1)
8ACB (qing3)
8ACC (jian4)
8ACD (zheng1,zheng4)
8ACE (ze2)
8ACF (zou1)
8AD0 (qian1)
8AD1 (zhuo2)
8AD2 (liang4)
8AD3 (jian4)
8AD4 (zhu4)
8AD5 (hao2)
8AD6 (lun4,lun2)
8AD7 (shen3)
8AD8 (biao3)
8AD9 (huai4)
8ADA (pian2)
8ADB (yu2)
8ADC (die2)
8ADD (xu3)
8ADE (pian2,pian3)
8ADF (shi4)
8AE0 (xuan1)
8AE1 (shi4)
8AE2 (hun4)
8AE3 (hua4)
8AE4 (e4)
8AE5 (zhong4)
8AE6 (di4)
8AE7 (xie2)
8AE8 (fu2)
8AE9 (pu3)
8AEA (ting2)
8AEB (jian4)
8AEC (qi3)
8AED (yu4)
8AEE (zi1)
8AEF (chuan2)
8AF0 (xi3)
8AF1 (hui4)
8AF2 (yin1)
8AF3 (an1)
8AF4 (xian2)
8AF5 (nan2)
8AF6 (chen2)
8AF7 (feng1,feng3,feng4)
8AF8 (zhu1)
8AF9 (yang2)
8AFA (yan4)
8AFB (heng1,heng2)
8AFC (xuan1)
8AFD (ge2)
8AFE (nuo4)
8AFF (qi4)
8B00 (mou2)
8B01 (ye4)
8B02 (wei4)
8B03 (none0)
8B04 (teng2)
8B05 (zou1,zhou1)
8B06 (shan4)
8B07 (jian3)
8B08 (bo2)
8B09 (none0)
8B0A (huang3)
8B0B (huo4)
8B0C (ge1)
8B0D (ying2)
8B0E (mi2,mei4)
8B0F (xiao3,sou3)
8B10 (mi4)
8B11 (xi4)
8B12 (qiang1)
8B13 (chen1)
8B14 (nu:e4,xue4)
8B15 (si1)
8B16 (su4)
8B17 (bang4)
8B18 (chi2)
8B19 (qian1)
8B1A (shi4,yi4)
8B1B (jiang3)
8B1C (yuan4)
8B1D (xie4)
8B1E (xue4)
8B1F (tao1)
8B20 (yao2)
8B21 (yao2)
8B22 (hu4)
8B23 (yu2)
8B24 (biao1)
8B25 (cong4)
8B26 (qing3,qing4)
8B27 (li2)
8B28 (mo2)
8B29 (mo4)
8B2A (shang1)
8B2B (zhe2)
8B2C (miu4)
8B2D (jian3)
8B2E (ze2)
8B2F (zha1)
8B30 (lian2)
8B31 (lou2)
8B32 (can1)
8B33 (ou1)
8B34 (guan4)
8B35 (xi2)
8B36 (zhuo2)
8B37 (ao2)
8B38 (ao2)
8B39 (jin3)
8B3A (zhe2)
8B3B (yi2)
8B3C (hu1)
8B3D (jiang4)
8B3E (man2,man4)
8B3F (chao2)
8B40 (han4)
8B41 (hua2)
8B42 (chan3)
8B43 (xu1)
8B44 (zeng1)
8B45 (se4)
8B46 (xi1)
8B47 (she1)
8B48 (dui4)
8B49 (zheng4)
8B4A (nao2)
8B4B (lan2)
8B4C (e2)
8B4D (ying4)
8B4E (jue2)
8B4F (ji1)
8B50 (zun3)
8B51 (jiao3)
8B52 (bo4)
8B53 (hui4)
8B54 (zhuan4)
8B55 (wu2)
8B56 (jian4,zen4)
8B57 (zha2)
8B58 (shi4,zhi4)
8B59 (qiao2,qiao4)
8B5A (tan2)
8B5B (zen4)
8B5C (pu3)
8B5D (sheng2)
8B5E (xuan1)
8B5F (zao4)
8B60 (zhan1)
8B61 (dang3)
8B62 (sui4)
8B63 (qian1)
8B64 (ji1)
8B65 (jiao4)
8B66 (jing3)
8B67 (lian2)
8B68 (nou4)
8B69 (yi1)
8B6A (ai4)
8B6B (zhan1)
8B6C (pi4)
8B6D (hui3)
8B6E (hua4)
8B6F (yi4)
8B70 (yi4)
8B71 (shan4)
8B72 (rang4)
8B73 (nou4)
8B74 (qian3)
8B75 (zhui4)
8B76 (ta4)
8B77 (hu4)
8B78 (zhou1)
8B79 (hao2)
8B7A (ni3)
8B7B (ying1)
8B7C (jian4,jian1)
8B7D (yu4)
8B7E (jian3)
8B7F (hui4)
8B80 (du2,dou4)
8B81 (zhe2)
8B82 (xuan4)
8B83 (zan4)
8B84 (lei3)
8B85 (shen3)
8B86 (wei4)
8B87 (chan3)
8B88 (li4)
8B89 (yi2)
8B8A (bian4)
8B8B (zhe2)
8B8C (yan4)
8B8D (e4)
8B8E (chou2)
8B8F (wei4)
8B90 (chou2)
8B91 (yao4)
8B92 (chan2)
8B93 (rang4)
8B94 (yin3)
8B95 (lan2)
8B96 (chen4)
8B97 (huo4)
8B98 (zhe2)
8B99 (huan1)
8B9A (zan4)
8B9B (yi4)
8B9C (dang3)
8B9D (zhan1)
8B9E (yan4)
8B9F (du2)
8BA0 (yan2)
8BA1 (ji4)
8BA2 (ding4)
8BA3 (fu4)
8BA4 (ren4)
8BA5 (ji1)
8BA6 (jie2)
8BA7 (hong4)
8BA8 (tao3)
8BA9 (rang4)
8BAA (shan4)
8BAB (qi4)
8BAC (tuo1)
8BAD (xun4)
8BAE (yi4)
8BAF (xun4)
8BB0 (ji4)
8BB1 (ren4)
8BB2 (jiang3)
8BB3 (hui4)
8BB4 (ou1)
8BB5 (ju4)
8BB6 (ya4)
8BB7 (ne4)
8BB8 (xu3)
8BB9 (e2)
8BBA (lun4,lun2)
8BBB (xiong1)
8BBC (song4)
8BBD (feng3)
8BBE (she4)
8BBF (fang3)
8BC0 (jue2)
8BC1 (zheng4)
8BC2 (gu3)
8BC3 (he1)
8BC4 (ping2)
8BC5 (zu3)
8BC6 (shi1,zhi4)
8BC7 (xiong4)
8BC8 (zha4)
8BC9 (su4)
8BCA (zhen3)
8BCB (di3)
8BCC (zhou1)
8BCD (ci2)
8BCE (qu1)
8BCF (zhao4)
8BD0 (bi4)
8BD1 (yi4)
8BD2 (yi2)
8BD3 (kuang1)
8BD4 (lei3)
8BD5 (shi4)
8BD6 (gua4)
8BD7 (shi1)
8BD8 (jie2,ji2)
8BD9 (hui1)
8BDA (cheng2)
8BDB (zhu1)
8BDC (shen1)
8BDD (hua4)
8BDE (dan4)
8BDF (gou4)
8BE0 (quan2)
8BE1 (gui3)
8BE2 (xun2)
8BE3 (yi4)
8BE4 (zheng4)
8BE5 (gai1)
8BE6 (xiang2)
8BE7 (cha4)
8BE8 (hun4)
8BE9 (xu3)
8BEA (zhou1)
8BEB (jie4)
8BEC (wu1)
8BED (yu3,yu4)
8BEE (qiao4)
8BEF (wu4)
8BF0 (gao4)
8BF1 (you4)
8BF2 (hui4)
8BF3 (kuang2)
8BF4 (shuo1,shui4,yue4)
8BF5 (song4)
8BF6 (ei4,ei2,ei3,ai3,e^1,e^2,e^3,e^4)
8BF7 (qing3)
8BF8 (zhu1)
8BF9 (zou1)
8BFA (nuo4)
8BFB (du2,dou4)
8BFC (zhuo2)
8BFD (fei3)
8BFE (ke4)
8BFF (wei3)
8C00 (yu2)
8C01 (shei2,shui2)
8C02 (shen3)
8C03 (diao4,tiao2)
8C04 (chan3)
8C05 (liang4)
8C06 (zhun1)
8C07 (sui4)
8C08 (tan2)
8C09 (shen3)
8C0A (yi4)
8C0B (mou2)
8C0C (chen2)
8C0D (die2)
8C0E (huang3)
8C0F (jian4)
8C10 (xie2)
8C11 (xue4)
8C12 (ye4)
8C13 (wei4)
8C14 (e4)
8C15 (yu4)
8C16 (xuan1)
8C17 (chan2)
8C18 (zi1)
8C19 (an1)
8C1A (yan4)
8C1B (di4)
8C1C (mi2,mei4)
8C1D (pian3)
8C1E (xu3)
8C1F (mo2)
8C20 (dang3)
8C21 (su4)
8C22 (xie4)
8C23 (yao2)
8C24 (bang4)
8C25 (shi4)
8C26 (qian1)
8C27 (mi4)
8C28 (jin3)
8C29 (man2,man4)
8C2A (zhe2)
8C2B (jian3)
8C2C (miu4)
8C2D (tan2)
8C2E (jian4,zen4)
8C2F (qiao2,qiao4)
8C30 (lan2)
8C31 (pu3)
8C32 (jue2)
8C33 (yan4)
8C34 (qian3)
8C35 (zhan1)
8C36 (chen4)
8C37 (gu3,yu4)
8C38 (qian1)
8C39 (hong2)
8C3A (ya2)
8C3B (jue2)
8C3C (hong2)
8C3D (han1)
8C3E (hong1)
8C3F (qi1,xi1)
8C40 (xi1)
8C41 (huo4,huo1,hua2)
8C42 (liao2)
8C43 (han3)
8C44 (du2)
8C45 (long2)
8C46 (dou4)
8C47 (jiang1)
8C48 (qi3,kai3)
8C49 (chi3)
8C4A (feng1,li3)
8C4B (deng1)
8C4C (wan1)
8C4D (bi1)
8C4E (shu4)
8C4F (xian4)
8C50 (feng1)
8C51 (zhi4)
8C52 (zhi4)
8C53 (yan4)
8C54 (yan4)
8C55 (shi3)
8C56 (chu4)
8C57 (hui1)
8C58 (tun2)
8C59 (yi4)
8C5A (tun2)
8C5B (yi4)
8C5C (jian1)
8C5D (ba1)
8C5E (hou4)
8C5F (e4)
8C60 (cu2)
8C61 (xiang4)
8C62 (huan4)
8C63 (jian1)
8C64 (ken3)
8C65 (gai1)
8C66 (qu2)
8C67 (fu1)
8C68 (xi1)
8C69 (bin1)
8C6A (hao2)
8C6B (yu4)
8C6C (zhu1)
8C6D (jia1)
8C6E (fen2)
8C6F (xi1)
8C70 (hu4)
8C71 (wen1)
8C72 (huan2)
8C73 (bin1)
8C74 (di2)
8C75 (zong1)
8C76 (fen2)
8C77 (yi4)
8C78 (zhi4)
8C79 (bao4)
8C7A (chai2)
8C7B (han4,an4)
8C7C (pi2)
8C7D (na4)
8C7E (pi1)
8C7F (gou3)
8C80 (duo4)
8C81 (you4)
8C82 (diao1)
8C83 (mo4)
8C84 (si4)
8C85 (xiu1)
8C86 (huan2)
8C87 (kun1)
8C88 (he2)
8C89 (he2,hao2,mo4)
8C8A (mo4)
8C8B (an4)
8C8C (mao4)
8C8D (li2)
8C8E (ni2)
8C8F (bi3)
8C90 (yu3)
8C91 (jia1)
8C92 (tuan1)
8C93 (mao1)
8C94 (pi2)
8C95 (xi1)
8C96 (e4)
8C97 (ju4)
8C98 (mo4)
8C99 (chu1)
8C9A (tan2)
8C9B (huan1)
8C9C (qu2)
8C9D (bei4)
8C9E (zhen1)
8C9F (yuan2,yun2,yun4)
8CA0 (fu4)
8CA1 (cai2)
8CA2 (gong4)
8CA3 (te4)
8CA4 (yi2)
8CA5 (hang2)
8CA6 (wan4)
8CA7 (pin2)
8CA8 (huo4)
8CA9 (fan4)
8CAA (tan1)
8CAB (guan4)
8CAC (ze2,zhai4)
8CAD (zhi4)
8CAE (er4)
8CAF (zhu3,zhu4)
8CB0 (shi4)
8CB1 (bi4)
8CB2 (zi1)
8CB3 (er4)
8CB4 (gui4)
8CB5 (pian1)
8CB6 (bian3)
8CB7 (mai3)
8CB8 (dai4)
8CB9 (sheng4)
8CBA (kuang4)
8CBB (fei4)
8CBC (tie1)
8CBD (yi2)
8CBE (chi2,chi1)
8CBF (mao4)
8CC0 (he4)
8CC1 (bi4,ben1)
8CC2 (lu4)
8CC3 (lin4,ren4)
8CC4 (hui4,hui3)
8CC5 (gai1)
8CC6 (pian2)
8CC7 (zi1)
8CC8 (jia3,gu3,jia4)
8CC9 (xu4)
8CCA (zei2,ze2)
8CCB (jiao3)
8CCC (gai1)
8CCD (zang1)
8CCE (jian4)
8CCF (ying4)
8CD0 (xun4)
8CD1 (zhen4)
8CD2 (she1)
8CD3 (bin1)
8CD4 (bin1)
8CD5 (qiu2)
8CD6 (she1)
8CD7 (chuan4)
8CD8 (zang1)
8CD9 (zhou1)
8CDA (lai4)
8CDB (zan4)
8CDC (si4,ci4)
8CDD (chen1)
8CDE (shang3)
8CDF (tian3)
8CE0 (pei2)
8CE1 (geng1)
8CE2 (xian2)
8CE3 (mai4)
8CE4 (jian4)
8CE5 (sui4)
8CE6 (fu4)
8CE7 (dan3)
8CE8 (cong2)
8CE9 (cong2)
8CEA (zhi2,zhi4)
8CEB (ji1)
8CEC (zhang4)
8CED (du3)
8CEE (jin4)
8CEF (xiong1)
8CF0 (shun3)
8CF1 (yun3)
8CF2 (bao3)
8CF3 (zai1)
8CF4 (lai4)
8CF5 (feng4)
8CF6 (cang4)
8CF7 (ji1)
8CF8 (sheng4)
8CF9 (ai4)
8CFA (zhuan4,zuan4)
8CFB (fu4)
8CFC (gou4)
8CFD (sai4)
8CFE (ze2)
8CFF (liao2)
8D00 (wei4)
8D01 (bai4)
8D02 (chen3)
8D03 (zhuan4)
8D04 (zhi4)
8D05 (zhui4)
8D06 (biao1)
8D07 (yun1)
8D08 (zeng4)
8D09 (tan3)
8D0A (zan4)
8D0B (yan4)
8D0C (none0)
8D0D (shan4)
8D0E (wan4)
8D0F (ying2)
8D10 (jin4)
8D11 (gan3)
8D12 (xian2)
8D13 (zang1)
8D14 (bi4)
8D15 (du2)
8D16 (shu2)
8D17 (yan4)
8D18 (none0)
8D19 (xuan4)
8D1A (long4)
8D1B (gan4)
8D1C (zang1)
8D1D (bei4)
8D1E (zhen1)
8D1F (fu4)
8D20 (yuan2,yun2,yun4)
8D21 (gong4)
8D22 (cai2)
8D23 (ze2)
8D24 (xian2)
8D25 (bai4)
8D26 (zhang4)
8D27 (huo4)
8D28 (zhi4)
8D29 (fan4)
8D2A (tan1)
8D2B (pin2)
8D2C (bian3)
8D2D (gou4)
8D2E (zhu4)
8D2F (guan4)
8D30 (er4)
8D31 (jian4)
8D32 (bi4,ben1)
8D33 (shi4)
8D34 (tie1)
8D35 (gui4)
8D36 (kuang4)
8D37 (dai4)
8D38 (mao4)
8D39 (fei4)
8D3A (he4)
8D3B (yi2)
8D3C (zei2)
8D3D (zhi4)
8D3E (jia3,gu3)
8D3F (hui4)
8D40 (zi1)
8D41 (lin4)
8D42 (lu4)
8D43 (zang1)
8D44 (zi1)
8D45 (gai1)
8D46 (jin4)
8D47 (qiu2)
8D48 (zhen4)
8D49 (lai4)
8D4A (she1)
8D4B (fu4)
8D4C (du3)
8D4D (ji1)
8D4E (shu2)
8D4F (shang3)
8D50 (ci4)
8D51 (bi4)
8D52 (zhou1)
8D53 (geng1)
8D54 (pei2)
8D55 (dan3)
8D56 (lai4)
8D57 (feng4)
8D58 (zhui4)
8D59 (fu4)
8D5A (zhuan4,zuan4)
8D5B (sai4)
8D5C (ze2)
8D5D (yan4)
8D5E (zan4)
8D5F (yun1)
8D60 (zeng4)
8D61 (shan4)
8D62 (ying2)
8D63 (gan4)
8D64 (chi4)
8D65 (xi1)
8D66 (she4)
8D67 (nan3)
8D68 (xiong2)
8D69 (xi4)
8D6A (cheng1)
8D6B (he4)
8D6C (cheng1)
8D6D (zhe3)
8D6E (xia2)
8D6F (tang2)
8D70 (zou3)
8D71 (zou3)
8D72 (li4)
8D73 (jiu1,jiu3)
8D74 (fu4)
8D75 (zhao4)
8D76 (gan3)
8D77 (qi3)
8D78 (shan4)
8D79 (qiong2)
8D7A (qin2)
8D7B (xian3)
8D7C (ci1)
8D7D (jue2)
8D7E (qin3)
8D7F (chi2)
8D80 (ci1)
8D81 (chen4)
8D82 (chen4)
8D83 (die2)
8D84 (ju1,qie4,qie5,ju4)
8D85 (chao1)
8D86 (di1)
8D87 (se4)
8D88 (zhan1)
8D89 (zhu2)
8D8A (yue4)
8D8B (qu1)
8D8C (jie2)
8D8D (chi2)
8D8E (chu2)
8D8F (gua1)
8D90 (xue4)
8D91 (zi1)
8D92 (tiao2)
8D93 (duo3)
8D94 (lie4)
8D95 (gan3)
8D96 (suo1)
8D97 (cu4)
8D98 (xi2)
8D99 (zhao4)
8D9A (su4)
8D9B (yin3)
8D9C (ju2)
8D9D (jian4)
8D9E (que4)
8D9F (tang4,tang1)
8DA0 (chuo4)
8DA1 (cui3)
8DA2 (lu4)
8DA3 (qu4,cu4)
8DA4 (dang4)
8DA5 (qiu1)
8DA6 (zi1)
8DA7 (ti2)
8DA8 (qu1,cu4)
8DA9 (chi4)
8DAA (huang2)
8DAB (qiao2)
8DAC (qiao1)
8DAD (yao4)
8DAE (zao4)
8DAF (yue4)
8DB0 (none0)
8DB1 (zan3)
8DB2 (zan3,zan4)
8DB3 (zu2,ju4)
8DB4 (pa1)
8DB5 (bao4,bo1)
8DB6 (ku4)
8DB7 (he2)
8DB8 (dun3)
8DB9 (jue2)
8DBA (fu1)
8DBB (chen3)
8DBC (jian3)
8DBD (fang4)
8DBE (zhi3)
8DBF (ta1)
8DC0 (yue4)
8DC1 (pa2)
8DC2 (qi2)
8DC3 (yue4)
8DC4 (qiang1,qiang4)
8DC5 (tuo4)
8DC6 (tai2)
8DC7 (yi4)
8DC8 (nian3)
8DC9 (ling2)
8DCA (mei4)
8DCB (ba2)
8DCC (die1,die2)
8DCD (ku1)
8DCE (tuo2)
8DCF (jia1)
8DD0 (ci3)
8DD1 (pao3,pao2)
8DD2 (qia3)
8DD3 (zhu4)
8DD4 (ju1)
8DD5 (die2)
8DD6 (zhi2,zhi1)
8DD7 (fu1)
8DD8 (pan2)
8DD9 (ju3)
8DDA (shan1)
8DDB (bo3)
8DDC (ni2)
8DDD (ju4)
8DDE (li4,luo4)
8DDF (gen1)
8DE0 (yi2)
8DE1 (ji1)
8DE2 (dai4)
8DE3 (xian3)
8DE4 (jiao1)
8DE5 (duo4)
8DE6 (chu2)
8DE7 (quan2)
8DE8 (kua4)
8DE9 (zhuai3,shi4)
8DEA (gui4)
8DEB (qiong2)
8DEC (kui3)
8DED (xiang2)
8DEE (chi4)
8DEF (lu4)
8DF0 (beng4)
8DF1 (zhi4)
8DF2 (jia2)
8DF3 (tiao4)
8DF4 (cai3)
8DF5 (jian4)
8DF6 (da5)
8DF7 (qiao1)
8DF8 (bi4)
8DF9 (xian1)
8DFA (duo4)
8DFB (ji1)
8DFC (ju2)
8DFD (ji4)
8DFE (shu2)
8DFF (tu2)
8E00 (chu4)
8E01 (xing4)
8E02 (nie4)
8E03 (xiao1)
8E04 (bo2)
8E05 (xue2)
8E06 (qun1)
8E07 (mou3)
8E08 (shu1)
8E09 (liang4,liang2)
8E0A (yong3)
8E0B (jiao3,jia3,jue2)
8E0C (chou2)
8E0D (xiao4)
8E0E (none0)
8E0F (ta4,ta1)
8E10 (jian4)
8E11 (qi2)
8E12 (wo1)
8E13 (wei3)
8E14 (chuo1)
8E15 (jie2)
8E16 (ji2)
8E17 (nie1)
8E18 (ju2)
8E19 (ju1)
8E1A (lun2)
8E1B (lu4)
8E1C (leng4)
8E1D (huai2)
8E1E (ju4)
8E1F (chi2)
8E20 (wan4)
8E21 (quan2)
8E22 (ti1)
8E23 (bo2)
8E24 (zu2)
8E25 (qie4)
8E26 (qi1)
8E27 (cu4)
8E28 (zong1)
8E29 (cai3)
8E2A (zong1)
8E2B (pan2)
8E2C (zhi4)
8E2D (zheng1)
8E2E (dian3,die1)
8E2F (zhi2)
8E30 (yu2)
8E31 (duo2)
8E32 (dun4)
8E33 (chun3)
8E34 (yong3)
8E35 (zhong3)
8E36 (di4)
8E37 (zha3)
8E38 (chen3)
8E39 (chuai4)
8E3A (jian4)
8E3B (gua1)
8E3C (tang2)
8E3D (ju3)
8E3E (fu2)
8E3F (zu2)
8E40 (die2)
8E41 (pian2)
8E42 (rou2)
8E43 (nuo4)
8E44 (ti2)
8E45 (cha3)
8E46 (tui3)
8E47 (jian3)
8E48 (dao3)
8E49 (cuo1)
8E4A (xi1,qi1)
8E4B (ta4)
8E4C (qiang1,qiang4)
8E4D (zhan3)
8E4E (dian1)
8E4F (ti2)
8E50 (ji2)
8E51 (nie4)
8E52 (pan2)
8E53 (liu4)
8E54 (zhan4)
8E55 (bi4)
8E56 (chong1)
8E57 (lu4)
8E58 (liao2)
8E59 (cu4)
8E5A (tang1)
8E5B (dai4)
8E5C (su4)
8E5D (xi3)
8E5E (kui3)
8E5F (ji1)
8E60 (zhi2)
8E61 (qiang1)
8E62 (di2,zhi2)
8E63 (man2,pan2)
8E64 (zong1)
8E65 (lian2)
8E66 (beng4)
8E67 (zao1)
8E68 (nian3)
8E69 (bie2)
8E6A (tui2)
8E6B (ju2)
8E6C (deng4,deng1)
8E6D (ceng4)
8E6E (xian1)
8E6F (fan2)
8E70 (chu2)
8E71 (zhong1)
8E72 (dun1,cun2)
8E73 (bo1)
8E74 (cu4)
8E75 (zu2)
8E76 (jue2,jue3)
8E77 (jue2)
8E78 (lin2)
8E79 (ta4)
8E7A (qiao1)
8E7B (qiao1)
8E7C (pu3,pu2)
8E7D (liao1)
8E7E (dun1)
8E7F (cuan1)
8E80 (kuang4)
8E81 (zao4)
8E82 (ta4)
8E83 (bi4)
8E84 (bi4)
8E85 (zhu2)
8E86 (ju4)
8E87 (chu2)
8E88 (qiao4)
8E89 (dun3)
8E8A (chou2)
8E8B (ji1,ji4)
8E8C (wu3)
8E8D (yue4)
8E8E (nian3)
8E8F (lin4)
8E90 (lie4)
8E91 (zhi2)
8E92 (li4)
8E93 (zhi4)
8E94 (chan2)
8E95 (chu2)
8E96 (duan4)
8E97 (wei4)
8E98 (long2)
8E99 (lin4)
8E9A (xian1)
8E9B (wei4)
8E9C (zuan1)
8E9D (lan2)
8E9E (xie4)
8E9F (rang2)
8EA0 (xie4)
8EA1 (nie4)
8EA2 (ta4)
8EA3 (qu2)
8EA4 (jie4)
8EA5 (cuan1)
8EA6 (zuan1)
8EA7 (xi3)
8EA8 (kui2)
8EA9 (jue2)
8EAA (lin4)
8EAB (shen1,juan1)
8EAC (gong1)
8EAD (dan1)
8EAE (none0)
8EAF (qu1)
8EB0 (ti3)
8EB1 (duo3)
8EB2 (duo3)
8EB3 (gong1)
8EB4 (lang2)
8EB5 (none0)
8EB6 (luo3)
8EB7 (ai3)
8EB8 (ji1)
8EB9 (ju2)
8EBA (tang3)
8EBB (none0)
8EBC (none0)
8EBD (yan3)
8EBE (none0)
8EBF (kang1)
8EC0 (qu1)
8EC1 (lou2)
8EC2 (lao4)
8EC3 (duo3)
8EC4 (zhi2)
8EC5 (none0)
8EC6 (ti3)
8EC7 (dao4)
8EC8 (none0)
8EC9 (yu4)
8ECA (che1,ju1)
8ECB (ya4,zha2,ga2)
8ECC (gui3)
8ECD (jun1)
8ECE (wei4)
8ECF (yue4)
8ED0 (xin4)
8ED1 (di4)
8ED2 (xuan1)
8ED3 (fan4)
8ED4 (ren4)
8ED5 (shan1)
8ED6 (qiang2)
8ED7 (shu1)
8ED8 (tun2)
8ED9 (chen2)
8EDA (dai4)
8EDB (e4)
8EDC (na4)
8EDD (qi2)
8EDE (mao2)
8EDF (ruan3)
8EE0 (ren4)
8EE1 (qian2)
8EE2 (zhuan3,zhuai3,zhuan4)
8EE3 (hong1)
8EE4 (hu1)
8EE5 (qu2)
8EE6 (huang4)
8EE7 (di3)
8EE8 (ling2)
8EE9 (dai4)
8EEA (ao1)
8EEB (zhen3)
8EEC (fan4)
8EED (kuang1)
8EEE (ang3)
8EEF (peng1)
8EF0 (bei4)
8EF1 (gu1)
8EF2 (gu1)
8EF3 (pao2)
8EF4 (zhu4)
8EF5 (rong3,fu3)
8EF6 (e4)
8EF7 (ba2)
8EF8 (zhou2,zhou4,zhu2)
8EF9 (zhi3)
8EFA (yao2)
8EFB (ke1,ke3)
8EFC (yi4)
8EFD (qing1)
8EFE (shi4)
8EFF (ping2)
8F00 (er2)
8F01 (qiong2)
8F02 (ju2)
8F03 (jiao4,jiao3)
8F04 (guang1)
8F05 (lu4)
8F06 (kai3)
8F07 (quan2)
8F08 (zhou1)
8F09 (zai4,zai3)
8F0A (zhi4)
8F0B (ju1)
8F0C (liang4)
8F0D (yu4)
8F0E (shao1)
8F0F (you2)
8F10 (huan3)
8F11 (yun3)
8F12 (zhe2)
8F13 (wan3)
8F14 (fu3)
8F15 (qing1)
8F16 (zhou1)
8F17 (ni2)
8F18 (ling2)
8F19 (zhe2)
8F1A (zhan4)
8F1B (liang4)
8F1C (zi1)
8F1D (hui1)
8F1E (wang3)
8F1F (chuo4)
8F20 (guo3)
8F21 (kan3)
8F22 (yi3)
8F23 (peng2)
8F24 (qian4)
8F25 (gun3)
8F26 (nian3)
8F27 (ping2)
8F28 (guan3)
8F29 (bei4)
8F2A (lun2)
8F2B (pai2)
8F2C (liang2)
8F2D (ruan3)
8F2E (rou2)
8F2F (ji2)
8F30 (yang2)
8F31 (xian2)
8F32 (chuan2)
8F33 (cou4)
8F34 (chun1)
8F35 (ge2)
8F36 (you2)
8F37 (hong1)
8F38 (shu1)
8F39 (fu4)
8F3A (zi1)
8F3B (fu2)
8F3C (wen1)
8F3D (ben4)
8F3E (zhan3)
8F3F (yu2)
8F40 (wen1)
8F41 (tao1)
8F42 (gu3,gu1)
8F43 (zhen1)
8F44 (xia2)
8F45 (yuan2)
8F46 (lu4)
8F47 (jiu1)
8F48 (chao2)
8F49 (zhuan3,zhuai3,zhuan4)
8F4A (wei4)
8F4B (hun2)
8F4C (none0)
8F4D (che4,zhe2)
8F4E (jiao4)
8F4F (zhan4)
8F50 (pu2)
8F51 (lao3)
8F52 (fen2)
8F53 (fan1)
8F54 (lin2)
8F55 (ge2)
8F56 (se4)
8F57 (kan3)
8F58 (huan4)
8F59 (yi3)
8F5A (ji2)
8F5B (dui4)
8F5C (er2)
8F5D (yu2)
8F5E (xian4)
8F5F (hong1)
8F60 (lei2)
8F61 (pei4)
8F62 (li4)
8F63 (li4)
8F64 (lu2)
8F65 (lin2)
8F66 (che1,ju1)
8F67 (ya4,zha2,ga2)
8F68 (gui3)
8F69 (xuan1)
8F6A (dai4)
8F6B (ren4)
8F6C (zhuan3,zhuan4,zhuai3)
8F6D (e4)
8F6E (lun2)
8F6F (ruan3)
8F70 (hong1)
8F71 (gu1)
8F72 (ke1,ke3)
8F73 (lu2,lu5)
8F74 (zhou2,zhou4)
8F75 (zhi3)
8F76 (yi4)
8F77 (hu1)
8F78 (zhen3)
8F79 (li4)
8F7A (yao2)
8F7B (qing1)
8F7C (shi4)
8F7D (zai3,zai4)
8F7E (zhi4)
8F7F (jiao4)
8F80 (zhou1)
8F81 (quan2)
8F82 (lu4)
8F83 (jiao4)
8F84 (zhe2)
8F85 (fu3)
8F86 (liang4)
8F87 (nian3)
8F88 (bei4)
8F89 (hui1)
8F8A (gun3)
8F8B (wang3)
8F8C (liang2)
8F8D (chuo4)
8F8E (zi1)
8F8F (cou4)
8F90 (fu2)
8F91 (ji2,ji5)
8F92 (wen1)
8F93 (shu1)
8F94 (pei4)
8F95 (yuan2)
8F96 (xia2)
8F97 (zhan3)
8F98 (lu4)
8F99 (zhe2)
8F9A (lin2)
8F9B (xin1)
8F9C (gu1)
8F9D (ci2)
8F9E (ci2)
8F9F (pi4,bi4,pi1)
8FA0 (zui4)
8FA1 (bian4)
8FA2 (la4)
8FA3 (la4)
8FA4 (ci2)
8FA5 (xue1)
8FA6 (ban4)
8FA7 (bian4)
8FA8 (bian4)
8FA9 (bian4)
8FAA (none0)
8FAB (bian4)
8FAC (ban1)
8FAD (ci2)
8FAE (bian4)
8FAF (bian4)
8FB0 (chen2)
8FB1 (ru3,ru4)
8FB2 (nong2)
8FB3 (nong2)
8FB4 (zhen3)
8FB5 (chuo4)
8FB6 (chuo4)
8FB7 (none0)
8FB8 (reng2)
8FB9 (bian1,bian5)
8FBA (bian1)
8FBB (none0)
8FBC (none0)
8FBD (liao2)
8FBE (da2)
8FBF (chan1)
8FC0 (gan1)
8FC1 (qian1)
8FC2 (yu1)
8FC3 (yu1)
8FC4 (qi4)
8FC5 (xun4)
8FC6 (yi3,yi2)
8FC7 (guo4,guo1)
8FC8 (mai4)
8FC9 (qi2)
8FCA (za1)
8FCB (wang4)
8FCC (none0)
8FCD (zhun1)
8FCE (ying2)
8FCF (ti4)
8FD0 (yun4)
8FD1 (jin4)
8FD2 (hang2)
8FD3 (ya4)
8FD4 (fan3)
8FD5 (wu3)
8FD6 (ta4)
8FD7 (e2)
8FD8 (hai2,huan2)
8FD9 (zhei4,zhe4)
8FDA (none0)
8FDB (jin4)
8FDC (yuan3)
8FDD (wei2)
8FDE (lian2)
8FDF (chi2)
8FE0 (che4)
8FE1 (ni4)
8FE2 (tiao2)
8FE3 (zhi4)
8FE4 (yi3,yi2)
8FE5 (jiong3)
8FE6 (jia1)
8FE7 (chen2)
8FE8 (dai4)
8FE9 (er3)
8FEA (di2)
8FEB (po4,pai3)
8FEC (wang3)
8FED (die2)
8FEE (ze2)
8FEF (tao2)
8FF0 (shu4)
8FF1 (tuo2)
8FF2 (none0)
8FF3 (jing4)
8FF4 (hui2)
8FF5 (tong2)
8FF6 (you4)
8FF7 (mi2)
8FF8 (beng4)
8FF9 (ji1,ji4)
8FFA (nai3)
8FFB (yi2)
8FFC (jie2)
8FFD (zhui1)
8FFE (lie4)
8FFF (xun4)
9000 (tui4)
9001 (song4)
9002 (shi4,kuo4)
9003 (tao2)
9004 (pang2)
9005 (hou4)
9006 (ni4)
9007 (dun4)
9008 (jiong3)
9009 (xuan3)
900A (xun4)
900B (bu1)
900C (you2)
900D (xiao1)
900E (qiu2)
900F (tou4)
9010 (zhu2)
9011 (qiu2)
9012 (di4)
9013 (di4)
9014 (tu2)
9015 (jing4)
9016 (ti4)
9017 (dou4)
9018 (yi3)
9019 (zhe4,zhei4)
901A (tong1,tong4)
901B (guang4)
901C (wu4)
901D (shi4)
901E (cheng3)
901F (su4)
9020 (zao4)
9021 (qun1)
9022 (feng2)
9023 (lian2)
9024 (suo4)
9025 (hui2)
9026 (li3)
9027 (none0)
9028 (zui4)
9029 (ben1)
902A (cuo4)
902B (jue2)
902C (beng4)
902D (huan4)
902E (dai4,dai3)
902F (lu4)
9030 (you2)
9031 (zhou1)
9032 (jin4)
9033 (yu4)
9034 (chuo4)
9035 (kui2)
9036 (wei1)
9037 (ti4)
9038 (yi4)
9039 (da2)
903A (yuan3)
903B (luo2)
903C (bi1)
903D (nuo4)
903E (yu2)
903F (dang4)
9040 (sui2)
9041 (dun4)
9042 (sui4,sui2)
9043 (yan3)
9044 (chuan2)
9045 (chi2)
9046 (ti2)
9047 (yu4)
9048 (shi2)
9049 (zhen1)
904A (you2)
904B (yun4)
904C (e4)
904D (bian4,pian4)
904E (guo4,guo1)
904F (e4)
9050 (xia2)
9051 (huang2)
9052 (qiu2)
9053 (dao4)
9054 (da2)
9055 (wei2)
9056 (none0)
9057 (yi2,wei4)
9058 (gou4)
9059 (yao2)
905A (chu4)
905B (liu2,liu4)
905C (xun4)
905D (ta4)
905E (di4)
905F (chi2)
9060 (yuan3,yuan4)
9061 (su4)
9062 (ta4,ta1)
9063 (qian3)
9064 (none0)
9065 (yao2)
9066 (guan4)
9067 (zhang1)
9068 (ao2)
9069 (shi4,kuo4)
906A (ce4)
906B (su4)
906C (su4)
906D (zao1)
906E (zhe1,zhe5)
906F (dun4)
9070 (zhi4)
9071 (lou2)
9072 (chi2)
9073 (cuo1)
9074 (lin2)
9075 (zun1)
9076 (rao4)
9077 (qian1)
9078 (xuan3)
9079 (yu4)
907A (yi2,wei4)
907B (wu4)
907C (liao2)
907D (ju4)
907E (shi4)
907F (bi4)
9080 (yao1)
9081 (mai4)
9082 (xie4)
9083 (sui4)
9084 (huan2,hai2,xuan2)
9085 (zhan1)
9086 (deng4)
9087 (er3)
9088 (miao3)
9089 (bian1)
908A (bian1)
908B (la1)
908C (li2)
908D (yuan2)
908E (you2)
908F (luo2)
9090 (li3)
9091 (yi4)
9092 (ting2)
9093 (deng4)
9094 (qi3)
9095 (yong1)
9096 (shan1)
9097 (han2)
9098 (yu2)
9099 (mang2)
909A (ru2)
909B (qiong2)
909C (none0)
909D (kuang4)
909E (fu1)
909F (kang4)
90A0 (bin1)
90A1 (fang1)
90A2 (xing2)
90A3 (nei4,na4,na1,na3)
90A4 (none0)
90A5 (shen3)
90A6 (bang1)
90A7 (yuan2)
90A8 (cun1)
90A9 (huo3)
90AA (xie2,ye2)
90AB (bang1)
90AC (wu1)
90AD (ju4)
90AE (you2)
90AF (han2)
90B0 (tai2)
90B1 (qiu1)
90B2 (bi4)
90B3 (pi1)
90B4 (bing3)
90B5 (shao4)
90B6 (bei4)
90B7 (wa3)
90B8 (di3)
90B9 (zou1)
90BA (ye4)
90BB (lin2)
90BC (kuang1)
90BD (gui1)
90BE (zhu1)
90BF (shi1)
90C0 (ku1)
90C1 (yu4)
90C2 (gai1)
90C3 (he2)
90C4 (qie4)
90C5 (zhi4)
90C6 (ji2)
90C7 (xun2,huan2)
90C8 (hou4)
90C9 (xing2)
90CA (jiao1)
90CB (xi1)
90CC (gui1)
90CD (nuo2)
90CE (lang2,lang4)
90CF (jia2)
90D0 (kuai4)
90D1 (zheng4)
90D2 (lang2,lang4)
90D3 (yun4)
90D4 (yan2)
90D5 (cheng2)
90D6 (dou1)
90D7 (xi1)
90D8 (lu:3)
90D9 (fu3)
90DA (wu2)
90DB (fu2)
90DC (gao4)
90DD (hao3)
90DE (lang2)
90DF (jia2)
90E0 (geng3)
90E1 (jun4)
90E2 (ying3)
90E3 (bo2)
90E4 (xi4)
90E5 (bei4)
90E6 (li4)
90E7 (yun2)
90E8 (bu4)
90E9 (xiao2)
90EA (qi1)
90EB (pi2)
90EC (qing1)
90ED (guo1)
90EE (none0)
90EF (tan2)
90F0 (zou1)
90F1 (ping2)
90F2 (lai2)
90F3 (ni2)
90F4 (chen1)
90F5 (you2)
90F6 (bu4)
90F7 (xiang1)
90F8 (dan1)
90F9 (ju2)
90FA (yong1)
90FB (qiao1)
90FC (yi1)
90FD (dou1,du1)
90FE (yan3)
90FF (mei2)
9100 (ruo4)
9101 (bei4)
9102 (e4)
9103 (yu2)
9104 (juan4)
9105 (yu3)
9106 (yun4)
9107 (hou4)
9108 (kui2)
9109 (xiang1)
910A (xiang1)
910B (sou1)
910C (tang2)
910D (ming2)
910E (xi4)
910F (ru4)
9110 (chu4)
9111 (zi1)
9112 (zou1)
9113 (ju2)
9114 (wu1)
9115 (xiang1)
9116 (yun2)
9117 (hao4)
9118 (yong1)
9119 (bi3,bi4)
911A (mao4)
911B (chao2)
911C (fu1)
911D (liao3)
911E (yin2)
911F (zhuan1)
9120 (hu4)
9121 (qiao1)
9122 (yan1)
9123 (zhang1)
9124 (fan4)
9125 (wu3)
9126 (xu3)
9127 (deng4)
9128 (bi4)
9129 (xin2)
912A (bi4)
912B (ceng2)
912C (wei2)
912D (zheng4)
912E (mao4)
912F (shan4)
9130 (lin2)
9131 (po2)
9132 (dan1)
9133 (meng2)
9134 (ye4)
9135 (cao1)
9136 (kuai4)
9137 (feng1)
9138 (meng2)
9139 (zou1)
913A (kuang4)
913B (lian3)
913C (zan4)
913D (chan2)
913E (you1)
913F (qi2)
9140 (yan1)
9141 (chan2)
9142 (cuo2)
9143 (ling2)
9144 (huan1)
9145 (xi1)
9146 (feng1)
9147 (zan4)
9148 (li4)
9149 (you3)
914A (ding3,ding1)
914B (qiu2)
914C (zhuo2)
914D (pei4)
914E (zhou4)
914F (yi2,yi4,yi3)
9150 (gan1)
9151 (yu3)
9152 (jiu3)
9153 (yan3)
9154 (zui4)
9155 (mao2)
9156 (dan1,zhen4)
9157 (xu4)
9158 (tou2)
9159 (zhen1)
915A (fen1)
915B (none0)
915C (none0)
915D (yun4)
915E (tai4)
915F (tian1)
9160 (qia3)
9161 (tuo2)
9162 (zuo4,cu4)
9163 (han1)
9164 (gu1)
9165 (su1)
9166 (fa1,po1)
9167 (chou2)
9168 (dai4)
9169 (ming3,ming2)
916A (lao4,luo4)
916B (chuo4)
916C (chou2)
916D (you4)
916E (tong2)
916F (zhi3)
9170 (xian1)
9171 (jiang4)
9172 (cheng2)
9173 (yin4)
9174 (tu2)
9175 (jiao4,xiao4)
9176 (mei2)
9177 (ku4)
9178 (suan1)
9179 (lei4)
917A (pu2)
917B (zui4)
917C (hai3)
917D (yan4)
917E (shi1,shai1)
917F (niang4,nian4,niang2)
9180 (wei2)
9181 (lu4)
9182 (lan3)
9183 (yan1)
9184 (tao2)
9185 (pei1)
9186 (zhan3)
9187 (chun2)
9188 (tan2)
9189 (zui4)
918A (chuo4)
918B (cu4)
918C (kun1)
918D (ti2)
918E (xian2)
918F (du1)
9190 (hu2)
9191 (xu3)
9192 (xing3)
9193 (tan3)
9194 (qiu2)
9195 (chun2)
9196 (yun4)
9197 (fa1,po1)
9198 (ke1)
9199 (sou1)
919A (mi2)
919B (quan2)
919C (chou3)
919D (cuo2)
919E (yun4)
919F (yong4)
91A0 (ang4)
91A1 (zha4)
91A2 (hai3)
91A3 (tang2)
91A4 (jiang4)
91A5 (piao3)
91A6 (lao2)
91A7 (yu4)
91A8 (li2)
91A9 (zao2)
91AA (lao2)
91AB (yi1)
91AC (jiang4)
91AD (bu2)
91AE (jiao4)
91AF (xi1,xi4)
91B0 (tan2)
91B1 (fa1,po4)
91B2 (nong2)
91B3 (yi4)
91B4 (li3)
91B5 (ju4)
91B6 (yan4)
91B7 (yi4)
91B8 (niang4)
91B9 (ru2)
91BA (xun1)
91BB (chou2)
91BC (yan4)
91BD (ling2)
91BE (mi2)
91BF (mi2)
91C0 (niang4)
91C1 (xin4)
91C2 (jiao4)
91C3 (shi1)
91C4 (mi2)
91C5 (yan4)
91C6 (bian4)
91C7 (cai3,cai4)
91C8 (shi4)
91C9 (you4)
91CA (shi4)
91CB (shi4)
91CC (li3,li5)
91CD (zhong4,chong2)
91CE (ye3)
91CF (liang4,liang2,liang5)
91D0 (li2,xi1)
91D1 (jin1)
91D2 (jin1)
91D3 (ga2)
91D4 (yi3)
91D5 (liao3,liao4)
91D6 (dao1)
91D7 (zhao1)
91D8 (ding1,ding4)
91D9 (li4)
91DA (qiu2)
91DB (he2)
91DC (fu3)
91DD (zhen1)
91DE (zhi2)
91DF (ba1)
91E0 (luan4)
91E1 (fu3)
91E2 (nai3)
91E3 (diao4)
91E4 (shan4,shan1)
91E5 (qiao3)
91E6 (kou4)
91E7 (chuan4)
91E8 (zi3)
91E9 (fan2)
91EA (yu2)
91EB (hua2)
91EC (han4)
91ED (gong1,gang1)
91EE (qi2)
91EF (mang2)
91F0 (jian4)
91F1 (di4)
91F2 (si4)
91F3 (xi4)
91F4 (yi4)
91F5 (chai1)
91F6 (ta1,tuo2)
91F7 (tu3)
91F8 (xi4)
91F9 (nu:3)
91FA (qian1)
91FB (none0)
91FC (jian4)
91FD (pi1)
91FE (ye2)
91FF (yin2)
9200 (ba3,pa2)
9201 (fang1)
9202 (chen2)
9203 (jian1)
9204 (tou3)
9205 (yue4)
9206 (yan2)
9207 (fu1)
9208 (bu4)
9209 (na4)
920A (xin1)
920B (e2)
920C (jue2)
920D (dun4)
920E (gou1)
920F (yin3)
9210 (qian2)
9211 (ban3)
9212 (ji2)
9213 (ren2)
9214 (chao1)
9215 (niu3)
9216 (fen1)
9217 (yun3)
9218 (yi2)
9219 (qin2)
921A (pi2)
921B (guo1)
921C (hong2)
921D (yin2)
921E (jun1)
921F (shi1)
9220 (yi4)
9221 (zhong1)
9222 (nie1)
9223 (gai4)
9224 (ri4)
9225 (huo2,huo3)
9226 (tai4)
9227 (kang4)
9228 (none0)
9229 (lu2)
922A (none0)
922B (none0)
922C (duo2)
922D (zi1)
922E (ni2)
922F (tu2)
9230 (shi4)
9231 (min2)
9232 (gu1)
9233 (ke1)
9234 (ling2)
9235 (bing3)
9236 (yi2)
9237 (gu1,gu3)
9238 (ba2)
9239 (pi1,pi2)
923A (yu4)
923B (si4)
923C (zuo2)
923D (bu4,bu1)
923E (you2)
923F (dian4,tian2)
9240 (jia3)
9241 (zhen1)
9242 (shi3)
9243 (shi4)
9244 (tie3)
9245 (ju4)
9246 (zhan1)
9247 (ta1,tuo2)
9248 (she2,tuo2,ta1)
9249 (xuan4)
924A (zhao1)
924B (bao4)
924C (he2)
924D (bi4)
924E (sheng1)
924F (chu2)
9250 (shi2)
9251 (bo2)
9252 (zhu4)
9253 (chi4)
9254 (za1)
9255 (po3)
9256 (tong2)
9257 (qian2)
9258 (fu2)
9259 (zhai3)
925A (liu3,mao3)
925B (qian1,yan2)
925C (fu2)
925D (li4)
925E (yue4)
925F (pi1)
9260 (yang1)
9261 (ban4)
9262 (bo1)
9263 (jie2)
9264 (gou1)
9265 (shu4)
9266 (zheng1)
9267 (mu3)
9268 (ni2)
9269 (xi3)
926A (di4)
926B (jia1)
926C (mu4)
926D (tan3)
926E (shen1)
926F (yi3)
9270 (si1)
9271 (kuang4)
9272 (ka1)
9273 (bei3)
9274 (jian4)
9275 (tong2)
9276 (xing2)
9277 (hong2)
9278 (jiao3,jia3)
9279 (chi3)
927A (er3)
927B (ge4)
927C (bing3)
927D (shi4)
927E (mou2)
927F (jia2,ha1)
9280 (yin2)
9281 (jun1)
9282 (zhou1)
9283 (chong4)
9284 (shang4)
9285 (tong2)
9286 (mo4)
9287 (lei4)
9288 (ji1)
9289 (yu4)
928A (xu4)
928B (ren2)
928C (cun4)
928D (zhi4)
928E (qiong2)
928F (shan4)
9290 (chi4)
9291 (xian3,xi3)
9292 (xing2)
9293 (quan2)
9294 (pi1)
9295 (yi2)
9296 (zhu1)
9297 (hou2)
9298 (ming2)
9299 (kua3)
929A (yao2,diao4,tiao2)
929B (xian1)
929C (xian2)
929D (xiu1)
929E (jun1)
929F (cha1)
92A0 (lao3)
92A1 (ji2)
92A2 (yong3)
92A3 (ru2)
92A4 (mi3)
92A5 (yi1)
92A6 (yin1)
92A7 (guang1)
92A8 (an1,an3)
92A9 (diu1)
92AA (you3)
92AB (se4)
92AC (kao4)
92AD (qian2)
92AE (luan2)
92AF (none0)
92B0 (ai1)
92B1 (diao4)
92B2 (han4)
92B3 (rui4)
92B4 (shi4)
92B5 (keng1)
92B6 (qiu2)
92B7 (xiao1)
92B8 (zhe2)
92B9 (xiu4)
92BA (zang4)
92BB (ti4,ti1)
92BC (cuo4)
92BD (gua1)
92BE (gong3)
92BF (zhong1)
92C0 (dou4)
92C1 (lu:3)
92C2 (mei2)
92C3 (lang2)
92C4 (wan3)
92C5 (xin1)
92C6 (yun2)
92C7 (bei4)
92C8 (wu4)
92C9 (su4)
92CA (yu4)
92CB (chan2)
92CC (ting3,ding4)
92CD (bo2)
92CE (han4)
92CF (jia2)
92D0 (hong2)
92D1 (cuan1)
92D2 (feng1)
92D3 (chan1)
92D4 (wan3)
92D5 (zhi4)
92D6 (si1)
92D7 (xuan1)
92D8 (wu2)
92D9 (wu2)
92DA (tiao2)
92DB (gong3)
92DC (zhuo2)
92DD (lu:e4)
92DE (xing2)
92DF (qin3)
92E0 (shen4)
92E1 (han2)
92E2 (none0)
92E3 (ye2)
92E4 (chu2)
92E5 (zeng4)
92E6 (ju2,ju1)
92E7 (xian4)
92E8 (e2)
92E9 (mang2)
92EA (pu1,pu4)
92EB (li2)
92EC (shi4)
92ED (rui4)
92EE (cheng2)
92EF (gao4)
92F0 (li3)
92F1 (te4)
92F2 (none0)
92F3 (zhu4)
92F4 (none0)
92F5 (tu1)
92F6 (liu3)
92F7 (zui4)
92F8 (ju4,ju1)
92F9 (chang3)
92FA (yuan1)
92FB (jian4)
92FC (gang1,gang4)
92FD (diao4)
92FE (tao2)
92FF (chang2)
9300 (lun2)
9301 (guo3)
9302 (ling2)
9303 (bei1)
9304 (lu4)
9305 (li2)
9306 (qing1,qiang1)
9307 (pei2)
9308 (juan3)
9309 (min2)
930A (zui4)
930B (peng2)
930C (an4)
930D (pi2)
930E (xian4)
930F (ya4)
9310 (zhui1)
9311 (lei4)
9312 (a1,e1)
9313 (kong1)
9314 (ta4)
9315 (kun1)
9316 (du3)
9317 (wei4)
9318 (chui2)
9319 (zi1)
931A (zheng1,zheng4)
931B (ben1)
931C (nie4)
931D (cong2)
931E (chun2)
931F (tan2)
9320 (ding4)
9321 (qi2)
9322 (qian2)
9323 (zhuo2)
9324 (qi2)
9325 (yu4)
9326 (jin3)
9327 (guan3)
9328 (mao2)
9329 (chang1)
932A (dian3)
932B (xi2,xi1)
932C (lian4)
932D (tao2)
932E (gu4)
932F (cuo4,cu4)
9330 (shu4)
9331 (zhen1)
9332 (lu4)
9333 (meng3)
9334 (lu4)
9335 (hua1)
9336 (biao3)
9337 (ga2)
9338 (lai2)
9339 (ken3)
933A (zhui4)
933B (none0)
933C (nai4)
933D (wan3)
933E (zan4)
933F (none0)
9340 (de2)
9341 (xian1)
9342 (none0)
9343 (huo1)
9344 (liang4)
9345 (none0)
9346 (men2)
9347 (kai3)
9348 (ying1)
9349 (di1)
934A (lian4)
934B (guo1)
934C (xian3)
934D (du4)
934E (tu2)
934F (wei2)
9350 (cong1)
9351 (fu4)
9352 (rou2)
9353 (ji2)
9354 (e4)
9355 (rou3)
9356 (chen3)
9357 (ti2)
9358 (zha2)
9359 (hong4)
935A (yang2)
935B (duan4)
935C (xia1)
935D (yu2)
935E (keng1)
935F (xing1)
9360 (huang2)
9361 (wei3)
9362 (fu4)
9363 (zhao1)
9364 (cha2,cha1)
9365 (qie4)
9366 (she2)
9367 (hong1)
9368 (kui2)
9369 (nuo4)
936A (mou2)
936B (qiao1)
936C (qiao1)
936D (hou2)
936E (zhen1)
936F (huo1)
9370 (huan2)
9371 (ye4)
9372 (min2)
9373 (jian4)
9374 (duan3)
9375 (jian4)
9376 (si1)
9377 (kui1)
9378 (hu2)
9379 (xuan1)
937A (zang1,zhe3)
937B (jie2)
937C (zhen1)
937D (bian1)
937E (zhong1)
937F (zi1)
9380 (xiu1)
9381 (ye2)
9382 (mei3)
9383 (pai4)
9384 (ai1)
9385 (jie4)
9386 (none0)
9387 (mei2)
9388 (cha1)
9389 (ta4)
938A (bang4)
938B (xia2)
938C (lian2)
938D (suo3)
938E (xi4)
938F (liu2)
9390 (zu2)
9391 (ye4)
9392 (nou4)
9393 (weng1)
9394 (rong2)
9395 (tang2)
9396 (suo3)
9397 (qiang1)
9398 (ge2)
9399 (shuo4)
939A (chui2)
939B (bo2)
939C (pan2)
939D (ta3)
939E (bi4)
939F (sang3)
93A0 (gang1)
93A1 (zi1)
93A2 (wu1)
93A3 (ying4,ying2)
93A4 (huang3)
93A5 (tiao2)
93A6 (liu2,liu4)
93A7 (kai3)
93A8 (sun3)
93A9 (sha1)
93AA (sou1)
93AB (wan4)
93AC (hao4,gao3)
93AD (zhen4)
93AE (zhen4)
93AF (luo3)
93B0 (yi4)
93B1 (yuan2)
93B2 (tang3)
93B3 (nie4)
93B4 (xi2)
93B5 (jia1)
93B6 (ge1)
93B7 (ma3)
93B8 (juan1)
93B9 (rong2)
93BA (none0)
93BB (suo3)
93BC (none0)
93BD (none0)
93BE (none0)
93BF (na2)
93C0 (lu3)
93C1 (suo3)
93C2 (kou1)
93C3 (zu2,cu4)
93C4 (tuan2)
93C5 (xiu1)
93C6 (guan4)
93C7 (xuan4)
93C8 (lian4)
93C9 (shou4)
93CA (ao4)
93CB (man3)
93CC (mo4)
93CD (luo2)
93CE (bi4)
93CF (wei4)
93D0 (liu2)
93D1 (di2,di1)
93D2 (qiao1)
93D3 (huo1)
93D4 (yin2)
93D5 (lu4)
93D6 (ao2)
93D7 (keng1)
93D8 (qiang1)
93D9 (cui1)
93DA (qi4)
93DB (chang2)
93DC (tang1,tang2)
93DD (man4)
93DE (yong1)
93DF (chan3)
93E0 (feng1)
93E1 (jing4)
93E2 (biao1)
93E3 (shu4)
93E4 (lou4)
93E5 (xiu4)
93E6 (cong1)
93E7 (long2)
93E8 (zan4)
93E9 (jian4)
93EA (cao2)
93EB (li2)
93EC (xia4)
93ED (xi1)
93EE (kang1)
93EF (none0)
93F0 (beng4)
93F1 (none0)
93F2 (none0)
93F3 (zheng1)
93F4 (lu4)
93F5 (hua2)
93F6 (ji2)
93F7 (pu2)
93F8 (hui4)
93F9 (qiang1,qiang3)
93FA (po1)
93FB (lin2)
93FC (suo3)
93FD (xiu4)
93FE (san3)
93FF (cheng1)
9400 (kui4)
9401 (san3)
9402 (liu4,liu2)
9403 (nao2)
9404 (huang2)
9405 (pie3)
9406 (sui4)
9407 (fan2)
9408 (qiao2)
9409 (chuan1)
940A (yang2)
940B (tang4,tang1)
940C (xiang4)
940D (jue2)
940E (jiao1)
940F (zun1)
9410 (liao2,liao4)
9411 (jie2)
9412 (lao2)
9413 (dui4,dun1)
9414 (tan2,chan2,xin2)
9415 (zan1)
9416 (ji1)
9417 (jian3,jian4)
9418 (zhong1)
9419 (deng1,deng4)
941A (lou4,lue2)
941B (ying4)
941C (dui4)
941D (jue2)
941E (nou4)
941F (ti4)
9420 (pu3)
9421 (tie3)
9422 (none0)
9423 (none0)
9424 (ding3)
9425 (shan4)
9426 (kai1)
9427 (jian3,jian4)
9428 (fei4)
9429 (sui4)
942A (lu3)
942B (juan1)
942C (hui4)
942D (yu4)
942E (lian2)
942F (zhuo2)
9430 (qiao1)
9431 (qian1)
9432 (zhuo2)
9433 (lei2)
9434 (bi4)
9435 (tie3)
9436 (huan2)
9437 (ye4)
9438 (duo2)
9439 (guo3)
943A (dang1,cheng1)
943B (ju4)
943C (fen2)
943D (da2)
943E (bei4)
943F (yi4)
9440 (ai4)
9441 (dang1,zheng1)
9442 (xun4)
9443 (diao4,yao2)
9444 (zhu4)
9445 (heng2)
9446 (zhui4)
9447 (ji1)
9448 (nie1)
9449 (ta4)
944A (huo4)
944B (qing4)
944C (bin1)
944D (ying1)
944E (kui4)
944F (ning2)
9450 (xu1)
9451 (jian4)
9452 (jian4)
9453 (qiang1)
9454 (cha3)
9455 (zhi4)
9456 (mie4)
9457 (li2)
9458 (lei2)
9459 (ji1)
945A (zuan4,zuan1)
945B (kuang4)
945C (shang3)
945D (peng2)
945E (la4)
945F (du2)
9460 (shuo4)
9461 (chuo4)
9462 (lu:4)
9463 (biao1)
9464 (bao4)
9465 (lu3)
9466 (none0)
9467 (none0)
9468 (long2)
9469 (e4)
946A (lu2)
946B (xin1)
946C (jian4)
946D (lan4,lan2)
946E (bo2)
946F (jian1)
9470 (yao4,yue4)
9471 (chan2)
9472 (xiang1)
9473 (jian4)
9474 (xi4)
9475 (guan4)
9476 (cang2)
9477 (nie4)
9478 (lei3)
9479 (cuan1)
947A (qu2)
947B (pan4)
947C (luo2)
947D (zuan4,zuan1,zuan3)
947E (luan2)
947F (zao2,zuo4)
9480 (nie4)
9481 (jue2)
9482 (tang3)
9483 (shu3)
9484 (lan2)
9485 (jin1)
9486 (ga2)
9487 (yi3)
9488 (zhen1)
9489 (ding1,ding4)
948A (zhao1)
948B (po1)
948C (liao3,liao4)
948D (tu3)
948E (qian1)
948F (chuan4)
9490 (shan4,shan1)
9491 (sa4)
9492 (fan2)
9493 (diao4)
9494 (men2)
9495 (nu:3)
9496 (yang2)
9497 (chai1)
9498 (xing2)
9499 (gai4)
949A (bu4)
949B (tai4)
949C (ju4)
949D (dun4)
949E (chao1)
949F (zhong1)
94A0 (na4)
94A1 (bei4)
94A2 (gang1,gang4)
94A3 (ban3)
94A4 (qian2)
94A5 (yao4,yue4)
94A6 (qin1)
94A7 (jun1)
94A8 (wu1)
94A9 (gou1)
94AA (kang4)
94AB (fang1)
94AC (huo3)
94AD (tou3)
94AE (niu3)
94AF (ba3,pa2)
94B0 (yu4)
94B1 (qian2)
94B2 (zheng1,zheng4)
94B3 (qian2)
94B4 (gu3)
94B5 (bo1)
94B6 (ke1)
94B7 (po3)
94B8 (bu1)
94B9 (bo2)
94BA (yue4)
94BB (zuan4,zuan1)
94BC (mu4)
94BD (tan3)
94BE (jia3)
94BF (dian4,tian2)
94C0 (you2)
94C1 (tie3)
94C2 (bo2)
94C3 (ling2)
94C4 (shuo4)
94C5 (qian1,yan2)
94C6 (mao3)
94C7 (bao4)
94C8 (shi4)
94C9 (xuan4)
94CA (tuo2,she2,ta1)
94CB (bi4)
94CC (ni2)
94CD (pi2,pi1)
94CE (duo2)
94CF (xing2)
94D0 (kao4)
94D1 (lao3)
94D2 (er3)
94D3 (mang2)
94D4 (ya4)
94D5 (you3)
94D6 (cheng2)
94D7 (jia2)
94D8 (ye2)
94D9 (nao2)
94DA (zhi4)
94DB (dang1,cheng1)
94DC (tong2)
94DD (lu:3)
94DE (diao4)
94DF (yin1)
94E0 (kai3)
94E1 (zha2)
94E2 (zhu1)
94E3 (xian3,xi3)
94E4 (ting3,ding4)
94E5 (diu1)
94E6 (xian1)
94E7 (hua2)
94E8 (quan2)
94E9 (sha1)
94EA (ha1)
94EB (yao2,diao4,tiao2)
94EC (ge4)
94ED (ming2)
94EE (zheng1,zheng4)
94EF (se4)
94F0 (jiao3,jia3)
94F1 (yi1)
94F2 (chan3)
94F3 (chong4)
94F4 (tang1)
94F5 (an3)
94F6 (yin2)
94F7 (ru2)
94F8 (zhu4)
94F9 (lao2)
94FA (pu1,pu4)
94FB (wu2)
94FC (lai2)
94FD (te4)
94FE (lian4)
94FF (keng1)
9500 (xiao1)
9501 (suo3)
9502 (li3)
9503 (zeng4)
9504 (chu2)
9505 (guo1)
9506 (gao4)
9507 (e2)
9508 (xiu4)
9509 (cuo4)
950A (lu:e4)
950B (feng1)
950C (xin1)
950D (liu3)
950E (kai1)
950F (jian3,jian4)
9510 (rui4)
9511 (ti1)
9512 (lang2)
9513 (qin3)
9514 (ju1,ju2)
9515 (a1)
9516 (qing1,qiang1)
9517 (zhe3,zang1)
9518 (nuo4)
9519 (cuo4)
951A (mao2)
951B (ben1)
951C (qi2)
951D (de2)
951E (ke4)
951F (kun1)
9520 (chang1)
9521 (xi1)
9522 (gu4)
9523 (luo2)
9524 (chui2)
9525 (zhui1)
9526 (jin3)
9527 (zhi4)
9528 (xian1)
9529 (juan3)
952A (huo4,huo1)
952B (pei2)
952C (tan2)
952D (ding4)
952E (jian4)
952F (ju4,ju1)
9530 (meng3)
9531 (zi1)
9532 (qie4)
9533 (ying1)
9534 (kai3)
9535 (qiang1)
9536 (si1)
9537 (e4)
9538 (cha1)
9539 (qiao1)
953A (zhong1)
953B (duan4)
953C (sou1)
953D (huang2)
953E (huan2)
953F (ai1)
9540 (du4)
9541 (mei3)
9542 (lou4)
9543 (zi1)
9544 (fei4)
9545 (mei2)
9546 (mo4)
9547 (zhen4)
9548 (bo2)
9549 (ge2)
954A (nie4)
954B (tang3)
954C (juan1)
954D (nie4)
954E (na2)
954F (liu2,liu4)
9550 (hao4,gao3)
9551 (bang4)
9552 (yi4)
9553 (jia1)
9554 (bin1)
9555 (rong2)
9556 (biao1)
9557 (tang1,tang2)
9558 (man4)
9559 (luo2)
955A (beng4)
955B (yong1)
955C (jing4)
955D (di2,di1)
955E (zu2)
955F (xuan4)
9560 (liu2)
9561 (chan2,xin2,tan2)
9562 (jue2)
9563 (liao4)
9564 (pu2)
9565 (lu3)
9566 (dun1,dui4)
9567 (lan2)
9568 (pu3)
9569 (cuan1)
956A (qiang1,qiang3)
956B (deng4)
956C (huo4)
956D (lei2)
956E (huan2)
956F (zhuo2)
9570 (lian2)
9571 (yi4)
9572 (cha3)
9573 (biao1)
9574 (la4)
9575 (chan2)
9576 (xiang1)
9577 (chang2,zhang3)
9578 (chang2,zhang3)
9579 (jiu3)
957A (ao3)
957B (die2)
957C (qu1)
957D (liao2)
957E (mi2)
957F (zhang3,chang2)
9580 (men2)
9581 (ma4)
9582 (shuan1)
9583 (shan3)
9584 (huo2)
9585 (men2)
9586 (yan4,yan2)
9587 (bi4)
9588 (han4)
9589 (bi4)
958A (none0)
958B (kai1)
958C (kang4,kang1)
958D (beng1)
958E (hong2)
958F (run4)
9590 (san4)
9591 (xian2)
9592 (xian2)
9593 (jian1,jian4)
9594 (min3)
9595 (xia1)
9596 (min3)
9597 (dou4)
9598 (zha2)
9599 (nao4)
959A (none0)
959B (peng1)
959C (ke3)
959D (ling2)
959E (bian4)
959F (bi4)
95A0 (run4)
95A1 (he2)
95A2 (guan1)
95A3 (ge2)
95A4 (he2,ge2)
95A5 (fa2)
95A6 (chu4)
95A7 (hong4,hong1,hong3)
95A8 (gui1)
95A9 (min3)
95AA (none0)
95AB (kun3)
95AC (lang3,lang2,lang4)
95AD (lu:2)
95AE (ting2)
95AF (sha4)
95B0 (yan2)
95B1 (yue4)
95B2 (yue4)
95B3 (chan3)
95B4 (qu4)
95B5 (lin4)
95B6 (chang1)
95B7 (shai4)
95B8 (kun3)
95B9 (yan1)
95BA (min2,wen2)
95BB (yan2)
95BC (e4,yan1)
95BD (hun1)
95BE (yu4)
95BF (wen2)
95C0 (xiang4)
95C1 (none0)
95C2 (xiang4)
95C3 (qu4)
95C4 (yao3)
95C5 (wen2)
95C6 (ban3)
95C7 (an4)
95C8 (wei2)
95C9 (yin1)
95CA (kuo4)
95CB (que4)
95CC (lan2)
95CD (du1,she2)
95CE (none0)
95CF (none0)
95D0 (tian2)
95D1 (nie4)
95D2 (da2,ta4)
95D3 (kai3)
95D4 (he2)
95D5 (que4,que1)
95D6 (chuang3,chuang4)
95D7 (guan1)
95D8 (dou4,dou3)
95D9 (qi3)
95DA (kui1)
95DB (tang2)
95DC (guan1)
95DD (piao2)
95DE (kan4,han3,kan3)
95DF (xi1)
95E0 (hui4)
95E1 (chan3)
95E2 (pi4,bi4,pi1)
95E3 (dang4)
95E4 (huan2)
95E5 (ta4)
95E6 (wen2)
95E7 (none0)
95E8 (men2)
95E9 (shuan1)
95EA (shan3)
95EB (yan2)
95EC (han4)
95ED (bi4)
95EE (wen4)
95EF (chuang3)
95F0 (run4)
95F1 (wei2)
95F2 (xian2)
95F3 (hong2)
95F4 (jian1,jian4)
95F5 (min3)
95F6 (kang1,kang4)
95F7 (men4,men1)
95F8 (zha2)
95F9 (nao4)
95FA (gui1)
95FB (wen2)
95FC (ta4)
95FD (min3)
95FE (lu:2)
95FF (kai3)
9600 (fa2)
9601 (ge2)
9602 (he2)
9603 (kun3)
9604 (jiu1)
9605 (yue4)
9606 (lang2,lang4)
9607 (du1,she2)
9608 (yu4)
9609 (yan1)
960A (chang1)
960B (xi4)
960C (wen2)
960D (hun1)
960E (yan2)
960F (yan1,e4)
9610 (chan3)
9611 (lan2)
9612 (qu4)
9613 (hui4)
9614 (kuo4)
9615 (que4)
9616 (he2)
9617 (tian2)
9618 (da2,ta4)
9619 (que1,que4)
961A (kan4,han3,kan3)
961B (huan2)
961C (fu4)
961D (fu4,yi4)
961E (le4)
961F (dui4)
9620 (xin4,shen1)
9621 (qian1)
9622 (wu4)
9623 (yi4)
9624 (tuo2)
9625 (yin1)
9626 (yang2)
9627 (dou3)
9628 (e4)
9629 (sheng1)
962A (ban3)
962B (pei2)
962C (keng1)
962D (yun3)
962E (ruan3)
962F (zhi3)
9630 (pi2)
9631 (jing3)
9632 (fang2)
9633 (yang2)
9634 (yin1)
9635 (zhen4)
9636 (jie1)
9637 (cheng1)
9638 (e4)
9639 (qu1)
963A (di3)
963B (zu3)
963C (zuo4)
963D (dian4,yan2)
963E (ling3)
963F (a1,e1,a5,a2,a4)
9640 (tuo2)
9641 (tuo2)
9642 (po1,bei1,pi2)
9643 (bing3)
9644 (fu4)
9645 (ji4)
9646 (lu4,liu4)
9647 (long3)
9648 (chen2)
9649 (xing2)
964A (duo4)
964B (lou4)
964C (mo4)
964D (jiang4,xiang2)
964E (shu1)
964F (duo4)
9650 (xian4)
9651 (er2)
9652 (gui3)
9653 (wu1)
9654 (gai1)
9655 (shan3)
9656 (jun4)
9657 (qiao4)
9658 (xing2)
9659 (chun2)
965A (fu4)
965B (bi4)
965C (shan3)
965D (shan3,xia2)
965E (sheng1)
965F (zhi4)
9660 (pu1)
9661 (dou3)
9662 (yuan4)
9663 (zhen4)
9664 (chu2)
9665 (xian4)
9666 (zhi4)
9667 (nie4)
9668 (yun3)
9669 (xian3)
966A (pei2)
966B (pei2)
966C (zou1)
966D (yi1,yi3)
966E (dui4)
966F (lun2)
9670 (yin1)
9671 (ju2)
9672 (chui2)
9673 (chen2)
9674 (pi2)
9675 (ling2)
9676 (tao2,yao2)
9677 (xian4)
9678 (lu4,liu4)
9679 (none0)
967A (xian3)
967B (yin1)
967C (zhu3)
967D (yang2)
967E (reng2)
967F (shan3)
9680 (chong2)
9681 (yan4)
9682 (yin1)
9683 (yu2)
9684 (ti2)
9685 (yu2)
9686 (long2,long1)
9687 (wei1)
9688 (wei1)
9689 (nie4)
968A (dui4)
968B (sui2)
968C (an3)
968D (huang2)
968E (jie1)
968F (sui2)
9690 (yin3)
9691 (gai1)
9692 (yan3)
9693 (hui1)
9694 (ge2)
9695 (yun3)
9696 (wu4)
9697 (wei3,kui2)
9698 (ai4)
9699 (xi4)
969A (tang2)
969B (ji4)
969C (zhang4)
969D (dao3)
969E (ao2)
969F (xi4)
96A0 (yin3)
96A1 (sa4)
96A2 (rao4)
96A3 (lin2)
96A4 (tui2)
96A5 (deng4)
96A6 (pi2)
96A7 (sui4)
96A8 (sui2)
96A9 (yu4)
96AA (xian3)
96AB (fen1)
96AC (ni3)
96AD (er2)
96AE (ji1)
96AF (dao3)
96B0 (xi2)
96B1 (yin3,yin4)
96B2 (zhi4)
96B3 (hui1)
96B4 (long3)
96B5 (xi1)
96B6 (li4)
96B7 (li4)
96B8 (li4)
96B9 (zhui1,cui1)
96BA (he4)
96BB (zhi1)
96BC (sun3,zhun3)
96BD (juan4,jun4)
96BE (nan2,nan4)
96BF (yi4)
96C0 (que4,qiao1,qiao3)
96C1 (yan4)
96C2 (qin2)
96C3 (ya3)
96C4 (xiong2)
96C5 (ya3,ya1)
96C6 (ji2)
96C7 (gu4)
96C8 (huan2)
96C9 (zhi4)
96CA (gou4)
96CB (jun4,juan4)
96CC (ci2,ci1)
96CD (yong1)
96CE (ju1)
96CF (chu2)
96D0 (hu1)
96D1 (za2)
96D2 (luo4)
96D3 (yu2)
96D4 (chou2)
96D5 (diao1)
96D6 (sui1)
96D7 (han4)
96D8 (huo4)
96D9 (shuang1)
96DA (guan4)
96DB (chu2)
96DC (za2)
96DD (yong1)
96DE (ji1)
96DF (sui2)
96E0 (chou2)
96E1 (liu4)
96E2 (li2)
96E3 (nan2,nan4)
96E4 (xue2)
96E5 (za2)
96E6 (ji2)
96E7 (ji2)
96E8 (yu3,yu4)
96E9 (yu2)
96EA (xue3,xue4)
96EB (na3)
96EC (fou3)
96ED (se4)
96EE (mu4)
96EF (wen2)
96F0 (fen1)
96F1 (pang2)
96F2 (yun2)
96F3 (li4)
96F4 (li4)
96F5 (yang1)
96F6 (ling2)
96F7 (lei2)
96F8 (an2)
96F9 (bao2)
96FA (meng2)
96FB (dian4)
96FC (dang4)
96FD (hang2,yu2)
96FE (wu4)
96FF (zhao4)
9700 (xu1)
9701 (ji4)
9702 (mu4)
9703 (chen2)
9704 (xiao1)
9705 (zha2)
9706 (ting2)
9707 (zhen4)
9708 (pei4)
9709 (mei2)
970A (ling2)
970B (qi1)
970C (chou1)
970D (huo4)
970E (sha4)
970F (fei1)
9710 (weng1)
9711 (zhan1)
9712 (ying1)
9713 (ni2)
9714 (chou4)
9715 (tun2)
9716 (lin2)
9717 (none0)
9718 (dong4)
9719 (ying1,ji1)
971A (wu4)
971B (ling2)
971C (shuang1)
971D (ling2)
971E (xia2)
971F (hong2)
9720 (yin1)
9721 (mai4)
9722 (mo4)
9723 (yun3)
9724 (liu4)
9725 (meng4)
9726 (bin1)
9727 (wu4)
9728 (wei4)
9729 (kuo4)
972A (yin2)
972B (xi2)
972C (yi4)
972D (ai3)
972E (dan4)
972F (deng4)
9730 (xian4,san3)
9731 (yu4)
9732 (lu4,lou4)
9733 (long2,long1)
9734 (dai4)
9735 (ji2)
9736 (pang2)
9737 (yang2)
9738 (ba4)
9739 (pi1)
973A (wei2)
973B (none0)
973C (xi3)
973D (ji4)
973E (mai2)
973F (meng4)
9740 (meng2)
9741 (lei2)
9742 (li4)
9743 (huo4,sui3)
9744 (ai3)
9745 (fei4)
9746 (dai4)
9747 (long2)
9748 (ling2)
9749 (ai4)
974A (feng1)
974B (li4)
974C (bao3)
974D (none0)
974E (he4)
974F (he4)
9750 (bing4)
9751 (qing1)
9752 (qing1)
9753 (jing4,liang4)
9754 (qi2)
9755 (zhen1)
9756 (jing4)
9757 (cheng1)
9758 (qing4)
9759 (jing4)
975A (jing4,liang4)
975B (dian4)
975C (jing4)
975D (tian1)
975E (fei1)
975F (fei1)
9760 (kao4)
9761 (mi3,mi2)
9762 (mian4)
9763 (mian4)
9764 (pao4)
9765 (ye4)
9766 (tian3,mian3)
9767 (hui4)
9768 (ye4)
9769 (ge2,ji2,ji3)
976A (ding1)
976B (ren4)
976C (jian1)
976D (ren4)
976E (di2)
976F (du4)
9770 (wu4)
9771 (ren4)
9772 (qin2)
9773 (jin4)
9774 (xue1)
9775 (niu3)
9776 (ba3)
9777 (yin3)
9778 (sa3)
9779 (ren4)
977A (mo4)
977B (zu3)
977C (da2)
977D (ban4)
977E (yi4)
977F (yao4)
9780 (tao2)
9781 (bei4,tuo2)
9782 (jia2)
9783 (hong2)
9784 (pao2)
9785 (yang1,yang4,yang3)
9786 (mo4)
9787 (yin1)
9788 (jia2)
9789 (tao2)
978A (ji2)
978B (xie2)
978C (an1)
978D (an1)
978E (hen2)
978F (gong3)
9790 (gong3)
9791 (da2)
9792 (qiao2)
9793 (ting1)
9794 (man2,wan3)
9795 (ying4)
9796 (sui1)
9797 (tiao2)
9798 (qiao4,shao1)
9799 (xuan4)
979A (kong4)
979B (beng3)
979C (ta4)
979D (zhang3)
979E (bing3)
979F (kuo4)
97A0 (ju1,ju2)
97A1 (la5)
97A2 (xie4)
97A3 (rou2)
97A4 (bang1)
97A5 (yi4,eng1)
97A6 (qiu1)
97A7 (qiu1)
97A8 (he2)
97A9 (xiao4)
97AA (mu4)
97AB (ju1,ju2)
97AC (jian1)
97AD (bian1)
97AE (di1)
97AF (jian1)
97B0 (none0)
97B1 (tao1)
97B2 (gou1)
97B3 (ta4)
97B4 (bei4)
97B5 (xie2)
97B6 (pan2)
97B7 (ge2)
97B8 (bi4)
97B9 (kuo4,kui1)
97BA (tang1)
97BB (lou2)
97BC (gui4)
97BD (qiao2)
97BE (xue1)
97BF (ji1)
97C0 (jian1)
97C1 (jiang1)
97C2 (chan4)
97C3 (da2)
97C4 (huo4)
97C5 (xian3)
97C6 (qian1)
97C7 (du2)
97C8 (wa4)
97C9 (jian1)
97CA (lan2)
97CB (wei2)
97CC (ren4)
97CD (fu2)
97CE (mei4)
97CF (juan4)
97D0 (ge2)
97D1 (wei3)
97D2 (qiao4)
97D3 (han2)
97D4 (chang4)
97D5 (none0)
97D6 (rou2)
97D7 (xun4)
97D8 (she4)
97D9 (wei3)
97DA (ge2)
97DB (bei4)
97DC (tao1)
97DD (gou4)
97DE (yun4)
97DF (gao1)
97E0 (bi4)
97E1 (wei3)
97E2 (hui4)
97E3 (shu3)
97E4 (wa4)
97E5 (du2)
97E6 (wei2)
97E7 (ren4)
97E8 (fu2)
97E9 (han2)
97EA (wei3)
97EB (yun4)
97EC (tao1)
97ED (jiu3)
97EE (jiu3)
97EF (xian1)
97F0 (xie4)
97F1 (xian1)
97F2 (ji1)
97F3 (yin1)
97F4 (za2)
97F5 (yun4)
97F6 (shao2)
97F7 (luo4)
97F8 (peng2)
97F9 (huang2)
97FA (ying1)
97FB (yun4)
97FC (peng2)
97FD (yin1,an1)
97FE (yin1)
97FF (xiang3)
9800 (hu4)
9801 (ye4)
9802 (ding3)
9803 (qing3,qing1)
9804 (pan4)
9805 (xiang4)
9806 (shun4)
9807 (han1)
9808 (xu1)
9809 (yi2)
980A (xu1)
980B (gu4)
980C (song4)
980D (kui3)
980E (qi2)
980F (hang2)
9810 (yu4)
9811 (wan2)
9812 (ban1)
9813 (dun4,du2)
9814 (di2)
9815 (dan1)
9816 (pan4)
9817 (po3)
9818 (ling3)
9819 (cheng1)
981A (jing3,geng3)
981B (lei3)
981C (he2,han4)
981D (qiao1)
981E (e4)
981F (e2)
9820 (wei3)
9821 (jie2,xie2)
9822 (gua1)
9823 (shen3)
9824 (yi2)
9825 (yi2)
9826 (ke1,ke2)
9827 (dui1)
9828 (pian1)
9829 (ping1)
982A (lei4)
982B (fu3)
982C (jia2)
982D (tou2,tou5)
982E (hui4)
982F (kui2)
9830 (jia2)
9831 (le4)
9832 (ting3)
9833 (cheng1)
9834 (ying3)
9835 (jun1)
9836 (hu2)
9837 (han4)
9838 (jing3,geng3)
9839 (tui2)
983A (tui2)
983B (pin2)
983C (lai4)
983D (tui2)
983E (zi1)
983F (zi1)
9840 (chui2)
9841 (ding4)
9842 (lai4)
9843 (yan2)
9844 (han4)
9845 (qian1)
9846 (ke1)
9847 (cui4)
9848 (jiong3)
9849 (qin3)
984A (yi2)
984B (sai1)
984C (ti2)
984D (e2)
984E (e4)
984F (yan2)
9850 (hun2)
9851 (kan3)
9852 (yong2)
9853 (zhuan1)
9854 (yan2)
9855 (xian3)
9856 (xin4)
9857 (yi3)
9858 (yuan4)
9859 (sang3)
985A (dian1)
985B (dian1)
985C (jiang3)
985D (ku1)
985E (lei4)
985F (liao2)
9860 (piao4)
9861 (yi4)
9862 (man2,man1)
9863 (qi1)
9864 (yao2)
9865 (hao4)
9866 (qiao2)
9867 (gu4)
9868 (xun4)
9869 (qian1)
986A (hui1)
986B (zhan4,chan4)
986C (ru2)
986D (hong1)
986E (bin1)
986F (xian3)
9870 (pin2)
9871 (lu2)
9872 (lan3)
9873 (nie4)
9874 (quan2)
9875 (ye4)
9876 (ding3)
9877 (qing3)
9878 (han1)
9879 (xiang4)
987A (shun4)
987B (xu1)
987C (xu1)
987D (wan2)
987E (gu4)
987F (dun4,du2)
9880 (qi2)
9881 (ban1)
9882 (song4)
9883 (hang2)
9884 (yu4)
9885 (lu2)
9886 (ling3)
9887 (po1)
9888 (jing3,geng3)
9889 (jie2,xie2)
988A (jia2)
988B (ting3)
988C (he2,ge2)
988D (ying3)
988E (jiong3)
988F (ke1,ke2)
9890 (yi2)
9891 (pin2)
9892 (hui4)
9893 (tui2)
9894 (han4)
9895 (ying3)
9896 (ying3)
9897 (ke1)
9898 (ti2)
9899 (yong2)
989A (e4)
989B (zhuan1)
989C (yan2)
989D (e2)
989E (nie4)
989F (man1)
98A0 (dian1)
98A1 (sang3)
98A2 (hao4)
98A3 (lei4)
98A4 (zhan4,chan4)
98A5 (ru2)
98A6 (pin2)
98A7 (quan2)
98A8 (feng1)
98A9 (biao1)
98AA (none0)
98AB (fu2)
98AC (xia1)
98AD (zhan3)
98AE (biao1)
98AF (sa4)
98B0 (fa1)
98B1 (tai2)
98B2 (lie4)
98B3 (gua1)
98B4 (xuan4)
98B5 (shao4)
98B6 (ju4)
98B7 (biao1)
98B8 (si1)
98B9 (wei3)
98BA (yang2)
98BB (yao2)
98BC (sou1)
98BD (kai3)
98BE (sao1)
98BF (fan2)
98C0 (liu2)
98C1 (xi2)
98C2 (liao2)
98C3 (piao1)
98C4 (piao1)
98C5 (liu2)
98C6 (biao1)
98C7 (biao1)
98C8 (biao1)
98C9 (liao2)
98CA (none0)
98CB (se4)
98CC (feng1)
98CD (biao1)
98CE (feng1)
98CF (yang2)
98D0 (zhan3)
98D1 (biao1)
98D2 (sa4)
98D3 (ju4)
98D4 (si1)
98D5 (sou1)
98D6 (yao2)
98D7 (liu2)
98D8 (piao1)
98D9 (biao1)
98DA (biao1)
98DB (fei1)
98DC (fan1)
98DD (fei1)
98DE (fei1)
98DF (shi2,si4,yi4)
98E0 (shi2,si4)
98E1 (can1)
98E2 (ji1)
98E3 (ding4)
98E4 (si4)
98E5 (tuo2)
98E6 (jian1)
98E7 (sun1)
98E8 (xiang3)
98E9 (tun5,tun2)
98EA (ren4)
98EB (yu4)
98EC (juan4)
98ED (chi4)
98EE (yin3,yin4)
98EF (fan4)
98F0 (fan4)
98F1 (sun1)
98F2 (yin3,yin4)
98F3 (zhu4)
98F4 (yi2)
98F5 (zhai3)
98F6 (bi4)
98F7 (jie3)
98F8 (tao1)
98F9 (liu3)
98FA (ci2)
98FB (tie4)
98FC (si4)
98FD (bao3)
98FE (shi4)
98FF (duo4)
9900 (hai4)
9901 (ren4)
9902 (tian3)
9903 (jiao3,jia3)
9904 (jia2)
9905 (bing3)
9906 (yao2)
9907 (tong2)
9908 (ci2)
9909 (xiang3)
990A (yang3,yang4)
990B (yang3)
990C (er3)
990D (yan4)
990E (le5)
990F (yi1)
9910 (can1)
9911 (bo1)
9912 (nei3)
9913 (e4)
9914 (bu1)
9915 (jun4)
9916 (dou4)
9917 (su4)
9918 (yu2)
9919 (shi4)
991A (yao2)
991B (hun2)
991C (guo3)
991D (shi4)
991E (jian4)
991F (zhui4)
9920 (bing3)
9921 (xian4)
9922 (bu4)
9923 (ye4)
9924 (tan2)
9925 (fei3)
9926 (zhang1)
9927 (wei4)
9928 (guan3)
9929 (e4)
992A (nuan3)
992B (hun2)
992C (hu2,hu1,hu4)
992D (huang2)
992E (tie4)
992F (hui4)
9930 (jian1)
9931 (hou2)
9932 (he2)
9933 (xing2,tang2)
9934 (fen1)
9935 (wei4)
9936 (gu3)
9937 (cha1)
9938 (song4)
9939 (tang2,xing2)
993A (bo2)
993B (gao1)
993C (xi4)
993D (kui4)
993E (liu4,liu2)
993F (sou1)
9940 (tao2)
9941 (ye4)
9942 (yun2)
9943 (mo2)
9944 (tang2)
9945 (man2)
9946 (bi4)
9947 (yu4)
9948 (xiu1)
9949 (jin3)
994A (san3)
994B (kui4)
994C (zhuan4)
994D (shan4)
994E (chi4)
994F (dan4)
9950 (yi4)
9951 (ji1)
9952 (rao2)
9953 (cheng1)
9954 (yong1)
9955 (tao1)
9956 (hui4)
9957 (xiang3)
9958 (zhan1)
9959 (fen1)
995A (hai4)
995B (meng2)
995C (yan4)
995D (mo2)
995E (chan2)
995F (xiang3)
9960 (luo2)
9961 (zuan4,zan4)
9962 (nang3,nang2)
9963 (shi2,si4)
9964 (ding4)
9965 (ji1)
9966 (tuo1)
9967 (xing2,tang2)
9968 (tun5,tun2)
9969 (xi4)
996A (ren4)
996B (yu4)
996C (chi4)
996D (fan4)
996E (yin3,yin4)
996F (jian4)
9970 (shi4)
9971 (bao3)
9972 (si4)
9973 (duo4)
9974 (yi2)
9975 (er3)
9976 (rao2)
9977 (xiang3)
9978 (he2)
9979 (le5)
997A (jiao3,jia3)
997B (xi1)
997C (bing3)
997D (bo1)
997E (dou4)
997F (e4)
9980 (yu2)
9981 (nei3)
9982 (jun4)
9983 (guo3)
9984 (hun2)
9985 (xian4)
9986 (guan3)
9987 (cha1)
9988 (kui4)
9989 (gu3)
998A (sou1)
998B (chan2)
998C (ye4)
998D (mo2)
998E (bo2)
998F (liu4,liu2)
9990 (xiu1)
9991 (jin3)
9992 (man2)
9993 (san3)
9994 (zhuan4)
9995 (nang3,nang2)
9996 (shou3)
9997 (kui2)
9998 (guo2)
9999 (xiang1)
999A (fen2)
999B (ba2)
999C (ni3)
999D (bi4)
999E (bo2)
999F (tu2)
99A0 (han1)
99A1 (fei1)
99A2 (jian1)
99A3 (yan3)
99A4 (ai3)
99A5 (fu4)
99A6 (xian1)
99A7 (wen1)
99A8 (xin1,xing1)
99A9 (fen2)
99AA (bin1)
99AB (xing1)
99AC (ma3)
99AD (yu4)
99AE (feng2,ping2)
99AF (han4)
99B0 (di4)
99B1 (tuo2,duo4)
99B2 (tuo1)
99B3 (chi2)
99B4 (xun4,xun2)
99B5 (zhu4)
99B6 (zhi1)
99B7 (pei4)
99B8 (xin4)
99B9 (ri4)
99BA (sa4)
99BB (yin3)
99BC (wen2)
99BD (zhi2)
99BE (dan4)
99BF (lu:2)
99C0 (you2)
99C1 (bo2)
99C2 (bao3)
99C3 (kuai4)
99C4 (tuo2,duo4)
99C5 (yi4)
99C6 (qu1)
99C7 (wen2)
99C8 (qu1)
99C9 (jiong1)
99CA (bo3)
99CB (zhao1)
99CC (yuan1)
99CD (peng1)
99CE (zhou4)
99CF (ju4)
99D0 (zhu4)
99D1 (nu2)
99D2 (ju1)
99D3 (pi1)
99D4 (zang3)
99D5 (jia4)
99D6 (ling2)
99D7 (zhen1)
99D8 (tai2)
99D9 (fu4)
99DA (yang3)
99DB (shi3)
99DC (bi4)
99DD (tuo2)
99DE (tuo2)
99DF (si4)
99E0 (liu2)
99E1 (ma4)
99E2 (pian2)
99E3 (tao2)
99E4 (zhi4)
99E5 (rong2)
99E6 (teng2)
99E7 (dong4)
99E8 (xun2)
99E9 (quan2)
99EA (shen1)
99EB (jiong1)
99EC (er3)
99ED (hai4,xie4)
99EE (bo2)
99EF (none0)
99F0 (yin1)
99F1 (luo4)
99F2 (none0)
99F3 (dan4)
99F4 (xie4)
99F5 (liu2)
99F6 (ju2)
99F7 (song3)
99F8 (qin1)
99F9 (mang2)
99FA (liang2)
99FB (han4)
99FC (tu2)
99FD (xuan4)
99FE (tui4)
99FF (jun4)
9A00 (e2)
9A01 (cheng3)
9A02 (xing1)
9A03 (ai2)
9A04 (lu4)
9A05 (zhui1)
9A06 (zhou1)
9A07 (she4)
9A08 (pian2)
9A09 (kun1)
9A0A (tao2)
9A0B (lai2)
9A0C (zong1)
9A0D (ke4)
9A0E (qi2,ji4)
9A0F (qi2)
9A10 (yan4)
9A11 (fei1)
9A12 (sao1)
9A13 (yan4)
9A14 (jie2,ge3)
9A15 (yao3)
9A16 (wu4)
9A17 (pian4)
9A18 (cong1)
9A19 (pian4)
9A1A (qian2)
9A1B (fei1)
9A1C (huang2)
9A1D (jian1)
9A1E (huo4)
9A1F (yu4)
9A20 (ti2)
9A21 (quan2)
9A22 (xia2)
9A23 (zong1)
9A24 (kui2)
9A25 (rou2)
9A26 (si1)
9A27 (gua1)
9A28 (tuo2,tan2)
9A29 (kui4)
9A2A (sou1)
9A2B (qian1)
9A2C (cheng2)
9A2D (zhi4)
9A2E (liu2)
9A2F (pang2)
9A30 (teng2)
9A31 (xi1)
9A32 (cao3)
9A33 (du2)
9A34 (yan4)
9A35 (yuan2)
9A36 (zou1)
9A37 (sao1)
9A38 (shan4)
9A39 (li2)
9A3A (zhi4)
9A3B (shuang3)
9A3C (lu4)
9A3D (xi2)
9A3E (luo2)
9A3F (zhang1)
9A40 (mo4)
9A41 (ao4)
9A42 (can1)
9A43 (piao4,biao1)
9A44 (cong1)
9A45 (qu1)
9A46 (bi4)
9A47 (zhi4)
9A48 (yu4)
9A49 (xu1)
9A4A (hua2)
9A4B (bo1)
9A4C (su4)
9A4D (xiao1)
9A4E (lin2)
9A4F (zhan4)
9A50 (dun1)
9A51 (liu2)
9A52 (tuo2)
9A53 (zeng1)
9A54 (tan2)
9A55 (jiao1)
9A56 (tie3)
9A57 (yan4)
9A58 (luo2)
9A59 (zhan1)
9A5A (jing1)
9A5B (yi4)
9A5C (ye4)
9A5D (tuo4)
9A5E (bin1)
9A5F (zou4,zhou4)
9A60 (yan4)
9A61 (peng2)
9A62 (lu:2)
9A63 (teng2)
9A64 (xiang1)
9A65 (ji4)
9A66 (shuang1)
9A67 (ju2)
9A68 (xi1)
9A69 (huan1)
9A6A (li2)
9A6B (biao1)
9A6C (ma3)
9A6D (yu4)
9A6E (tuo2,duo4)
9A6F (xun4)
9A70 (chi2)
9A71 (qu1)
9A72 (ri4)
9A73 (bo2)
9A74 (lu:2)
9A75 (zang3)
9A76 (shi3)
9A77 (si4)
9A78 (fu4)
9A79 (ju1)
9A7A (zou1)
9A7B (zhu4)
9A7C (tuo2)
9A7D (nu2)
9A7E (jia4)
9A7F (yi4)
9A80 (tai2,dai4)
9A81 (xiao1)
9A82 (ma4)
9A83 (yin1)
9A84 (jiao1)
9A85 (hua2)
9A86 (luo4)
9A87 (hai4)
9A88 (pian2)
9A89 (biao1)
9A8A (li2)
9A8B (cheng3)
9A8C (yan4)
9A8D (xing1)
9A8E (qin1)
9A8F (jun4)
9A90 (qi2)
9A91 (qi2)
9A92 (ke4)
9A93 (zhui1)
9A94 (zong1)
9A95 (su4)
9A96 (can1)
9A97 (pian4)
9A98 (zhi4)
9A99 (kui2)
9A9A (sao1)
9A9B (wu4)
9A9C (ao4)
9A9D (liu2)
9A9E (qian1)
9A9F (shan4)
9AA0 (piao4,biao1)
9AA1 (luo2)
9AA2 (cong1)
9AA3 (zhan4,chan3)
9AA4 (zhou4)
9AA5 (ji4)
9AA6 (shuang1)
9AA7 (xiang1)
9AA8 (gu2,gu3,gu1)
9AA9 (wei3)
9AAA (wei3)
9AAB (wei3)
9AAC (yu2)
9AAD (gan4)
9AAE (yi4)
9AAF (ang1)
9AB0 (tou2,shai3)
9AB1 (jie4,xie4)
9AB2 (bo2)
9AB3 (bi4)
9AB4 (ci1)
9AB5 (ti3)
9AB6 (di3)
9AB7 (ku1)
9AB8 (hai2)
9AB9 (qiao1)
9ABA (hou2)
9ABB (kua4)
9ABC (ge2)
9ABD (tui3)
9ABE (geng3)
9ABF (pian2)
9AC0 (bi4)
9AC1 (ke1)
9AC2 (qia4)
9AC3 (yu2)
9AC4 (sui3)
9AC5 (lou2)
9AC6 (bo2)
9AC7 (xiao1)
9AC8 (bang3)
9AC9 (bo1)
9ACA (cuo1)
9ACB (kuan1)
9ACC (bin4)
9ACD (mo2)
9ACE (liao2)
9ACF (lou2)
9AD0 (nao2)
9AD1 (du2)
9AD2 (zang1)
9AD3 (sui3)
9AD4 (ti3)
9AD5 (bin4)
9AD6 (kuan1)
9AD7 (lu2)
9AD8 (gao1)
9AD9 (gao1)
9ADA (qiao4)
9ADB (kao1)
9ADC (qiao1)
9ADD (lao4)
9ADE (zao4)
9ADF (biao1,shan1)
9AE0 (kun1)
9AE1 (kun1)
9AE2 (ti4)
9AE3 (fang3)
9AE4 (xiu1)
9AE5 (ran2)
9AE6 (mao2)
9AE7 (dan4)
9AE8 (kun1)
9AE9 (bin4)
9AEA (fa4)
9AEB (tiao2)
9AEC (pi1)
9AED (zi1)
9AEE (fa4,fa3)
9AEF (ran2,ran3)
9AF0 (ti4)
9AF1 (pao4)
9AF2 (pi4)
9AF3 (mao2)
9AF4 (fu2,fo2)
9AF5 (er2)
9AF6 (rong2)
9AF7 (qu1)
9AF8 (none0)
9AF9 (xiu1)
9AFA (gua4)
9AFB (ji4)
9AFC (peng2)
9AFD (zhua1)
9AFE (shao1)
9AFF (sha1)
9B00 (ti4)
9B01 (li4)
9B02 (bin4)
9B03 (zong1)
9B04 (ti4)
9B05 (peng2)
9B06 (song1)
9B07 (zheng1)
9B08 (quan2,qian2)
9B09 (zong1)
9B0A (shun4)
9B0B (jian1)
9B0C (duo3)
9B0D (hu2)
9B0E (la4)
9B0F (jiu1)
9B10 (qi2)
9B11 (lian2)
9B12 (zhen3)
9B13 (bin4)
9B14 (peng2)
9B15 (mo4)
9B16 (san1)
9B17 (man2)
9B18 (man2)
9B19 (seng1)
9B1A (xu1)
9B1B (lie4)
9B1C (qian1)
9B1D (qian1)
9B1E (nong2)
9B1F (huan2)
9B20 (kuai4)
9B21 (ning2)
9B22 (bin4)
9B23 (lie4)
9B24 (rang2)
9B25 (dou4,dou3)
9B26 (dou4,dou3)
9B27 (nao4)
9B28 (hong4)
9B29 (xi4)
9B2A (dou4,dou3)
9B2B (kan4)
9B2C (dou4)
9B2D (dou4,dou3)
9B2E (jiu1)
9B2F (chang4)
9B30 (yu4)
9B31 (yu4)
9B32 (li4,ge2)
9B33 (juan4)
9B34 (fu3)
9B35 (qian2)
9B36 (gui1)
9B37 (zong1)
9B38 (liu4)
9B39 (gui1)
9B3A (shang1)
9B3B (yu4)
9B3C (gui3)
9B3D (mei4)
9B3E (ji4)
9B3F (qi2)
9B40 (jie4)
9B41 (kui2)
9B42 (hun2)
9B43 (ba2)
9B44 (po4,tuo4,bo2)
9B45 (mei4)
9B46 (xu1)
9B47 (yan3)
9B48 (xiao1)
9B49 (liang3)
9B4A (yu4)
9B4B (tui2)
9B4C (qi1)
9B4D (wang3)
9B4E (liang3)
9B4F (wei4)
9B50 (jian1)
9B51 (chi1)
9B52 (piao1)
9B53 (bi4)
9B54 (mo2)
9B55 (ji3)
9B56 (xu1)
9B57 (chou3)
9B58 (yan3)
9B59 (zhan3)
9B5A (yu2)
9B5B (dao1)
9B5C (ren2)
9B5D (ji4)
9B5E (ba1)
9B5F (hong1)
9B60 (tuo1)
9B61 (diao4)
9B62 (ji3)
9B63 (yu2)
9B64 (e2)
9B65 (que4)
9B66 (sha1)
9B67 (hang2)
9B68 (tun2)
9B69 (mo4)
9B6A (gai4)
9B6B (shen3)
9B6C (fan3)
9B6D (yuan2)
9B6E (pi2)
9B6F (lu3)
9B70 (wen2)
9B71 (hu2)
9B72 (lu2)
9B73 (za2)
9B74 (fang2)
9B75 (fen4)
9B76 (na4)
9B77 (you2)
9B78 (none0)
9B79 (none0)
9B7A (he2,ge3)
9B7B (xia2)
9B7C (qu1)
9B7D (han1)
9B7E (pi2)
9B7F (ling2)
9B80 (tuo2)
9B81 (ba4)
9B82 (qiu2)
9B83 (ping2)
9B84 (fu2)
9B85 (bi4)
9B86 (ji4)
9B87 (wei4)
9B88 (ju1)
9B89 (diao1)
9B8A (ba4)
9B8B (you2)
9B8C (gun3)
9B8D (pi2)
9B8E (nian2)
9B8F (xing1)
9B90 (tai2)
9B91 (bao4)
9B92 (fu4)
9B93 (zha3,zha4)
9B94 (ju4)
9B95 (gu1)
9B96 (none0)
9B97 (none0)
9B98 (none0)
9B99 (ta4)
9B9A (jie2)
9B9B (shua1)
9B9C (hou4)
9B9D (xiang3)
9B9E (er2)
9B9F (an4)
9BA0 (wei2)
9BA1 (tiao1)
9BA2 (zhu1)
9BA3 (yin4)
9BA4 (lie4)
9BA5 (luo4)
9BA6 (tong2)
9BA7 (yi2)
9BA8 (qi2)
9BA9 (bing4)
9BAA (wei3)
9BAB (jiao1)
9BAC (pu4)
9BAD (gui1,xie2)
9BAE (xian1,xian3)
9BAF (ge2)
9BB0 (hui2)
9BB1 (none0)
9BB2 (none0)
9BB3 (kao3)
9BB4 (none0)
9BB5 (duo2)
9BB6 (jun1)
9BB7 (ti2)
9BB8 (mian3)
9BB9 (shao1)
9BBA (za3)
9BBB (suo1)
9BBC (qin1)
9BBD (yu2)
9BBE (nei3)
9BBF (zhe2)
9BC0 (gun3)
9BC1 (geng3)
9BC2 (none0)
9BC3 (wu2)
9BC4 (qiu2)
9BC5 (ting2)
9BC6 (fu3)
9BC7 (huan4)
9BC8 (chou2)
9BC9 (li3)
9BCA (sha1)
9BCB (sha1)
9BCC (gao4)
9BCD (meng2)
9BCE (none0)
9BCF (none0)
9BD0 (none0)
9BD1 (none0)
9BD2 (yong3)
9BD3 (ni2)
9BD4 (zi1)
9BD5 (qi2)
9BD6 (qing1,zheng1)
9BD7 (xiang3)
9BD8 (nei3)
9BD9 (chun2)
9BDA (ji4)
9BDB (diao1)
9BDC (qie4)
9BDD (gu4)
9BDE (zhou3)
9BDF (dong1)
9BE0 (lai2)
9BE1 (fei1)
9BE2 (ni2)
9BE3 (yi4)
9BE4 (kun1)
9BE5 (lu4)
9BE6 (jiu4)
9BE7 (chang1)
9BE8 (jing1)
9BE9 (lun2)
9BEA (ling2)
9BEB (zou1)
9BEC (li2)
9BED (meng3)
9BEE (zong1)
9BEF (zhi2)
9BF0 (nian2,nian3)
9BF1 (none0)
9BF2 (none0)
9BF3 (none0)
9BF4 (shi1)
9BF5 (sao1)
9BF6 (hun3)
9BF7 (ti2)
9BF8 (hou2)
9BF9 (xing1)
9BFA (ju1)
9BFB (la4)
9BFC (zong1)
9BFD (ji4)
9BFE (bian1)
9BFF (bian1)
9C00 (huan4)
9C01 (quan2)
9C02 (ji4)
9C03 (wei1)
9C04 (wei1)
9C05 (yu2)
9C06 (chun1)
9C07 (rou2)
9C08 (die2)
9C09 (huang2)
9C0A (lian4)
9C0B (yan3)
9C0C (qiu1)
9C0D (qiu1)
9C0E (jian4)
9C0F (bi4)
9C10 (e4)
9C11 (yang2)
9C12 (fu4)
9C13 (sai1,xi3)
9C14 (jian3)
9C15 (ha2,xia1)
9C16 (tuo3)
9C17 (hu2)
9C18 (none0)
9C19 (ruo4)
9C1A (none0)
9C1B (wen1)
9C1C (jian1)
9C1D (hao4)
9C1E (wu1,wu4)
9C1F (pang2)
9C20 (sao1)
9C21 (liu2)
9C22 (ma3)
9C23 (shi2)
9C24 (shi1)
9C25 (guan1)
9C26 (zi1)
9C27 (teng2)
9C28 (ta4,ta3)
9C29 (yao2)
9C2A (ge2)
9C2B (rong2)
9C2C (qian2)
9C2D (qi2)
9C2E (wen1)
9C2F (ruo4)
9C30 (none0)
9C31 (lian2)
9C32 (ao2)
9C33 (le4)
9C34 (hui1)
9C35 (min3)
9C36 (ji4)
9C37 (tiao2)
9C38 (qu1)
9C39 (jian1)
9C3A (sao1)
9C3B (man2)
9C3C (xi2)
9C3D (qiu2)
9C3E (biao4)
9C3F (ji1)
9C40 (ji4)
9C41 (zhu2)
9C42 (jiang1)
9C43 (qiu1)
9C44 (zhuan1)
9C45 (yong1)
9C46 (zhang1)
9C47 (kang1)
9C48 (xue3)
9C49 (bie1)
9C4A (jue2)
9C4B (qu1)
9C4C (xiang4)
9C4D (bo1)
9C4E (jiao1)
9C4F (xun2)
9C50 (su4)
9C51 (huang2)
9C52 (zun1,zun4)
9C53 (shan4)
9C54 (shan4)
9C55 (fan1)
9C56 (gui4)
9C57 (lin2)
9C58 (xun2)
9C59 (miao2)
9C5A (xi3)
9C5B (none0)
9C5C (xiang1)
9C5D (fen4)
9C5E (guan1)
9C5F (hou4)
9C60 (kuai4)
9C61 (zei2)
9C62 (sao1)
9C63 (zhan1)
9C64 (gan3)
9C65 (gui4)
9C66 (sheng2)
9C67 (li3)
9C68 (chang2)
9C69 (none0)
9C6A (none0)
9C6B (ai4)
9C6C (ru2)
9C6D (ji4)
9C6E (xu4)
9C6F (huo4)
9C70 (none0)
9C71 (li4)
9C72 (lie4)
9C73 (li4)
9C74 (mie4)
9C75 (zhen1)
9C76 (xiang3)
9C77 (e4)
9C78 (lu2)
9C79 (guan4)
9C7A (li2)
9C7B (xian1)
9C7C (yu2)
9C7D (dao1)
9C7E (ji3)
9C7F (you2)
9C80 (tun2)
9C81 (lu3)
9C82 (fang2)
9C83 (ba1)
9C84 (ke3)
9C85 (ba4)
9C86 (ping2)
9C87 (nian2)
9C88 (lu2)
9C89 (you2)
9C8A (zha3)
9C8B (fu4)
9C8C (ba4,bo2)
9C8D (bao4)
9C8E (hou4)
9C8F (pi2)
9C90 (tai2)
9C91 (gui1,xie2)
9C92 (jie2)
9C93 (kao4)
9C94 (wei3)
9C95 (er2)
9C96 (tong2)
9C97 (zei2)
9C98 (hou4)
9C99 (kuai4)
9C9A (ji4)
9C9B (jiao1)
9C9C (xian1,xian3)
9C9D (zha3)
9C9E (xiang3)
9C9F (xun2)
9CA0 (geng3)
9CA1 (li2)
9CA2 (lian2)
9CA3 (jian1)
9CA4 (li3)
9CA5 (shi2)
9CA6 (tiao2)
9CA7 (gun3)
9CA8 (sha1)
9CA9 (huan4)
9CAA (jun1)
9CAB (ji4)
9CAC (yong3)
9CAD (qing1,zheng1)
9CAE (ling2)
9CAF (qi2)
9CB0 (zou1)
9CB1 (fei1)
9CB2 (kun1)
9CB3 (chang1)
9CB4 (gu4)
9CB5 (ni2)
9CB6 (nian2)
9CB7 (diao1)
9CB8 (jing1)
9CB9 (shen1)
9CBA (shi1)
9CBB (zi1)
9CBC (fen4)
9CBD (die2)
9CBE (bi1)
9CBF (chang2)
9CC0 (ti2)
9CC1 (wen1)
9CC2 (wei1)
9CC3 (sai1)
9CC4 (e4)
9CC5 (qiu1)
9CC6 (fu4)
9CC7 (huang2)
9CC8 (quan2)
9CC9 (jiang1)
9CCA (bian1)
9CCB (sao1)
9CCC (ao2)
9CCD (qi2)
9CCE (ta3)
9CCF (guan1)
9CD0 (yao2)
9CD1 (pang2)
9CD2 (jian1)
9CD3 (le4)
9CD4 (biao4)
9CD5 (xue3)
9CD6 (bie1)
9CD7 (man2)
9CD8 (min3)
9CD9 (yong1)
9CDA (wei4)
9CDB (xi2)
9CDC (gui4)
9CDD (shan4)
9CDE (lin2)
9CDF (zun1)
9CE0 (hu4)
9CE1 (gan3)
9CE2 (li3)
9CE3 (shan4)
9CE4 (guan3)
9CE5 (niao3)
9CE6 (yi3)
9CE7 (fu2)
9CE8 (li4)
9CE9 (jiu1)
9CEA (bu3)
9CEB (yan4)
9CEC (fu2)
9CED (diao1)
9CEE (ji1)
9CEF (feng4)
9CF0 (none0)
9CF1 (gan1)
9CF2 (shi1)
9CF3 (feng4)
9CF4 (ming2)
9CF5 (bao3)
9CF6 (yuan1)
9CF7 (zhi1)
9CF8 (hu4)
9CF9 (qian2)
9CFA (fu1)
9CFB (fen1)
9CFC (wen2)
9CFD (jian1)
9CFE (shi1)
9CFF (yu4)
9D00 (fou3)
9D01 (yiao1)
9D02 (ju2)
9D03 (jue2)
9D04 (pi1)
9D05 (huan1)
9D06 (zhen4)
9D07 (bao3)
9D08 (yan4)
9D09 (ya1)
9D0A (zheng4)
9D0B (fang1)
9D0C (feng4)
9D0D (wen2)
9D0E (ou1)
9D0F (te4)
9D10 (jia1)
9D11 (nu1)
9D12 (ling2)
9D13 (mie4)
9D14 (fu2)
9D15 (tuo2)
9D16 (wen2)
9D17 (li4)
9D18 (bian4)
9D19 (zhi4)
9D1A (ge1)
9D1B (yuan1)
9D1C (zi1)
9D1D (qu2)
9D1E (xiao1)
9D1F (chi1,zhi1)
9D20 (dan4)
9D21 (ju1)
9D22 (you4)
9D23 (gu1)
9D24 (zhong1)
9D25 (yu4)
9D26 (yang1)
9D27 (rong4)
9D28 (ya1)
9D29 (zhi4)
9D2A (yu4)
9D2B (none0)
9D2C (ying1)
9D2D (zhui1)
9D2E (wu1)
9D2F (er2)
9D30 (gua1)
9D31 (ai4)
9D32 (zhi1)
9D33 (yan4)
9D34 (heng2)
9D35 (jiao1)
9D36 (ji2)
9D37 (lie4)
9D38 (zhu1)
9D39 (ren2)
9D3A (ti2)
9D3B (hong2)
9D3C (luo4)
9D3D (ru2)
9D3E (mou2)
9D3F (ge1)
9D40 (ren4)
9D41 (jiao1)
9D42 (xiu1)
9D43 (zhou1)
9D44 (chi1)
9D45 (luo4)
9D46 (none0)
9D47 (none0)
9D48 (none0)
9D49 (luan2)
9D4A (jia2)
9D4B (ji4)
9D4C (yu2)
9D4D (huan1)
9D4E (tuo3)
9D4F (bu1)
9D50 (wu2)
9D51 (juan1)
9D52 (yu4)
9D53 (bo2)
9D54 (xun4)
9D55 (xun4)
9D56 (bi4)
9D57 (xi1)
9D58 (jun4)
9D59 (ju2)
9D5A (tu2,tu1)
9D5B (jing1)
9D5C (ti2,ti4)
9D5D (e2)
9D5E (e2)
9D5F (kuang2)
9D60 (hu2,gu3)
9D61 (wu3)
9D62 (shen1)
9D63 (la4)
9D64 (none0)
9D65 (none0)
9D66 (lu4)
9D67 (bing4)
9D68 (shu1)
9D69 (fu2)
9D6A (an1)
9D6B (zhao4)
9D6C (peng2)
9D6D (qin2)
9D6E (qian1)
9D6F (bei1)
9D70 (diao1)
9D71 (lu4)
9D72 (que4,qiao3)
9D73 (jian1)
9D74 (ju2)
9D75 (tu4)
9D76 (ya1)
9D77 (yuan1)
9D78 (qi2)
9D79 (li2)
9D7A (ye4)
9D7B (zhui1)
9D7C (kong1)
9D7D (duo4)
9D7E (kun1)
9D7F (sheng1)
9D80 (qi2)
9D81 (jing1)
9D82 (ni2)
9D83 (e4)
9D84 (jing1)
9D85 (zi1)
9D86 (lai2)
9D87 (dong1)
9D88 (qi1)
9D89 (chun2)
9D8A (geng1)
9D8B (ju1)
9D8C (qu1)
9D8D (none0)
9D8E (none0)
9D8F (ji1)
9D90 (shu4)
9D91 (none0)
9D92 (chi3)
9D93 (miao2)
9D94 (rou2)
9D95 (fu2)
9D96 (qiu1)
9D97 (ti2)
9D98 (hu2)
9D99 (ti2)
9D9A (e4)
9D9B (jie1)
9D9C (mao2)
9D9D (fu2)
9D9E (chun1)
9D9F (tu2)
9DA0 (yan3)
9DA1 (he2)
9DA2 (yuan2)
9DA3 (pian1,bin4)
9DA4 (yun4)
9DA5 (mei2)
9DA6 (hu2)
9DA7 (ying1)
9DA8 (dun4)
9DA9 (mu4,wu4)
9DAA (ju2)
9DAB (none0)
9DAC (cang1)
9DAD (fang3)
9DAE (ge4)
9DAF (ying1)
9DB0 (yuan2)
9DB1 (xuan1)
9DB2 (weng1)
9DB3 (shi1)
9DB4 (he4,hao2)
9DB5 (chu2)
9DB6 (tang2)
9DB7 (xia4)
9DB8 (ruo4)
9DB9 (liu2)
9DBA (ji2)
9DBB (gu3,hu2,gu2)
9DBC (jian1)
9DBD (zhun3)
9DBE (han4)
9DBF (zi1)
9DC0 (ci2)
9DC1 (yi4,ni4)
9DC2 (yao4)
9DC3 (yan4)
9DC4 (ji1)
9DC5 (li4,piao3)
9DC6 (tian2)
9DC7 (kou4)
9DC8 (ti1)
9DC9 (ti1)
9DCA (ni4)
9DCB (tu2)
9DCC (ma3)
9DCD (jiao1)
9DCE (liu2)
9DCF (zhen1)
9DD0 (chen2)
9DD1 (li4)
9DD2 (zhuan1)
9DD3 (zhe4)
9DD4 (ao2)
9DD5 (yao3)
9DD6 (yi1)
9DD7 (ou1)
9DD8 (chi4)
9DD9 (zhi4)
9DDA (liao2,liu4)
9DDB (rong2)
9DDC (lou2)
9DDD (bi4)
9DDE (shuang1)
9DDF (zhuo2)
9DE0 (yu2)
9DE1 (wu2)
9DE2 (jue2)
9DE3 (yin2)
9DE4 (tan2)
9DE5 (si1)
9DE6 (jiao1)
9DE7 (yi4)
9DE8 (hua1)
9DE9 (bi4)
9DEA (ying1)
9DEB (su4)
9DEC (huang2)
9DED (fan2)
9DEE (jiao1)
9DEF (liao2)
9DF0 (yan4)
9DF1 (kao1)
9DF2 (jiu4)
9DF3 (xian2)
9DF4 (xian2)
9DF5 (tu2)
9DF6 (mai3)
9DF7 (zun1)
9DF8 (yu4)
9DF9 (ying1)
9DFA (lu4)
9DFB (tuan2)
9DFC (xian2)
9DFD (xue2)
9DFE (yi4)
9DFF (pi4)
9E00 (shu2)
9E01 (luo2)
9E02 (qi1)
9E03 (yi2)
9E04 (ji1)
9E05 (zhe2)
9E06 (yu2)
9E07 (zhan1)
9E08 (ye4)
9E09 (yang2)
9E0A (pi4)
9E0B (ning2)
9E0C (hu4)
9E0D (mi2)
9E0E (ying1)
9E0F (meng2)
9E10 (di2)
9E11 (yue4)
9E12 (yu2)
9E13 (lei3)
9E14 (bo2)
9E15 (lu2)
9E16 (he4)
9E17 (long2)
9E18 (shuang1)
9E19 (yue4)
9E1A (ying1)
9E1B (guan4)
9E1C (qu2)
9E1D (li2)
9E1E (luan2)
9E1F (niao3,diao3)
9E20 (jiu1)
9E21 (ji1)
9E22 (yuan1)
9E23 (ming2)
9E24 (shi1)
9E25 (ou1)
9E26 (ya1)
9E27 (cang1)
9E28 (bao3)
9E29 (zhen4)
9E2A (gu1)
9E2B (dong1)
9E2C (lu2)
9E2D (ya1)
9E2E (xiao1)
9E2F (yang1)
9E30 (ling2)
9E31 (chi1)
9E32 (qu2)
9E33 (yuan1)
9E34 (xue2)
9E35 (tuo2)
9E36 (si1)
9E37 (zhi4)
9E38 (er2)
9E39 (gua1)
9E3A (xiu1)
9E3B (heng2)
9E3C (zhou1)
9E3D (ge1)
9E3E (luan2)
9E3F (hong2)
9E40 (wu2)
9E41 (bo2)
9E42 (li2)
9E43 (juan1)
9E44 (hu2,gu3)
9E45 (e2)
9E46 (yu4)
9E47 (xian2)
9E48 (ti2)
9E49 (wu3)
9E4A (que4)
9E4B (miao2)
9E4C (an1)
9E4D (kun1)
9E4E (bei1)
9E4F (peng2)
9E50 (qian1)
9E51 (chun2)
9E52 (geng1)
9E53 (yuan1)
9E54 (su4)
9E55 (hu2)
9E56 (he2)
9E57 (e4)
9E58 (gu3,hu2)
9E59 (qiu1)
9E5A (ci2)
9E5B (mei2)
9E5C (wu4)
9E5D (yi4)
9E5E (yao4)
9E5F (weng1)
9E60 (liu2)
9E61 (ji2)
9E62 (yi4)
9E63 (jian1)
9E64 (he4)
9E65 (yi1)
9E66 (ying1)
9E67 (zhe4)
9E68 (liu4)
9E69 (liao2)
9E6A (jiao1)
9E6B (jiu4)
9E6C (yu4)
9E6D (lu4)
9E6E (huan2)
9E6F (zhan1)
9E70 (ying1)
9E71 (hu4)
9E72 (meng2)
9E73 (guan4)
9E74 (shuang1)
9E75 (lu3)
9E76 (jin1)
9E77 (ling2)
9E78 (jian3)
9E79 (xian2)
9E7A (cuo2)
9E7B (jian3)
9E7C (jian3)
9E7D (yan2)
9E7E (cuo2)
9E7F (lu4)
9E80 (you1)
9E81 (cu1)
9E82 (ji3)
9E83 (biao1)
9E84 (cu1)
9E85 (pao2)
9E86 (zhu4)
9E87 (jun1,qun2)
9E88 (zhu3)
9E89 (jian1,qian1)
9E8A (mi2)
9E8B (mi2)
9E8C (wu2)
9E8D (liu2)
9E8E (chen2)
9E8F (jun1,qun2)
9E90 (lin2)
9E91 (ni2)
9E92 (qi2)
9E93 (lu4)
9E94 (jiu4)
9E95 (jun1,qun2)
9E96 (jing1)
9E97 (li4,li2)
9E98 (xiang1)
9E99 (yan2)
9E9A (jia1)
9E9B (mi2)
9E9C (li4)
9E9D (she4)
9E9E (zhang1)
9E9F (lin2)
9EA0 (jing1)
9EA1 (qi2)
9EA2 (ling2)
9EA3 (yan2)
9EA4 (cu1)
9EA5 (mai4)
9EA6 (mai4)
9EA7 (ge1)
9EA8 (chao3)
9EA9 (fu1)
9EAA (mian4)
9EAB (mian3)
9EAC (fu1)
9EAD (pao4)
9EAE (qu4)
9EAF (qu1,qu3)
9EB0 (mou2)
9EB1 (fu1)
9EB2 (xian4)
9EB3 (lai2)
9EB4 (qu1,qu2)
9EB5 (mian4)
9EB6 (chi1,li2)
9EB7 (feng1)
9EB8 (fu1)
9EB9 (qu1)
9EBA (mian4)
9EBB (ma2,ma1)
9EBC (ma2,me5,mo5)
9EBD (mo2,me5)
9EBE (hui1)
9EBF (none0)
9EC0 (zou1)
9EC1 (nen1)
9EC2 (fen2)
9EC3 (huang2)
9EC4 (huang2)
9EC5 (jin1)
9EC6 (guang1)
9EC7 (tian1)
9EC8 (tou3)
9EC9 (hong2)
9ECA (xi1)
9ECB (kuang4)
9ECC (hong2)
9ECD (shu3)
9ECE (li2)
9ECF (nian2)
9ED0 (chi1,li2)
9ED1 (hei1)
9ED2 (hei1)
9ED3 (yi4)
9ED4 (qian2)
9ED5 (zhen3)
9ED6 (xi4)
9ED7 (tuan3)
9ED8 (mo4)
9ED9 (mo4)
9EDA (qian2)
9EDB (dai4)
9EDC (chu4)
9EDD (you3)
9EDE (dian3)
9EDF (yi1)
9EE0 (xia2)
9EE1 (yan3)
9EE2 (qu1)
9EE3 (mei3)
9EE4 (yan3)
9EE5 (qing2,jing1)
9EE6 (yu4)
9EE7 (li2)
9EE8 (dang3)
9EE9 (du2)
9EEA (can3)
9EEB (yin1)
9EEC (an4)
9EED (yan3)
9EEE (tan2)
9EEF (an4)
9EF0 (zhen3)
9EF1 (dai4)
9EF2 (can3)
9EF3 (yi1)
9EF4 (mei2)
9EF5 (dan3)
9EF6 (yan3)
9EF7 (du2)
9EF8 (lu2)
9EF9 (zhi3)
9EFA (fen3)
9EFB (fu2)
9EFC (fu3)
9EFD (min3,mian3)
9EFE (min3,mian3)
9EFF (yuan2)
9F00 (cu4)
9F01 (qu4)
9F02 (chao2)
9F03 (wa1)
9F04 (zhu1)
9F05 (zhi1)
9F06 (mang2)
9F07 (ao2)
9F08 (bie1)
9F09 (tuo2)
9F0A (bi4)
9F0B (yuan2)
9F0C (chao2)
9F0D (tuo2)
9F0E (ding3)
9F0F (mi4)
9F10 (nai4)
9F11 (ding3)
9F12 (zi1)
9F13 (gu3,hu2)
9F14 (gu3)
9F15 (dong1)
9F16 (fen2)
9F17 (tao2)
9F18 (yuan1)
9F19 (pi2)
9F1A (chang1)
9F1B (gao1)
9F1C (qi4)
9F1D (yuan1)
9F1E (tang1)
9F1F (teng1)
9F20 (shu3)
9F21 (shu3)
9F22 (fen2)
9F23 (fei4)
9F24 (wen2)
9F25 (ba2)
9F26 (diao1)
9F27 (tuo2)
9F28 (tong2)
9F29 (qu2)
9F2A (sheng1)
9F2B (shi2)
9F2C (you4)
9F2D (shi2)
9F2E (ting2)
9F2F (wu2)
9F30 (nian4)
9F31 (jing1)
9F32 (hun2)
9F33 (ju2)
9F34 (yan3)
9F35 (tu2)
9F36 (si1)
9F37 (xi1)
9F38 (xian3)
9F39 (yan3)
9F3A (lei2)
9F3B (bi2)
9F3C (yao2)
9F3D (yan3,qui2)
9F3E (han1)
9F3F (hui1)
9F40 (wu4)
9F41 (hou1)
9F42 (xi4)
9F43 (ge2)
9F44 (zha1)
9F45 (xiu4)
9F46 (weng4)
9F47 (zha1)
9F48 (nong2)
9F49 (nang4)
9F4A (qi2,zhai1)
9F4B (zhai1)
9F4C (ji4)
9F4D (zi1,ji1)
9F4E (ji1)
9F4F (ji1)
9F50 (qi2,ji4,qi4)
9F51 (ji1)
9F52 (chi3)
9F53 (chen3)
9F54 (chen4)
9F55 (he2)
9F56 (ya2)
9F57 (ken3)
9F58 (xie4)
9F59 (bao1)
9F5A (ze2)
9F5B (shi4)
9F5C (zi1)
9F5D (chi1)
9F5E (nian4)
9F5F (ju3)
9F60 (tiao2)
9F61 (ling2)
9F62 (ling2)
9F63 (chu1)
9F64 (quan2)
9F65 (xie4)
9F66 (yin2,ken3)
9F67 (nie4)
9F68 (jiu4)
9F69 (nie4)
9F6A (chuo4)
9F6B (kun3)
9F6C (yu3)
9F6D (chu3)
9F6E (yi3)
9F6F (ni2)
9F70 (cuo4)
9F71 (chuo4)
9F72 (qu3)
9F73 (nian3)
9F74 (xian3)
9F75 (yu2)
9F76 (e4)
9F77 (wo4)
9F78 (yi4)
9F79 (chi1)
9F7A (zou1)
9F7B (dian1)
9F7C (chu3)
9F7D (jin4)
9F7E (ya4)
9F7F (chi3)
9F80 (chen4)
9F81 (he2)
9F82 (yin2)
9F83 (ju3)
9F84 (ling2)
9F85 (bao1)
9F86 (tiao2)
9F87 (zi1)
9F88 (yin2,ken3)
9F89 (yu3)
9F8A (chuo4)
9F8B (qu3)
9F8C (wo4)
9F8D (long2)
9F8E (pang2)
9F8F (gong1)
9F90 (pang2)
9F91 (yan3)
9F92 (long2)
9F93 (long2)
9F94 (gong1)
9F95 (kan1)
9F96 (ta4)
9F97 (ling2)
9F98 (ta4)
9F99 (long2)
9F9A (gong1)
9F9B (kan1)
9F9C (gui1,jun1,qiu1)
9F9D (qiu1)
9F9E (bie1)
9F9F (gui1,jun1,qiu1)
9FA0 (yue4)
9FA1 (chui1)
9FA2 (he2)
9FA3 (jue2)
9FA4 (xie2)
9FA5 (yue4)
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCAttributedLabel.h
================================================
//
// RCAttributedLabel.h
// iOS-IMKit
//
// Created by YangZigang on 14/10/29.
// Copyright (c) 2014年 RongCloud. All rights reserved.
//
#import
/**
* RCAttributedLabelClickedTextInfo
*/
@interface RCAttributedLabelClickedTextInfo : NSObject
/**
* NSTextCheckingType
*/
@property(nonatomic, assign) NSTextCheckingType textCheckingType;
/**
* text
*/
@property(nonatomic, strong) NSString *text;
@end
/**
* RCAttributedDataSource
*/
@protocol RCAttributedDataSource
/**
* attributeDictionaryForTextType
*
* @param textType textType
*
* @return return NSDictionary
*/
- (NSDictionary *)attributeDictionaryForTextType:(NSTextCheckingTypes)textType;
/**
* highlightedAttributeDictionaryForTextType
*
* @param textType textType
*
* @return NSDictionary
*/
- (NSDictionary *)highlightedAttributeDictionaryForTextType:(NSTextCheckingType)textType;
@end
@protocol RCAttributedLabelDelegate;
/**
* Override UILabel @property to accept both NSString and NSAttributedString
*/
@protocol RCAttributedLabel
/**
* text
*/
@property (nonatomic, copy) id text;
@end
/**
* RCAttributedLabel
*/
@interface RCAttributedLabel : UILabel
/**
* 可以通过设置attributeDataSource或者attributeDictionary、highlightedAttributeDictionary来自定义不同文本的字体颜色
*/
@property(nonatomic, strong) id attributeDataSource;
/**
* 可以通过设置attributedStrings可以给一些字符添加点击事件等,例如在实现的会话列表里修改文本消息内容
* -(void)willDisplayConversationTableCell:(RCMessageBaseCell *)cell atIndexPath:(NSIndexPath *)indexPath{
*
* if ([cell isKindOfClass:[RCTextMessageCell class]]) {
* RCTextMessageCell *newCell = (RCTextMessageCell *)cell;
* if (newCell.textLabel.text.length>3) {
* NSTextCheckingResult *textCheckingResult = [NSTextCheckingResult linkCheckingResultWithRange:(NSMakeRange(0, 3)) URL:[NSURL URLWithString:@"http://www.baidu.com"]];
* [newCell.textLabel.attributedStrings addObject:textCheckingResult];
* [newCell.textLabel setTextHighlighted:YES atPoint:CGPointMake(0, 3)];
* }
* }
*}
*
*/
@property(nonatomic, strong) NSMutableArray *attributedStrings;
/*!
点击回调
*/
@property (nonatomic, assign) id delegate;
/**
* attributeDictionary
*/
@property(nonatomic, strong) NSDictionary *attributeDictionary;
/**
* highlightedAttributeDictionary
*/
@property(nonatomic, strong) NSDictionary *highlightedAttributeDictionary;
/**
* NSTextCheckingTypes 格式类型
*/
@property(nonatomic, assign) NSTextCheckingTypes textCheckingTypes;
/**
* NSTextCheckingTypes current格式类型
*/
@property(nonatomic, readonly, assign) NSTextCheckingType currentTextCheckingType;
/**
* setTextdataDetectorEnabled
*
* @param text text
* @param dataDetectorEnabled dataDetectorEnabled
*/
- (void)setText:(NSString *)text dataDetectorEnabled:(BOOL)dataDetectorEnabled;
/**
* textInfoAtPoint
*
* @param point point
*
* @return RCAttributedLabelClickedTextInfo
*/
- (RCAttributedLabelClickedTextInfo *)textInfoAtPoint:(CGPoint)point;
/**
* setTextHighlighted
*
* @param highlighted highlighted
* @param point point
*/
- (void)setTextHighlighted:(BOOL)highlighted atPoint:(CGPoint)point;
@end
/*!
RCAttributedLabel点击回调
*/
@protocol RCAttributedLabelDelegate
@optional
/*!
点击URL的回调
@param label 当前Label
@param url 点击的URL
*/
- (void)attributedLabel:(RCAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url;
/*!
点击电话号码的回调
@param label 当前Label
@param phoneNumber 点击的URL
*/
- (void)attributedLabel:(RCAttributedLabel *)label didSelectLinkWithPhoneNumber:(NSString *)phoneNumber;
/*!
点击Label的回调
@param label 当前Label
@param content 点击的内容
*/
- (void)attributedLabel:(RCAttributedLabel *)label didTapLabel:(NSString *)content;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCBaseViewController.h
================================================
//
// RCBaseViewController.h
// RongIMKit
//
// Created by xugang on 15/1/22.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCBaseViewController
#define __RCBaseViewController
#import
#import
/*!
IMKit ViewController基类
@discussion 主要定义了View的默认大小。
*/
@interface RCBaseViewController : UIViewController
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCChatSessionInputBarControl.h
================================================
//
// RCChatSessionInputBarControl.h
// RongIMKit
//
// Created by xugang on 15/2/12.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCChatSessionInputBarControl
#define __RCChatSessionInputBarControl
#import
#import
#import "RCTextView.h"
#define Height_ChatSessionInputBar 50.0f
/*!
输入工具栏的显示布局
*/
typedef NS_ENUM(NSInteger, RCChatSessionInputBarControlStyle) {
/*!
切换-输入框-扩展
*/
RC_CHAT_INPUT_BAR_STYLE_SWITCH_CONTAINER_EXTENTION = 0,
/*!
扩展-输入框-切换
*/
RC_CHAT_INPUT_BAR_STYLE_EXTENTION_CONTAINER_SWITCH = 1,
/*!
输入框-切换-扩展
*/
RC_CHAT_INPUT_BAR_STYLE_CONTAINER_SWITCH_EXTENTION = 2,
/*!
输入框-扩展-切换
*/
RC_CHAT_INPUT_BAR_STYLE_CONTAINER_EXTENTION_SWITCH = 3,
/*!
切换-输入框
*/
RC_CHAT_INPUT_BAR_STYLE_SWITCH_CONTAINER = 4,
/*!
输入框-切换
*/
RC_CHAT_INPUT_BAR_STYLE_CONTAINER_SWITCH = 5,
/*!
扩展-输入框
*/
RC_CHAT_INPUT_BAR_STYLE_EXTENTION_CONTAINER = 6,
/*!
输入框-扩展
*/
RC_CHAT_INPUT_BAR_STYLE_CONTAINER_EXTENTION = 7,
/*!
输入框
*/
RC_CHAT_INPUT_BAR_STYLE_CONTAINER = 8,
};
/*!
输入工具栏的菜单类型
*/
typedef NS_ENUM(NSInteger, RCChatSessionInputBarControlType) {
/*!
默认类型,非公众服务
*/
RCChatSessionInputBarControlDefaultType = 0,
/*!
公众服务
*/
RCChatSessionInputBarControlPubType = 1
};
/*!
输入工具栏的输入模式
*/
typedef NS_ENUM(NSInteger, RCChatSessionInputBarInputType) {
/*!
文本输入模式
*/
RCChatSessionInputBarInputText = 0,
/*!
语音输入模式
*/
RCChatSessionInputBarInputVoice = 1,
/*!
扩展输入模式
*/
RCChatSessionInputBarInputExtention = 2
};
/*!
输入工具栏的输入模式
*/
typedef NS_ENUM(NSInteger, KBottomBarStatus) {
/*!
初始状态
*/
KBottomBarDefaultStatus = 0,
/*!
文本输入状态
*/
KBottomBarKeyboardStatus,
/*!
功能板输入模式
*/
KBottomBarPluginStatus,
/*!
表情输入模式
*/
KBottomBarEmojiStatus,
/*!
语音消息输入模式
*/
KBottomBarRecordStatus
};
/*!
输入工具栏的点击监听器
*/
@protocol RCChatSessionInputBarControlDelegate;
/*!
输入工具栏
*/
@interface RCChatSessionInputBarControl : UIView
/*!
输入工具栏的点击回调监听
*/
@property(weak, nonatomic) id delegate;
/*!
公众服务菜单的容器View
*/
@property(weak, nonatomic) UIView *clientView;
/*!
公众服务菜单切换的按钮
*/
@property(strong, nonatomic) UIButton *pubSwitchButton;
/*!
容器View
*/
@property(strong, nonatomic) UIView *inputContainerView;
/*!
公众服务菜单的容器View
*/
@property(strong, nonatomic) UIView *menuContainerView;
/*!
语音与文本输入切换的按钮
*/
@property(strong, nonatomic) UIButton *switchButton;
/*!
录制语音消息的按钮
*/
@property(strong, nonatomic) UIButton *recordButton;
/*!
文本输入框
*/
@property(strong, nonatomic) RCTextView *inputTextView;
/*!
表情的按钮
*/
@property(strong, nonatomic) UIButton *emojiButton;
/*!
扩展输入的按钮
*/
@property(strong, nonatomic) UIButton *additionalButton;
/*!
所处的聊天界面View
*/
@property(assign, nonatomic, readonly) UIView *contextView;
/*!
Frame 起点X坐标
*/
@property(assign, nonatomic) float currentPositionY;
/*!
Frame 起点Y坐标
*/
@property(assign, nonatomic) float originalPositionY;
/*!
文本输入框的高度
*/
@property(assign, nonatomic) float inputTextview_height;
/*!
公众服务账号菜单
*/
@property(strong, nonatomic) RCPublicServiceMenu *publicServiceMenu;
/*!
初始化输入工具栏
@param frame 显示的Frame
@param contextView 所处的聊天界面View
@param type 菜单类型
@param style 显示布局
@return 输入工具栏对象
*/
- (id)initWithFrame:(CGRect)frame
withContextView:(UIView *)contextView
type:(RCChatSessionInputBarControlType)type
style:(RCChatSessionInputBarControlStyle)style;
/*!
设置输入工具栏的样式
@param type 菜单类型
@param style 显示布局
@discussion 您可以在聊天界面RCConversationViewController的viewDidLoad之后设置,改变输入工具栏的样式。
*/
- (void)setInputBarType:(RCChatSessionInputBarControlType)type style:(RCChatSessionInputBarControlStyle)style;
/**
* dismiss公众账号弹出菜单
*/
- (void)dismissPublicServiceMenuPopupView;
@end
/*!
输入工具栏的点击监听器
*/
@protocol RCChatSessionInputBarControlDelegate
@optional
/*!
键盘积即将显示的回调
@param keyboardFrame 键盘最终需要显示的Frame
*/
- (void)keyboardWillShowWithFrame:(CGRect)keyboardFrame;
/*!
键盘即将隐藏的回调
*/
- (void)keyboardWillHide;
/*!
输入工具栏尺寸(高度)发生变化的回调
@param frame 输入工具栏最终需要显示的Frame
*/
- (void)chatSessionInputBarControlContentSizeChanged:(CGRect)frame;
/*!
点击键盘Return按钮的回调
@param inputControl 当前输入工具栏
@param text 当前输入框中国的文本内容
*/
- (void)didTouchKeyboardReturnKey:(RCChatSessionInputBarControl *)inputControl text:(NSString *)text;
/*!
点击表情按钮的回调
@param sender 表情按钮
*/
- (void)didTouchEmojiButton:(UIButton *)sender;
/*!
点击扩展输入按钮的回调
@param sender 扩展输入的按钮
*/
- (void)didTouchAddtionalButton:(UIButton *)sender;
/*!
输入模式发生变化的回调
@param switched 文本输入框最终是否隐藏
*/
- (void)didTouchSwitchButton:(BOOL)switched;
/*!
点击公众服务的菜单切换按钮的回调
@param switched 文本输入框最终是否隐藏
*/
- (void)didTouchPubSwitchButton:(BOOL)switched;
/*!
点击录音按钮回调
@param sender 录音按钮
@param event 点击事件
*/
- (void)didTouchRecordButon:(UIButton *)sender event:(UIControlEvents)event;
/*!
输入框中内容发生变化的回调
@param inputTextView 文本输入框
@param range 当前操作的范围
@param text 插入的文本
*/
- (void)inputTextView:(UITextView *)inputTextView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text;
/*!
公众服务菜单的点击回调
@param selectedMenuItem 点击的公众服务菜单项
*/
- (void)onPublicServiceMenuItemSelected:(RCPublicServiceMenuItem *)selectedMenuItem;
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCContentView.h
================================================
//
// RCContentView.h
// RongIMKit
//
// Created by xugang on 3/31/15.
// Copyright (c) 2015 RongCloud. All rights reserved.
//
#import
/*!
消息内容的View
*/
@interface RCContentView : UIView
/*!
Frame发生变化的回调
*/
@property(nonatomic, copy) void (^eventBlock)(CGRect frame);
/*!
注册Frame发生变化的回调
@param eventBlock Frame发生变化的回调
*/
- (void)registerFrameChangedEvent:(void (^)(CGRect frame))eventBlock;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationBaseCell.h
================================================
//
// RCConversationBaseTableCell.h
// RongIMKit
//
// Created by xugang on 15/1/24.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCConversationBaseTableCell
#define __RCConversationBaseTableCell
#import
#import "RCConversationModel.h"
/*!
会话Cell基类
*/
@interface RCConversationBaseCell : UITableViewCell
/*!
会话Cell的数据模型
*/
@property(nonatomic, strong) RCConversationModel *model;
/*!
设置会话Cell的数据模型
@param model 会话Cell的数据模型
*/
- (void)setDataModel:(RCConversationModel *)model;
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationCell.h
================================================
//
// RCConversationTableCell.h
// RongIMKit
//
// Created by xugang on 15/1/24.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCConversationTableCell
#define __RCConversationTableCell
#import
#import "RCConversationBaseCell.h"
#import "RCMessageBubbleTipView.h"
#import "RCThemeDefine.h"
#define CONVERSATION_ITEM_HEIGHT 65.0f
@protocol RCConversationCellDelegate;
@class RCloudImageView;
/*!
会话Cell类
*/
@interface RCConversationCell : RCConversationBaseCell
/*!
会话Cell的点击监听器
*/
@property(weak, nonatomic) id delegate;
/*!
Cell的头像背景View
*/
@property(strong, nonatomic) UIView *headerImageViewBackgroundView;
/*!
Cell头像View
*/
@property(strong, nonatomic) RCloudImageView *headerImageView;
/*!
会话的标题
*/
@property(strong, nonatomic) UILabel *conversationTitle;
/*!
显示最后一条内容的Label
*/
@property(strong, nonatomic) UILabel *messageContentLabel;
/*!
显示最后一条消息发送时间的Label
*/
@property(strong, nonatomic) UILabel *messageCreatedTimeLabel;
/*!
头像右上角未读消息提示的View
*/
@property(strong, nonatomic) RCMessageBubbleTipView *bubbleTipView;
/*!
会话免打扰状态显示的View
*/
@property(strong, nonatomic) UIImageView *conversationStatusImageView;
/*!
Cell中显示的头像形状
@discussion 默认值为当前IMKit的全局设置值(RCIM中的globalConversationAvatarStyle)。
*/
@property(nonatomic) RCUserAvatarStyle portraitStyle;
/*!
是否进行新消息提醒
@discussion 此属性默认会根据会话设置的提醒状态进行设置。
*/
@property(nonatomic) BOOL enableNotification;
/*!
会话中有未读消息时,是否在头像右上角的bubbleTipView中显示数字
@discussion 默认值为YES。
您可以在RCConversationListViewController的willDisplayConversationTableCell:atIndexPath:回调中进行设置。
*/
@property(nonatomic) BOOL isShowNotificationNumber;
/*!
Cell的背景颜色
*/
@property(nonatomic) UIColor *cellBackgroundColor;
/*!
置顶Cell的背景颜色
*/
@property(nonatomic) UIColor *topCellBackgroundColor;
/*!
显示最后一台消息发送状态
*/
@property(strong, nonatomic) UIImageView *lastSendMessageStatusView;
/*!
设置Cell中显示的头像形状
@param portraitStyle 头像形状
@discussion 此设置仅当前会话Cell有效。
*/
- (void)setHeaderImagePortraitStyle:(RCUserAvatarStyle)portraitStyle;
/*!
设置当前会话Cell的数据模型
@param model 会话Cell的数据模型
*/
- (void)setDataModel:(RCConversationModel *)model;
@end
/*!
会话Cell的点击监听器
*/
@protocol RCConversationCellDelegate
/*!
点击Cell头像的回调
@param model 会话Cell的数据模型
*/
- (void)didTapCellPortrait:(RCConversationModel *)model;
/*!
长按Cell头像的回调
@param model 会话Cell的数据模型
*/
- (void)didLongPressCellPortrait:(RCConversationModel *)model;
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationListViewController.h
================================================
//
// RCConversationListViewController.h
// RongIMKit
//
// Created by xugang on 15/1/22.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCConversationListViewController
#define __RCConversationListViewController
#import
#import "RCConversationModel.h"
#import "RCBaseViewController.h"
#import "RCThemeDefine.h"
#import "RCConversationBaseCell.h"
@class RCNetworkIndicatorView;
/*!
会话列表界面类
*/
@interface RCConversationListViewController: RCBaseViewController
#pragma mark - 初始化
/*!
初始化会话列表
@param displayConversationTypeArray 列表中需要显示的会话类型数组(需要将RCConversationType转为NSNumber构建Array)
@param collectionConversationTypeArray 列表中需要聚合为一条显示的会话类型数组(需要将RCConversationType转为NSNumber构建Array)
@return 会话列表对象
@discussion 聚合为一条显示指的是,将指定会话类型的所有会话在会话列表中聚合显示成一条,点击进入会显示该会话类型的所有会话列表。
*/
- (id)initWithDisplayConversationTypes:(NSArray *)displayConversationTypeArray
collectionConversationType:(NSArray *)collectionConversationTypeArray;
#pragma mark - 设置需要显示和聚合显示的会话类型
/*!
列表中需要显示的会话类型数组
@discussion 数组中的元素为RCConversationType转换的NSNumber
*/
@property(nonatomic, strong) NSArray *displayConversationTypeArray;
/*!
列表中需要聚合为一条显示的会话类型数组
@discussion 数组中的元素为RCConversationType转换的NSNumber
*/
@property(nonatomic, strong) NSArray *collectionConversationTypeArray;
/*!
设置在列表中需要显示的会话类型
@param conversationTypeArray 列表中需要显示的会话类型数组(需要将RCConversationType转为NSNumber构建Array)
*/
- (void)setDisplayConversationTypes:(NSArray *)conversationTypeArray;
/*!
设置在列表中需要聚合为一条显示的会话类型
@param conversationTypeArray 列表中需要聚合为一条显示的会话类型数组(需要将RCConversationType转为NSNumber构建Array)
*/
- (void)setCollectionConversationType:(NSArray *)conversationTypeArray;
/*!
当前会话列表是否为从聚合Cell点击进入的子会话列表
@discussion 您在点击会话列表中的聚合Cell跳转到到子会话列表时,需要将此属性设置为YES。
*/
@property(nonatomic, assign) BOOL isEnteredToCollectionViewController;
#pragma mark - 列表属性
/*!
列表中会话数据模型的数据源
@discussion 数据源中存放的元素为会话Cell的数据模型,即RCConversationModel对象。
*/
@property(nonatomic, strong) NSMutableArray *conversationListDataSource;
/*!
列表的TableView
*/
@property(nonatomic, strong) UITableView *conversationListTableView;
#pragma mark - 网络连接变化状态提醒
/*!
当网络断开时,是否在Tabel View Header中显示网络连接不可用的提示。
@discussion 默认值为YES。
*/
@property(nonatomic, assign) BOOL isShowNetworkIndicatorView;
/*!
当连接状态变化SDK自动重连时,是否在NavigationBar中显示连接中的提示。
@discussion 默认是是NO。
*/
@property(nonatomic) BOOL showConnectingStatusOnNavigatorBar;
#pragma mark - 显示相关
/*!
列表为空时显示的View
*/
@property(nonatomic, strong) UIView *emptyConversationView;
/*!
Cell的背景颜色
*/
@property(nonatomic) UIColor *cellBackgroundColor;
/*!
置顶会话的Cell背景颜色
*/
@property(nonatomic) UIColor *topCellBackgroundColor;
/*!
设置在会话列表中显示的头像形状,矩形或者圆形(全局有效)
@param avatarStyle 显示的头像形状
@discussion 默认值为矩形,即RC_USER_AVATAR_RECTANGLE。
请在viewDidLoad之前设置,此设置在SDK中全局有效。
*/
- (void)setConversationAvatarStyle:(RCUserAvatarStyle)avatarStyle;
/*!
设置会话列表界面中显示的头像大小(全局有效),高度必须大于或者等于36
@param size 显示的头像大小
@discussion 默认值为46*46。
请在viewDidLoad之前设置,此设置在SDK中全局有效。
*/
- (void)setConversationPortraitSize:(CGSize)size;
#pragma mark - UI操作回调
#pragma mark 点击事件的回调
/*!
点击会话列表中Cell的回调
@param conversationModelType 当前点击的会话的Model类型
@param model 当前点击的会话的Model
@param indexPath 当前会话在列表数据源中的索引值
@discussion 您需要重写此点击事件,跳转到指定会话的聊天界面。
如果点击聚合Cell进入具体的子会话列表,在跳转时,需要将isEnteredToCollectionViewController设置为YES。
*/
- (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
conversationModel:(RCConversationModel *)model
atIndexPath:(NSIndexPath *)indexPath;
/*!
点击Cell头像的回调
@param model 会话Cell的数据模型
*/
- (void)didTapCellPortrait:(RCConversationModel *)model;
/*!
长按Cell头像的回调
@param model 会话Cell的数据模型
*/
- (void)didLongPressCellPortrait:(RCConversationModel *)model;
#pragma mark 删除会话的回调
/*!
删除会话的回调
@param model 会话Cell的数据模型
*/
- (void)didDeleteConversationCell:(RCConversationModel *)model;
#pragma mark - Cell加载显示的回调
/*!
即将加载列表数据源的回调
@param dataSource 即将加载的列表数据源(元素为RCConversationModel对象)
@return 修改后的数据源(元素为RCConversationModel对象)
@discussion 您可以在回调中修改、添加、删除数据源的元素来定制显示的内容,会话列表会根据您返回的修改后的数据源进行显示。
数据源中存放的元素为会话Cell的数据模型,即RCConversationModel对象。
*/
- (NSMutableArray *)willReloadTableData:(NSMutableArray *)dataSource;
/*!
即将显示Cell的回调
@param cell 即将显示的Cell
@param indexPath 该Cell对应的会话Cell数据模型在数据源中的索引值
@discussion 您可以在此回调中修改Cell的一些显示属性。
*/
- (void)willDisplayConversationTableCell:(RCConversationBaseCell *)cell
atIndexPath:(NSIndexPath *)indexPath;
#pragma mark - 自定义会话列表Cell
/*!
自定义会话Cell显示时的回调
@param tableView 当前TabelView
@param indexPath 该Cell对应的会话Cell数据模型在数据源中的索引值
@return 自定义会话需要显示的Cell
*/
- (RCConversationBaseCell *)rcConversationListTableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
/*!
自定义会话Cell显示时的回调
@param tableView 当前TabelView
@param indexPath 该Cell对应的会话Cell数据模型在数据源中的索引值
@return 自定义会话需要显示的Cell的高度
*/
- (CGFloat)rcConversationListTableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath;
/*!
左滑删除自定义会话时的回调
@param tableView 当前TabelView
@param editingStyle 当前的Cell操作,默认为UITableViewCellEditingStyleDelete
@param indexPath 该Cell对应的会话Cell数据模型在数据源中的索引值
@discussion 自定义会话Cell在删除时会回调此方法,您可以在此回调中,定制删除的提示UI、是否删除。
如果确定删除该会话,您需要在调用RCIMClient中的接口删除会话或其中的消息,
并从conversationListDataSource和conversationListTableView中删除该会话。
*/
- (void)rcConversationListTableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath;
#pragma mark - 界面刷新操作
/*!
从数据库中重新读取会话列表数据,并刷新会话列表
@warning 从数据库中重新读取并刷新,会比较耗时,请谨慎使用。
*/
- (void)refreshConversationTableViewIfNeeded;
/*!
向列表中插入或更新一条会话,并刷新会话列表界面
@param conversationModel 会话Cell的数据模型
@discussion 如果该会话Cell数据模型在数据源中已经存在,则会更新数据源中的数据并更新UI;
如果数据源没有该会话Cell的数据模型,则插入数据源再更新UI。
*/
- (void)refreshConversationTableViewWithConversationModel:(RCConversationModel *)conversationModel;
#pragma mark - 其他
/*!
在会话列表中,收到新消息的回调
@param notification 收到新消息的notification
@discussion SDK在此方法中有针对消息接收有默认的处理(如刷新等),如果您重写此方法,请注意调用super。
notification的object为RCMessage消息对象,userInfo为NSDictionary对象,其中key值为@"left",value为还剩余未接收的消息数的NSNumber对象。
*/
- (void)didReceiveMessageNotification:(NSNotification *)notification;
/*!
即将更新未读消息数的回调
@discussion 当收到消息或删除会话时,会调用此回调,您可以在此回调中执行未读消息数相关的操作。
*/
- (void)notifyUpdateUnreadMessageCount;
#pragma mark - 已废弃方法
/*!
移除SDK中会话列表为空时显示的默认View(已废弃,请勿使用)
@discussion 此方法已废弃,您可以直接通过emptyConversationView设置列表为空时需要显示的View。.
@warning **已废弃,请勿使用。**
*/
- (void)resetConversationListBackgroundViewIfNeeded
__deprecated_msg("已废弃,请勿使用。");
/*!
提示网络连接不可用的View(已废弃,请勿使用)
@warning **已废弃,请勿使用。**
*/
@property(nonatomic, strong) RCNetworkIndicatorView *networkIndicatorView
__deprecated_msg("已废弃,请勿使用。");
/*!
当showConnectingStatusOnNavigatorBar设置为YES时,连接状态变化时更新NavigationBar的回调(已废弃,请勿使用)
@discussion SDK在此方法中有默认的处理,如果您在子类中需要重写此方法,请注意调用super。
@warning **已废弃,请勿使用。**
*/
- (void)updateConnectionStatusOnNavigatorBar
__deprecated_msg("已废弃,请勿使用。");
/*!
当showConnectingStatusOnNavigatorBar设置为YES时,连接恢复后的回调(已废弃,请勿使用)
@discussion 您需要在此回调中更新NavigationBar的标题显示。
@warning **已废弃,请勿使用。**
*/
- (void)setNavigationItemTitleView
__deprecated_msg("已废弃,请勿使用。");
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationModel.h
================================================
//
// RongConversationModel.h
// RongIMKit
//
// Created by xugang on 15/1/22.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RongConversationModel
#define __RongConversationModel
#import
#import
/*!
会话Cell数据模型的显示类型
*/
typedef NS_ENUM(NSUInteger, RCConversationModelType) {
/*!
默认显示
*/
RC_CONVERSATION_MODEL_TYPE_NORMAL = 1,
/*!
聚合显示
*/
RC_CONVERSATION_MODEL_TYPE_COLLECTION = 2,
/*!
用户自定义的会话显示
*/
RC_CONVERSATION_MODEL_TYPE_CUSTOMIZATION = 3,
/*!
公众服务的会话显示
*/
RC_CONVERSATION_MODEL_TYPE_PUBLIC_SERVICE = 4
};
/*!
会话Cell的数据模型类
*/
@interface RCConversationModel : NSObject
/*!
会话Cell数据模型的显示类型
*/
@property(nonatomic) RCConversationModelType conversationModelType;
/*!
用户自定义的扩展数据
*/
@property(nonatomic, strong) id extend;
/*!
会话类型
*/
@property(nonatomic, assign) RCConversationType conversationType;
/*!
目标会话ID
*/
@property(nonatomic, strong) NSString *targetId;
/*!
会话的标题
*/
@property(nonatomic, strong) NSString *conversationTitle;
/*!
会话中的未读消息数
*/
@property(nonatomic, assign) NSInteger unreadMessageCount;
/*!
当前会话是否置顶
*/
@property(nonatomic, assign) BOOL isTop;
/*!
会话中最后一条消息的接收状态
*/
@property(nonatomic, assign) RCReceivedStatus receivedStatus;
/*!
会话中最后一条消息的发送状态
*/
@property(nonatomic, assign) RCSentStatus sentStatus;
/*!
会话中最后一条消息的接收时间(Unix时间戳、毫秒)
*/
@property(nonatomic, assign) long long receivedTime;
/*!
会话中最后一条消息的发送时间(Unix时间戳、毫秒)
*/
@property(nonatomic, assign) long long sentTime;
/*!
会话中存在的草稿
*/
@property(nonatomic, strong) NSString *draft;
/*!
会话中最后一条消息的类型名
*/
@property(nonatomic, strong) NSString *objectName;
/*!
会话中最后一条消息的发送者用户ID
*/
@property(nonatomic, strong) NSString *senderUserId;
/*!
会话中最后一条消息的发送者的用户名(已废弃,请勿使用)
@warning **已废弃,请勿使用。**
*/
@property(nonatomic, strong) __deprecated_msg("已废弃,请勿使用。") NSString *senderUserName;
/*!
会话中最后一条消息的消息ID
*/
@property(nonatomic, assign) long lastestMessageId;
/*!
会话中最后一条消息的内容
*/
@property(nonatomic, strong) RCMessageContent *lastestMessage;
/*!
会话中最后一条消息的json Dictionary
*/
@property(nonatomic, strong) NSDictionary *jsonDict;
/*!
初始化会话Cell的数据模型(已废弃,请勿使用)
@param conversationModelType 会话Cell数据模型的显示类型
@param extend 用户自定义的扩展数据
@return 会话Cell的数据模型对象
@warning **已废弃,请勿使用。**
*/
- (id)init:(RCConversationModelType)conversationModelType exntend:(id)extend
__deprecated_msg("已废弃,请勿使用。");
/*!
初始化会话显示数据模型
@param conversationModelType 会话Cell数据模型的显示类型
@param conversation 会话
@param extend 用户自定义的扩展数据
@return 会话Cell的数据模型对象
*/
- (id)init:(RCConversationModelType)conversationModelType conversation:(RCConversation *)conversation extend:(id)extend;
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationSettingTableViewController.h
================================================
//
// RCConversationSettingTableViewController.h
// RongIMKit
//
// Created by Liv on 15/4/20.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#import
#import
@class RCConversationSettingTableViewHeader;
/*!
会话设置的ViewController
*/
@interface RCConversationSettingTableViewController : UITableViewController
/*!
内置置顶聊天,新消息通知,清除消息记录三个cell
*/
@property(nonatomic, strong, readonly) NSArray *defaultCells;
/*!
是否隐藏顶部视图
*/
@property(nonatomic, assign) BOOL headerHidden;
/*!
是否将该会话置顶
*/
@property(nonatomic, assign) BOOL switch_isTop;
/*!
是否接收新通知提醒
*/
@property(nonatomic, assign) BOOL switch_newMessageNotify;
/*!
顶部视图显示的用户的用户信息RCUserInfo列表
*/
@property(nonatomic, strong) NSArray *users;
/*!
禁止删除用户
@param disable 是否禁止删除用户
*/
- (void)disableDeleteMemberEvent:(BOOL)disable;
/*!
设置添加用户
@param disable 是否禁止删除用户
*/
- (void)disableInviteMemberEvent:(BOOL)disable;
/*!
开闭置顶聊天的回调
@param sender 点击的Switch开关
*/
- (void)onClickIsTopSwitch:(id)sender;
/*!
开闭新通知提醒的回调
@param sender 点击的Switch开关
*/
- (void)onClickNewMessageNotificationSwitch:(id)sender;
/*!
点击清除聊天记录的回调
@param sender 清除聊天记录的按钮
*/
- (void)onClickClearMessageHistory:(id)sender;
/*!
添加用户到顶部视图
@param users 用户信息RCUserInfo列表
*/
- (void)addUsers:(NSArray *)users;
/*!
点击Item(用户头像或加减号)的回调
@param settingTableViewHeader 当前会话设置界面
@param indexPathOfSelectedItem 点击的Item索引值
@param users 当前的用户信息RCUserInfo列表
*/
- (void)settingTableViewHeader:(RCConversationSettingTableViewHeader *)settingTableViewHeader
indexPathOfSelectedItem:(NSIndexPath *)indexPathOfSelectedItem
allTheSeletedUsers:(NSArray *)users;
/*!
点击删除用户的回调
@param indexPath 当前删除的用户的头像索引值
@discussion 点击头像左上角的删除按钮时的回调。
*/
- (void)deleteTipButtonClicked:(NSIndexPath *)indexPath;
/*!
点击头像的回调
@param userId 头像对应的用户ID
*/
- (void)didTipHeaderClicked:(NSString*)userId;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationSettingTableViewHeader.h
================================================
//
// RCConversationSettingTableViewHeader.h
// RongIMToolkit
//
// Created by Liv on 15/3/25.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#import
@class RCConversationSettingTableViewHeader;
/*!
会话设置界面头像区域的点击回调
*/
@protocol RCConversationSettingTableViewHeaderDelegate
@optional
/*!
点击Item(用户头像或加减号)的回调
@param settingTableViewHeader 当前会话设置界面
@param indexPathOfSelectedItem 点击的Item索引值
@param users 当前的用户信息RCUserInfo列表
*/
- (void)settingTableViewHeader:(RCConversationSettingTableViewHeader *)settingTableViewHeader
indexPathOfSelectedItem:(NSIndexPath *)indexPathOfSelectedItem
allTheSeletedUsers:(NSArray *)users;
/*!
点击删除的回调
@param indexPath 点击的索引
*/
- (void)deleteTipButtonClicked:(NSIndexPath *)indexPath;
/*!
点击头像的回调
@param userId 头像对应的用户ID
*/
- (void)didTipHeaderClicked:(NSString *)userId;
@end
/*!
会话设置界面的头像区域
*/
@interface RCConversationSettingTableViewHeader
: UICollectionView
/*!
是否显示删除(减号)
*/
@property(nonatomic, assign) BOOL showDeleteTip;
/*!
是否允许删除用户
*/
@property(nonatomic, assign) BOOL isAllowedDeleteMember;
/*!
是否允许添加用户
*/
@property(nonatomic, assign) BOOL isAllowedInviteMember;
/*!
会话设置界面头像区域的点击回调
*/
@property(weak, nonatomic) id settingTableViewHeaderDelegate;
/*!
用户信息RCUserInfo的列表
*/
@property(strong, nonatomic) NSMutableArray *users;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCConversationViewController.h
================================================
//
// RCConversationViewController.h
// RongIMKit
//
// Created by xugang on 15/1/22.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RCConversationViewController
#define __RCConversationViewController
#import
#import "RCBaseViewController.h"
#import "RCPluginBoardView.h"
#import "RCChatSessionInputBarControl.h"
#import "RCEmojiBoardView.h"
#import "RCThemeDefine.h"
#import "RCMessageBaseCell.h"
#import "RCMessageModel.h"
///输入栏扩展输入的唯一标示
#define PLUGIN_BOARD_ITEM_ALBUM_TAG 1001
#define PLUGIN_BOARD_ITEM_CAMERA_TAG 1002
#define PLUGIN_BOARD_ITEM_LOCATION_TAG 1003
#if RC_VOIP_ENABLE
#define PLUGIN_BOARD_ITEM_VOIP_TAG 1004
#endif
/*!
聊天界面类
*/
@interface RCConversationViewController: RCBaseViewController
#pragma mark - 初始化
/*!
初始化聊天界面
@param conversationType 会话类型
@param targetId 目标会话ID
@return 聊天界面对象
*/
- (id)initWithConversationType:(RCConversationType)conversationType
targetId:(NSString *)targetId;
#pragma mark - 会话属性
/*!
当前会话的会话类型
*/
@property(nonatomic) RCConversationType conversationType;
/*!
目标会话ID
*/
@property(nonatomic, strong) NSString *targetId;
/*!
当前的用户名称(已废弃,请勿使用)
@warning **已废弃,请勿使用。**
*/
@property(nonatomic, strong) __deprecated_msg("已废弃,请勿使用。") NSString *userName;
#pragma mark - 聊天界面属性
/*!
聊天内容的消息Cell数据模型的数据源
@discussion 数据源中存放的元素为消息Cell的数据模型,即RCMessageModel对象。
*/
@property(nonatomic, strong) NSMutableArray *conversationDataRepository;
/*!
聊天界面的CollectionView
*/
@property(nonatomic, strong) UICollectionView *conversationMessageCollectionView;
/*!
聊天界面的CollectionView Layout
*/
@property(nonatomic, strong) UICollectionViewFlowLayout *customFlowLayout;
#pragma mark - 未读消息数
#pragma mark 导航栏返回按钮中的未读消息数提示
/*!
需要统计未读数的会话类型数组(在导航栏的返回按钮中显示)
@discussion 此属性表明在导航栏的返回按钮中需要统计显示哪部分的会话类型的未读数。
(需要将RCConversationType转为NSNumber构建Array)
*/
@property(nonatomic, strong) NSArray *displayConversationTypeArray;
/*!
更新导航栏返回按钮中显示的未读消息数
@discussion 如果您重写此方法,需要注意调用super。
*/
- (void)notifyUpdateUnreadMessageCount;
#pragma mark 右上角的未读消息数提示
/*!
当收到的消息超过一个屏幕时,进入会话之后,是否在右上角提示上方存在的未读消息数
@discussion 默认值为NO。
开启该提示功能之后,当一个会话收到大量消息时(操作一个屏幕能显示的内容),
进入该会话后,会在右上角提示用户上方存在的未读消息数,用户点击该提醒按钮,会跳转到最开始的未读消息。
*/
@property(nonatomic, assign) BOOL enableUnreadMessageIcon;
/*!
右上角提示的未读消息数
@discussion 右上角未读消息数支持的最大值是150。
*/
@property(nonatomic, assign) NSInteger unReadMessage;
/*!
右上角未读消息数提示的Label
*/
@property(nonatomic,strong) UILabel *unReadMessageLabel;
/*!
右上角未读消息数提示的按钮
*/
@property(nonatomic, strong) UIButton *unReadButton;
#pragma mark 右下角的未读消息数提示
/*!
当前阅读区域的下方收到消息时,是否在聊天界面的右下角提示下方存在未读消息
@discussion 默认值为NO。
开启该提示功能之后,当聊天界面滑动到最下方时,此会话中收到消息会自动更新;
当用户停留在上方某个区域阅读时,此会话收到消息时,会在右下角显示未读消息提示,而不会自动滚动到最下方,
用户点击该提醒按钮,会滚动到最下方。
*/
@property(nonatomic, assign) BOOL enableNewComingMessageIcon;
/*!
右下角未读消息数提示的Label
*/
@property(nonatomic, strong) UILabel *unReadNewMessageLabel;
#pragma mark - 输入工具栏
/*!
聊天界面下方的输入工具栏
*/
@property(nonatomic, strong) RCChatSessionInputBarControl *chatSessionInputBarControl;
/*!
输入框的默认输入模式
@discussion 默认值为RCChatSessionInputBarInputText,即文本输入模式。
*/
@property(nonatomic) RCChatSessionInputBarInputType defaultInputType;
/*!
输入扩展功能板View
*/
@property(nonatomic, strong) RCPluginBoardView *pluginBoardView;
/*!
表情View
*/
@property(nonatomic, strong) RCEmojiBoardView *emojiBoardView;
/*!
扩展功能板的点击回调
@param pluginBoardView 输入扩展功能板View
@param tag 输入扩展功能(Item)的唯一标示
*/
-(void)pluginBoardView:(RCPluginBoardView*)pluginBoardView
clickedItemWithTag:(NSInteger)tag;
/*!
输入框中内容发生变化的回调
@param inputTextView 文本输入框
@param range 当前操作的范围
@param text 插入的文本
*/
- (void)inputTextView:(UITextView *)inputTextView shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text;
/*!
设置输入框的输入状态
@param inputBarStatus 输入框状态
@param animated 是否使用动画效果
*/
-(void)setChatSessionInputBarStatus:(KBottomBarStatus)inputBarStatus animated:(BOOL)animated;
#pragma mark - 显示设置
/*!
设置在聊天界面中显示的头像形状,矩形或者圆形(全局有效)
@param avatarStyle 显示的头像形状
@discussion 默认值为矩形,即RC_USER_AVATAR_RECTANGLE。
请在viewDidLoad之前设置,此设置在SDK中全局有效。
*/
- (void)setMessageAvatarStyle:(RCUserAvatarStyle)avatarStyle;
/*!
设置聊天界面中显示的头像大小(全局有效),高度必须大于或者等于36
@param size 显示的头像形状
@discussion 默认值为46*46。
请在viewDidLoad之前设置,此设置在SDK中全局有效。
*/
- (void)setMessagePortraitSize:(CGSize)size;
/*!
收到的消息是否显示发送者的名字
@discussion 默认值为YES。
您可以针对群聊、聊天室、单聊等不同场景,自己定制是否显示发送方的名字。
*/
@property(nonatomic) BOOL displayUserNameInCell;
/*!
设置进入聊天室需要获取的历史消息数量(仅在当前会话为聊天室时生效)
@discussion 此属性需要在viewDidLoad之前进行设置。
-1表示不获取任何历史消息,0表示不特殊设置而使用SDK默认的设置(默认为获取10条),0
@class RCEmojiPageControl;
@class RCEmojiBoardView;
/*!
表情输入的回调
*/
@protocol RCEmojiViewDelegate
@optional
/*!
点击表情的回调
@param emojiView 表情输入的View
@param string 点击的表情对应的字符串编码
*/
- (void)didTouchEmojiView:(RCEmojiBoardView *)emojiView touchedEmoji:(NSString *)string;
/*!
点击发送按钮的回调
@param emojiView 表情输入的View
@param sendButton 发送按钮
*/
- (void)didSendButtonEvent:(RCEmojiBoardView *)emojiView sendButton:(UIButton *)sendButton;
@end
/*!
表情输入的View
*/
@interface RCEmojiBoardView : UIView {
/*!
PageControl
*/
RCEmojiPageControl *pageCtrl;
/*!
当前所在页的索引值
*/
NSInteger currentIndex;
}
/*!
表情背景的View
*/
@property(nonatomic, strong) UIScrollView *emojiBackgroundView;
/*!
表情的Label(已废弃,请勿使用)
@warning **已废弃,请勿使用。**
*/
@property(nonatomic, strong) __deprecated_msg("已废弃,请勿使用。") UILabel *emojiLabel;
/*!
表情输入的回调
*/
@property(nonatomic, assign) id delegate;
/*!
加载表情Label
*/
- (void)loadLabelView;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCIM.h
================================================
//
// RongUIKit.h
// RongIMKit
//
// Created by xugang on 15/1/13.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#ifndef __RongUIKit
#define __RongUIKit
#import
#import
#import "RCThemeDefine.h"
/*!
@const 收到消息的Notification
@discussion 接收到消息后,SDK会分发此通知。
Notification的object为RCMessage消息对象。
userInfo为NSDictionary对象,其中key值为@"left",value为还剩余未接收的消息数的NSNumber对象。
与RCIMReceiveMessageDelegate的区别:
RCKitDispatchMessageNotification只要注册都可以收到通知;RCIMReceiveMessageDelegate需要设置监听,并同时只能存在一个监听。
*/
FOUNDATION_EXPORT NSString *const RCKitDispatchMessageNotification;
/*!
@const 连接状态变化的Notification
@discussion SDK连接状态发生变化时,SDK会分发此通知。
Notification的object为NSNumber对象,对应于RCConnectionStatus的值。
与RCIMConnectionStatusDelegate的区别:
RCKitDispatchConnectionStatusChangedNotification只要注册都可以收到通知;RCIMConnectionStatusDelegate需要设置监听,同时只能存在一个监听。
*/
FOUNDATION_EXPORT NSString *const RCKitDispatchConnectionStatusChangedNotification;
#pragma mark - 用户信息提供者、群组信息提供者、群名片信息提供者
/*!
用户信息提供者
@discussion SDK需要通过您实现的用户信息提供者,获取用户信息并显示。
*/
@protocol RCIMUserInfoDataSource
/*!
获取用户信息
@param userId 用户ID
@param completion 获取用户信息完成之后需要执行的Block [userInfo:该用户ID对应的用户信息]
@discussion SDK通过此方法获取用户信息并显示,请在completion中返回该用户ID对应的用户信息。
在您设置了用户信息提供者之后,SDK在需要显示用户信息的时候,会调用此方法,向您请求用户信息用于显示。
*/
- (void)getUserInfoWithUserId:(NSString *)userId
completion:(void (^)(RCUserInfo *userInfo))completion;
@end
/*!
群组信息提供者
@discussion SDK需要通过您实现的群组信息提供者,获取群组信息并显示。
*/
@protocol RCIMGroupInfoDataSource
/*!
获取群组信息
@param groupId 群组ID
@param completion 获取群组信息完成之后需要执行的Block [groupInfo:该群组ID对应的群组信息]
@discussion SDK通过此方法获取用户信息并显示,请在completion的block中返回该用户ID对应的用户信息。
在您设置了用户信息提供者之后,SDK在需要显示用户信息的时候,会调用此方法,向您请求用户信息用于显示。
*/
- (void)getGroupInfoWithGroupId:(NSString *)groupId
completion:(void (^)(RCGroup *groupInfo))completion;
@end
/*!
群名片信息提供者
@discussion 如果您使用了群名片功能,SDK需要通过您实现的群名片信息提供者,获取用户在群组中的名片信息并显示。
*/
@protocol RCIMGroupUserInfoDataSource
/*!
获取用户在群组中的群名片信息
@param userId 用户ID
@param groupId 群组ID
@param completion 获取群名片信息完成之后需要执行的Block [userInfo:该用户ID在群组中对应的群名片信息]
@discussion 如果您使用了群名片功能,SDK需要通过您实现的群名片信息提供者,获取用户在群组中的名片信息并显示。
*/
- (void)getUserInfoWithUserId:(NSString *)userId
inGroup:(NSString *)groupId
completion:(void (^)(RCUserInfo *userInfo))completion;
@end
#pragma mark - 消息接收监听器
/*!
IMKit消息接收的监听器
@discussion 设置IMKit的消息接收监听器请参考RCIM的receiveMessageDelegate属性。
@warning 如果您使用IMKit,可以设置并实现此Delegate监听消息接收;
如果您使用IMLib,请使用RCIMClient中的RCIMClientReceiveMessageDelegate监听消息接收,而不要使用此监听器。
*/
@protocol RCIMReceiveMessageDelegate
/*!
接收消息的回调方法
@param message 当前接收到的消息
@param left 还剩余的未接收的消息数,left>=0
@discussion 如果您设置了IMKit消息监听之后,SDK在接收到消息时候会执行此方法(无论App处于前台或者后台)。
其中,left为还剩余的、还未接收的消息数量。比如刚上线一口气收到多条消息时,通过此方法,您可以获取到每条消息,left会依次递减直到0。
您可以根据left数量来优化您的App体验和性能,比如收到大量消息时等待left为0再刷新UI。
*/
- (void)onRCIMReceiveMessage:(RCMessage *)message
left:(int)left;
@optional
/*!
当App处于后台时,接收到消息并弹出本地通知的回调方法
@param message 接收到的消息
@param senderName 消息发送者的用户名称
@return 当返回值为NO时,SDK会弹出默认的本地通知提示;当返回值为YES时,SDK针对此消息不再弹本地通知提示
@discussion 如果您设置了IMKit消息监听之后,当App处于后台,收到消息时弹出本地通知之前,会执行此方法。
如果App没有实现此方法,SDK会弹出默认的本地通知提示。
流程:
SDK接收到消息 -> App处于后台状态 -> 通过用户/群组/群名片信息提供者获取消息的用户/群组/群名片信息
-> 用户/群组信息为空 -> 不弹出本地通知
-> 用户/群组信息存在 -> 回调此方法准备弹出本地通知 -> App实现并返回YES -> SDK不再弹出此消息的本地通知
-> App未实现此方法或者返回NO -> SDK弹出默认的本地通知提示
您可以通过RCIM的disableMessageNotificaiton属性,关闭所有的本地通知(此时不再回调此接口)。
@warning 如果App在后台想使用SDK默认的本地通知提醒,需要实现用户/群组/群名片信息提供者,并返回正确的用户信息或群组信息。
参考RCIMUserInfoDataSource、RCIMGroupInfoDataSource与RCIMGroupUserInfoDataSource
*/
-(BOOL)onRCIMCustomLocalNotification:(RCMessage*)message
withSenderName:(NSString *)senderName;
/*!
当App处于前台时,接收到消息并播放提示音的回调方法
@param message 接收到的消息
@return 当返回值为NO时,SDK会播放默认的提示音;当返回值为YES时,SDK针对此消息不再播放提示音
@discussion 到消息时播放提示音之前,会执行此方法。
如果App没有实现此方法,SDK会播放默认的提示音。
流程:
SDK接收到消息 -> App处于前台状态 -> 回调此方法准备播放提示音 -> App实现并返回YES -> SDK针对此消息不再播放提示音
-> App未实现此方法或者返回NO -> SDK会播放默认的提示音
您可以通过RCIM的disableMessageAlertSound属性,关闭所有前台消息的提示音(此时不再回调此接口)。
*/
-(BOOL)onRCIMCustomAlertSound:(RCMessage*)message;
@end
#pragma mark - 连接状态监听器
/*!
IMKit连接状态的的监听器
@discussion 设置IMKit的连接状态监听器,请参考RCIM的connectionStatusDelegate属性。
@warning 如果您使用IMKit,可以设置并实现此Delegate监听消息接收;
如果您使用IMLib,请使用RCIMClient中的RCIMClientReceiveMessageDelegate监听消息接收,而不要使用此监听器。
*/
@protocol RCIMConnectionStatusDelegate
/*!
IMKit连接状态的的监听器
@param status SDK与融云服务器的连接状态
@discussion 如果您设置了IMKit消息监听之后,当SDK与融云服务器的连接状态发生变化时,会回调此方法。
*/
- (void)onRCIMConnectionStatusChanged:(RCConnectionStatus)status;
@end
#pragma mark - IMKit核心类
/*!
融云IMKit核心类
@discussion 您需要通过sharedRCIM方法,获取单例对象
*/
@interface RCIM : NSObject
/*!
获取融云界面组件IMKit的核心类单例
@return 融云界面组件IMKit的核心类单例
@discussion 您可以通过此方法,获取IMKit的单例,访问对象中的属性和方法。
*/
+ (instancetype)sharedRCIM;
#pragma mark - SDK初始化
/*!
初始化融云SDK
@param appKey 从融云开发者平台创建应用后获取到的App Key
@discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
在App整个生命周期中,您只需要执行一次初始化。
@warning 如果您使用IMKit,请使用此方法初始化SDK;
如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
*/
- (void)initWithAppKey:(NSString *)appKey;
#pragma mark - 连接与断开服务器
/*!
与融云服务器建立连接
@param token 从您服务器端获取的token(用户身份令牌)
@param successBlock 连接建立成功的回调 [userId:当前连接成功所用的用户ID
@param errorBlock 连接建立失败的回调 [status:连接失败的错误码]
@param tokenIncorrectBlock token错误或者过期的回调
@discussion 在App整个生命周期,您只需要调用一次此方法与融云服务器建立连接。
之后无论是网络出现异常或者App有前后台的切换等,SDK都会负责自动重连。
除非您已经手动将连接断开,否则您不需要自己再手动重连。
tokenIncorrectBlock有两种情况:
一是token错误,请您检查客户端初始化使用的AppKey和您服务器获取token使用的AppKey是否一致;
二是token过期,是因为您在开发者后台设置了token过期时间,您需要请求您的服务器重新获取token并再次用新的token建立连接。
@warning 如果您使用IMKit,请使用此方法建立与融云服务器的连接;
如果您使用IMLib,请使用RCIMClient中的同名方法建立与融云服务器的连接,而不要使用此方法。
在tokenIncorrectBlock的情况下,您需要请求您的服务器重新获取token并建立连接,但是注意避免无限循环,以免影响App用户体验。
此方法的回调并非为原调用线程,您如果需要进行UI操作,请注意切换到主线程。
*/
- (void)connectWithToken:(NSString *)token
success:(void (^)(NSString *userId))successBlock
error:(void (^)(RCConnectErrorCode status))errorBlock
tokenIncorrect:(void (^)())tokenIncorrectBlock;
/*!
断开与融云服务器的连接
@param isReceivePush App在断开连接之后,是否还接收远程推送
@discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。
所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。
@warning 如果您使用IMKit,请使用此方法断开与融云服务器的连接;
如果您使用IMLib,请使用RCIMClient中的同名方法断开与融云服务器的连接,而不要使用此方法。
isReceivePush指断开与融云服务器的连接之后,是否还接收远程推送。
[[RCIM sharedRCIM] disconnect:YES]与[[RCIM sharedRCIM] disconnect]完全一致;
[[RCIM sharedRCIM] disconnect:NO]与[[RCIM sharedRCIM] logout]完全一致。
您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。
*/
- (void)disconnect:(BOOL)isReceivePush;
/*!
断开与融云服务器的连接,但仍然接收远程推送
@discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。
所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。
@warning 如果您使用IMKit,请使用此方法断开与融云服务器的连接;
如果您使用IMLib,请使用RCIMClient中的同名方法断开与融云服务器的连接,而不要使用此方法。
[[RCIM sharedRCIM] disconnect:YES]与[[RCIM sharedRCIM] disconnect]完全一致;
[[RCIM sharedRCIM] disconnect:NO]与[[RCIM sharedRCIM] logout]完全一致。
您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。
*/
- (void)disconnect;
/*!
断开与融云服务器的连接,并不再接收远程推送
@discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。
所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。
@warning 如果您使用IMKit,请使用此方法断开与融云服务器的连接;
如果您使用IMLib,请使用RCIMClient中的同名方法断开与融云服务器的连接,而不要使用此方法。
[[RCIM sharedRCIM] disconnect:YES]与[[RCIM sharedRCIM] disconnect]完全一致;
[[RCIM sharedRCIM] disconnect:NO]与[[RCIM sharedRCIM] logout]完全一致。
您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。
*/
- (void)logout;
#pragma mark 连接状态监听
/*!
IMKit连接状态的监听器
@warning 如果您使用IMKit,可以设置并实现此Delegate监听消息接收;
如果您使用IMLib,请使用RCIMClient中的RCIMClientReceiveMessageDelegate监听消息接收,而不要使用此方法。
*/
@property(nonatomic, weak) id connectionStatusDelegate;
/*!
获取当前SDK的连接状态
@return 当前SDK的连接状态
*/
- (RCConnectionStatus)getConnectionStatus;
#pragma mark - 消息接收与发送
/*!
注册自定义的消息类型
@param messageClass 自定义消息的类,该自定义消息需要继承于RCMessageContent
@discussion 如果您需要自定义消息,必须调用此方法注册该自定义消息的消息类型,否则SDK将无法识别和解析该类型消息。
@warning 如果您使用IMKit,请使用此方法注册自定义的消息类型;
如果您使用IMLib,请使用RCIMClient中的同名方法注册自定义的消息类型,而不要使用此方法。
*/
- (void)registerMessageType:(Class)messageClass;
#pragma mark 消息发送
/*!
发送消息(除图片消息外的所有消息),会自动更新UI
@param conversationType 发送消息的会话类型
@param targetId 发送消息的目标会话ID
@param content 消息的内容
@param pushContent 接收方离线时需要显示的远程推送内容
@param pushData 接收方离线时需要在远程推送中携带的非显示数据
@param successBlock 消息发送成功的回调 [messageId:消息的ID]
@param errorBlock 消息发送失败的回调 [nErrorCode:发送失败的错误码, messageId:消息的ID]
@return 发送的消息实体
@discussion 当接收方离线并允许远程推送时,会收到远程推送。
远程推送中包含两部分内容,一是pushContent,用于显示;二是pushData,用于携带不显示的数据。
SDK内置的消息类型,如果您将pushContent和pushData置为nil,会使用默认的推送格式进行远程推送。
自定义类型的消息,需要您自己设置pushContent和pushData来定义推送内容,否则将不会进行远程推送。
@warning 如果您使用IMKit,使用此方法发送消息SDK会自动更新UI;
如果您使用IMLib,请使用RCIMClient中的同名方法发送消息,不会自动更新UI。
*/
- (RCMessage *)sendMessage:(RCConversationType)conversationType
targetId:(NSString *)targetId
content:(RCMessageContent *)content
pushContent:(NSString *)pushContent
pushData:(NSString *)pushData
success:(void (^)(long messageId))successBlock
error:(void (^)(RCErrorCode nErrorCode, long messageId))errorBlock;
/*!
发送图片消息,会自动更新UI
@param conversationType 发送消息的会话类型
@param targetId 发送消息的目标会话ID
@param content 消息的内容
@param pushContent 接收方离线时需要显示的远程推送内容
@param pushData 接收方离线时需要在远程推送中携带的非显示数据
@param progressBlock 消息发送进度更新的回调 [progress:当前的发送进度, 0 <= progress <= 100, messageId:消息的ID]
@param successBlock 消息发送成功的回调 [messageId:消息的ID]
@param errorBlock 消息发送失败的回调 [errorCode:发送失败的错误码, messageId:消息的ID]
@return 发送的消息实体
@discussion 当接收方离线并允许远程推送时,会收到远程推送。
远程推送中包含两部分内容,一是pushContent,用于显示;二是pushData,用于携带不显示的数据。
SDK内置的消息类型,如果您将pushContent和pushData置为nil,会使用默认的推送格式进行远程推送。
自定义类型的消息,需要您自己设置pushContent和pushData来定义推送内容,否则将不会进行远程推送。
@warning 如果您使用IMKit,使用此方法发送图片消息SDK会自动更新UI;
如果您使用IMLib,请使用RCIMClient中的同名方法发送图片消息,不会自动更新UI。
*/
- (RCMessage *)sendImageMessage:(RCConversationType)conversationType
targetId:(NSString *)targetId
content:(RCMessageContent *)content
pushContent:(NSString *)pushContent
pushData:(NSString *)pushData
progress:(void (^)(int progress, long messageId))progressBlock
success:(void (^)(long messageId))successBlock
error:(void (^)(RCErrorCode errorCode, long messageId))errorBlock;
/*!
发起VoIP语音通话
@param targetId 要发起语音通话的对方的用户ID
@discussion 使用此方法,必须要求是带VoIP功能的IMKit SDK
*/
- (void)startVoIPCallWithTargetId:(NSString *)targetId;
#pragma mark 消息接收监听
/*!
IMKit消息接收的监听器
@warning 如果您使用IMKit,可以设置并实现此Delegate监听消息接收;
如果您使用IMLib,请使用RCIMClient中的RCIMClientReceiveMessageDelegate监听消息接收,而不要使用此方法。
*/
@property(nonatomic, weak) id receiveMessageDelegate;
#pragma mark 消息通知提醒
/*!
是否关闭所有的本地通知,默认值是NO
@discussion 当App处于后台时,默认会弹出本地通知提示,您可以通过将此属性设置为YES,关闭所有的本地通知。
*/
@property(nonatomic, assign) BOOL disableMessageNotificaiton;
/*!
是否关闭所有的前台消息提示音,默认值是NO
@discussion 当App处于前台时,默认会播放消息提示音,您可以通过将此属性设置为YES,关闭所有的前台消息提示音。
*/
@property(nonatomic, assign) BOOL disableMessageAlertSound;
/*!
是否开启发送输入状态,默认值是NO,开启之后在输入消息的时候对方可以看到正在输入的提示(目前只支持单聊)
*/
@property(nonatomic, assign) BOOL enableTypingStatus;
/*!
是否开启发送已读回执,默认值是NO,开启之后在会话页面展示对方的消息之后会发送回执给对方(目前只支持单聊)
*/
@property(nonatomic, assign) BOOL enableReadReceipt;
/*!
是否在聊天界面和会话列表界面显示未注册的消息类型,默认值是NO
@discussion App不断迭代开发,可能会在以后的新版本中不断增加某些自定义类型的消息,但是已经发布的老版本无法识别此类消息。
针对这种情况,可以预先定义好未注册的消息的显示,以提升用户体验(如提示当前版本不支持,引导用户升级版本等)
未注册的消息,可以通过RCConversationViewController中的rcUnkownConversationCollectionView:cellForItemAtIndexPath:和rcUnkownConversationCollectionView:layout:sizeForItemAtIndexPath:方法定制在聊天界面的显示。
未注册的消息,可以通过修改unknown_message_cell_tip字符串资源定制在会话列表界面的显示。
*/
@property(nonatomic, assign) BOOL showUnkownMessage;
/*!
未注册的消息类型是否显示本地通知,默认值是NO
@discussion App不断迭代开发,可能会在以后的新版本中不断增加某些自定义类型的消息,但是已经发布的老版本无法识别此类消息。
针对这种情况,可以预先定义好未注册的消息的显示,以提升用户体验(如提示当前版本不支持,引导用户升级版本等)
未注册的消息,可以通过修改unknown_message_notification_tip字符串资源定制本地通知的显示。
*/
@property(nonatomic, assign) BOOL showUnkownMessageNotificaiton;
#pragma mark - 用户信息、群组信息相关
/*!
当前登录的用户的用户信息
@discussion 与融云服务器建立连接之后,应该设置当前用户的用户信息,用于SDK显示和发送。
*/
@property(nonatomic, strong) RCUserInfo *currentUserInfo;
/*!
用户信息提供者
@discussion SDK需要通过您实现的用户信息提供者,获取用户信息并显示。
*/
@property(nonatomic, weak) id userInfoDataSource;
/*!
群组信息提供者
@discussion SDK需要通过您实现的群组信息提供者,获取群组信息并显示。
*/
@property(nonatomic, weak) id groupInfoDataSource;
/*!
群名片信息提供者
@discussion 如果您使用了群名片功能,SDK需要通过您实现的群名片信息提供者,获取用户在群组中的名片信息并显示。
*/
@property(nonatomic, weak) id groupUserInfoDataSource;
/*!
是否在发送的所有消息中携带当前登录的用户信息,默认值为NO
@discussion 如果设置为YES,则会在每一条发送的消息中携带当前登录用户的用户信息。从2.4.1 之后附加用户信息之后cell默认会显示附加的用户信息的头像,即用户信息不会取用户信息提供者里提供的用户信息
需要先设置当前登录用户的用户信息,参考RCIM的currentUserInfo。
*/
@property(nonatomic, assign) BOOL enableMessageAttachUserInfo;
/*!
语音消息的最大长度
@discussion 默认值是60s,有效值为不小于5秒,不大于60秒
*/
@property(nonatomic, assign) NSUInteger maxVoiceDuration;
#pragma mark 用户信息、群组信息缓存
/*!
更新SDK中的用户信息缓存
@param userInfo 需要更新的用户信息
@param userId 需要更新的用户ID
@discussion 使用此方法,可以更新SDK缓存的用户信息。
但是处于性能和使用场景权衡,SDK不会在当前View立即自动刷新(会在切换到其他View的时候再刷新该用户的显示信息)。
如果您想立即刷新,您可以在会话列表或者聊天界面reload强制刷新。
*/
- (void)refreshUserInfoCache:(RCUserInfo *)userInfo
withUserId:(NSString *)userId;
/*!
更新SDK中的群组信息缓存
@param groupInfo 需要更新的群组信息
@param groupId 需要更新的群组ID
@discussion 使用此方法,可以更新SDK缓存的群组信息。
但是处于性能和使用场景权衡,SDK不会在当前View立即自动刷新(会在切换到其他View的时候再刷新该群组的显示信息)。
如果您想立即刷新,您可以在会话列表或者聊天界面reload强制刷新。
*/
- (void)refreshGroupInfoCache:(RCGroup *)groupInfo
withGroupId:(NSString *)groupId;
/*!
更新SDK中的群名片信息缓存
@param userInfo 需要更新的用户信息
@param userId 需要更新的用户ID
@param groupId 需要更新群名片信息的群组ID
@discussion 使用此方法,可以更新SDK缓存的群名片信息。
但是处于性能和使用场景权衡,SDK不会在当前View立即自动刷新(会在切换到其他View的时候再刷新该群名片的显示信息)。
如果您想立即刷新,您可以在会话列表或者聊天界面reload强制刷新。
*/
- (void)refreshGroupUserInfoCache:(RCUserInfo *)userInfo
withUserId:(NSString *)userId
withGroupId:(NSString *)groupId;
/*!
清空SDK中所有的用户信息缓存
@discussion 使用此方法,会清空SDK中所有的用户信息缓存。
但是处于性能和使用场景权衡,SDK不会在当前View立即自动刷新(会在切换到其他View的时候再刷新所显示的用户信息)。
如果您想立即刷新,您可以在会话列表或者聊天界面reload强制刷新。
*/
- (void)clearUserInfoCache;
/*!
清空SDK中所有的群组信息缓存
@discussion 使用此方法,会清空SDK中所有的群组信息缓存。
但是处于性能和使用场景权衡,SDK不会在当前View立即自动刷新(会在切换到其他View的时候再刷新所显示的群组信息)。
如果您想立即刷新,您可以在会话列表或者聊天界面reload强制刷新。
*/
- (void)clearGroupInfoCache;
#pragma mark 头像显示
/*!
SDK中全局的导航按钮字体颜色
@discussion 默认值为[UIColor whiteColor]
*/
@property(nonatomic) UIColor *globalNavigationBarTintColor;
/*!
SDK会话列表界面中显示的头像形状,矩形或者圆形
@discussion 默认值为矩形,即RC_USER_AVATAR_RECTANGLE
*/
@property(nonatomic) RCUserAvatarStyle globalConversationAvatarStyle;
/*!
SDK会话列表界面中显示的头像大小,高度必须大于或者等于36
@discussion 默认值为46*46
*/
@property(nonatomic) CGSize globalConversationPortraitSize;
/*!
SDK聊天界面中显示的头像形状,矩形或者圆形
@discussion 默认值为矩形,即RC_USER_AVATAR_RECTANGLE
*/
@property(nonatomic) RCUserAvatarStyle globalMessageAvatarStyle;
/*!
SDK聊天界面中显示的头像大小
@discussion 默认值为46*46
*/
@property(nonatomic) CGSize globalMessagePortraitSize;
/*!
SDK会话列表界面和聊天界面的头像的圆角曲率半径
@discussion 默认值为4,只有当头像形状设置为矩形时才会生效。
参考RCIM的globalConversationAvatarStyle和globalMessageAvatarStyle。
*/
@property(nonatomic) CGFloat portraitImageViewCornerRadius;
@end
#endif
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCImageMessageCell.h
================================================
//
// RCImageMessageCell.h
// RongIMKit
//
// Created by xugang on 15/2/2.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#import "RCMessageCell.h"
#import "RCImageMessageProgressView.h"
/*!
图片消息Cell
*/
@interface RCImageMessageCell : RCMessageCell
/*!
消息的背景View
*/
@property(nonatomic, strong) UIImageView *bubbleBackgroundView;
/*!
显示图片缩略图的View
*/
@property(nonatomic, strong) UIImageView *pictureView;
/*!
显示发送进度的View
*/
@property(nonatomic, strong) RCImageMessageProgressView *progressView;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCImageMessageProgressView.h
================================================
//
// RCNumberProgressView.h
// RCIM
//
// Created by xugang on 6/5/14.
// Copyright (c) 2014 Heq.Shinoda. All rights reserved.
//
#import
/*!
图片消息进度的View
*/
@interface RCImageMessageProgressView : UIView
/*!
显示进度的Label
*/
@property(nonatomic, assign) UILabel *label;
/*!
进度指示的View
*/
@property(nonatomic, strong) UIActivityIndicatorView *indicatorView;
/*!
更新进度
@param progress 进度值,0 <= progress <= 100
*/
- (void)updateProgress:(NSInteger)progress;
/*!
开始播放动画
*/
- (void)startAnimating;
/*!
停止播放动画
*/
- (void)stopAnimating;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCImagePreviewController.h
================================================
//
// PreviewViewController.h
// RCIM
//
// Created by Heq.Shinoda on 14-5-27.
// Copyright (c) 2014年 Heq.Shinoda. All rights reserved.
//
#import
#import "RCBaseViewController.h"
#import "RCImageMessageProgressView.h"
@class RCMessageModel;
/*!
查看图片消息中的原始图片的ViewController
*/
@interface RCImagePreviewController : RCBaseViewController
/*!
原始图片的View
*/
@property(nonatomic, strong) UIImageView *originalImageView;
/*!
消息的数据模型
*/
@property(nonatomic, strong) RCMessageModel *messageModel;
/*!
图片消息进度的View
*/
@property(nonatomic, strong) RCImageMessageProgressView *rcImageProressView;
/*!
取消按钮的点击事件
@param sender 取消按钮
@discussion SDK在此方法中,会针对默认的NavigationBar退出当前界面;
如果您使用自定义导航按钮或者自定义按钮,可以重写此方法退出当前界面。
*/
- (void)leftBarButtonItemPressed:(id)sender;
/*!
保存按钮的点击事件
@param sender 保存按钮
@discussion SDK在此方法中,默认会进行图片的保存。
*/
- (void)rightBarButtonItemPressed:(id)sender;
/*!
图片下载完成的回调
*/
- (void)imageDownloadDone;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCKitUtility.h
================================================
//
// RCKitUtility.h
// iOS-IMKit
//
// Created by xugang on 7/7/14.
// Copyright (c) 2014 Heq.Shinoda. All rights reserved.
//
#import
#import
#import
/*!
IMKit工具类
*/
@interface RCKitUtility : NSObject
/*!
时间转换
@param secs Unix时间戳(秒)
@return 可视化的时间字符串
@discussion 如果该时间是今天的,则返回值为"HH:mm"格式的字符串;
如果该时间是昨天的,则返回字符串资源中Yesterday对应语言的字符串;
如果该时间是昨天之前或者今天之后的,则返回"yyyy-MM-dd"的字符串。
*/
+ (NSString *)ConvertMessageTime:(long long)secs;
/*!
时间转换
@param secs Unix时间戳(秒)
@return 可视化的时间字符串
@discussion 如果该时间是今天的,则返回值为"HH:mm"格式的字符串;
如果该时间是昨天的,则返回"Yesterday HH:mm"的字符串(其中,Yesterday为字符串资源中Yesterday对应语言的字符串);
如果该时间是昨天之前或者今天之后的,则返回"yyyy-MM-dd HH:mm"的字符串。
*/
+ (NSString *)ConvertChatMessageTime:(long long)secs;
/*!
获取资源包中的图片
@param name 图片名
@param bundleName 图片所在的Bundle名
@return 图片
*/
+ (UIImage *)imageNamed:(NSString *)name ofBundle:(NSString *)bundleName;
/*!
获取指定颜色的图片
@param color 颜色值
@return 坐标为(0.0f, 0.0f, 1.0f, 1.0f)的纯色图片
*/
+ (UIImage *)createImageWithColor:(UIColor *)color;
/*!
获取消息内容的摘要
@param messageContent 消息内容
@return 消息内容的摘要
@discussion SDK默认的消息有内置的处理,
自定义消息会调用RCMessageContent中RCMessageContentView协议的conversationDigest获取消息摘要。
*/
+ (NSString *)formatMessage:(RCMessageContent *)messageContent;
/*!
以消息的类型名为Key值在字符串资源中查找对应语言的字符串
@param messageContent 消息内容
@return 对应语言的字符串
*/
+ (NSString *)localizedDescription:(RCMessageContent *)messageContent;
/*!
获取消息对应的本地消息Dictionary
@param message 消息实体
@return 本地通知的Dictionary
*/
+ (NSDictionary *)getNotificationUserInfoDictionary:(RCMessage *)message;
/*!
获取消息对应的本地消息Dictionary(已废弃,请勿使用)
@param conversationType 会话类型
@param fromUserId 发送者的用户ID
@param targetId 消息的目标会话ID
@param messageContent 消息内容
@return 本地通知的Dictionary
@warning **已废弃,请勿使用。**
*/
+ (NSDictionary *)getNotificationUserInfoDictionary:(RCConversationType)conversationType fromUserId:(NSString *)fromUserId targetId:(NSString *)targetId messageContent:(RCMessageContent *)messageContent
__deprecated_msg("已废弃,请勿使用。");
/*!
获取消息对应的本地消息Dictionary
@param conversationType 会话类型
@param fromUserId 发送者的用户ID
@param targetId 消息的目标会话ID
@param objectName 消息的类型名
@return 本地通知的Dictionary
*/
+ (NSDictionary *)getNotificationUserInfoDictionary:(RCConversationType)conversationType fromUserId:(NSString *)fromUserId targetId:(NSString *)targetId objectName:(NSString *)objectName;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCLocationMessageCell.h
================================================
//
// RCLocationMessageCell.h
// RongIMKit
//
// Created by xugang on 15/2/2.
// Copyright (c) 2015年 RongCloud. All rights reserved.
//
#import "RCMessageCell.h"
#import "RCImageMessageProgressView.h"
/*!
位置消息Cell
*/
@interface RCLocationMessageCell : RCMessageCell
/*!
消息的背景View
*/
@property(nonatomic, strong) UIImageView *bubbleBackgroundView;
/*!
当前位置在地图中的概览图
*/
@property(nonatomic, strong) UIImageView *pictureView;
/*!
显示位置名称的Label
*/
@property(nonatomic, strong) UILabel *locationNameLabel;
@end
================================================
FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCLocationPickerViewController.h
================================================
//
// RCLocationPickerViewController.h
// iOS-IMKit
//
// Created by YangZigang on 14/10/31.
// Copyright (c) 2014年 RongCloud. All rights reserved.
//
#import "RCBaseViewController.h"
#import
#import
#import
/*!
POI搜索结束后的回调block
@param pois 需要显示的POI列表
@param clearPreviousResult 如果地图位置已经发生变化,需要清空之前的POI数据
@param hasMore 如果POI数据很多,可以进行“更多”显示
@param error 搜索POI出现错误时,返回错误信息
*/
typedef void (^OnPoiSearchResult)(NSArray *pois, BOOL clearPreviousResult, BOOL hasMore, NSError *error);
@protocol RCLocationPickerViewControllerDelegate;
@protocol RCLocationPickerViewControllerDataSource;
/*!
地理位置选取的ViewController
*/
@interface RCLocationPickerViewController
: RCBaseViewController
/*!
地理位置选择完成之后的回调
*/
@property(nonatomic, weak) id delegate;
/*!
位置选择的数据源
*/
@property(nonatomic, strong) id dataSource;
/*!
mapViewContainer
*/
@property(nonatomic, strong) IBOutlet UIView *mapViewContainer;
/*!
初始化地理位置选取的ViewController
@param dataSource 位置选择的数据源
@return 地理位置选取的ViewController对象
*/
- (instancetype)initWithDataSource:(id)dataSource;
/*!
退出当前界面
@param sender 返回按钮
@discussion SDK在此方法中,会针对默认的NavigationBar退出当前界面;
如果您使用自定义导航按钮或者自定义按钮,可以重写此方法退出当前界面。
*/
- (void)leftBarButtonItemPressed:(id)sender;
/*!
完成位置获取
@param sender 完成按钮
@discussion 点击完成按钮的后会调用本函数。
*/
- (void)rightBarButtonItemPressed:(id)sender;
@end
/*!
位置选择的数据源
*/
@protocol RCLocationPickerViewControllerDataSource
@optional
/*!
获取显示的地图控件
@return 在界面上显示的地图控件
*/
- (UIView *)mapView;
/*!
获取显示的中心点标记
@return 界面上显示的中心点标记
@discussion 如不想显示中心点标记,可以返回nil。
*/
- (CALayer *)annotationLayer;
/*!
获取位置标注的名称
@param placeMark 位置标注
@return 位置标注的名称
*/
- (NSString *)titleOfPlaceMark:(id)placeMark;
/*!
获取位置标注的坐标
@param placeMark 位置标注
@return 位置标注的二维坐标值
*/
- (CLLocationCoordinate2D)locationCoordinate2DOfPlaceMark:(id)placeMark;
/*!
设置地图显示的中心点坐标
@param location 中心点坐标
@param animated 是否开启动画效果
*/
- (void)setMapViewCenter:(CLLocationCoordinate2D)location animated:(BOOL)animated;
/*!
设置地图显示区域
@param coordinateRegion 地图显示区域
@param animated 是否开启动画效果
*/
- (void)setMapViewCoordinateRegion:(MKCoordinateRegion)coordinateRegion animated:(BOOL)animated;
/*!
选择位置标示
@param placeMark 选择的位置标注
@discussion 开发者自己实现的RCLocationPickerViewControllerDataSource可以据此进行特定处理。
当有新的POI列表时,默认选中第一个。
*/
- (void)userSelectPlaceMark:(id)placeMark;
/*!
获取地图当前中心点的坐标
@return 当前地图中心点
*/
- (CLLocationCoordinate2D)mapViewCenter;
/*!
设置POI搜索完毕后的回调
@param poiSearchResult POI查询结果
*/
- (void)setOnPoiSearchResult:(OnPoiSearchResult)poiSearchResult;
/*!
获取当前视野中POI
*/
- (void)beginFetchPoisOfCurrentLocation;
/*!
获取位置在地图中的缩略图
@return 位置在地图中的缩略图
*/
- (UIImage *)mapViewScreenShot;
@end
/*!
地理位置选择完成之后的回调
*/
@protocol RCLocationPickerViewControllerDelegate