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 [![star this repo](http://github-svg-buttons.herokuapp.com/star.svg?user=Urinx&repo=SublimeCode&style=flat&background=1081C1)](http://github.com/Urinx/SublimeCode) [![fork this repo](http://github-svg-buttons.herokuapp.com/fork.svg?user=Urinx&repo=SublimeCode&style=flat&background=1081C1)](http://github.com/Urinx/SublimeCode/fork) [![license](https://img.shields.io/github/license/Urinx/SublimeCode.svg)](https://github.com/Urinx/SublimeCode/blob/master/LICENSE) ![platform](https://img.shields.io/badge/platform-iOS 9-lightgrey.svg) [![download](https://img.shields.io/github/downloads/Urinx/SublimeCode/total.svg)](https://github.com/Urinx/SublimeCode/releases) 一个代码阅读应用 - iOS ### 屏幕截图 ![main](Screenshot/main.png) ## 功能说明 ### 代码阅读 支持多种编程语言的语法高亮,全屏阅读模式,以及支持生成图片的形式分享代码到朋友圈等。 ![Code Reading](Screenshot/code_reading.png) ### 多种文件支持 支持查看多种格式的文件类型,包括图片,视频,音频,PDF等。 ![Multi File Support](Screenshot/multi_file_support.png) ### Github支持 现在你可以在本应用里浏览Github里自己的项目和Star的项目了,也能够下载到本地离线阅读代码哟!是不是很方便呢。 ![Github](Screenshot/github.png) ### 本地HTTP服务器 还可以是一个本地HTTP服务器哦,支持Log纪录,在手机上方便的与朋友分享自己的网页。 ![HTTP Server](Screenshot/http_server.png) ### Cycript支持 Cycript是混合了objective-c与javascript语法的一个工具,让开发者在命令行下和应用交互,在运行时查看和修改应用。而我们的应用也集成了Cycript,是不是很酷炫呢!小伙伴们赶快来体验吧。 ![Cycript](Screenshot/cycript.png) ### 乱七八糟的功能 是的,你还可以像朋友圈一样的浏览Gist,还能SSH到自己的服务器,以及RSS订阅,与Github好友聊天,二维码扫描等等。没有做不到,只有想不到。 ![Other](Screenshot/other.png) ### 以及更多 其实里面还有超级多的功能等待着你去探索和发现,在关于页面里摇一摇还有彩蛋哟!如果你有好的想法和建议也可以告诉我们,说不定下次就加进去了呢。 ### 如何安装 鉴于该应用没有上架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 ![Screenshot](screenshot.gif) ## 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 ================================================ ![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/Alamofire/Alamofire/assets/alamofire.png) [![Build Status](https://travis-ci.org/Alamofire/Alamofire.svg)](https://travis-ci.org/Alamofire/Alamofire) [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg)](https://img.shields.io/cocoapods/v/Alamofire.svg) [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Platform](https://img.shields.io/cocoapods/p/Alamofire.svg?style=flat)](http://cocoadocs.org/docsets/Alamofire) [![Twitter](https://img.shields.io/badge/twitter-@AlamofireSF-blue.svg?style=flat)](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 [![CI Status](http://img.shields.io/travis/AdeptusAstartes/AlamofireRSSParser.svg?style=flat)](https://travis-ci.org/AdeptusAstartes/AlamofireRSSParser) [![Version](https://img.shields.io/cocoapods/v/AlamofireRSSParser.svg?style=flat)](http://cocoapods.org/pods/AlamofireRSSParser) [![License](https://img.shields.io/cocoapods/l/AlamofireRSSParser.svg?style=flat)](http://cocoapods.org/pods/AlamofireRSSParser) [![Platform](https://img.shields.io/cocoapods/p/AlamofireRSSParser.svg?style=flat)](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) ![alt tag](https://raw.github.com/danielgindi/Charts/master/Assets/feature_graphic.png) ![Supported Platforms](https://img.shields.io/cocoapods/p/Charts.svg) [![Releases](https://img.shields.io/github/release/danielgindi/Charts.svg)](https://github.com/danielgindi/Charts/releases) [![Latest pod release](https://img.shields.io/cocoapods/v/Charts.svg)](http://cocoapods.org/pods/charts) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/danielgindi/Charts.svg?branch=master)](https://travis-ci.org/danielgindi/Charts) [![Join the chat at https://gitter.im/danielgindi/Charts](https://badges.gitter.im/danielgindi/Charts.svg)](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:) * [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](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 [![Doc-Percent](https://img.shields.io/cocoapods/metrics/doc-percent/Charts.svg)](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)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart4.png) - **LineChart (with legend, simple design)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart3.png) - **LineChart (cubic lines)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/cubiclinechart.png) - **LineChart (gradient fill)** ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/line_chart_gradient.png) - **Combined-Chart (bar- and linechart in this case)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/combined_chart.png) - **BarChart (with legend, simple design)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_barchart3.png) - **BarChart (grouped DataSets)** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/groupedbarchart.png) - **Horizontal-BarChart** ![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/horizontal_barchart.png) - **PieChart (with selection, ...)** ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/simpledesign_piechart1.png) - **ScatterChart** (with squares, triangles, circles, ... and more) ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/scatterchart.png) - **CandleStickChart** (for financial data) ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/candlestickchart.png) - **BubbleChart** (area covered by bubbles indicates the value) ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/bubblechart.png) - **RadarChart** (spider web chart) ![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/radarchart.png) 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/). ![](https://raw.githubusercontent.com/gontovnik/DGElasticPullToRefresh/master/DGElasticPullToRefreshPreview1.gif) ![](https://raw.githubusercontent.com/gontovnik/DGElasticPullToRefresh/master/DGElasticPullToRefreshPreview2.gif) ## 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 ================================================ ![alt text](https://s3-us-west-1.amazonaws.com/ezaudio-media/EZAudioJumbo-Alt.png "EZAudioLogo") #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 ![alt text](https://s3-us-west-1.amazonaws.com/ezaudio-media/EZAudioSummary.png "EZAudioFeatures") **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. ![alt text](https://s3-us-west-1.amazonaws.com/ezaudio-media/fftMacExample.png) ### 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 ================================================ # ![Gifu](https://db.tt/mZ1iMNXO) 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 /*! 地理位置选择完成之后的回调 @param locationPicker 地理位置选取的ViewController @param location 位置的二维坐标 @param locationName 位置的名称 @param mapScreenShot 位置在地图中的缩略图 @discussion 如果您需要重写地理位置选择的界面,当选择地理位置完成后,需要调用此回调通知RCConversationViewController定位已完成,可以进一步生成位置消息并发送。 */ - (void)locationPicker:(RCLocationPickerViewController *)locationPicker didSelectLocation:(CLLocationCoordinate2D)location locationName:(NSString *)locationName mapScreenShot:(UIImage *)mapScreenShot; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCLocationViewController.h ================================================ // // RCLocationViewController.h // iOS-IMKit // // Created by YangZigang on 14/11/4. // Copyright (c) 2014年 RongCloud. All rights reserved. // #import "RCBaseViewController.h" #import #import /*! 在地图中展示位置消息的ViewController */ @interface RCLocationViewController : RCBaseViewController /*! 位置信息中的地理位置的二维坐标 */ @property(nonatomic, assign) CLLocationCoordinate2D location; /*! 位置消息中的地理位置的名称 */ @property(nonatomic, strong) NSString *locationName; /*! 返回按钮的点击事件 @param sender 返回按钮 @discussion SDK在此方法中,会针对默认的NavigationBa退出当前界面; 如果您使用自定义导航按钮或者自定义按钮,可以重写此方法退出当前界面。 */ - (void)leftBarButtonItemPressed:(id)sender; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageBaseCell.h ================================================ // // RCMessageBaseCell.h // RongIMKit // // Created by xugang on 15/1/28. // Copyright (c) 2015年 RongCloud. All rights reserved. // #ifndef __RCMessageBaseCell #define __RCMessageBaseCell #import #import #import "RCMessageModel.h" #import "RCMessageCellNotificationModel.h" #import "RCMessageCellDelegate.h" #import "RCTipLabel.h" /*! 消息发送状态更新的Notification */ UIKIT_EXTERN NSString *const KNotificationMessageBaseCellUpdateSendingStatus; #define TIME_LABEL_HEIGHT 20 /*! 消息Cell基类 @discussion 消息Cell基类包含了所有消息Cell的必要信息。 消息Cell基类针对用户头像是否显示,主要可以分为两类的: 一是提醒类的Cell,不显示用户信息,如:RCTipMessageCell和RCUnknownMessageCell; 二是展示类的Cell,显示用户信息和内容,如:RCMessageCell以及RCMessageCell的子类。 */ @interface RCMessageBaseCell : UICollectionViewCell /*! 消息Cell点击回调 */ @property(nonatomic, weak) id delegate; /*! 显示时间的Label */ @property(strong, nonatomic) RCTipLabel *messageTimeLabel; /*! 消息Cell的数据模型 */ @property(strong, nonatomic) RCMessageModel *model; /*! Cell显示的View */ @property(strong, nonatomic) UIView *baseContentView; /*! 消息的方向 */ @property(nonatomic) RCMessageDirection messageDirection; /*! 时间Label是否显示 */ @property(nonatomic, readonly) BOOL isDisplayMessageTime; /*! 是否显示阅读状态 */ @property(nonatomic) BOOL isDisplayReadStatus; /*! 初始化消息Cell @param frame 显示的Frame @return 消息Cell基类对象 */ - (instancetype)initWithFrame:(CGRect)frame; /*! 设置当前消息Cell的数据模型 @param model 消息Cell的数据模型 */ - (void)setDataModel:(RCMessageModel *)model; /*! 消息发送状态更新的监听回调 @param notification 消息发送状态更新的Notification */ - (void)messageCellUpdateSendingStatusEvent:(NSNotification *)notification; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageBubbleTipView.h ================================================ // // RCMessageBubbleTipView.h // RCIM // // Created by xugang on 14-6-20. // Copyright (c) 2014年 xugang. All rights reserved. // #import /*! 角标的位置 */ typedef NS_ENUM(NSInteger, RCMessageBubbleTipViewAlignment) { /*! 左上 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_TOP_LEFT, /*! 右上 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_TOP_RIGHT, /*! 中上 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_TOP_CENTER, /*! 左中 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_CENTER_LEFT, /*! 右中 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_CENTER_RIGHT, /*! 左下 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_BOTTOM_LEFT, /*! 右下 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_BOTTOM_RIGHT, /*! 中下 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_BOTTOM_CENTER, /*! 正中 */ RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_CENTER }; /*! 消息未读提示角标的View */ @interface RCMessageBubbleTipView : UIView /*! 角标显示的文本 */ @property(nonatomic, copy) NSString *bubbleTipText; /*! 角标的位置 @discussion 默认值为RC_MESSAGE_BUBBLE_TIP_VIEW_ALIGNMENT_TOP_RIGHT,即右上。 */ @property(nonatomic, assign) RCMessageBubbleTipViewAlignment bubbleTipAlignment; /*! 角标文本的颜色 */ @property(nonatomic, strong) UIColor *bubbleTipTextColor; /*! 角标文本的阴影值 */ @property(nonatomic, assign) CGSize bubbleTipTextShadowOffset; /*! 角标文本的阴影颜色 */ @property(nonatomic, strong) UIColor *bubbleTipTextShadowColor; /*! 角标文本的字体 */ @property(nonatomic, strong) UIFont *bubbleTipTextFont; /*! 角标的背景颜色 */ @property(nonatomic, strong) UIColor *bubbleTipBackgroundColor; /*! 角标的覆盖颜色(已废弃,请勿使用) @warning **已废弃,请勿使用。** */ @property(nonatomic, strong) __deprecated_msg("已废弃,请勿使用。") UIColor *bubbleTipOverlayColor; /*! 角标View偏移的Rect */ @property(nonatomic, assign) CGPoint bubbleTipPositionAdjustment; /*! 角标依附于的View Rect */ @property(nonatomic, assign) CGRect frameToPositionInRelationWith; /*! 角标是否显示数字 @discussion 如果为NO,会显示红点,不显示具体数字。 */ @property(nonatomic) BOOL isShowNotificationNumber; /*! 初始化角标View @param parentView 角标依附于的View @param alignment 角标的位置 @return 角标View对象 */ - (instancetype)initWithParentView:(UIView *)parentView alignment:(RCMessageBubbleTipViewAlignment)alignment; /*! 设置角标的值 @param msgCount 角标值 */ - (void)setBubbleTipNumber:(int)msgCount; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageCell.h ================================================ // // RCMessageCommonCell.h // RongIMKit // // Created by xugang on 15/1/28. // Copyright (c) 2015年 RongCloud. All rights reserved. // #ifndef __RCMessageCommonCell #define __RCMessageCommonCell #import "RCMessageBaseCell.h" #import "RCThemeDefine.h" #import "RCMessageCellNotificationModel.h" #import "RCMessageCellDelegate.h" #import "RCContentView.h" //#define PORTRAIT_WIDTH 45 //#define PORTRAIT_HEIGHT 45 @class RCloudImageView; /*! 展示的消息Cell类 @discussion 需要展示用户信息和内容的消息Cell可以继承此类, 如:RCTextMessageCell、RCImageMessageCell、RCLocationMessageCell、RCVoiceMessageCell、RCRichContentMessageCell等。 如果您需要显示自定义消息,可以继承此类。 */ @interface RCMessageCell : RCMessageBaseCell /*! 消息发送者的用户头像 */ @property(nonatomic, strong) RCloudImageView *portraitImageView; /*! 消息发送者的用户名称 */ @property(nonatomic, strong) UILabel *nicknameLabel; /*! 消息内容的View */ @property(nonatomic, strong) RCContentView *messageContentView; /*! 显示发送状态的View @discussion 其中包含messageFailedStatusView子View。 */ @property(nonatomic, strong) UIView *statusContentView; /*! 显示发送失败状态的View */ @property(nonatomic, strong) UIButton *messageFailedStatusView; /*! 消息发送指示View */ @property(nonatomic, strong) UIActivityIndicatorView *messageActivityIndicatorView; /*! 消息内容的View的宽度 */ @property(nonatomic, readonly) CGFloat messageContentViewWidth; /*! 显示的用户头像形状 */ @property(nonatomic, assign, setter=setPortraitStyle:) RCUserAvatarStyle portraitStyle; /*! 是否显示用户名称 */ @property(nonatomic, readonly) BOOL isDisplayNickname; /*! 显示消息已阅读状态的View */ @property(nonatomic, strong) UIView *messageHasReadStatusView; /*! 显示消息发送成功状态的View */ @property(nonatomic, strong) UIView *messageSendSuccessStatusView; /*! 设置当前消息Cell的数据模型 @param model 消息Cell的数据模型 */ - (void)setDataModel:(RCMessageModel *)model; /*! 更新消息发送状态 @param model 消息Cell的数据模型 */ - (void)updateStatusContentView:(RCMessageModel *)model; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageCellDelegate.h ================================================ // // RCMessageCellDelegate.h // RongIMKit // // Created by xugang on 3/14/15. // Copyright (c) 2015 RongCloud. All rights reserved. // #ifndef RongIMKit_RCMessageCellDelegate_h #define RongIMKit_RCMessageCellDelegate_h #import "RCMessageModel.h" /*! 消息Cell点击的回调 */ @protocol RCMessageCellDelegate @optional /*! 点击Cell内容的回调 @param model 消息Cell的数据模型 */ - (void)didTapMessageCell:(RCMessageModel *)model; /*! 点击Cell中URL的回调 @param url 点击的URL @param model 消息Cell的数据模型 @discussion 点击Cell中的URL,会调用此回调,不会再触发didTapMessageCell:。 */ - (void)didTapUrlInMessageCell:(NSString *)url model:(RCMessageModel *)model; /*! 点击Cell中电话号码的回调 @param phoneNumber 点击的电话号码 @param model 消息Cell的数据模型 @discussion 点击Cell中的电话号码,会调用此回调,不会再触发didTapMessageCell:。 */ - (void)didTapPhoneNumberInMessageCell:(NSString *) phoneNumber model:(RCMessageModel *)model; /*! 点击Cell中用户头像的回调 @param userId 头像对应的用户ID */ - (void)didTapCellPortrait:(NSString *)userId; /*! 长按Cell中用户头像的回调 @param userId 头像对应的用户ID */ - (void)didLongPressCellPortrait:(NSString *)userId; /*! 长按Cell内容的回调 @param model 消息Cell的数据模型 @param view 长按区域的View */ - (void)didLongTouchMessageCell:(RCMessageModel *)model inView:(UIView *)view; /*! 点击消息发送失败红点的回调 @param model 消息Cell的数据模型 */ - (void)didTapmessageFailedStatusViewForResend:(RCMessageModel *)model; @end /*! 公众服务会话中消息Cell点击的回调 */ @protocol RCPublicServiceMessageCellDelegate @optional /*! 公众服务会话中,点击Cell内容的回调 @param model 消息Cell的数据模型 */ - (void)didTapPublicServiceMessageCell:(RCMessageModel *)model; /*! 公众服务会话中,点击Cell中URL的回调 @param url 点击的URL @param model 消息Cell的数据模型 @discussion 点击Cell中的URL,会调用此回调,不会再触发didTapMessageCell:。 */ - (void)didTapUrlInPublicServiceMessageCell:(NSString *)url model:(RCMessageModel *)model; /*! 公众服务会话中,点击Cell中电话号码的回调 @param phoneNumber 点击的电话号码 @param model 消息Cell的数据模型 @discussion 点击Cell中的电话号码,会调用此回调,不会再触发didTapMessageCell:。 */ - (void)didTapPhoneNumberInPublicServiceMessageCell:(NSString *) phoneNumber model:(RCMessageModel *)model; /*! 公众服务会话中,长按Cell内容的回调 @param model 消息Cell的数据模型 @param view 长按区域的View */ - (void)didLongTouchPublicServiceMessageCell:(RCMessageModel *)model inView:(UIView *)view; /*! 公众服务会话中,点击消息发送失败红点的回调 @param model 消息Cell的数据模型 */ - (void)didTapPublicServiceMessageFailedStatusViewForResend:(RCMessageModel *)model; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageCellNotificationModel.h ================================================ // // RCMessageCellNotificationModel.h // RongIMKit // // Created by xugang on 15/1/29. // Copyright (c) 2015年 RongCloud. All rights reserved. // #ifndef __RCMessageCellNotificationModel #define __RCMessageCellNotificationModel #import // 消息Cell需要更新的状态名 UIKIT_EXTERN NSString *const CONVERSATION_CELL_STATUS_SEND_BEGIN; UIKIT_EXTERN NSString *const CONVERSATION_CELL_STATUS_SEND_FAILED; UIKIT_EXTERN NSString *const CONVERSATION_CELL_STATUS_SEND_SUCCESS; UIKIT_EXTERN NSString *const CONVERSATION_CELL_STATUS_SEND_PROGRESS; UIKIT_EXTERN NSString *const CONVERSATION_CELL_DATA_IMAGE_KEY_UPDATE; UIKIT_EXTERN NSString *const CONVERSATION_CELL_STATUS_SEND_HASREAD; #import /*! 消息Cell状态更新通知的数据模型 */ @interface RCMessageCellNotificationModel : NSObject /*! 消息ID */ @property(nonatomic) long messageId; /*! 更新的状态名 */ @property(strong, nonatomic) NSString *actionName; /*! 进度 */ @property(nonatomic) NSInteger progress; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCMessageModel.h ================================================ // // RongMessageModel.h // RongIMKit // // Created by xugang on 15/1/22. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import #import /*! 消息Cell的数据模型类 */ @interface RCMessageModel : NSObject /*! 是否显示时间 */ @property(nonatomic, assign) BOOL isDisplayMessageTime; /*! 是否显示用户名 */ @property(nonatomic, assign) BOOL isDisplayNickname; /*! 用户信息 */ @property(nonatomic, strong) RCUserInfo *userInfo; /*! 会话类型 */ @property(nonatomic, assign) RCConversationType conversationType; /*! 目标会话ID */ @property(nonatomic, strong) NSString *targetId; /*! 消息ID */ @property(nonatomic, assign) long messageId; /*! 消息方向 */ @property(nonatomic, assign) RCMessageDirection messageDirection; /*! 发送者的用户ID */ @property(nonatomic, strong) NSString *senderUserId; /*! 消息的接收状态 */ @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 *objectName; /*! 消息的内容 */ @property(nonatomic, strong) RCMessageContent *content; /*! 消息的附加字段 */ @property(nonatomic, strong) NSString *extra; /*! 消息展示时的Cell高度 @discussion 用于大量消息的显示优化 */ @property(nonatomic) CGSize cellSize; /*! 初始化消息Cell的数据模型 @param rcMessage 消息实体 @return 消息Cell的数据模型对象 */ - (instancetype)initWithMessage:(RCMessage *)rcMessage; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCPluginBoardView.h ================================================ // // RCPluginBoard.h // CollectionViewTest // // Created by Liv on 15/3/15. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import @protocol RCPluginBoardViewDelegate; /*! 输入扩展功能板的View */ @interface RCPluginBoardView : UICollectionView /*! 当前所有的扩展项 */ @property(nonatomic, strong) NSMutableArray *allItems; /*! 扩展功能板的点击回调 */ @property(nonatomic, weak) id pluginBoardDelegate; /*! 向扩展功能板中插入扩展项 @param image 扩展项的展示图片 @param title 扩展项的展示标题 @param index 需要添加到的索引值 @param tag 扩展项的唯一标示符 @discussion 您以在RCConversationViewController的viewdidload后,添加自定义的扩展项。 SDK默认的扩展项的唯一标示符为1XXX,我们建议您在自定义扩展功能时不要选用1XXX,以免与SDK预留的扩展项唯一标示符重复。 */ - (void)insertItemWithImage:(UIImage*)image title:(NSString*)title atIndex:(NSInteger)index tag:(NSInteger)tag; /*! 添加扩展项到扩展功能板,并在显示为最后一项 @param image 扩展项的展示图片 @param title 扩展项的展示标题 @param tag 扩展项的唯一标示符 @discussion 您以在RCConversationViewController的viewdidload后,添加自定义的扩展项。 SDK默认的扩展项的唯一标示符为1XXX,我们建议您在自定义扩展功能时不要选用1XXX,以免与SDK预留的扩展项唯一标示符重复。 */ -(void)insertItemWithImage:(UIImage*)image title:(NSString*)title tag:(NSInteger)tag; /*! 更新指定扩展项 @param index 扩展项的索引值 @param image 扩展项的展示图片 @param title 扩展项的展示标题 */ -(void)updateItemAtIndex:(NSInteger)index image:(UIImage*)image title:(NSString*)title; /*! 更新指定扩展项 @param tag 扩展项的唯一标示符 @param image 扩展项的展示图片 @param title 扩展项的展示标题 */ -(void)updateItemWithTag:(NSInteger)tag image:(UIImage*)image title:(NSString*)title; /*! 删除扩展功能板中的指定扩展项 @param index 指定扩展项的索引值 */ - (void)removeItemAtIndex:(NSInteger)index; /*! 删除扩展功能板中的指定扩展项 @param tag 指定扩展项的唯一标示符 */ - (void)removeItemWithTag:(NSInteger)tag; /*! 删除扩展功能板中的所有扩展项 */ - (void)removeAllItems; @end /*! 扩展功能板的点击回调 */ @protocol RCPluginBoardViewDelegate /*! 点击扩展功能板中的扩展项的回调 @param pluginBoardView 当前扩展功能板 @param tag 点击的扩展项的唯一标示符 */ -(void)pluginBoardView:(RCPluginBoardView*)pluginBoardView clickedItemWithTag:(NSInteger)tag; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCPublicServiceChatViewController.h ================================================ // // RCPublicServiceChatViewController.h // RongIMKit // // Created by litao on 15/6/12. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import #import "RCConversationViewController.h" /*! 公众服务聊天界面的ViewController */ @interface RCPublicServiceChatViewController : RCConversationViewController /*! 点击富文本(图文)消息中URL的回调 @param tapedUrl 点击的URL @param rcWebViewController 已包含融云JS鉴权的WebViewController @discussion SDK在回调中默认会使用WebView打开URL,您可以重写此回调。 此回调中的rcWebViewController,已经包含了融云公众账号的JS鉴权,您在重写时可以直接使用此WebView来显示URL。 */ - (void)didTapImageTxtMsgCell:(NSString *)tapedUrl webViewController:(UIViewController *)rcWebViewController; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCPublicServiceListViewController.h ================================================ // // RCPublicServiceListViewController.h // RongIMKit // // Created by litao on 15/4/20. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import /*! 已关注公众服务账号列表的展示ViewController */ @interface RCPublicServiceListViewController : UITableViewController @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCPublicServiceProfileViewController.h ================================================ // // RCPublicServiceProfileViewController.h // HelloIos // // Created by litao on 15/4/10. // Copyright (c) 2015年 litao. All rights reserved. // #import #import #import "RCThemeDefine.h" /*! 公众服务账号信息中的URL点击回调 */ @protocol RCPublicServiceProfileViewUrlDelegate /*! 点击公众服务账号信息的URL回调 @param url 点击的URL */ - (void)gotoUrl:(NSString *)url; @end /*! 公众服务账号信息的ViewController */ @interface RCPublicServiceProfileViewController : UITableViewController /*! 公众服务账号信息 */ @property(nonatomic, strong) RCPublicServiceProfile *serviceProfile; /*! 头像显示的形状 */ @property(nonatomic) RCUserAvatarStyle portraitStyle; /*! 当前界面的是否源于聊天会话界面 */ @property(nonatomic) BOOL fromConversation; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCPublicServiceSearchViewController.h ================================================ // // RCPublicServiceSearchViewController.h // RongIMKit // // Created by litao on 15/4/21. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import /*! 查找公众服务账号的ViewController */ @interface RCPublicServiceSearchViewController : UITableViewController @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCRichContentMessageCell.h ================================================ // // RCRichContentMessageCell.h // RongIMKit // // Created by xugang on 15/2/2. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageCell.h" #import "RCAttributedLabel.h" #define RichContent_Title_Font_Size 16 #define RichContent_Message_Font_Size 12 #define RICH_CONTENT_THUMBNAIL_WIDTH 60 #define RICH_CONTENT_THUMBNAIL_HIGHT 60 /*! 富文本(图文)消息Cell */ @interface RCRichContentMessageCell : RCMessageCell /*! 消息的背景View */ @property(nonatomic, strong) UIImageView *bubbleBackgroundView; /*! 图片内容显示的View */ @property(nonatomic, strong) RCloudImageView *richContentImageView; /*! 文本内容显示的Label */ @property(nonatomic, strong) RCAttributedLabel *digestLabel; /*! 标题显示的Label */ @property(nonatomic, strong) RCAttributedLabel *titleLabel; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCSettingViewController.h ================================================ // // RCSettingController.h // RongIMKit // // Created by Liv on 15/4/20. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import #import "RCConversationSettingTableViewController.h" /*! 清空会话中所有消息的回调 @param isSuccess 是否删除会话中的所有消息 */ typedef void (^clearHistory)(BOOL isSuccess); /*! 会话设置的ViewController */ @interface RCSettingViewController : RCConversationSettingTableViewController /*! 当前会话的目标会话ID */ @property(nonatomic, copy) NSString *targetId; /*! 当前会话的会话类型 */ @property(nonatomic, assign) RCConversationType conversationType; /*! 清空会话中所有消息的回调 @discussion 在清空消息的的回调中,您需要调用聊天界面的reloadData进行刷新。 */ @property(nonatomic, copy) clearHistory clearHistoryCompletion; /*! 默认的Cell @discussion 内置置顶聊天、新消息通、清除消息记录三个cell */ @property(nonatomic, readonly, strong) NSArray *defaultCells; /*! 清空会话中所有消息的ActionSheet */ @property(nonatomic, readonly, strong) UIActionSheet *clearMsgHistoryActionSheet; /*! 清空会话中所有消息 */ - (void)clearHistoryMessage; /*! 点击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; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCTextMessageCell.h ================================================ // // RCTextMessageCell.h // RongIMKit // // Created by xugang on 15/2/2. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageCell.h" #import "RCAttributedLabel.h" #define Text_Message_Font_Size 16 /*! 文本消息Cell */ @interface RCTextMessageCell : RCMessageCell /*! 显示消息内容的Label */ @property(strong, nonatomic) RCAttributedLabel *textLabel; /*! 消息的背景View */ @property(nonatomic, strong) UIImageView *bubbleBackgroundView; /*! 设置当前消息Cell的数据模型 @param model 消息Cell的数据模型 */ - (void)setDataModel:(RCMessageModel *)model; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCTextView.h ================================================ // // RCTextView.h // iOS-IMKit // // Created by Liv on 14/10/30. // Copyright (c) 2014年 RongCloud. All rights reserved. // #import /*! 文本输入框的View */ @interface RCTextView : UITextView /*! 是否关闭菜单 @discussion 默认值为NO。 */ @property(nonatomic, assign) BOOL disableActionMenu; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCThemeDefine.h ================================================ // // RCThemeDefine.h // iOS-IMKit // // Created by xugang on 14-9-19. // Copyright (c) 2014年 Heq.Shinoda. All rights reserved. // #ifndef iOS_IMKit_RCThemeDefine_h #define iOS_IMKit_RCThemeDefine_h /*! 头像显示的形状 */ typedef NS_ENUM(NSInteger, RCUserAvatarStyle) { /*! 矩形 */ RC_USER_AVATAR_RECTANGLE = 0, /*! 圆形 */ RC_USER_AVATAR_CYCLE }; #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCTipLabel.h ================================================ // // RCMessageTipLabel.h // iOS-IMKit // // Created by Gang Li on 10/27/14. // Copyright (c) 2014 RongCloud. All rights reserved. // #ifndef __RCTipLabel #define __RCTipLabel #import #import "RCAttributedLabel.h" /*! 灰条提示Label */ @interface RCTipLabel : RCAttributedLabel /*! 边缘间隙 */ @property(nonatomic, assign) UIEdgeInsets marginInsets; /*! 初始化灰条提示Label对象 @return 灰条提示Label对象 */ + (instancetype)greyTipLabel; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCTipMessageCell.h ================================================ // // RCTipMessageCell.h // RongIMKit // // Created by xugang on 15/1/29. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageBaseCell.h" /*! 提示消息Cell */ @interface RCTipMessageCell : RCMessageBaseCell /*! 提示的Label */ @property(strong, nonatomic) RCTipLabel *tipMessageLabel; /*! 设置当前消息Cell的数据模型 @param model 消息Cell的数据模型 */ - (void)setDataModel:(RCMessageModel *)model; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCUnknownMessageCell.h ================================================ // // RCUnknownMessageCell.h // RongIMKit // // Created by xugang on 3/31/15. // Copyright (c) 2015 RongCloud. All rights reserved. // #ifndef __RCUnknownMessageCell #define __RCUnknownMessageCell #import /*! 未知消息Cell */ @interface RCUnknownMessageCell : RCMessageBaseCell /*! 提示的Label */ @property(strong, nonatomic) RCTipLabel *messageLabel; /*! 设置当前消息Cell的数据模型 @param model 消息Cell的数据模型 */ - (void)setDataModel:(RCMessageModel *)model; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RCVoiceMessageCell.h ================================================ // // RCVoiceMessageCell.h // RongIMKit // // Created by xugang on 15/2/2. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageCell.h" #define kAudioBubbleMinWidth 70 #define kAudioBubbleMaxWidth 180 #define kBubbleBackgroundViewHeight 36 /*! 语音消息播放停止的Notification */ UIKIT_EXTERN NSString *const kNotificationStopVoicePlayer; /*! 语音消息Cell */ @interface RCVoiceMessageCell : RCMessageCell /*! 消息的背景View */ @property(nonatomic, strong) UIImageView *bubbleBackgroundView; /*! 语音播放的View */ @property(nonatomic, strong) UIImageView *playVoiceView; /*! 显示是否已播放的View */ @property(nonatomic, strong) UIImageView *voiceUnreadTagView; /*! 显示语音时长的Label */ @property(nonatomic, strong) UILabel *voiceDurationLabel; /*! 播放语音 */ - (void)playVoice; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/Headers/RongIMKit.h ================================================ // // RongIMKit.h // RongIMKit // // Created by xugang on 15/1/13. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import //! Project version number for RongIMKit. FOUNDATION_EXPORT double RongIMKitVersionNumber; //! Project version string for RongIMKit. FOUNDATION_EXPORT const unsigned char RongIMKitVersionString[]; /// IMKit核心类 #import /// 会话列表相关类 #import #import /// 聊天界面相关类 #import #import #import #import #import /// 会话列表Cell相关类 #import #import #import /// 消息Cell相关类 #import #import #import #import #import #import #import #import #import #import #import #import #import /// 工具类 #import #import /// 其他 #import #import #import #import #import #import #import #import #import ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMKit.framework/RongIMKit ================================================ [File too large to display: 19.3 MB] ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCAMRDataConverter.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCAmrDataConverter.h // Created by Heq.Shinoda on 14-6-17. #ifndef __RCAmrDataConverter #define __RCAmrDataConverter #import #include #include #include #include "interf_dec.h" #include "interf_enc.h" /*! AMR格式与WAV格式音频转换工具类 */ @interface RCAMRDataConverter : NSObject /*! 获取AMR格式与WAV格式音频转换工具类单例 @return AMR格式与WAV格式音频转换工具类单例 */ + (RCAMRDataConverter *)sharedAMRDataConverter; /*! 将AMR格式的音频数据转化为WAV格式的音频数据 @param data AMR格式的音频数据,必须是AMR-NB的格式 @return WAV格式的音频数据 */ - (NSData *)decodeAMRToWAVE:(NSData *)data; /*! 将WAV格式的音频数据转化为AMR格式的音频数据(8KHz采样) @param data WAV格式的音频数据 @param nChannels 声道数 @param nBitsPerSample 采样位数(精度) @return AMR-NB格式的音频数据 @discussion 此方法为工具类方法,您可以使用此方法将任意WAV音频转换为AMR-NB格式的音频。 @warning 如果您想和SDK自带的语音消息保持一致和互通,考虑到跨平台和传输的原因,SDK对于WAV音频有所限制. 具体可以参考RCVoiceMessage中的音频参数说明(nChannels为1,nBitsPerSample为16)。 */ - (NSData *)encodeWAVEToAMR:(NSData *)data channel:(int)nChannels nBitsPerSample:(int)nBitsPerSample; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCChatRoomInfo.h ================================================ // // RCChatRoomInfo.h // RongIMLib // // Created by 岑裕 on 16/1/11. // Copyright © 2016年 RongCloud. All rights reserved. // #import #import "RCStatusDefine.h" /*! 聊天室信息类 */ @interface RCChatRoomInfo : NSObject /*! 聊天室ID */ @property(nonatomic, strong) NSString *targetId; /*! 包含的成员信息类型 */ @property(nonatomic, assign) RCChatRoomMemberOrder memberOrder; /*! 聊天室中的部分成员信息RCChatRoomMemberInfo列表 @discussion 如果成员类型为RC_ChatRoom_Member_Asc,则为最早加入的成员列表,按成员加入时间升序排列; 如果成员类型为RC_ChatRoom_Member_Desc,则为最晚加入的成员列表,按成员加入时间升序排列。 */ @property(nonatomic, strong) NSArray *memberInfoArray; /*! 当前聊天室的成员总数 */ @property(nonatomic, assign) int totalMemberCount; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCChatRoomMemberInfo.h ================================================ // // RCChatRoomMemberInfo.h // RongIMLib // // Created by 岑裕 on 16/1/10. // Copyright © 2016年 RongCloud. All rights reserved. // #import /*! 聊天室成员信息类 */ @interface RCChatRoomMemberInfo : NSObject /*! 用户ID */ @property(nonatomic, strong) NSString *userId; /*! 加入时间(Unix时间戳,毫秒) */ @property(nonatomic,assign) long long joinTime; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCCommandMessage.h ================================================ // // RCCommandMessage.h // RongIMLib // // Created by 张改红 on 15/12/2. // Copyright © 2015年 RongCloud. All rights reserved. // #import "RCMessageContent.h" /*! 命令消息的类型名 */ #define RCCommandMessageIdentifier @"RC:CmdMsg" /*! 命令消息类 @discussion 命令消息类,此消息不存储不计入未读消息数。 与RCCommandNotificationMessage的区别是,此消息不存储,也不会在界面上显示。 */ @interface RCCommandMessage : RCMessageContent /*! 命令的名称 */ @property(nonatomic, strong) NSString *name; /*! 命令的扩展数据 @discussion 命令的扩展数据,可以为任意字符串,如存放您定义的json数据。 */ @property(nonatomic, strong) NSString *data; /*! 初始化命令消息 @param name 命令的名称 @param data 命令的扩展数据 @return 命令消息对象 */ + (instancetype)messageWithName:(NSString *)name data:(NSString *)data; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCCommandNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCCommandNotificationMessage.h // Created by xugang on 14/11/28. #import "RCMessageContent.h" /*! 命令提醒消息的类型名 */ #define RCCommandNotificationMessageIdentifier @"RC:CmdNtf" /*! 命令提醒消息类 @discussion 命令消息类,此消息会进行存储,但不计入未读消息数。 与RCCommandMessage的区别是,此消息会进行存储并在界面上显示。 */ @interface RCCommandNotificationMessage : RCMessageContent /*! 命令提醒的名称 */ @property(nonatomic, strong) NSString *name; /*! 命令提醒消息的扩展数据 @discussion 命令提醒消息的扩展数据,可以为任意字符串,如存放您定义的json数据。 */ @property(nonatomic, strong) NSString *data; /*! 初始化命令提醒消息 @param name 命令的名称 @param data 命令的扩展数据 @return 命令提醒消息对象 */ + (instancetype)notificationWithName:(NSString *)name data:(NSString *)data; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCContactNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCContactNotificationMessage.h // Created by xugang on 14/11/28. #import "RCMessageContent.h" /*! 好友请求消息的类型名 */ #define RCContactNotificationMessageIdentifier @"RC:ContactNtf" /*! 请求添加好友 */ #define ContactNotificationMessage_ContactOperationRequest @"Request" /*! 同意添加好友的请求 */ #define ContactNotificationMessage_ContactOperationAcceptResponse @"AcceptResponse" /*! 拒绝添加好友的请求 */ #define ContactNotificationMessage_ContactOperationRejectResponse @"RejectResponse" /*! 好友请求消息类 @discussion 好友请求消息类,此消息会进行存储,但不计入未读消息数。 */ @interface RCContactNotificationMessage : RCMessageContent /*! 好友请求的当前操作名 @discussion 好友请求当前的操作名称,您可以使用预定义好的操作名,也可以是您自己定义的任何操作名。 预定义的操作名:ContactNotificationMessage_ContactOperationRequest、ContactNotificationMessage_ContactOperationAcceptResponse、ContactNotificationMessage_ContactOperationRejectResponse。 */ @property(nonatomic, strong) NSString *operation; /*! 当前操作发起用户的用户ID */ @property(nonatomic, strong) NSString *sourceUserId; /*! 当前操作目标用户的用户ID */ @property(nonatomic, strong) NSString *targetUserId; /*! 当前操作的消息内容 @discussion 当前操作的消息内容,如同意、拒绝的理由等。 */ @property(nonatomic, strong) NSString *message; /*! 当前操作的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化好友请求消息 @param operation 好友请求当前的操作名 @param sourceUserId 当前操作发起用户的用户ID @param targetUserId 当前操作目标用户的用户ID @param message 当前操作的消息内容 @param extra 当前操作的附加信息 @return 好友请求消息对象 @discussion 融云不介入您的好友关系,所有的好友关系都由您的服务器自己维护。 所以好友请求的操作名和消息内容、扩展信息您均可以自己定制,只要您发送方和接收方针对具体字段内容做好UI显示即可。 */ + (instancetype)notificationWithOperation:(NSString *)operation sourceUserId:(NSString *)sourceUserId targetUserId:(NSString *)targetUserId message:(NSString *)message extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCConversation.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCConversation.h // Created by Heq.Shinoda on 14-6-13. #import #import "RCMessageContent.h" /*! 会话类 @discussion 会话类,包含会话的所有属性。 */ @interface RCConversation : NSObject /*! 会话类型 */ @property(nonatomic, assign) RCConversationType conversationType; /*! 目标会话ID */ @property(nonatomic, strong) NSString *targetId; /*! 会话的标题 */ @property(nonatomic, strong) NSString *conversationTitle; /*! 会话中的未读消息数量 */ @property(nonatomic, assign) int unreadMessageCount; /*! 是否置顶,默认值为NO @discussion 如果设置了置顶,在IMKit的RCConversationListViewController中会将此会话置顶显示。 */ @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; /*! 最后一条消息的全局唯一ID @discussion 服务器消息唯一ID(在同一个Appkey下全局唯一) */ @property(nonatomic, strong) NSString *lastestMessageUId; /*! RCConversation初始化方法(已废弃,请勿使用) @param json 会话的json Dictionary @return 会话对象 @warning **已废弃,请勿使用。** */ + (instancetype)conversationWithProperties:(NSDictionary *)json __deprecated_msg("已废弃,请勿使用。"); @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCDiscussion.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCDiscussion.h // Created by Heq.Shinoda on 14-6-23. #ifndef __RCDiscussion #define __RCDiscussion #import /*! 讨论组类 */ @interface RCDiscussion : NSObject /*! 讨论组ID */ @property(nonatomic, strong) NSString *discussionId; /*! 讨论组名称 */ @property(nonatomic, strong) NSString *discussionName; /*! 讨论组的创建者的用户ID */ @property(nonatomic, strong) NSString *creatorId; /*! 讨论组成员的用户ID列表 */ @property(nonatomic, strong) NSArray *memberIdList; /*! 讨论组是否开放加人权限 @discussion 是否允许非创建者添加用户,0表示允许,1表示不允许,默认值为0。 */ @property(nonatomic, assign) int inviteStatus; /*! 讨论组的会话类型(已废弃,请勿使用) @warning **已废弃,请勿使用。** */ @property(nonatomic, assign) __deprecated_msg("已废弃,请勿使用。") int conversationType; /*! 讨论组是否允许消息提醒(已废弃,请勿使用) @warning **已废弃,请勿使用。** */ @property(nonatomic, assign) __deprecated_msg("已废弃,请勿使用。") int pushMessageNotificationStatus; /*! 讨论组初始化方法 @param discussionId 讨论组ID @param discussionName 讨论组名称 @param creatorId 创建者的用户ID @param conversationType 会话类型 @param memberIdList 讨论组成员的用户ID列表 @param inviteStatus 是否开放加人权限 @param pushMessageNotificationStatus 是否允许消息提醒 @return 讨论组对象 */ - (instancetype)initWithDiscussionId:(NSString *)discussionId discussionName:(NSString *)discussionName creatorId:(NSString *)creatorId conversationType:(int)conversationType memberIdList:(NSArray *)memberIdList inviteStatus:(int)inviteStatus msgNotificationStatus:(int)pushMessageNotificationStatus; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCDiscussionNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCDiscussionNotification.h // Created by Heq.Shinoda on 14-6-26. #import "RCMessageContent.h" /*! 讨论组通知消息的类型名 */ #define RCDiscussionNotificationTypeIdentifier @"RC:DizNtf" /*! 讨论组通知的类型 */ typedef NS_ENUM(NSInteger, RCDiscussionNotificationType) { /*! 有成员加入讨论组的通知 */ RCInviteDiscussionNotification = 1, /*! 有成员退出讨论组的通知 */ RCQuitDiscussionNotification, /*! 讨论组名称发生变更的通知 */ RCRenameDiscussionTitleNotification, /*! 有成员被踢出讨论组的通知 */ RCRemoveDiscussionMemberNotification, /*! 讨论组加入权限的变更 */ RCSwichInvitationAccessNotification }; /*! 讨论组通知消息类 @discussion 讨论组通知消息类,此消息会进行存储,但不计入未读消息数。 */ @interface RCDiscussionNotificationMessage : RCMessageContent /*! 讨论组通知的类型 */ @property(nonatomic, assign) RCDiscussionNotificationType type; /*! 操作者的用户ID */ @property(nonatomic, strong) NSString *operatorId; /*! 讨论组通知的扩展信息 */ @property(nonatomic, strong) NSString *extension; /*! 初始化讨论组通知消息 @param type 讨论组通知的扩展信息 @param operatorId 操作者的用户ID @param extension 讨论组通知的扩展信息 @return 讨论组通知对象 */ + (instancetype)notificationWithType:(RCDiscussionNotificationType)type operator:(NSString *)operatorId extension:(NSString *)extension; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCGroup.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCGroup.h // Created by Heq.Shinoda on 14-9-6. #import /*! 群组信息类 */ @interface RCGroup : NSObject /*! 群组ID */ @property(nonatomic, strong) NSString *groupId; /*! 群组名称 */ @property(nonatomic, strong) NSString *groupName; /*! 群组头像的URL */ @property(nonatomic, strong) NSString *portraitUri; /*! 群组信息的初始化方法 @param groupId 群组ID @param groupName 群组名称 @param portraitUri 群组头像的URL @return 群组信息对象 */ - (instancetype)initWithGroupId:(NSString *)groupId groupName:(NSString *)groupName portraitUri:(NSString *)portraitUri; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCGroupNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCGroupNotification.h // Created by xugang on 14/11/24. #import "RCMessageContent.h" /*! 群组通知消息的类型名 */ #define RCGroupNotificationMessageIdentifier @"RC:GrpNtf" /*! 有成员加入群组的通知 */ #define GroupNotificationMessage_GroupOperationAdd @"Add" /*! 有成员退出群组的通知 */ #define GroupNotificationMessage_GroupOperationQuit @"Quit" /*! 有成员被踢出群组的通知 */ #define GroupNotificationMessage_GroupOperationKicked @"Kicked" /*! 群组名称发生变更的通知 */ #define GroupNotificationMessage_GroupOperationRename @"Rename" /*! 群组公告发生变更的通知 */ #define GroupNotificationMessage_GroupOperationBulletin @"Bulletin" /*! 群组通知消息类 @discussion 群组通知消息类,此消息会进行存储,但不计入未读消息数。 */ @interface RCGroupNotificationMessage : RCMessageContent /*! 群组通知的当前操作名 @discussion 群组通知的当前操作名称,您可以使用预定义好的操作名,也可以是您自己定义的任何操作名。 预定义的操作名:GroupNotificationMessage_GroupOperationAdd、GroupNotificationMessage_GroupOperationQuit、GroupNotificationMessage_GroupOperationKicked、GroupNotificationMessage_GroupOperationRename、GroupNotificationMessage_GroupOperationBulletin。 */ @property(nonatomic, strong) NSString *operation; /*! 当前操作发起用户的用户ID */ @property(nonatomic, strong) NSString *operatorUserId; /*! 当前操作的目标对象 @discussion 当前操作的目标对象,如被当前操作目标用户的用户ID或变更后的群主名称等。 */ @property(nonatomic, strong) NSString *data; /*! 当前操作的消息内容 */ @property(nonatomic, strong) NSString *message; /*! 当前操作的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化群组通知消息 @param operation 群组通知的当前操作名 @param operatorUserId 当前操作发起用户的用户ID @param data 当前操作的目标对象 @param message 当前操作的消息内容 @param extra 当前操作的附加信息 @return 群组通知消息对象 @discussion 群组关系有开发者文虎,所有的群组操作都由您的服务器自己管理和维护。 所以群组通知的操作名和目标对象、消息内容、扩展信息您均可以自己定制,只要您发送方和接收方针对具体字段内容做好UI显示即可。 */ + (instancetype)notificationWithOperation:(NSString *)operation operatorUserId:(NSString *)operatorUserId data:(NSString *)data message:(NSString *)message extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCHandShakeMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCHandShakeMessage.h // Created by Heq.Shinoda on 14-6-30. #import "RCMessageContent.h" /*! 客服握手消息的类型名 */ #define RCHandShakeMessageTypeIdentifier @"RC:HsMsg" /*! 客服握手消息类 @discussion 客服握手消息类,此消息不存储不计入未读消息数。 给客服发送消息之前,可以向客服发送一条此消息,客服服务器即可获取当前的用户ID或用户信息。 */ @interface RCHandShakeMessage : RCMessageContent /*! 初始化客服握手消息 @return 客服握手消息的对象 */ - (instancetype)init; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCIMClient.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RongIMClient.h // Created by xugang on 14/12/23. #ifndef __RongIMClient #define __RongIMClient #import #import #import "RCStatusDefine.h" #import "RCMessage.h" #import "RCUserInfo.h" #import "RCPublicServiceProfile.h" #import "RCWatchKitStatusDelegate.h" #import "RCUploadImageStatusListener.h" #import "RCConversation.h" #import "RCDiscussion.h" #import "RCChatRoomInfo.h" #pragma mark - 消息接收监听器 /*! IMlib消息接收的监听器 @discussion 设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。 @warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收; 如果您使用IMKit,请使用RCIM中的RCIMReceiveMessageDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI! */ @protocol RCIMClientReceiveMessageDelegate /*! 接收消息的回调方法 @param message 当前接收到的消息 @param nLeft 还剩余的未接收的消息数,left>=0 @param object 消息监听设置的key值 @discussion 如果您设置了IMlib消息监听之后,SDK在接收到消息时候会执行此方法。 其中,left为还剩余的、还未接收的消息数量。比如刚上线一口气收到多条消息时,通过此方法,您可以获取到每条消息,left会依次递减直到0。 您可以根据left数量来优化您的App体验和性能,比如收到大量消息时等待left为0再刷新UI。 object为您在设置消息接收监听时的key值。 */ - (void)onReceived:(RCMessage *)message left:(int)nLeft object:(id)object; @end #pragma mark - 连接状态监听器 /*! IMLib连接状态的的监听器 @discussion 设置IMLib的连接状态监听器,请参考RCIMClient的setRCConnectionStatusChangeDelegate:方法。 @warning 如果您使用IMLib,可以设置并实现此Delegate监听消息接收; 如果您使用IMKit,请使用RCIM中的RCIMConnectionStatusDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI! */ @protocol RCConnectionStatusChangeDelegate /*! IMLib连接状态的的监听器 @param status SDK与融云服务器的连接状态 @discussion 如果您设置了IMLib消息监听之后,当SDK与融云服务器的连接状态发生变化时,会回调此方法。 */ - (void)onConnectionStatusChanged:(RCConnectionStatus)status; @end #pragma mark - 输入状态监听器 /*! IMLib输入状态的的监听器 @discussion 设置IMLib的输入状态监听器,请参考RCIMClient的setRCTypingStatusDelegate:方法。 @warning 如果您使用IMLib,可以设置并实现此Delegate监听消息接收; 如果您使用IMKit,请直接设置RCIM中的enableSendComposingStatus,而不要使用此监听器,否则会导致IMKit中无法自动更新UI! */ @protocol RCTypingStatusDelegate /*! 用户输入状态变化的回调 @param conversationType 会话类型 @param targetId 会话目标ID @param userTypingStatusList 正在输入的RCUserTypingStatus列表(nil标示当前没有用户正在输入) @discussion 当客户端收到用户输入状态的变化时,会回调此接口,通知发生变化的会话以及当前正在输入的RCUserTypingStatus列表。 @warning 目前仅支持单聊。 */ - (void)onTypingStatusChanged:(RCConversationType)conversationType targetId:(NSString *)targetId status:(NSArray *)userTypingStatusList; @end #pragma mark - IMLib核心类 /*! 融云IMLib核心类 @discussion 您需要通过sharedRCIMClient方法,获取单例对象。 */ @interface RCIMClient : NSObject /*! 获取融云通讯能力库IMLib的核心类单例 @return 融云通讯能力库IMLib的核心类单例 @discussion 您可以通过此方法,获取IMLib的单例,访问对象中的属性和方法. */ + (instancetype)sharedRCIMClient; #pragma mark - SDK初始化 /*! 初始化融云SDK @param appKey 从融云开发者平台创建应用后获取到的App Key @discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。 在App整个生命周期中,您只需要执行一次初始化。 @warning 如果您使用IMLib,请使用此方法初始化SDK; 如果您使用IMKit,请使用RCIM中的initWithAppKey:方法初始化,而不要使用此方法。 **升级说明:** **从2.4.1版本开始,为了兼容Swift的风格与便于使用,将此方法升级为initWithAppKey:方法,方法的功能和使用均不变。** */ - (void)init:(NSString *)appKey; /*! 初始化融云SDK @param appKey 从融云开发者平台创建应用后获取到的App Key @discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。 在App整个生命周期中,您只需要执行一次初始化。 **升级说明:** **从2.4.1版本开始,为了兼容Swift的风格与便于使用,将原有的init:方法升级为此方法,方法的功能和使用均不变。** @warning 如果您使用IMLib,请使用此方法初始化SDK; 如果您使用IMKit,请使用RCIM中的同名方法初始化,而不要使用此方法。 */ - (void)initWithAppKey:(NSString *)appKey; /*! 设置deviceToken,用于远程推送 @param deviceToken 从系统获取到的设备号deviceToken(需要去掉空格和尖括号) @discussion deviceToken是系统提供的,从苹果服务器获取的,用于APNs远程推送必须使用的设备唯一值。 您需要将-application:didRegisterForRemoteNotificationsWithDeviceToken:获取到的deviceToken,转为NSString类型,并去掉其中的空格和尖括号,作为参数传入此方法。 如: - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *token = [deviceToken description]; token = [token stringByReplacingOccurrencesOfString:@"<" withString:@""]; token = [token stringByReplacingOccurrencesOfString:@">" withString:@""]; token = [token stringByReplacingOccurrencesOfString:@" " withString:@""]; [[RCIMClient sharedRCIMClient] setDeviceToken:token]; } */ - (void)setDeviceToken:(NSString *)deviceToken; #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 如果您使用IMLib,请使用此方法建立与融云服务器的连接; 如果您使用IMKit,请使用RCIM中的同名方法建立与融云服务器的连接,而不要使用此方法。 在tokenIncorrectBlock的情况下,您需要请求您的服务器重新获取token并建立连接,但是注意避免无限循环,以免影响App用户体验。 此方法的回调并非为原调用线程,您如果需要进行UI操作,请注意切换到主线程。 */ - (void)connectWithToken:(NSString *)token success:(void (^)(NSString *userId))successBlock error:(void (^)(RCConnectErrorCode status))errorBlock tokenIncorrect:(void (^)())tokenIncorrectBlock; ///*! // 重新建立与服务器的连接 // // @param successBlock 重新连接成功的回调 // @param errorBlock 重新连接失败的回调 // // @warning 升级说明:从2.2.3版本开始,删除此方法。 // SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性,不需要App手动进行重连操作。 // */ //- (void)reconnect:(void (^)(NSString *userId))successBlock // error:(void (^)(RCConnectErrorCode status))errorBlock; /*! 断开与融云服务器的连接 @param isReceivePush App在断开连接之后,是否还接收远程推送 @discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。 所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。 @warning 如果您使用IMLib,请使用此方法断开与融云服务器的连接; 如果您使用IMKit,请使用RCIM中的同名方法断开与融云服务器的连接,而不要使用此方法。 isReceivePush指断开与融云服务器的连接之后,是否还接收远程推送。 [[RCIMClient sharedRCIMClient] disconnect:YES]与[[RCIMClient sharedRCIMClient] disconnect]完全一致; [[RCIMClient sharedRCIMClient] disconnect:NO]与[[RCIMClient sharedRCIMClient] logout]完全一致。 您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。 */ - (void)disconnect:(BOOL)isReceivePush; /*! 断开与融云服务器的连接,但仍然接收远程推送 @discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。 所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。 @warning 如果您使用IMLib,请使用此方法断开与融云服务器的连接; 如果您使用IMKit,请使用RCIM中的同名方法断开与融云服务器的连接,而不要使用此方法。 [[RCIMClient sharedRCIMClient] disconnect:YES]与[[RCIMClient sharedRCIMClient] disconnect]完全一致; [[RCIMClient sharedRCIMClient] disconnect:NO]与[[RCIMClient sharedRCIMClient] logout]完全一致。 您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。 */ - (void)disconnect; /*! 断开与融云服务器的连接,并不再接收远程推送 @discussion 因为SDK在前后台切换或者网络出现异常都会自动重连,会保证连接的可靠性。 所以除非您的App逻辑需要登出,否则一般不需要调用此方法进行手动断开。 @warning 如果您使用IMKit,请使用此方法断开与融云服务器的连接; 如果您使用IMLib,请使用RCIMClient中的同名方法断开与融云服务器的连接,而不要使用此方法。 [[RCIMClient sharedRCIMClient] disconnect:YES]与[[RCIMClient sharedRCIMClient] disconnect]完全一致; [[RCIMClient sharedRCIMClient] disconnect:NO]与[[RCIMClient sharedRCIMClient] logout]完全一致。 您只需要按照您的需求,使用disconnect:与disconnect以及logout三个接口其中一个即可。 */ - (void)logout; #pragma mark - 连接状态监听 /*! 设置IMLib的连接状态监听器 @param delegate IMLib连接状态监听器 @warning 如果您使用IMLib,可以设置并实现此Delegate监听消息接收; 如果您使用IMKit,请使用RCIM中的connectionStatusDelegate监听连接状态变化,而不要使用此方法,否则会导致IMKit中无法自动更新UI! */ - (void)setRCConnectionStatusChangeDelegate: (id)delegate; /*! 获取当前SDK的连接状态 @return 当前SDK的连接状态 */ - (RCConnectionStatus)getConnectionStatus; /*! 获取当前的网络状态 @return 当前的网路状态 */ - (RCNetworkStatus)getCurrentNetworkStatus; /*! SDK当前所处的运行状态 */ @property(nonatomic, assign, readonly) RCSDKRunningMode sdkRunningMode; #pragma mark - Apple Watch状态监听 /*! 用于Apple Watch的IMLib事务监听器 */ @property(nonatomic, strong) id watchKitStatusDelegate; #pragma mark - 用户信息 /*! 当前登录用户的用户信息 @discussion 与融云服务器建立连接之后,应该设置当前用户的用户信息。 @warning 如果您使用IMLib,请使用此字段设置当前登录用户的用户信息; 如果您使用IMKit,请使用RCIM中的currentUserInfo设置当前登录用户的用户信息,而不要使用此字段。 */ @property(nonatomic, strong) RCUserInfo *currentUserInfo; /*! 从融云服务器获取用户信息(已废弃,请勿使用) @param userId 用户ID @param successBlock 获取用户信息成功的回调 [userInfo:获取到的用户信息] @param errorBlock 获取用户信息失败的回调 [status:失败的错误码] @warning **已废弃,请勿使用。** */ - (void)getUserInfo:(NSString *)userId success:(void (^)(RCUserInfo *userInfo))successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); #pragma mark - 消息接收与发送 /*! 注册自定义的消息类型 @param messageClass 自定义消息的类,该自定义消息需要继承于RCMessageContent @discussion 如果您需要自定义消息,必须调用此方法注册该自定义消息的消息类型,否则SDK将无法识别和解析该类型消息。 @warning 如果您使用IMLib,请使用此方法注册自定义的消息类型; 如果您使用IMKit,请使用RCIM中的同名方法注册自定义的消息类型,而不要使用此方法。 */ - (void)registerMessageType:(Class)messageClass; #pragma mark 消息发送 /*! 发送消息 @param conversationType 发送消息的会话类型 @param targetId 发送消息的目标会话ID @param content 消息的内容 @param pushContent 接收方离线时需要显示的远程推送内容 @param successBlock 消息发送成功的回调 [messageId:消息的ID] @param errorBlock 息发送失败的回调 [nErrorCode:发送失败的错误码, messageId:消息的ID] @return 发送的消息实体 @discussion 当接收方离线并允许远程推送时,会收到远程推送。 远程推送中包含两部分内容,一是pushContent,用于显示;二是pushData,用于携带不显示的数据。 SDK内置的消息类型,如果您将pushContent和pushData置为nil,会使用默认的推送格式进行远程推送。 自定义类型的消息,需要您自己设置pushContent和pushData来定义推送内容,否则将不会进行远程推送。 使此方法会将pushData设置为nil,如果需要设置pushData可以使用RCIMClient的 sendMessage:targetId:content:pushContent:pushData:success:error:方法。 如果您使用此方法发送图片消息,需要您自己实现图片的上传,然后构建一个RCImageMessage对象, 并将RCImageMessage中的imageUrl字段设置为最终上传的地址,使用此方法发送。 @warning 如果您使用IMLib,可以使用此方法发送消息; 如果您使用IMKit,请使用RCIM中的同名方法发送消息,否则不会自动更新UI。 */ - (RCMessage *)sendMessage:(RCConversationType)conversationType targetId:(NSString *)targetId content:(RCMessageContent *)content pushContent:(NSString *)pushContent success:(void (^)(long messageId))successBlock error:(void (^)(RCErrorCode nErrorCode, long messageId))errorBlock; /*! 发送消息 @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来定义推送内容,否则将不会进行远程推送。 如果您使用此方法发送图片消息,需要您自己实现图片的上传,构建一个RCImageMessage对象, 并将RCImageMessage中的imageUrl字段设置为上传成功的URL地址,然后使用此方法发送。 @warning 如果您使用IMLib,可以使用此方法发送消息; 如果您使用IMKit,请使用RCIM中的同名方法发送消息,否则不会自动更新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; /*! 发送图片消息 @param conversationType 发送消息的会话类型 @param targetId 发送消息的目标会话ID @param content 消息的内容 @param pushContent 接收方离线时需要显示的远程推送内容 @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来定义推送内容,否则将不会进行远程推送。 使此方法会将pushData设置为nil,如果需要设置pushData可以使用RCIMClient的 sendImageMessage:targetId:content:pushContent:pushData:progress:success:error:方法。 如果您需要上传图片到自己的服务器并使用IMLib,构建一个RCImageMessage对象, 并将RCImageMessage中的imageUrl字段设置为上传成功的URL地址,然后使用RCIMClient的 sendMessage:targetId:content:pushContent:pushData:success:error:方法 或sendMessage:targetId:content:pushContent:success:error:方法进行发送,不要使用此方法。 @warning 如果您使用IMKit,使用此方法发送图片消息SDK会自动更新UI; 如果您使用IMLib,请使用RCIMClient中的同名方法发送图片消息,不会自动更新UI。 */ - (RCMessage *)sendImageMessage:(RCConversationType)conversationType targetId:(NSString *)targetId content:(RCMessageContent *)content pushContent:(NSString *)pushContent progress:(void (^)(int progress, long messageId))progressBlock success:(void (^)(long messageId))successBlock error:(void (^)(RCErrorCode errorCode, long messageId))errorBlock; /*! 发送图片消息 @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来定义推送内容,否则将不会进行远程推送。 如果您需要上传图片到自己的服务器,构建一个RCImageMessage对象, 并将RCImageMessage中的imageUrl字段设置为上传成功的URL地址,然后使用RCIMClient的 sendMessage:targetId:content:pushContent:pushData:success:error:方法 或sendMessage:targetId:content:pushContent:success:error:方法进行发送,不要使用此方法。 @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; /*! 发送图片消息(上传图片到指定的服务器) @param conversationType 发送消息的会话类型 @param targetId 发送消息的目标会话ID @param content 消息的内容 @param pushContent 接收方离线时需要显示的远程推送内容 @param pushData 接收方离线时需要在远程推送中携带的非显示数据 @param uploadPrepareBlock 图片上传进度更新的IMKit监听 [uploadListener:当前的发送进度监听,SDK通过此监听更新IMKit UI] @param progressBlock 消息发送进度更新的回调 [progress:当前的发送进度, 0 <= progress <= 100, messageId:消息的ID] @param successBlock 消息发送成功的回调 [messageId:消息的ID] @param errorBlock 消息发送失败的回调 [errorCode:发送失败的错误码, messageId:消息的ID] @return 发送的消息实体 @discussion 此方法仅用于IMKit。 如果您需要上传图片到自己的服务器并使用IMLib,构建一个RCImageMessage对象, 并将RCImageMessage中的imageUrl字段设置为上传成功的URL地址,然后使用RCIMClient的 sendMessage:targetId:content:pushContent:pushData:success:error:方法 或sendMessage:targetId:content:pushContent:success:error:方法进行发送,不要使用此方法。 */ - (RCMessage *)sendImageMessage:(RCConversationType)conversationType targetId:(NSString *)targetId content:(RCMessageContent *)content pushContent:(NSString *)pushContent pushData:(NSString *)pushData uploadPrepare:(void (^)(RCUploadImageStatusListener *uploadListener))uploadPrepareBlock progress:(void (^)(int progress, long messageId))progressBlock success:(void (^)(long messageId))successBlock error:(void (^)(RCErrorCode errorCode, long messageId))errorBlock; /*! 发送状态消息 @param conversationType 会话类型 @param targetId 目标会话ID @param content 消息内容 @param successBlock 发送消息成功的回调 [messageId:消息的ID] @param errorBlock 发送消息失败的回调 [nErrorCode:发送失败的错误码, messageId:消息的ID] @discussion 通过此方法发送的消息,根据接收方的状态进行投递。 如果接收方不在线,则不会收到远程推送,再上线也不会收到此消息。 */ - (RCMessage *)sendStatusMessage:(RCConversationType)conversationType targetId:(NSString *)targetId content:(RCMessageContent *)content success:(void (^)(long messageId))successBlock error:(void (^)(RCErrorCode nErrorCode, long messageId))errorBlock; /*! 插入消息 @param conversationType 会话类型 @param targetId 目标会话ID @param senderUserId 消息发送者的用户ID @param sendStatus 发送状态 @param content 消息的内容 @return 插入的消息实体 @discussion 此方法不支持聊天室的会话类型。 @warning 目前仅支持插入向外发送的消息,不支持插入接收的消息。 */ - (RCMessage *)insertMessage:(RCConversationType)conversationType targetId:(NSString *)targetId senderUserId:(NSString *)senderUserId sendStatus:(RCSentStatus)sendStatus content:(RCMessageContent *)content; /*! 下载消息内容中的媒体信息 @param conversationType 消息的会话类型 @param targetId 消息的目标会话ID @param mediaType 消息内容中的多媒体文件类型,目前仅支持图片 @param mediaUrl 多媒体文件的网络URL @param progressBlock 消息下载进度更新的回调 [progress:当前的下载进度, 0 <= progress <= 100] @param successBlock 下载成功的回调 [mediaPath:下载成功后本地存放的文件路径] @param errorBlock 下载失败的回调[errorCode:下载失败的错误码] */ - (void)downloadMediaFile:(RCConversationType)conversationType targetId:(NSString *)targetId mediaType:(RCMediaType)mediaType mediaUrl:(NSString *)mediaUrl progress:(void (^)(int progress))progressBlock success:(void (^)(NSString *mediaPath))successBlock error:(void (^)(RCErrorCode errorCode))errorBlock; #pragma mark 消息接收监听 /*! 设置IMlib的消息接收监听器 @param delegate IMLib消息接收监听器 @param userData 用户自定义的监听器Key值,可以为nil @discussion 设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。 userData为您自定义的任意数据,SDK会在回调的onReceived:left:object:方法中传入作为object参数。 您如果有设置多个监听,会只有最终的一个监听器起作用,您可以通过该userData值区分您设置的监听器。如果不需要直接设置为nil就可以。 @warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收; 如果您使用IMKit,请使用RCIM中的receiveMessageDelegate监听消息接收,而不要使用此方法,否则会导致IMKit中无法自动更新UI! */ - (void)setReceiveMessageDelegate:(id)delegate object:(id)userData; #pragma mark 消息阅读回执 /*! @const 收到已读回执的Notification @discussion 收到消息已读回执之后,IMLib会分发此通知。 Notification的object为nil,userInfo为NSDictionary对象, 其中key值分别为@"cType"、@"tId"、@"messageTime", 对应的value为会话类型的NSNumber对象、会话的targetId、已阅读的最后一条消息的sendTime。 如: NSNumber *ctype = [notification.userInfo objectForKey:@"cType"]; NSNumber *time = [notification.userInfo objectForKey:@"messageTime"]; NSString *targetId = [notification.userInfo objectForKey:@"tId"]; 收到这个消息之后可以更新这个会话中messageTime以前的消息UI为已读(底层数据库消息状态已经改为已读)。 @warning 目前仅支持单聊。 */ FOUNDATION_EXPORT NSString *const RCLibDispatchReadReceiptNotification; /*! 发送某个会话中消息阅读的回执 @param conversationType 会话类型 @param targetId 目标会话ID @param timestamp 该会话中已阅读的最后一条消息的发送时间戳 @discussion 消息回执功能目前只支持单聊, 如果使用Lib 可以注册监听 RCLibDispatchReadReceiptNotification 通知,使用kit 直接开启RCIM.h 中enableReadReceipt。 @warning 目前仅支持单聊。 */ -(void)sendReadReceiptMessage:(RCConversationType)conversationType targetId:(NSString *)targetId time:(long long)timestamp; #pragma mark - 消息操作 /*! 获取某个会话中指定数量的最新消息实体 @param conversationType 会话类型 @param targetId 目标会话ID @param count 需要获取的消息数量 @return 消息实体RCMessage对象列表 @discussion 此方法会获取该会话中指定数量的最新消息实体,返回的消息实体按照时间从新到旧排列。 如果会话中的消息数量小于参数count的值,会将该会话中的所有消息返回。 */ - (NSArray *)getLatestMessages:(RCConversationType)conversationType targetId:(NSString *)targetId count:(int)count; /*! 获取会话中,从指定消息之前、指定数量的最新消息实体 @param conversationType 会话类型 @param targetId 目标会话ID @param oldestMessageId 截止的消息ID @param count 需要获取的消息数量 @return 消息实体RCMessage对象列表 @discussion 此方法会获取该会话中,oldestMessageId之前的、指定数量的最新消息实体,返回的消息实体按照时间从新到旧排列。 返回的消息中不包含oldestMessageId对应那条消息,如果会话中的消息数量小于参数count的值,会将该会话中的所有消息返回。 如: oldestMessageId为10,count为2,会返回messageId为9和8的RCMessage对象列表。 */ - (NSArray *)getHistoryMessages:(RCConversationType)conversationType targetId:(NSString *)targetId oldestMessageId:(long)oldestMessageId count:(int)count; /*! 获取会话中,从指定消息之前、指定数量的、指定消息类型的最新消息实体 @param conversationType 会话类型 @param targetId 目标会话ID @param objectName 消息内容的类型名 @param oldestMessageId 截止的消息ID @param count 需要获取的消息数量 @return 消息实体RCMessage对象列表 @discussion 此方法会获取该会话中,oldestMessageId之前的、指定数量和消息类型的最新消息实体,返回的消息实体按照时间从新到旧排列。 返回的消息中不包含oldestMessageId对应的那条消息,如果会话中的消息数量小于参数count的值,会将该会话中的所有消息返回。 如: oldestMessageId为10,count为2,会返回messageId为9和8的RCMessage对象列表。 */ -(NSArray*)getHistoryMessages:(RCConversationType)conversationType targetId:(NSString*)targetId objectName:(NSString *)objectName oldestMessageId:(long)oldestMessageId count:(int)count; /*! 从服务器端获取之前的历史消息 @param conversationType 会话类型 @param targetId 目标会话ID @param recordTime 最早的发送时间,第一次可以传0 @param count 需要获取的消息数量, 0< count <= 20 @param successBlock 获取成功的回调 [messages:获取到的历史消息数组] @param errorBlock 获取失败的回调 [status:获取失败的错误码] @discussion 此方法从服务器端获取之前的历史消息,但是必须先开通历史消息云存储功能。 */ - (void)getRemoteHistoryMessages:(RCConversationType)conversationType targetId:(NSString *)targetId recordTime:(long)recordTime count:(int)count success:(void (^)(NSArray *messages))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 获取消息的发送时间(Unix时间戳、毫秒) @param messageId 消息ID @return 消息的发送时间(Unix时间戳、毫秒) */ -(long long)getMessageSendTime:(long)messageId; /*! 通过messageId获取消息实体 @param messageId 消息ID(数据库索引唯一值) @return 通过消息ID获取到的消息实体,当获取失败的时候,会返回nil。 */ -(RCMessage *)getMessage:(long)messageId; /*! 通过全局唯一ID获取消息实体 @param messageUId 全局唯一ID(服务器消息唯一ID) @return 通过全局唯一ID获取到的消息实体,当获取失败的时候,会返回nil。 */ -(RCMessage *)getMessageByUId:(NSString *)messageUId; /*! 删除消息 @param messageIds 消息ID的列表 @return 是否删除成功 */ - (BOOL)deleteMessages:(NSArray *)messageIds; /*! 删除某个会话中的所有消息 @param conversationType 会话类型,不支持聊天室 @param targetId 目标会话ID @return 是否删除成功 */ - (BOOL)clearMessages:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 设置消息的附加信息 @param messageId 消息ID @param value 附加信息 @return 是否设置成功 */ - (BOOL)setMessageExtra:(long)messageId value:(NSString *)value; /*! 设置消息的接收状态 @param messageId 消息ID @param receivedStatus 消息的接收状态 @return 是否设置成功 */ - (BOOL)setMessageReceivedStatus:(long)messageId receivedStatus:(RCReceivedStatus)receivedStatus; /*! 设置消息的发送状态 @param messageId 消息ID @param sentStatus 消息的发送状态 @return 是否设置成功 */ - (BOOL)setMessageSentStatus:(long)messageId sentStatus:(RCSentStatus)sentStatus; #pragma mark - 会话列表操作 /*! 获取会话列表 @param conversationTypeList 会话类型的数组(需要将RCConversationType转为NSNumber构建Array) @return 会话RCConversation的列表 @discussion 此方法会从本地数据库中,读取会话列表。 返回的会话列表按照时间从前往后排列,如果有置顶的会话,则置顶的会话会排列在前面。 */ - (NSArray *)getConversationList:(NSArray *)conversationTypeList; /*! 获取单个会话数据 @param conversationType 会话类型 @param targetId 目标会话ID @return 会话的对象 */ - (RCConversation *)getConversation:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 获取会话中的消息数量 @param conversationType 会话类型 @param targetId 目标会话ID @return 会话中的消息数量 @discussion -1表示获取消息数量出错。 */ - (int)getMessageCount:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 删除指定类型的会话 @param conversationTypeList 会话类型的数组(需要将RCConversationType转为NSNumber构建Array) @return 是否删除成功 */ - (BOOL)clearConversations:(NSArray *)conversationTypeList; /*! 从本地存储中删除会话 @param conversationType 会话类型 @param targetId 目标会话ID @return 是否删除成功 @discussion 此方法会从本地存储中删除该会话,但是不会删除会话中的消息。 */ - (BOOL)removeConversation:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 设置会话的置顶状态 @param conversationType 会话类型 @param targetId 目标会话ID @param isTop 是否置顶 @return 设置是否成功 */ - (BOOL)setConversationToTop:(RCConversationType)conversationType targetId:(NSString *)targetId isTop:(BOOL)isTop; #pragma mark 会话中的草稿操作 /*! 获取会话中的草稿信息 @param conversationType 会话类型 @param targetId 会话目标ID @return 该会话中的草稿 */ - (NSString *)getTextMessageDraft:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 保存草稿信息 @param conversationType 会话类型 @param targetId 会话目标ID @param content 草稿信息 @return 是否保存成功 */ - (BOOL)saveTextMessageDraft:(RCConversationType)conversationType targetId:(NSString *)targetId content:(NSString *)content; /*! 删除会话中的草稿信息 @param conversationType 会话类型 @param targetId 会话目标ID @return 是否删除成功 */ - (BOOL)clearTextMessageDraft:(RCConversationType)conversationType targetId:(NSString *)targetId; #pragma mark 未读消息数 /*! 获取所有的未读消息数 @return 所有的未读消息数 */ - (int)getTotalUnreadCount; /*! 获取某个会话内的未读消息数 @param conversationType 会话类型 @param targetId 会话目标ID @return 该会话内的未读消息数 */ - (int)getUnreadCount:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 获取某个类型的会话中所有的未读消息数 @param conversationTypes 会话类型的数组 @return 该类型的会话中所有的未读消息数 */ - (int)getUnreadCount:(NSArray *)conversationTypes; /*! 清除某个会话中的未读消息数 @param conversationType 会话类型,不支持聊天室 @param targetId 目标会话ID @return 是否清除成功 */ - (BOOL)clearMessagesUnreadStatus:(RCConversationType)conversationType targetId:(NSString *)targetId; #pragma mark 会话的消息提醒 /*! 设置会话的消息提醒状态 @param conversationType 会话类型 @param targetId 目标会话ID @param isBlocked 是否屏蔽消息提醒 @param successBlock 设置成功的回调 [nStatus:会话设置的消息提醒状态] @param errorBlock 设置失败的回调 [status:设置失败的错误码] @discussion 如果您使用IMLib,此方法会屏蔽该会话的远程推送;如果您使用IMKit,此方法会屏蔽该会话的所有提醒(远程推送、本地通知、前台提示音)。 */ - (void)setConversationNotificationStatus:(RCConversationType)conversationType targetId:(NSString *)targetId isBlocked:(BOOL)isBlocked success:(void (^)(RCConversationNotificationStatus nStatus))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 查询会话的消息提醒状态 @param conversationType 会话类型 @param targetId 目标会话ID @param successBlock 查询成功的回调 [nStatus:会话设置的消息提醒状态] @param errorBlock 查询失败的回调 [status:设置失败的错误码] */ - (void)getConversationNotificationStatus:(RCConversationType)conversationType targetId:(NSString *)targetId success:(void (^)(RCConversationNotificationStatus nStatus))successBlock error:(void (^)(RCErrorCode status))errorBlock; #pragma mark 全局消息提醒 /*! 全局屏蔽某个时间段的消息提醒 @param startTime 开始屏蔽消息提醒的时间,格式为HH:MM:SS @param spanMins 需要屏蔽消息提醒的分钟数,0 < spanMins < 1440 @param successBlock 屏蔽成功的回调 @param errorBlock 屏蔽失败的回调 [status:屏蔽失败的错误码] @discussion 此方法设置的屏蔽时间会在每天该时间段时生效。 如果您使用IMLib,此方法会屏蔽该会话在该时间段的远程推送;如果您使用IMKit,此方法会屏蔽该会话在该时间段的所有提醒(远程推送、本地通知、前台提示音)。 */ - (void)setNotificationQuietHours:(NSString *)startTime spanMins:(int)spanMins success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 删除已设置的全局时间段消息提醒屏蔽 @param successBlock 删除屏蔽成功的回调 @param errorBlock 删除屏蔽失败的回调 [status:失败的错误码] */ - (void)removeNotificationQuietHours:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 查询已设置的全局时间段消息提醒屏蔽 @param successBlock 屏蔽成功的回调 [startTime:已设置的屏蔽开始时间, spansMin:已设置的屏蔽时间分钟数,0 < spansMin < 1440] @param errorBlock 查询失败的回调 [status:查询失败的错误码] */ - (void)getNotificationQuietHours:(void (^)(NSString *startTime, int spansMin))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 全局屏蔽某个时间段的消息提醒 @param startTime 开始屏蔽消息提醒的时间,格式为HH:MM:SS @param spanMins 需要屏蔽消息提醒的分钟数,0 < spanMins < 1440 @param successBlock 屏蔽成功的回调 @param errorBlock 屏蔽失败的回调 [status:屏蔽失败的错误码] @discussion 此方法设置的屏蔽时间会在每天该时间段时生效。 如果您使用IMLib,此方法会屏蔽该会话在该时间段的远程推送;如果您使用IMKit,此方法会屏蔽该会话在该时间段的所有提醒(远程推送、本地通知、前台提示音)。 @warning **已废弃,请勿使用。** 升级说明:如果您之前使用了此接口,可以直接替换为setNotificationQuietHours:spanMins:success:error:接口,行为和实现完全一致。 */ - (void)setConversationNotificationQuietHours:(NSString *)startTime spanMins:(int)spanMins success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); /*! 删除已设置的全局时间段消息提醒屏蔽 @param successBlock 删除屏蔽成功的回调 @param errorBlock 删除屏蔽失败的回调 [status:失败的错误码] @warning **已废弃,请勿使用。** 升级说明:如果您之前使用了此接口,可以直接替换为removeNotificationQuietHours:error:接口,行为和实现完全一致。 */ - (void)removeConversationNotificationQuietHours:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); #pragma mark - 输入状态提醒 /*! 设置输入状态的监听器 @param delegate IMLib输入状态的的监听器 @warning 目前仅支持单聊。 */ - (void)setRCTypingStatusDelegate:(id)delegate; /*! 向会话中发送正在输入的状态 @param conversationType 会话类型 @param targetId 会话目标ID @param objectName 正在输入的消息的类型名 @discussion contentType为用户当前正在编辑的消息类型名,即RCMessageContent中getObjectName的返回值。 如文本消息,应该传类型名"RC:TxtMsg"。 @warning 目前仅支持单聊。 */ - (void)sendTypingStatus:(RCConversationType)conversationType targetId:(NSString *)targetId contentType:(NSString *)objectName; #pragma mark - 黑名单 /*! 将某个用户加入黑名单 @param userId 需要加入黑名单的用户ID @param successBlock 加入黑名单成功的回调 @param errorBlock 加入黑名单失败的回调 [status:失败的错误码] */ - (void)addToBlacklist:(NSString *)userId success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 将某个用户移出黑名单 @param userId 需要移出黑名单的用户ID @param successBlock 移出黑名单成功的回调 @param errorBlock 移出黑名单失败的回调[status:失败的错误码] */ - (void)removeFromBlacklist:(NSString *)userId success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 查询某个用户是否已经在黑名单中 @param userId 需要查询的用户ID @param successBlock 查询成功的回调 [bizStatus:该用户是否在黑名单中。0表示已经在黑名单中,101表示不在黑名单中] @param errorBlock 查询失败的回调 [status:失败的错误码] */ - (void)getBlacklistStatus:(NSString *)userId success:(void (^)(int bizStatus))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 查询已经设置的黑名单列表 @param successBlock 查询成功的回调 [blockUserIds:已经设置的黑名单中的用户ID列表] @param errorBlock 查询失败的回调 [status:失败的错误码] */ - (void)getBlacklist:(void (^)(NSArray *blockUserIds))successBlock error:(void (^)(RCErrorCode status))errorBlock; #pragma mark - 讨论组操作 /*! 创建讨论组 @param name 讨论组名称 @param userIdList 用户ID的列表 @param successBlock 创建讨论组成功的回调 [discussion:创建成功返回的讨论组对象] @param errorBlock 创建讨论组失败的回调 [status:创建失败的错误码] */ - (void)createDiscussion:(NSString *)name userIdList:(NSArray *)userIdList success:(void (^)(RCDiscussion *discussion))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 讨论组加人,将用户加入讨论组 @param discussionId 讨论组ID @param userIdList 需要加入的用户ID列表 @param successBlock 讨论组加人成功的回调 [discussion:讨论组加人成功返回的讨论组对象] @param errorBlock 讨论组加人失败的回调 [status:讨论组加人失败的错误码] @discussion 设置的讨论组名称长度不能超过40个字符,否则将会截断为前40个字符。 */ - (void)addMemberToDiscussion:(NSString *)discussionId userIdList:(NSArray *)userIdList success:(void (^)(RCDiscussion *discussion))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 讨论组踢人,将用户移出讨论组 @param discussionId 讨论组ID @param userId 需要移出的用户ID @param successBlock 讨论组踢人成功的回调 [discussion:讨论组踢人成功返回的讨论组对象] @param errorBlock 讨论组踢人失败的回调 [status:讨论组踢人失败的错误码] @discussion 如果当前登陆用户不是此讨论组的创建者并且此讨论组没有开放加人权限,则会返回错误。 @warning 不能使用此接口将自己移除,否则会返回错误。 如果您需要退出该讨论组,可以使用-quitDiscussion:success:error:方法。 */ - (void)removeMemberFromDiscussion:(NSString *)discussionId userId:(NSString *)userId success:(void (^)(RCDiscussion *discussion))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 退出当前讨论组 @param discussionId 讨论组ID @param successBlock 退出成功的回调 [discussion:退出成功返回的讨论组对象] @param errorBlock 退出失败的回调 [status:退出失败的错误码] */ - (void)quitDiscussion:(NSString *)discussionId success:(void (^)(RCDiscussion *discussion))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 获取讨论组的信息 @param discussionId 需要获取信息的讨论组ID @param successBlock 获取讨论组信息成功的回调 [discussion:获取的讨论组信息] @param errorBlock 获取讨论组信息失败的回调 [status:获取讨论组信息失败的错误码] */ - (void)getDiscussion:(NSString *)discussionId success:(void (^)(RCDiscussion *discussion))successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 设置讨论组名称 @param targetId 需要设置的讨论组ID @param discussionName 需要设置的讨论组名称,discussionName长度<=40 @param successBlock 设置成功的回调 @param errorBlock 设置失败的回调 [status:设置失败的错误码] @discussion 设置的讨论组名称长度不能超过40个字符,否则将会截断为前40个字符。 */ - (void)setDiscussionName:(NSString *)targetId name:(NSString *)discussionName success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; /*! 设置讨论组是否开放加人权限 @param targetId 讨论组ID @param isOpen 是否开放加人权限 @param successBlock 设置成功的回调 @param errorBlock 设置失败的回调[status:设置失败的错误码] @discussion 讨论组默认开放加人权限,即所有成员都可以加人。 如果关闭加人权限之后,只有讨论组的创建者有加人权限。 */ - (void)setDiscussionInviteStatus:(NSString *)targetId isOpen:(BOOL)isOpen success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock; #pragma mark - 群组操作(已废弃,请勿使用) /*! 同步当前用户所在的群组列表信息(已废弃,建议您通过您的App Server进行群组操作) @param groupList 群组信息RCGroup的列表 @param successBlock 同步成功的回调 @param errorBlock 同步失败的回调 [status:同步失败的错误码] @discussion 此方法已废弃,建议您通过您的App Server进行群组操作。 群组操作的流程,可以参考:http://support.rongcloud.cn/kb/MzY5 @warning **已废弃,请勿使用。** */ - (void)syncGroups:(NSArray *)groupList success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); /*! 加入群组(已废弃,建议您通过您的App Server进行群组操作) @param groupId 要加入的群组ID @param groupName 群组的名称 @param successBlock 加入成功的回调 @param errorBlock 加入失败的回调 [status:加入失败的错误码] @discussion 此方法已废弃,建议您通过您的App Server进行群组操作。 群组操作的流程,可以参考:http://support.rongcloud.cn/kb/MzY5 @warning **已废弃,请勿使用。** */ - (void)joinGroup:(NSString *)groupId groupName:(NSString *)groupName success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); /*! 退出群组(已废弃,建议您通过您的App Server进行群组操作) @param groupId 要退出的群组ID @param successBlock 退出成功的回调 @param errorBlock 退出失败的回调 [status:退出失败的错误码] @discussion 此方法已废弃,建议您通过您的App Server进行群组操作。 群组操作的流程,可以参考:http://support.rongcloud.cn/kb/MzY5 @warning **已废弃,请勿使用。** */ - (void)quitGroup:(NSString *)groupId success:(void (^)())successBlock error:(void (^)(RCErrorCode status))errorBlock __deprecated_msg("已废弃,请勿使用。"); #pragma mark - 聊天室操作 /*! 加入聊天室(如果聊天室不存在则会创建) @param targetId 聊天室ID @param messageCount 进入聊天室时获取历史消息的数量,-1<=messageCount<=50 @param successBlock 加入聊天室成功的回调 @param errorBlock 加入聊天室失败的回调 [status:加入聊天室失败的错误码] @discussion 可以通过传入的messageCount设置加入聊天室成功之后,需要获取的历史消息数量。 -1表示不获取任何历史消息,0表示不特殊设置而使用SDK默认的设置(默认为获取10条),0 /*! 图片消息的类型名 */ #define RCImageMessageTypeIdentifier @"RC:ImgMsg" /*! 图片消息类 @discussion 图片消息类,此消息会进行存储并计入未读消息数。 */ @interface RCImageMessage : RCMessageContent /*! 图片消息的URL地址 @discussion 发送方此字段为图片的本地路径,接收方此字段为网络URL地址。 */ @property(nonatomic, strong) NSString *imageUrl; /*! 图片消息的缩略图 */ @property(nonatomic, strong) UIImage *thumbnailImage; /*! 是否发送原图 @discussion 在发送图片的时候,是否发送原图,默认值为NO。 */ @property(nonatomic, getter=isFull) BOOL full; /*! 图片消息的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 图片消息的原始图片信息 */ @property(nonatomic, strong) UIImage *originalImage; /*! 初始化图片消息 @param image 原始图片 @return 图片消息对象 */ + (instancetype)messageWithImage:(UIImage *)image; /*! 初始化图片消息 @param imageURI 图片的本地路径 @return 图片消息对象 */ + (instancetype)messageWithImageURI:(NSString *)imageURI; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCInformationNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCInformationNotificationMessage.h // Created by xugang on 14/12/4. #import "RCMessageContent.h" /*! 通知消息的类型名 */ #define RCInformationNotificationMessageIdentifier @"RC:InfoNtf" /*! 通知消息类 @discussion 通知消息类,此消息会进行存储,但不计入未读消息数。 */ @interface RCInformationNotificationMessage : RCMessageContent /*! 通知的内容 */ @property(nonatomic, strong) NSString *message; /*! 通知的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化通知消息 @param message 通知的内容 @param extra 通知的附加信息 @return 通知消息对象 */ + (instancetype)notificationWithMessage:(NSString *)message extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCLocationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCLocationMessage.h // Created by Heq.Shinoda on 14-6-13. #import #import #import "RCMessageContent.h" /*! 地理位置消息的类型名 */ #define RCLocationMessageTypeIdentifier @"RC:LBSMsg" /*! 地理位置消息类 @discussion 地理位置消息类,此消息会进行存储并计入未读消息数。 */ @interface RCLocationMessage : RCMessageContent /*! 地理位置的二维坐标 */ @property(nonatomic, assign) CLLocationCoordinate2D location; /*! 地理位置的名称 */ @property(nonatomic, strong) NSString *locationName; /*! 地理位置的缩略图 */ @property(nonatomic, strong) UIImage *thumbnailImage; /*! 地理位置的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化地理位置消息 @param image 地理位置的缩略图 @param location 地理位置的二维坐标 @param locationName 地理位置的名称 @return 地理位置消息的对象 */ + (instancetype)messageWithLocationImage:(UIImage *)image location:(CLLocationCoordinate2D)location locationName:(NSString *)locationName; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCMessage.h // Created by Heq.Shinoda on 14-6-13. #ifndef __RCMessage #define __RCMessage #import #import "RCStatusDefine.h" #import "RCMessageContent.h" /*! 消息实体类 @discussion 消息实体类,包含消息的所有属性。 */ @interface RCMessage : NSObject /*! 会话类型 */ @property(nonatomic, assign) RCConversationType conversationType; /*! 目标会话ID */ @property(nonatomic, strong) NSString *targetId; /*! 消息的ID @discussion 本地存储的消息的唯一值(数据库索引唯一值) */ @property(nonatomic, assign) long messageId; /*! 消息的方向 */ @property(nonatomic, assign) RCMessageDirection messageDirection; /*! 消息的发送者ID */ @property(nonatomic, strong) NSString *senderUserId; /*! 消息的接收状态 */ @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 *objectName; /*! 消息的内容 */ @property(nonatomic, strong) RCMessageContent *content; /*! 消息的附加字段 */ @property(nonatomic, strong) NSString *extra; /*! 全局唯一ID @discussion 服务器消息唯一ID(在同一个Appkey下全局唯一) */ @property(nonatomic, strong) NSString *messageUId; /*! RCMessage初始化方法 @param conversationType 会话类型 @param targetId 目标会话ID @param messageDirection 消息的方向 @param messageId 消息的ID @param content 消息的内容 */ - (instancetype)initWithType:(RCConversationType)conversationType targetId:(NSString *)targetId direction:(RCMessageDirection)messageDirection messageId:(long)messageId content:(RCMessageContent *)content; /*! RCMessage初始化方法(已废弃,请勿使用) @param jsonData 消息的JSON Dictionary @return 消息实体对象 @warning **已废弃,请勿使用。** */ + (instancetype)messageWithJSON:(NSDictionary *)jsonData __deprecated_msg("已废弃,请勿使用。"); @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCMessageContent.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCMessageContent.h // Created by Heq.Shinoda on 14-6-13. #ifndef __RCMessageContent #define __RCMessageContent #import #import "RCStatusDefine.h" #import "RCUserInfo.h" /*! 消息内容的编解码协议 @discussion 用于标示消息内容的类型,进行消息的编码和解码。 所有自定义消息必须实现此协议,否则将无法正常传输和使用。 */ @protocol RCMessageCoding @required /*! 将消息内容序列化,编码成为可传输的json数据 @discussion 消息内容通过此方法,将消息中的所有数据,编码成为json数据,返回的json数据将用于网络传输。 */ - (NSData *)encode; /*! 将json数据的内容反序列化,解码生成可用的消息内容 @param data 消息中的原始json数据 @discussion 网络传输的json数据,会通过此方法解码,获取消息内容中的所有数据,生成有效的消息内容。 */ - (void)decodeWithData:(NSData *)data; /*! 返回消息的类型名 @return 消息的类型名 @discussion 您定义的消息类型名,需要在各个平台上保持一致,以保证消息互通。 @warning 请勿使用@"RC:"开头的类型名,以免和SDK默认的消息名称冲突 */ + (NSString *)getObjectName; @end /*! 消息内容的存储协议 @discussion 用于确定消息内容的存储策略。 所有自定义消息必须实现此协议,否则将无法正常存储和使用。 */ @protocol RCMessagePersistentCompatible @required /*! 返回消息的存储策略 @return 消息的存储策略 @discussion 指明此消息类型在本地是否存储、是否计入未读消息数。 */ + (RCMessagePersistent)persistentFlag; @end /*! 消息内容摘要的协议 @discussion 用于在会话列表和本地通知中显示消息的摘要。 */ @protocol RCMessageContentView @optional /*! 返回在会话列表和本地通知中显示的消息内容摘要 @return 会话列表和本地通知中显示的消息内容摘要 @discussion 如果您使用IMKit,当会话的最后一条消息为自定义消息时,需要通过此方法获取在会话列表展现的内容摘要; 当App在后台收到消息时,需要通过此方法获取在本地通知中展现的内容摘要。 */ - (NSString *)conversationDigest; @end /*! 消息内容的基类 @discussion 此类为消息实体类RCMessage中的消息内容content的基类。 所有的消息内容均为此类的子类,包括SDK自带的消息(如RCTextMessage、RCImageMessage等)和用户自定义的消息。 所有的自定义消息必须继承此类,并实现RCMessageCoding和RCMessagePersistentCompatible、RCMessageContentView协议。 */ @interface RCMessageContent : NSObject /*! 消息内容中携带的发送者的用户信息 @discussion 如果您使用IMKit,可以通过RCIM的enableMessageAttachUserInfo属性设置在每次发送消息中携带发送者的用户信息。 */ @property(nonatomic, strong) RCUserInfo *senderUserInfo; /*! 将消息内容中携带的用户信息解码 @param dictionary 用户信息的Dictionary */ -(void)decodeUserInfo:(NSDictionary *)dictionary; /*! 消息内容的原始json数据 @discussion 此字段存放消息内容中未编码的json数据。 SDK内置的消息,如果消息解码失败,默认会将消息的内容存放到此字段;如果编码和解码正常,此字段会置为nil。 */ @property(nonatomic, strong, setter=setRawJSONData:) NSData *rawJSONData; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCMessageContentView.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCMessageContentView.h // Created by litao on 15/4/27. #ifndef RongIMLib_RCMessageContentView_h #define RongIMLib_RCMessageContentView_h ///此协议已经移到RCMessageContent中 ///*! // 消息内容摘要的协议 // // @discussion 用于在会话列表中显示消息的摘要。 // // @warning 此协议已经移到RCMessageContent中 // */ //@protocol RCMessageContentView //@optional // ///*! // 返回在会话列表中显示的消息内容摘要 // // @return 会话列表中显示的消息内容摘要 // // @discussion 当会话的最后一条消息为自定义消息时,需要在会话列表展现消息内容的摘要。 // 如果您使用IMKit,实现了此接口,RCConversationListViewController会在会话列表中显示该内容摘要。 // */ //- (NSString *)conversationDigest; // //@end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCProfileNotificationMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCProfileNotificationMessage.h // Created by xugang on 14/11/28. #import "RCMessageContent.h" /*! 公众服务账号信息变更消息的类型名 */ #define RCProfileNotificationMessageIdentifier @"RC:ProfileNtf" /*! 公众服务账号信息变更消息类 @discussion 公众服务账号信息变更消息类,此消息会进行存储,但不计入未读消息数。 */ @interface RCProfileNotificationMessage : RCMessageContent /*! 公众服务账号信息变更的操作名 */ @property(nonatomic, strong) NSString *operation; /*! 信息变更的数据,可以为任意格式,如json数据。 */ @property(nonatomic, strong) NSString *data; /*! 信息变更的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化公众服务账号信息变更消息 @param operation 信息变更的操作名 @param data 信息变更的数据 @param extra 信息变更的附加信息 @return 公众服务账号信息变更消息的对象 */ + (instancetype)notificationWithOperation:(NSString *)operation data:(NSString *)data extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceCommandMessage.h ================================================ // // RCPublicServiceCommandMessage.h // RongIMLib // // Created by litao on 15/6/23. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageContent.h" #import "RCPublicServiceMenuItem.h" /*! 公众服务请求消息的类型名 */ #define RCPublicServiceCommandMessageTypeIdentifier @"RC:PSCmd" /*! 公众服务请求消息类 @discussion 公众服务请求消息类,此消息不存储,也不计入未读消息数。 此消息仅用于客户端公共服务账号中的菜单,向服务器发送请求。 */ @interface RCPublicServiceCommandMessage : RCMessageContent /*! 请求的名称 */ @property(nonatomic, strong) NSString *command; /*! 请求的内容 */ @property(nonatomic, strong) NSString *data; /*! 请求的扩展数据 */ @property(nonatomic, strong) NSString *extra; /*! 初始化公众服务请求消息 @param item 公众服务菜单项 @return 公众服务请求消息对象 */ + (instancetype)messageFromMenuItem:(RCPublicServiceMenuItem *)item; /*! 初始化公众服务请求消息 @param command 请求的名称 @param data 请求的内容 @return 公众服务请求消息对象 */ + (instancetype)messageWithCommand:(NSString *)command data:(NSString *)data; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceMenu.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCPublicServiceMenu.h // Created by litao on 15/4/14. #import #import "RCPublicServiceMenuItem.h" /*! 公众服务账号菜单类 @discussion 公众服务菜单类,其中包含若干数量的菜单项,每个菜单项可能还包含子菜单项。 公众服务菜单的树状结构如下所示: Menu -> MenuItem1 MenuItem2 -> MenuItem2.1 MenuItem2.2 MenuItem3 -> MenuItem3.1 MenuItem3.2 MenuItem3.3 */ @interface RCPublicServiceMenu : NSObject /*! 菜单中包含的所有菜单项RCPublicServiceMenuItem数组 */ @property(nonatomic, strong) NSArray *menuItems; /*! 将公众服务菜单下的所有菜单项解码(已废弃,请勿使用) @param jsonDictionary 公众服务菜单项Json组成的数组 @warning **已废弃,请勿使用。** */ - (void)decodeWithJsonDictionaryArray:(NSArray *)jsonDictionary __deprecated_msg("已废弃,请勿使用。"); @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceMenuItem.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCPublicServiceMenuItem.h // Created by litao on 15/4/14. #import #import "RCStatusDefine.h" /*! 公众服务的菜单项 */ @interface RCPublicServiceMenuItem : NSObject /*! 菜单的ID */ @property(nonatomic, strong) NSString *id; /*! 菜单的标题 */ @property(nonatomic, strong) NSString *name; /*! 菜单的URL链接 */ @property(nonatomic, strong) NSString *url; /*! 菜单的类型 */ @property(nonatomic) RCPublicServiceMenuItemType type; /*! 菜单中的子菜单 @discussion 子菜单为RCPublicServiceMenuItem的数组 */ @property(nonatomic, strong) NSArray *subMenuItems; /*! 将菜单项的json数组解码(已废弃,请勿使用) @param jsonArray 由菜单项原始Json数据组成的数组 @return 公众服务菜单项RCPublicServiceMenuItem的数组 @warning **已废弃,请勿使用。** */ + (NSArray *)menuItemsFromJsonArray:(NSArray *)jsonArray __deprecated_msg("已废弃,请勿使用。"); @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceMultiRichContentMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCPublicServiceMultiRichContentMessage.h // Created by litao on 15/4/13. #import "RCMessageContent.h" /*! 公众服务的多图文消息的类型名 */ #define RCPublicServiceRichContentTypeIdentifier @"RC:PSMultiImgTxtMsg" /*! 公众服务的多图文消息类 @discussion 公众服务的多图文消息类,此消息会进行存储并计入未读消息数。 */ @interface RCPublicServiceMultiRichContentMessage : RCMessageContent /*! 多图文消息的内容RCRichContentItem数组 */ @property(nonatomic, strong) NSArray *richConents; /*! 多图文消息的附加信息 */ @property(nonatomic, strong) NSString *extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceProfile.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCPublicServiceProfile.h // Created by litao on 15/4/9. #import #import #import "RCStatusDefine.h" #import "RCPublicServiceMenu.h" /*! 公众服务账号信息 */ @interface RCPublicServiceProfile : NSObject /*! 公众服务账号的名称 */ @property(nonatomic, strong) NSString *name; /*! 公众服务账号的描述 */ @property(nonatomic, strong) NSString *introduction; /*! 公众服务账号的ID */ @property(nonatomic, strong) NSString *publicServiceId; /*! 公众服务账号头像URL */ @property(nonatomic, strong) NSString *portraitUrl; /*! 公众服务账号的所有者 @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) NSString *owner; /*! 公众服务账号所有者的URL @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) NSString *ownerUrl; /*! 公众服务账号的联系电话 @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) NSString *publicServiceTel; /*! 公众服务账号历史消息 @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) NSString *histroyMsgUrl; /*! 公众服务账号地理位置 @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) CLLocation *location; /*! 公众服务账号经营范围 @discussion 当前版本暂不支持。 */ @property(nonatomic, strong) NSString *scope; /*! 公众服务账号类型 */ @property(nonatomic) RCPublicServiceType publicServiceType; /*! 是否关注该公众服务账号 */ @property(nonatomic, getter=isFollowed) BOOL followed; /*! 公众服务账号菜单 */ @property(nonatomic, strong) RCPublicServiceMenu *menu; /*! 公众服务账号的全局属性 @discussion 此公众服务账号是否设置为所有用户均关注。 */ @property(nonatomic, getter=isGlobal) BOOL global; /*! 公众服务账号信息的json数据 */ @property(nonatomic, strong) NSDictionary *jsonDict; /*! 初始化公众服务账号信息 @param jsonContent 公众藏獒信息的json数据 */ - (void)initContent:(NSString *)jsonContent; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCPublicServiceRichContentMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCPublicServiceMultiRichContentMessage.h // Created by litao on 15/4/15. #import "RCMessageContent.h" #import "RCRichContentItem.h" /*! 公众服务图文消息的类型名 */ #define RCSingleNewsMessageTypeIdentifier @"RC:PSImgTxtMsg" /*! 公众服务图文消息类 @discussion 公众服务图文消息类,此消息会进行存储并计入未读消息数。 */ @interface RCPublicServiceRichContentMessage : RCMessageContent /*! 公众服务图文信息条目RCRichContentItem内容 */ @property(nonatomic, strong) RCRichContentItem *richConent; /*! 图文消息的附加信息 */ @property(nonatomic, strong) NSString *extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCRealTimeLocationEndMessage.h ================================================ // // RCRealTimeLocationEndMessage.h // RongIMLib // // Created by 杜立召 on 15/8/13. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageContent.h" /*! 实时位置共享的结束消息的类型名 */ #define RCRealTimeLocationEndMessageTypeIdentifier @"RC:RLEnd" /*! 实时位置共享的结束消息类 @discussion 实时位置共享的结束消息类,此消息会进行存储并计入未读消息数。 */ @interface RCRealTimeLocationEndMessage : RCMessageContent /*! 结束消息的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化实时位置共享的结束消息 @param extra 附加信息 @return 初始化实时位置共享的结束消息对象 */ + (instancetype)messageWithExtra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCRealTimeLocationManager.h ================================================ // // RCRealTimeLocationManager.h // RongIMLib // // Created by litao on 15/7/14. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import #import #import "RCIMClient.h" /*! 实时位置共享状态 */ typedef NS_ENUM(NSInteger, RCRealTimeLocationStatus) { /*! 实时位置共享,初始状态 */ RC_REAL_TIME_LOCATION_STATUS_IDLE, /*! 实时位置共享,接收状态 */ RC_REAL_TIME_LOCATION_STATUS_INCOMING, /*! 实时位置共享,发起状态 */ RC_REAL_TIME_LOCATION_STATUS_OUTGOING, /*! 实时位置共享,共享状态 */ RC_REAL_TIME_LOCATION_STATUS_CONNECTED }; /*! 实时位置共享错误码 */ typedef NS_ENUM(NSInteger, RCRealTimeLocationErrorCode) { /*! 当前设备不支持实时位置共享 */ RC_REAL_TIME_LOCATION_NOT_SUPPORT, /*! 当前会话不支持实时位置共享 */ RC_REAL_TIME_LOCATION_CONVERSATION_NOT_SUPPORT, /*! 当前会话超出了参与者人数限制 */ RC_REAL_TIME_LOCATION_EXCEED_MAX_PARTICIPANT, /*! 获取当前会话信息失败 */ RC_REAL_TIME_LOCATION_GET_CONVERSATION_FAILURE }; /*! 实时位置共享监听器 */ @protocol RCRealTimeLocationObserver @optional /*! 实时位置共享状态改变的回调 @param status 当前实时位置共享的状态 */ - (void)onRealTimeLocationStatusChange:(RCRealTimeLocationStatus)status; /*! 参与者位置发生变化的回调 @param location 参与者的当前位置 @param userId 位置发生变化的参与者的用户ID */ - (void)onReceiveLocation:(CLLocation *)location fromUserId:(NSString *)userId; /*! 有参与者加入实时位置共享的回调 @param userId 加入实时位置共享的参与者的用户ID */ - (void)onParticipantsJoin:(NSString *)userId; /*! 有参与者退出实时位置共享的回调 @param userId 退出实时位置共享的参与者的用户ID */ - (void)onParticipantsQuit:(NSString *)userId; /*! 更新位置信息失败的回调 @param description 失败信息 */ - (void)onUpdateLocationFailed:(NSString *)description; /*! 发起实时位置共享失败后执行 @param messageId 发起失败的消息ID */ - (void)onStartRealTimeLocationFailed:(long)messageId; @end /*! 实时位置共享代理 */ @protocol RCRealTimeLocationProxy /*! 发起实时位置共享 */ - (void)startRealTimeLocation; /*! 加入实时位置共享 */ - (void)joinRealTimeLocation; /*! 退出实时位置共享 */ - (void)quitRealTimeLocation; /*! 注册实时位置共享监听 @param delegate 实时位置共享监听 */ - (void)addRealTimeLocationObserver:(id)delegate; /*! 移除实时位置共享监听 @param delegate 实时位置共享监听 */ - (void)removeRealTimeLocationObserver:(id)delegate; /*! 获取当前实时位置共享的参与者列表 @return 当前参与者列表 */ - (NSArray *)getParticipants; /*! 获取当前实时位置共享状态 @return 当前实时位置共享状态 */ - (RCRealTimeLocationStatus)getStatus; /*! 获取参与者的当前位置 @param userId 需要获取参与者的用户ID @return 该参与者的位置信息 */ - (CLLocation *)getLocation:(NSString *)userId; @end /*! 实时位置共享管理类 */ @interface RCRealTimeLocationManager : NSObject /*! 获取实时位置共享的核心类单例 @return 实时位置共享的核心类单例 */ + (instancetype)sharedManager; /*! 获取实时位置共享的代理 @param conversationType 会话类型 @param targetId 目标会话ID @param successBlock 获取代理成功的处理 @param errorBlock 获取代理失败的处理 */ - (void)getRealTimeLocationProxy:(RCConversationType)conversationType targetId:(NSString *)targetId success:(void (^)(id locationShare))successBlock error:(void (^)(RCRealTimeLocationErrorCode status))errorBlock; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCRealTimeLocationStartMessage.h ================================================ // // RCRealTimeLocationStartMessage.h // RongIMLib // // Created by litao on 15/7/14. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCMessageContent.h" /*! 实时位置共享的发起消息的类型名 */ #define RCRealTimeLocationStartMessageTypeIdentifier @"RC:RLStart" /*! 实时位置共享的发起消息类 @discussion 实时位置共享的发起消息类,此消息会进行存储并计入未读消息数。 */ @interface RCRealTimeLocationStartMessage : RCMessageContent /*! 发起消息的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化实时位置共享的发起消息 @param extra 附加信息 @return 初始化实时位置共享的发起消息对象 */ + (instancetype)messageWithExtra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCRichContentItem.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCRichContentItem.h // Created by Dulizhao on 15/4/21. #import /*! 公众服务图文信息条目类 @discussion 图文消息类,此消息会进行存储并计入未读消息数。 */ @interface RCRichContentItem : NSObject /*! 图文信息条目的标题 */ @property(nonatomic, strong) NSString *title; /*! 图文信息条目的内容摘要 */ @property(nonatomic, strong) NSString *digest; /*! 图文信息条目的图片URL */ @property(nonatomic, strong) NSString *imageURL; /*! 图文信息条目中包含的需要跳转到的URL */ @property(nonatomic, strong) NSString *url; /*! 图文信息条目的扩展信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化公众服务图文信息条目 @param title 图文信息条目的标题 @param digest 图文信息条目的内容摘要 @param imageURL 图文信息条目的图片URL @param extra 图文信息条目的扩展信息 @return 图文信息条目对象 */ + (instancetype)messageWithTitle:(NSString *)title digest:(NSString *)digest imageURL:(NSString *)imageURL extra:(NSString *)extra; /*! 初始化公众服务图文信息条目 @param title 图文信息条目的标题 @param digest 图文信息条目的内容摘要 @param imageURL 图文信息条目的图片URL @param url 图文信息条目中包含的需要跳转到的URL @param extra 图文信息条目的扩展信息 @return 图文信息条目对象 */ + (instancetype)messageWithTitle:(NSString *)title digest:(NSString *)digest imageURL:(NSString *)imageURL url:(NSString *)url extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCRichContentMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCRichContentMessage.h // Created by Gang Li on 10/17/14. #import "RCMessageContent.h" #import /*! 图文消息的类型名 */ #define RCRichContentMessageTypeIdentifier @"RC:ImgTextMsg" /*! 图文消息类 @discussion 图文消息类,此消息会进行存储并计入未读消息数。 */ @interface RCRichContentMessage : RCMessageContent /*! 图文消息的标题 */ @property(nonatomic, strong) NSString *title; /*! 图文消息的内容摘要 */ @property(nonatomic, strong) NSString *digest; /*! 图文消息图片URL */ @property(nonatomic, strong) NSString *imageURL; /*! 图文消息中包含的需要跳转到的URL */ @property(nonatomic, strong) NSString *url; /*! 图文消息的扩展信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化图文消息 @param title 图文消息的标题 @param digest 图文消息的内容摘要 @param imageURL 图文消息的图片URL @param extra 图文消息的扩展信息 @return 图文消息对象 */ + (instancetype)messageWithTitle:(NSString *)title digest:(NSString *)digest imageURL:(NSString *)imageURL extra:(NSString *)extra; /*! 初始化图文消息 @param title 图文消息的标题 @param digest 图文消息的内容摘要 @param imageURL 图文消息的图片URL @param url 图文消息中包含的需要跳转到的URL @param extra 图文消息的扩展信息 @return 图文消息对象 */ + (instancetype)messageWithTitle:(NSString *)title digest:(NSString *)digest imageURL:(NSString *)imageURL url:(NSString *)url extra:(NSString *)extra; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCStatusDefine.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCCommonDefine.h // Created by Heq.Shinoda on 14-4-21. #import #ifndef __RCStatusDefine #define __RCStatusDefine #pragma mark - 错误码相关 #pragma mark RCConnectErrorCode - 建立连接返回的错误码 /*! 建立连接返回的错误码 @discussion 开发者仅需要关注以下几种连接错误码,其余错误码SDK均会进行自动重连,开发者无须处理。 RC_CONN_ID_REJECT, RC_CONN_TOKEN_INCORRECT, RC_CONN_NOT_AUTHRORIZED, RC_CONN_PACKAGE_NAME_INVALID, RC_CONN_APP_BLOCKED_OR_DELETED, RC_CONN_USER_BLOCKED, RC_DISCONN_KICK, RC_CLIENT_NOT_INIT, RC_INVALID_PARAMETER, RC_INVALID_ARGUMENT */ typedef NS_ENUM(NSInteger, RCConnectErrorCode) { /*! 导航路由失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_NET_NAVI_ERROR = 30000, /*! 连接已被释放 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_NET_CHANNEL_INVALID = 30001, /*! 连接不可用 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_NET_UNAVAILABLE = 30002, /*! 请求响应超时 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_MSG_RESP_TIMEOUT = 30003, /*! 导航HTTP发送失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_HTTP_SEND_FAIL = 30004, /*! 导航HTTP请求超时 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_HTTP_REQ_TIMEOUT = 30005, /*! 导航HTTP接收失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_HTTP_RECV_FAIL = 30006, /*! 导航HTTP请求失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_NAVI_RESOURCE_ERROR = 30007, /*! 导航HTTP返回数据格式错误 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_NODE_NOT_FOUND = 30008, /*! 导航HTTP返回数据不可用 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_DOMAIN_NOT_RESOLVE = 30009, /*! 创建Socket连接失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_SOCKET_NOT_CREATED = 30010, /*! Socket断开 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_SOCKET_DISCONNECTED = 30011, /*! PING失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_PING_SEND_FAIL = 30012, /*! PING超时 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_PONG_RECV_FAIL = 30013, /*! 信令发送失败 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_MSG_SEND_FAIL = 30014, /*! 连接ACK超时 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_CONN_ACK_TIMEOUT = 31000, /*! 信令版本错误 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_CONN_PROTO_VERSION_ERROR = 31001, /*! AppKey错误 @discussion 请检查您使用的AppKey是否正确。 */ RC_CONN_ID_REJECT = 31002, /*! 服务器当前不可用(预留) @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_CONN_SERVER_UNAVAILABLE = 31003, /*! Token无效 @discussion Token无效一般有以下两种原因。 一是token错误,请您检查客户端初始化使用的AppKey和您服务器获取token使用的AppKey是否一致; 二是token过期,是因为您在开发者后台设置了token过期时间,您需要请求您的服务器重新获取token并再次用新的token建立连接。 */ RC_CONN_TOKEN_INCORRECT = 31004, /*! AppKey与Token不匹配 @discussion 请检查您使用的AppKey与Token是否正确,是否匹配。一般有以下两种原因。 一是token错误,请您检查客户端初始化使用的AppKey和您服务器获取token使用的AppKey是否一致; 二是token过期,是因为您在开发者后台设置了token过期时间,您需要请求您的服务器重新获取token并再次用新的token建立连接。 */ RC_CONN_NOT_AUTHRORIZED = 31005, /*! 连接重定向 @discussion 建立连接的临时错误码,SDK会做好自动重连,开发者无须处理。 */ RC_CONN_REDIRECTED = 31006, /*! BundleID不正确 @discussion 请检查您App的BundleID是否正确。 */ RC_CONN_PACKAGE_NAME_INVALID = 31007, /*! AppKey被封禁或已删除 @discussion 请检查您使用的AppKey是否正确。 */ RC_CONN_APP_BLOCKED_OR_DELETED = 31008, /*! 用户被封禁 @discussion 请检查您使用的Token是否正确,以及对应的UserId是否被封禁。 */ RC_CONN_USER_BLOCKED = 31009, /*! 当前用户在其他设备上登陆,此设备被踢下线 */ RC_DISCONN_KICK = 31010, /*! 信令数据无效 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ RC_QUERY_ACK_NO_DATA = 32001, /*! 信令数据错误 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ RC_MSG_DATA_INCOMPLETE = 32002, /*! SDK没有初始化 @discussion 在使用SDK任何功能之前,必须先Init。 */ RC_CLIENT_NOT_INIT = 33001, /*! 开发者接口调用时传入的参数错误 @discussion 请检查接口调用时传入的参数类型和值。 */ RC_INVALID_PARAMETER = 33003, /*! 开发者接口调用时传入的参数错误 @discussion 请检查接口调用时传入的参数类型和值。 */ RC_INVALID_ARGUMENT = -1000 }; #pragma mark RCErrorCode - 具体业务错误码 /*! 具体业务错误码 */ typedef NS_ENUM(NSInteger, RCErrorCode) { /*! 未知错误(预留) */ ERRORCODE_UNKNOWN = -1, /*! 已被对方加入黑名单 */ REJECTED_BY_BLACKLIST = 405, /*! 超时 */ ERRORCODE_TIMEOUT = 5004, /*! 发送消息频率过高,1秒钟最多只允许发送5条消息 */ SEND_MSG_FREQUENCY_OVERRUN = 20604, /*! 不在该讨论组中 */ NOT_IN_DISCUSSION = 21406, /*! 不在该群组中 */ NOT_IN_GROUP = 22406, /*! 在群组中已被禁言 */ FORBIDDEN_IN_GROUP = 22408, /*! 不在该聊天室中 */ NOT_IN_CHATROOM = 23406, /*! 在该聊天室中已被禁言 */ FORBIDDEN_IN_CHATROOM = 23408, /*! 已被踢出聊天室 */ KICKED_FROM_CHATROOM = 23409, /*! 聊天室不存在 */ RC_CHATROOM_NOT_EXIST = 23410, /*! 聊天室成员超限 */ RC_CHATROOM_IS_FULL = 23411, /*! 当前连接不可用(连接已经被释放) */ RC_CHANNEL_INVALID = 30001, /*! 当前连接不可用 */ RC_NETWORK_UNAVAILABLE = 30002, /*! SDK没有初始化 @discussion 在使用SDK任何功能之前,必须先Init。 */ CLIENT_NOT_INIT = 33001, /*! 数据库错误 @discussion 请检查您使用的Token和userId是否正确。 */ DATABASE_ERROR = 33002, /*! 开发者接口调用时传入的参数错误 @discussion 请检查接口调用时传入的参数类型和值。 */ INVALID_PARAMETER = 33003, /*! 历史消息云存储业务未开通 */ MSG_ROAMING_SERVICE_UNAVAILABLE = 33007, }; #pragma mark - 连接状态 #pragma mark RCConnectionStatus - 网络连接状态码 /*! 网络连接状态码 @discussion 开发者仅需要关注以下几种连接状态,其余状态SDK均会进行自动重连。 ConnectionStatus_Connected, ConnectionStatus_Connecting, ConnectionStatus_Unconnected, ConnectionStatus_SignUp, ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT, ConnectionStatus_TOKEN_INCORRECT */ typedef NS_ENUM(NSInteger, RCConnectionStatus) { /*! 未知状态 */ ConnectionStatus_UNKNOWN = -1, /*! 连接成功 */ ConnectionStatus_Connected = 0, /*! 当前设备网络不可用 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_NETWORK_UNAVAILABLE = 1, /*! 当前设备切换到飞行模式 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_AIRPLANE_MODE = 2, /*! 当前设备切换到 2G(GPRS、EDGE)低速网络 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_Cellular_2G = 3, /*! 当前设备切换到 3G 或 4G 高速网络 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_Cellular_3G_4G = 4, /*! 当前设备切换到 WIFI 网络 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_WIFI = 5, /*! 当前用户在其他设备上登陆,此设备被踢下线 */ ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT = 6, /*! 当前用户在 Web 端登陆 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_LOGIN_ON_WEB = 7, /*! 服务器异常 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_SERVER_INVALID = 8, /*! 连接验证异常 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_VALIDATE_INVALID = 9, /*! 连接中 */ ConnectionStatus_Connecting = 10, /*! 连接失败或未连接 */ ConnectionStatus_Unconnected = 11, /*! 已注销 */ ConnectionStatus_SignUp = 12, /*! Token无效 @discussion Token无效一般有两种原因。一是token错误,请您检查客户端初始化使用的AppKey和您服务器获取token使用的AppKey是否一致;二是token过期,是因为您在开发者后台设置了token过期时间,您需要请求您的服务器重新获取token并再次用新的token建立连接。 */ ConnectionStatus_TOKEN_INCORRECT = 31004, /*! 与服务器的连接已断开 @discussion 建立连接的临时状态,SDK会做好自动重连,开发者无须处理。 */ ConnectionStatus_DISCONN_EXCEPTION = 31011 }; #pragma mark RCNetworkStatus - 当前所处的网络 /*! 当前所处的网络 */ typedef NS_ENUM(NSUInteger, RCNetworkStatus) { /*! 当前网络不可用 */ RC_NotReachable = 0, /*! 当前处于WiFi网络 */ RC_ReachableViaWiFi = 1, /*! 当前处于LTE网络 */ RC_ReachableViaLTE = 2, /*! 当前处于3G网络 */ RC_ReachableVia3G = 3, /*! 当前处于2G网络 */ RC_ReachableVia2G = 4 }; #pragma mark RCSDKRunningMode - SDK当前所处的状态 /*! SDK当前所处的状态 */ typedef NS_ENUM(NSUInteger, RCSDKRunningMode) { /*! 前台运行状态 */ RCSDKRunningMode_Backgroud = 0, /*! 后台运行状态 */ RCSDKRunningMode_Foregroud = 1 }; #pragma mark - 会话相关 #pragma mark RCConversationType - 会话类型 /*! 会话类型 */ typedef NS_ENUM(NSUInteger, RCConversationType) { /*! 单聊 */ ConversationType_PRIVATE = 1, /*! 讨论组 */ ConversationType_DISCUSSION = 2, /*! 群组 */ ConversationType_GROUP = 3, /*! 聊天室 */ ConversationType_CHATROOM = 4, /*! 客服1.0会话 @discussion 客服2.0使用应用内公众服务会话(ConversationType_APPSERVICE)的方式实现。 即客服2.0会话是其中一个应用内公众服务会话,我们推荐您使用和迁移到客服2.0服务。 */ ConversationType_CUSTOMERSERVICE = 5, /*! 系统会话 */ ConversationType_SYSTEM = 6, /*! 应用内公众服务会话 */ ConversationType_APPSERVICE = 7, /*! 跨应用公众服务会话 */ ConversationType_PUBLICSERVICE = 8, /*! 推送服务会话 */ ConversationType_PUSHSERVICE = 9 }; #pragma mark RCConversationNotificationStatus - 会话提醒状态 /*! 会话提醒状态 */ typedef NS_ENUM(NSUInteger, RCConversationNotificationStatus) { /*! 免打扰 */ DO_NOT_DISTURB = 0, /*! 新消息提醒 */ NOTIFY = 1, }; #pragma mark RCReadReceiptMessageType - 消息回执 /*! 已读状态消息类型 */ typedef NS_ENUM(NSUInteger, RCReadReceiptMessageType) { /*! 根据会话来更新未读消息状态 */ RC_ReadReceipt_Conversation = 1, }; #pragma mark RCChatRoomMemberOrder - 聊天室成员排列顺序 /*! 聊天室成员的排列顺序 */ typedef NS_ENUM(NSUInteger, RCChatRoomMemberOrder) { /*! 升序,返回最早加入的成员列表 */ RC_ChatRoom_Member_Asc = 1, /*! 降序,返回最晚加入的成员列表 */ RC_ChatRoom_Member_Desc = 2, }; #pragma mark - 消息相关 #pragma mark RCMessagePersistent - 消息的存储策略 /*! 消息的存储策略 */ typedef NS_ENUM(NSUInteger, RCMessagePersistent) { /*! 在本地不存储,不计入未读数 */ MessagePersistent_NONE = 0, /*! 在本地只存储,但不计入未读数 */ MessagePersistent_ISPERSISTED = 1, /*! 在本地进行存储并计入未读数 */ MessagePersistent_ISCOUNTED = 3, /*! 在本地不存储,不计入未读数,并且如果对方不在线,服务器会直接丢弃该消息,对方如果之后再上线也不会再收到此消息。 @discussion 一般用于发送输入状态之类的消息,该类型消息的messageUId为nil。 */ MessagePersistent_STATUS = 16 }; #pragma mark RCMessageDirection - 消息的方向 /*! 消息的方向 */ typedef NS_ENUM(NSUInteger, RCMessageDirection) { /*! 发送 */ MessageDirection_SEND = 1, /*! 接收 */ MessageDirection_RECEIVE = 2 }; #pragma mark RCSentStatus - 消息的发送状态 /*! 消息的发送状态 */ typedef NS_ENUM(NSUInteger, RCSentStatus) { /*! 发送中 */ SentStatus_SENDING = 10, /*! 发送失败 */ SentStatus_FAILED = 20, /*! 已发送成功 */ SentStatus_SENT = 30, /*! 对方已接收 */ SentStatus_RECEIVED = 40, /*! 对方已阅读 */ SentStatus_READ = 50, /*! 对方已销毁 */ SentStatus_DESTROYED = 60 }; #pragma mark RCReceivedStatus - 消息的接收状态 /*! 消息的接收状态 */ typedef NS_ENUM(NSUInteger, RCReceivedStatus) { /*! 未读 */ ReceivedStatus_UNREAD = 0, /*! 已读 */ ReceivedStatus_READ = 1, /*! 已听 @discussion 仅用于语音消息 */ ReceivedStatus_LISTENED = 2, /*! 已下载 */ ReceivedStatus_DOWNLOADED = 4, }; #pragma mark RCMediaType - 消息内容中多媒体文件的类型 /*! 消息内容中多媒体文件的类型 */ typedef NS_ENUM(NSUInteger, RCMediaType) { /*! 图片 */ MediaType_IMAGE = 1, /*! 语音 */ MediaType_AUDIO = 2, /*! 视频 */ MediaType_VIDEO = 3, /*! 其他文件 */ MediaType_FILE = 100 }; #pragma mark - 公众服务相关 #pragma mark RCPublicServiceType - 公众服务账号类型 /*! 公众服务账号类型 */ typedef NS_ENUM(NSUInteger, RCPublicServiceType) { /*! 应用内公众服务账号 */ RC_APP_PUBLIC_SERVICE = 7, /*! 跨应用公众服务账号 */ RC_PUBLIC_SERVICE = 8, }; #pragma mark RCPublicServiceMenuItemType - 公众服务菜单类型 /*! 公众服务菜单类型 */ typedef NS_ENUM(NSUInteger, RCPublicServiceMenuItemType) { /*! 包含子菜单的一组菜单 */ RC_PUBLIC_SERVICE_MENU_ITEM_GROUP = 0, /*! 包含查看事件的菜单 */ RC_PUBLIC_SERVICE_MENU_ITEM_VIEW = 1, /*! 包含点击事件的菜单 */ RC_PUBLIC_SERVICE_MENU_ITEM_CLICK = 2, }; #pragma mark RCSearchType - 公众服务查找匹配方式 /*! 公众服务查找匹配方式 */ typedef NS_ENUM(NSUInteger, RCSearchType) { /*! 精确匹配 */ RC_SEARCH_TYPE_EXACT = 0, /*! 模糊匹配 */ RC_SEARCH_TYPE_FUZZY = 1, }; #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCStatusMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCStatusMessage.h // Created by Heq.Shinoda on 14-6-13. #import "RCMessageContent.h" @interface RCStatusMessage : RCMessageContent @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCSuspendMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCInterruptMessage.h // Created by xugang on 15/1/12. #import #import "RCMessageContent.h" /*! 客服挂断消息的类型名 */ #define RCInterruptMessageTypeIdentifier @"RC:SpMsg" /*! 客服挂断消息类 @discussion 客服挂断消息类,此消息不存储不计入未读消息数。 结束与客服的会话之前,可以向客服发送一条此消息,客服服务器即可知道用户即将离开客服会话。 */ @interface RCSuspendMessage : RCMessageContent /*! 初始化客服挂断消息 @return 客服挂断消息的对象 */ - (instancetype)init; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCTextMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCTextMessage.h // Created by Heq.Shinoda on 14-6-13. #import "RCMessageContent.h" /*! 文本消息的类型名 */ #define RCTextMessageTypeIdentifier @"RC:TxtMsg" /*! 文本消息类 @discussion 文本消息类,此消息会进行存储并计入未读消息数。 */ @interface RCTextMessage : RCMessageContent /*! 文本消息的内容 */ @property(nonatomic, strong) NSString *content; /*! 文本消息的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化文本消息 @param content 文本消息的内容 @return 文本消息对象 */ + (instancetype)messageWithContent:(NSString *)content; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCUnknownMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCUnknownMessage.h // Created by xugang on 15/1/24. #import "RCMessageContent.h" /*! 未知消息的类型名 */ #define RCUnknownMessageTypeIdentifier @"RC:UnknownMsg" /*! 未知消息类 @discussion 所有未注册的消息类型,在IMKit中都会作为此类消息处理和显示。 */ @interface RCUnknownMessage : RCMessageContent @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCUploadImageStatusListener.h ================================================ // // RCUploadImageStatusListener.h // RongIMLib // // Created by litao on 15/8/28. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import #import "RCMessage.h" /*! 图片上传进度更新的IMKit监听 @discussion 此监听用于IMKit发送图片消息(上传到指定服务器)。 App在上传图片时,需要在监听中调用updateBlock、successBlock与errorBlock,通知IMKit SDK当前上传图片的进度和状态,SDK会更新UI。 */ @interface RCUploadImageStatusListener : NSObject /*! 上传的图片消息的消息实体 */ @property (nonatomic, strong)RCMessage *currentMessage; /*! 更新上传进度需要调用的block [progress:当前上传的进度,0 <= progress < 100] */ @property (nonatomic, strong)void (^updateBlock)(int progress); /*! 上传成功需要调用的block [imageUrl:图片的网络URL] */ @property (nonatomic, strong)void (^successBlock)(NSString *imageUrl); /*! 上传成功需要调用的block [errorCode:上传失败的错误码,非0整数] */ @property (nonatomic, strong)void (^errorBlock)(RCErrorCode errorCode); /*! 初始化图片上传进度更新的IMKit监听 @param message 图片消息的消息实体 @param progressBlock 更新上传进度需要调用的block @param successBlock 上传成功需要调用的block @param errorBlock 上传失败需要调用的block @return 图片上传进度更新的IMKit监听对象 */ - (instancetype)initWithMessage:(RCMessage *)message uploadProgress:(void (^)(int progress))progressBlock uploadSuccess:(void (^)(NSString *imageUrl))successBlock uploadError:(void (^)(RCErrorCode errorCode))errorBlock; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCUserInfo.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCUserInfo.h // Created by Heq.Shinoda on 14-6-16. #import /*! 用户信息类 */ @interface RCUserInfo : NSObject /*! 用户ID */ @property(nonatomic, strong) NSString *userId; /*! 用户名称 */ @property(nonatomic, strong) NSString *name; /*! 用户头像的URL */ @property(nonatomic, strong) NSString *portraitUri; /*! 用户信息的初始化方法 @param userId 用户ID @param username 用户名称 @param portrait 用户头像的URL @return 用户信息对象 */ - (instancetype)initWithUserId:(NSString *)userId name:(NSString *)username portrait:(NSString *)portrait; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCUserTypingStatus.h ================================================ // // RCUserTypingStatus.h // RongIMLib // // Created by 岑裕 on 16/1/8. // Copyright © 2016年 RongCloud. All rights reserved. // #import /*! 用户输入状态类 */ @interface RCUserTypingStatus : NSObject /*! 当前正在输入的用户ID */ @property(nonatomic, strong) NSString *userId; /*! 当前正在输入的消息类型名 @discussion contentType为用户当前正在编辑的消息类型名,即RCMessageContent中getObjectName的返回值。 如文本消息,应该传类型名"RC:TxtMsg"。 */ @property(nonatomic, strong) NSString *contentType; /*! 初始化用户输入状态对象 @param userId 当前正在输入的用户ID @param objectName 当前正在输入的消息类型名 @return 用户输入状态对象 */ -(instancetype)initWithUserId:(NSString *)userId contentType:(NSString *)objectName; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCUtilities.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCUtilities.h // Created by Heq.Shinoda on 14-5-15. #ifndef __RCUtilities #define __RCUtilities #import /*! 工具类 */ @interface RCUtilities : NSObject /*! 将base64编码的字符串解码并转换为NSData数据 @param string base64编码的字符串 @return 解码后的NSData数据 @discussion 此方法主要用于iOS6解码base64。 */ + (NSData *)dataWithBase64EncodedString:(NSString *)string; /*! 将NSData数据转化并编码为base64的字符串 @param data 未编码的NSData数据 @return 编码后的base64字符串 @discussion 此方法主要用于iOS6编码base64。 */ + (NSString *)base64EncodedStringFrom:(NSData *)data; /*! scaleImage @param image image @param scaleSize scaleSize @return scaled image */ + (UIImage *)scaleImage:(UIImage *)image toScale:(float)scaleSize; /*! imageByScalingAndCropSize @param image image @param targetSize targetSize @return image */ + (UIImage *)imageByScalingAndCropSize:(UIImage *)image targetSize:(CGSize)targetSize; /*! compressedImageWithMaxDataLength @param image image @param maxDataLength maxDataLength @return nsdate */ + (NSData *)compressedImageWithMaxDataLength:(UIImage *)image maxDataLength:(CGFloat)maxDataLength; /*! compressedImageAndScalingSize @param image image @param targetSize targetSize @param maxDataLen maxDataLen @return image nsdata */ + (NSData *)compressedImageAndScalingSize:(UIImage *)image targetSize:(CGSize)targetSize maxDataLen:(CGFloat)maxDataLen; /*! compressedImageAndScalingSize @param image image @param targetSize targetSize @param percent percent @return image nsdata */ + (NSData *)compressedImageAndScalingSize:(UIImage *)image targetSize:(CGSize)targetSize percent:(CGFloat)percent; /*! compressedImage @param image image @param percent percent @return image nsdata */ + (NSData *)compressedImage:(UIImage *)image percent:(CGFloat)percent; /*! excludeBackupKeyForURL @param storageURL storageURL @return BOOL */ + (BOOL)excludeBackupKeyForURL:(NSURL *)storageURL; /*! 获取App的文件存放路径 @return App的文件存放路径 */ + (NSString *)applicationDocumentsDirectory; /*! 获取融云SDK的文件存放路径 @return 融云SDK的文件存放路径 */ + (NSString *)rongDocumentsDirectory; /*! 获取融云SDK的缓存路径 @return 融云SDK的缓存路径 */ + (NSString *)rongImageCacheDirectory; /*! 获取当前系统时间 @return 当前系统时间 */ + (NSString *)currentSystemTime; /*! 获取当前运营商名称 @return 当前运营商名称 */ + (NSString *)currentCarrier; /*! 获取当前网络类型 @return 当前网络类型 */ + (NSString *)currentNetWork; /*! 获取系统版本 @return 系统版本 */ + (NSString *)currentSystemVersion; /*! 获取设备型号 @return 设备型号 */ + (NSString *)currentDeviceModel; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCVoiceMessage.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RCVoiceMessage.h // Created by Heq.Shinoda on 14-6-13. #import "RCMessageContent.h" /*! 语音消息的类型名 */ #define RCVoiceMessageTypeIdentifier @"RC:VcMsg" /*! 语音消息类 @discussion 语音消息类,此消息会进行存储并计入未读消息数。 */ @interface RCVoiceMessage : RCMessageContent /*! wav格式的音频数据 */ @property(nonatomic, strong) NSData *wavAudioData; /*! 语音消息的时长 */ @property(nonatomic, assign) long duration; /*! 语音消息的附加信息 */ @property(nonatomic, strong) NSString *extra; /*! 初始化语音消息 @param audioData wav格式的音频数据 @param duration 语音消息的时长(单位:秒) @return 语音消息对象 @discussion 如果您不是使用IMKit中的录音功能,则在初始化语音消息的时候,需要确保以下几点。 1. audioData必须是单声道的wav格式音频数据; 2. audioData的采样率必须是8000Hz,采样位数(精度)必须为16位。 您可以参考IMKit中的录音参数: NSDictionary *settings = @{AVFormatIDKey: @(kAudioFormatLinearPCM), AVSampleRateKey: @8000.00f, AVNumberOfChannelsKey: @1, AVLinearPCMBitDepthKey: @16, AVLinearPCMIsNonInterleaved: @NO, AVLinearPCMIsFloatKey: @NO, AVLinearPC'MIsBigEndianKey: @NO}; */ + (instancetype)messageWithAudio:(NSData *)audioData duration:(long)duration; @end ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RCWatchKitStatusDelegate.h ================================================ // // RCWatchKitStatusDelegate.h // RongIMLib // // Created by litao on 15/6/4. // Copyright (c) 2015年 RongCloud. All rights reserved. // #ifndef RongIMLib_RCwatchKitStatusDelegate_h #define RongIMLib_RCwatchKitStatusDelegate_h /*! 用于Apple Watch的IMLib事务监听器 @discussion 此协议定义了IMLib在状态变化和各种活动时的回调,主要用于Apple Watch。 */ @protocol RCWatchKitStatusDelegate @optional #pragma mark 连接状态 /*! 连接状态发生变化的回调 @param status SDK与融云服务器的连接状态 */ - (void)notifyWatchKitConnectionStatusChanged:(RCConnectionStatus) status; #pragma mark 消息接收与发送 /*! 收到消息的回调 @param receivedMsg 收到的消息实体 */ - (void)notifyWatchKitReceivedMessage:(RCMessage *)receivedMsg; /*! 向外发送消息的回调 @param message 待发送消息 */ - (void)notifyWatchKitSendMessage:(RCMessage *)message; /*! 发送消息完成的回调 @param messageId 消息ID @param status 完成的状态吗。0表示成功,非0表示失败 */ - (void)notifyWatchKitSendMessageCompletion:(long)messageId status:(RCErrorCode)status; /*! 上传图片进度更新的回调 @param progress 进度 @param messageId 消息ID */ - (void)notifyWatchKitUploadFileProgress:(int)progress messageId:(long)messageId; #pragma mark 消息与会话操作 /*! 删除会话的回调 @param conversationTypeList 会话类型的数组 */ - (void)notifyWatchKitClearConversations:(NSArray *)conversationTypeList; /*! 删除消息的回调 @param conversationType 会话类型 @param targetId 目标会话ID */ - (void)notifyWatchKitClearMessages:(RCConversationType)conversationType targetId:(NSString *)targetId; /*! 删除消息的回调 @param messageIds 消息ID的数组 */ - (void)notifyWatchKitDeleteMessages:(NSArray *)messageIds; /*! 清除未读消息数的回调 @param conversationType 会话类型 @param targetId 目标会话ID */ - (void)notifyWatchKitClearUnReadStatus:(RCConversationType)conversationType targetId:(NSString *)targetId; #pragma mark 讨论组 /*! 创建讨论组的回调 @param name 讨论组名称 @param userIdList 成员的用户ID列表 */ - (void)notifyWatchKitCreateDiscussion:(NSString *)name userIdList:(NSArray *)userIdList; /*! 创建讨论组成功的回调 @param discussionId 讨论组的ID */ - (void)notifyWatchKitCreateDiscussionSuccess:(NSString *)discussionId; /*! 创建讨论组失败 @param errorCode 创建失败的错误码 */ - (void)notifyWatchKitCreateDiscussionError:(RCErrorCode)errorCode; /*! 讨论组加人的回调 @param discussionId 讨论组的ID @param userIdList 添加成员的用户ID列表 @discussion 加人的结果可以通过notifyWatchKitDiscussionOperationCompletion获得。 */ - (void)notifyWatchKitAddMemberToDiscussion:(NSString *)discussionId userIdList:(NSArray *)userIdList; /*! 讨论组踢人的回调 @param discussionId 讨论组ID @param userId 用户ID @discussion 踢人的结果可以通过notifyWatchKitDiscussionOperationCompletion获得。 */ - (void)notifyWatchKitRemoveMemberFromDiscussion:(NSString *)discussionId userId:(NSString *)userId; /*! 退出讨论组的回调 @param discussionId 讨论组ID @discussion 创建的结果可以通过notifyWatchKitDiscussionOperationCompletion获得。 */ - (void)notifyWatchKitQuitDiscussion:(NSString *)discussionId; /*! 讨论组操作的回调。tag:100-邀请;101-踢人;102-退出。status:0成功,非0失败 @param tag 讨论组的操作类型。100为加人,101为踢人,102为退出 @param status 操作的结果。0表示成功,非0表示失败 */ - (void)notifyWatchKitDiscussionOperationCompletion:(int)tag status:(RCErrorCode)status; @end #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/RongIMLib.h ================================================ /** * Copyright (c) 2014-2015, RongCloud. * All rights reserved. * * All the contents are the copyright of RongCloud Network Technology Co.Ltd. * Unless otherwise credited. http://rongcloud.cn * */ // RongIMLib.h // Created by xugang on 14/12/11. #import //! Project version number for RongIMLib. FOUNDATION_EXPORT double RongIMLibVersionNumber; //! Project version string for RongIMLib. FOUNDATION_EXPORT const unsigned char RongIMLibVersionString[]; /// IMLib核心类 #import #import /// 会话相关类 #import #import #import #import #import /// 消息相关类 #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import /// 工具类 #import #import #import #import /// 其他 #import #import #import #import #import #import #import #import ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/interf_dec.h ================================================ /* ------------------------------------------------------------------ * Copyright (C) 2009 Martin Storsjo * * 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. * ------------------------------------------------------------------- */ #ifndef OPENCORE_AMRNB_INTERF_DEC_H #define OPENCORE_AMRNB_INTERF_DEC_H #ifdef __cplusplus extern "C" { #endif void* Decoder_Interface_init(void); void Decoder_Interface_exit(void* state); void Decoder_Interface_Decode(void* state, const unsigned char* in, short* out, int bfi); #ifdef __cplusplus } #endif #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/Headers/interf_enc.h ================================================ /* ------------------------------------------------------------------ * Copyright (C) 2009 Martin Storsjo * * 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. * ------------------------------------------------------------------- */ #ifndef OPENCORE_AMRNB_INTERF_ENC_H #define OPENCORE_AMRNB_INTERF_ENC_H #ifdef __cplusplus extern "C" { #endif #ifndef AMRNB_WRAPPER_INTERNAL /* Copied from enc/src/gsmamr_enc.h */ enum Mode { MR475 = 0,/* 4.75 kbps */ MR515, /* 5.15 kbps */ MR59, /* 5.90 kbps */ MR67, /* 6.70 kbps */ MR74, /* 7.40 kbps */ MR795, /* 7.95 kbps */ MR102, /* 10.2 kbps */ MR122, /* 12.2 kbps */ MRDTX, /* DTX */ N_MODES /* Not Used */ }; #endif void* Encoder_Interface_init(int dtx); void Encoder_Interface_exit(void* state); int Encoder_Interface_Encode(void* state, enum Mode mode, const short* speech, unsigned char* out, int forceSpeech); #ifdef __cplusplus } #endif #endif ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongIMLib.framework/RongIMLib ================================================ [File too large to display: 18.3 MB] ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/en.lproj/RongCloudKit.strings ================================================ /* RongCloudKit.strings RongIMKit Created by xugang on 1/15/15. Copyright (c) 2015 RongCloud. All rights reserved. */ "RC:ImgMsg" = "[Image]"; "RC:LBSMsg" = "[Location]"; "RC:VcMsg" = "[Voice]"; "RC:ImgTextMsg" = "[RichContent]"; "RC:VoipCallMsg" = "[VoIP Start]"; "RC:VoipFinishMsg" = "[VoIP End]"; "RC:PSMultiImgTxtMsg" = "[RichContent]"; "RC:PSImgTxtMsg" = "[RichContent]"; "Draft"="[Draft]"; "conversation_private_collection_title" = "Private Groups"; "conversation_customer_collection_title" = "Customer Groups"; "conversation_group_collection_title" = "My Groups"; "conversation_discussion_collection_title" = "Discussion Groups"; "conversation_systemMessage_collection_title" = "System Messages"; "hold_to_talk_title"="Hold to talk"; "release_to_send_title"="Release to send"; "message_too_short"="Message too short"; "slide_up_to_cancel_title"="Slide up to cancel"; "release_to_cancel_title"="Release to cancel "; "whiteSpaceMessage"="Can't send white space message"; "OK"="Ok"; "Cancel"="Cancel"; "speakerAccessRight"="You don't have the access right of speaker, please set it in Settings"; "VoIP_Mute"="Mute"; "VoIP_Speaker"="Speaker"; "VoIP_End"="End"; "VoIP_Answer"="Answer"; "VoIP_Reject"="Reject"; "VoIP_Drop"="Drop"; "Request_Friends_extra"="You have received a message for requesting add friends"; "Setting"="Setting"; "Back"="Back"; "IsDeleteHistoryMsg"="Do you want to delete history message?"; "ConnectionIsNotReachable"="Network connection is not reachable, please check it"; "Album"="Album"; "Photo"="Photo"; "Location"="Location"; "Audio"="Audio"; "Albums"="Albums"; "unknown_message_cell_tip"="The current version is not available for viewing this message"; "unknown_message_notification_tip"="Receive an unkown message"; "Copy"="Copy"; "Delete"="Delete"; "Save"="Save"; "SavePhotoFailed"="Failed to save this photo"; "SavePhotoSuccess"="Saved"; "PickLocation"="Pick Location"; "More"="More"; "Done"="Done"; "Longitude"="Longitude"; "Latitude"="Latitude"; "LocationInformation"="Location information"; "LocalNotificationShow"="Show"; "PhotoAccessRight"="You have no access right"; "MaxNumSelectPhoto"="Max number is 9 for selection"; "AllPhoto"="All Photo"; "NoPhotoTitle"="No Photos or Videos"; "NoPhotoDesc"="You can sync photos and videos onto your iPhone using iTunes."; "Send"="Send"; "SetToTop"="Sticky to Top"; "NewMsgNotification"="New Message Notification"; "ClearRecord"="Clear Chat History"; "CanNotRemoveSelf"="Can't remove youself"; "MemberNumber"="members"; "Invite"="invite"; "JoinDiscussion"="joined discussion"; "QuitDiscussion"="quite discussion"; "By"="by"; "RemoveDiscussion"="removed from discussion"; "ModifyDiscussion"="modify discussion"; "InviteStatus"="invitation"; "Open"="Open"; "Close"="Close"; "VoIP_Calling"="Calling..."; "VoIP_Talking"="Calling number is talking"; "VoIP_Offline"="Calling number is offline"; "VoIP_Net_busy"="Network is busy"; "VoIP_Not_Accept"="Call has no answer"; "VoIP_Rejected_By_Blacklist"="Your call has sent out, but been rejected by the receiver"; "WaitingForAcceptInvitation"="Waiting for accept calling invitation..."; "VoIP_CallingFailed"="Calling is failed, please try again"; "VoIP_invite"="Invite you for talking"; "VoIP_Incoming_Notification"="Invite you for a call"; "VoIP_Accepted_Notification"="Call accepted"; "VoIP_SessionIDWrong"="Session ID is wrong"; "Yesterday"="Yesterday"; "SearchPublicService"="Search Public Service"; "PublicService"="Public Service"; "NOT_IN_DISCUSSION"="You are not in current discussion"; "NOT_IN_GROUP"="You are not in current group"; "FORBIDDEN_IN_GROUP"="You were forbidden to send message in current group."; "NOT_IN_CHATROOM"="You are not in current chat room"; "Message rejected"="Your message have sent out, but rejected by the receiver"; "AccessRightTitle"="no access right"; "ForbiddenInChatRoom"="You were forbidden to send message in current chatroom."; "KickedFromChatRoom"="You were kicked from current chatroom."; "JoinChatRoomRejected"="You were forbidden to join current chatroom, please contact customer service."; "JoinChatRoomFailed"="Join chat room failed"; "Connecting..."="Connecting..."; "FromFriendInvitation"="From %@ friend invitation"; "AddFriendInvitation"="Add Friend Invitation"; "ReadAll"="Read all"; "OfficialAccounts"="Official Accounts"; "Share"="Share Name Card"; "Report"="Report"; "OpenURLInBrowser"="Open in Safari"; "CopyURL"="Copy URL"; "ClearHistory"="Clear History"; "Unfollow"="Unfollow"; "Introduced"="Intro"; "AccountType"="Account Type"; "ServicePhone"="Customer service hotline"; "BusinessScope"="Business Scope"; "NewMessageNotification"="New message notification"; "ViewHistory"="View History"; "EnterOfficialAccount"="Enter Official Account"; "Attention"="Follow"; "PublicNum"="Public service : %@"; "Wait"="Please wait a moment..."; "Searching"="Searching..."; "Search"="Search:"; "Right_unReadMessage"="%ld new message"; "HistoryMessageTip"="Above is the historical messages"; "DISCUSSION"="discussion"; "DateFormat"="MM-dd"; "MessageHasRead"="Read"; "MessageHasSend"="Sent"; "Full_Image"="Full Image"; "typing"="typing..."; "Speaking"="Speaking..."; ================================================ FILE: Sublime/Pods/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/zh-Hans.lproj/RongCloudKit.strings ================================================ /* RongCloudKit.strings RongIMKit Created by xugang on 1/15/15. Copyright (c) 2015 RongCloud. All rights reserved. */ "RC:ImgMsg" = "[图片]"; "RC:LBSMsg" = "[位置]"; "RC:VcMsg" = "[语音]"; "RC:ImgTextMsg" = "[图文]"; "RC:VoipCallMsg" = "[语音通话]"; "RC:VoipFinishMsg" = "[语音结束]"; "RC:PSMultiImgTxtMsg" = "[图文]"; "RC:PSImgTxtMsg" = "[图文]"; "Draft"="[草稿]"; "conversation_private_collection_title" = "聊天助手"; "conversation_customer_collection_title" = "客服助手"; "conversation_group_collection_title" = "群助手"; "conversation_discussion_collection_title" = "讨论组助手"; "conversation_systemMessage_collection_title" = "系统消息助手"; "hold_to_talk_title"="按住说话"; "release_to_send_title"="松开发送"; "slide_up_to_cancel_title"="手指上滑 取消发送"; "release_to_cancel_title"="手指松开 取消发送"; "message_too_short"="录音时间短"; "whiteSpaceMessage"="不能发送空白消息"; "OK"="确定"; "Cancel"="取消"; "speakerAccessRight"="您没有麦克风访问权限,请前往“设置-隐私-麦克风”选项中,允许访问您的手机麦克风!"; "VoIP_Mute"="静音"; "VoIP_Speaker"="免提"; "VoIP_End"="结束"; "VoIP_Answer"="应答"; "VoIP_Reject"="拒接"; "VoIP_Drop"="挂断"; "Request_Friends_extra"="请求添加好友消息"; "Setting"="设置"; "Back"="返回"; "IsDeleteHistoryMsg"="是否删除历史消息?"; "ConnectionIsNotReachable"="网络连接不可用,请检查"; "Album"="相册"; "Photo"="照相"; "Location"="位置"; "Audio"="语音通话"; "Albums"="相册列表"; "unknown_message_cell_tip"="当前版本暂不支持查看此消息"; "unknown_message_notification_tip"="收到一条不支持的消息"; "Copy"="复制"; "Delete"="删除"; "Save"="保存"; "SavePhotoFailed"="图片保存失败"; "SavePhotoSuccess"="图片保存成功"; "PickLocation"="选取位置"; "More"="更多"; "Done"="完成"; "Longitude"="经度"; "Latitude"="纬度"; "LocationInformation"="位置信息"; "LocalNotificationShow"="显示"; "PhotoAccessRight"="没有访问权限,请前往“设置-隐私-照片”选项中,允许访问您的照片"; "MaxNumSelectPhoto"="最多选择9张"; "AllPhoto"="全部照片"; "NoPhotoTitle"="无照片或视频"; "NoPhotoDesc"="您可以使用相机拍摄照片和视频,或使用iTunes将照片和视频同步到iPhone."; "Send"="发送"; "SetToTop"="置顶聊天"; "NewMsgNotification"="新消息通知"; "ClearRecord"="清除聊天记录"; "CanNotRemoveSelf"="不能移除自己"; "MemberNumber"="位成员"; "Invite"="邀请"; "JoinDiscussion"="加入了讨论组"; "QuitDiscussion"="退出了讨论组"; "By"="被"; "RemoveDiscussion"="移除了讨论组"; "ModifyDiscussion"="修改讨论组为"; "InviteStatus"="了成员邀请"; "Open"="开启"; "Close"="关闭"; "VoIP_Calling"="正在拨号..."; "VoIP_Talking"="对方正在通话!"; "VoIP_Offline"="对方不在线!"; "VoIP_Net_busy"="网络繁忙,稍后再试!"; "VoIP_Not_Accept"="对方未接听"; "VoIP_Rejected_By_Blacklist"="您的通话请求已发出,但被对方拒绝"; "WaitingForAcceptInvitation"="正在等待对方接受邀请..."; "VoIP_CallingFailed"="呼叫建立失败,请重新再拨"; "VoIP_invite"="邀请您接受聊天"; "VoIP_Incoming_Notification"="发起了语音通话"; "VoIP_Accepted_Notification"="接受了语音通话"; "VoIP_SessionIDWrong"="呼叫Session ID 错误"; "Yesterday"="昨天"; "SearchPublicService"="查找服务号"; "PublicService"="服务号"; "NOT_IN_DISCUSSION"="您当前不在此讨论组"; "NOT_IN_GROUP"="您当前不在此群组"; "FORBIDDEN_IN_GROUP"="您在当前群组中被禁言。"; "NOT_IN_CHATROOM"="您当前不在此聊天室"; "Message rejected"="您的消息已发出,但被对方拒绝"; "AccessRightTitle"="无法访问"; "ForbiddenInChatRoom"="你已被禁言,不能发送消息。"; "KickedFromChatRoom"="你已被踢出聊天室。"; "JoinChatRoomRejected"="你被禁止加入聊天室,请联系客服。"; "JoinChatRoomFailed"="加入聊天室失败"; "Connecting..."="连接中..."; "FromFriendInvitation"="来自%@的好友请求"; "AddFriendInvitation"="添加好友请求"; "ReadAll"="阅读全文"; "OfficialAccounts"="公共账号"; "Share"="推荐给朋友"; "Report"="举报"; "OpenURLInBrowser"="在Safari中打开"; "CopyURL"="复制链接"; "ClearHistory"="清空内容"; "Unfollow"="不再关注"; "Introduced"="功能介绍"; "AccountType"="账号主体"; "ServicePhone"="服务电话"; "BusinessScope"="经营范围"; "NewMessageNotification"="新消息通知"; "ViewHistory"="查看历史消息"; "EnterOfficialAccount"="进入公众账号"; "Attention"="关注"; "PublicNum"="公众号:%@"; "Wait"="请稍等..."; "Searching"="搜索中..."; "Search"="搜索:"; "Right_unReadMessage"="%ld 条新消息"; "HistoryMessageTip"="以上是历史消息"; "DISCUSSION"="讨论组"; "DateFormat"="MM月dd日"; "MessageHasRead"="已读"; "MessageHasSend"="已发"; "Full_Image"="原图"; "typing"="对方正在输入..."; "Speaking"="对方正在讲话..."; ================================================ FILE: Sublime/Pods/SJCSimplePDFView/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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/SJCSimplePDFView/README.md ================================================ # SJCSimplePDFView A simple UIView subclass for displaying PDFs on iOS. I created this for a project when displaying a PDF in a UIWebView didn't provide either the styling options or feedback required. The PDFView: * Provides 3 different display modes * Allows customisation of page backgrounds, borders and insets * Allows display to be limited to a subset of pages within a PDF document * Allows observation of visible page number (or numbers) * Integrates with Interface Builder (mostly IBInspectable) This repository contains an example app which you can use to play around with the PDFView's settings to see what it can do. Installation ------------ Copy the `SJCSimplePDFView.h` and `SJCSimplePDFView.m` files into your project. (Cocopods integration coming soon.) Use --- The PDFView can be created and configured via Interface Builder, or in code (using `-initWithFrame:`). A PDF document can be loaded into the PDFView in one of 3 ways: * Set the `.PDFData` property to an NSData object containing a PDF file. * Set the `.PDFFileURL` to the URL of a PDF document. Note that this should be a local file URL (file://...). An exception will be thrown if you attempt to set this value with any other URL. * Set the `.PDFBundleFileName` property to the filename of a PDF document included in your app bundle. This property can also be set in Interface Builder (although the content of the PDF is not currently shown in Interface Builder). `.viewMode` can be specified in Interface Builder. (Due to current limitations with working with enums this is an integer field which can take any value. Only the values noted in brackets below are valid, other values will be interpreted as 0.) It has 3 possible display modes: * `kSJCPDFViewModeContinuous` [0] -- pages are displayed end-to-end, with width set to the widht of the PDFView, and scroll vertically * `kSJCPDFViewModePageVertical` [1] -- pages are displayed individually, scaled to fit the PDFView, and scroll vertically * `kSJCPDFViewModePageHorizontal` [2] -- pages are displayed individually, scaled to fit the PDFView, and scroll horizontally Once a document is set, the number of pages it contain can be found in `.documentPageCount`. By default, all pages from the document are shown. To display only a subset of pages, set `.displayPages` to a NSIndexSet containing the page numbers to display. `.displayedPageCount` contains the number of pages from the document which will actually be displayed. `.currentPage` is the number of the page currently displayed. If more than one page can be visible at once (if `.viewMode` is `kSJCPDFViewModeContinuous`) `.currentPages` returns as NSIndexSet containing the page numbers of all the visible pages (in other modes it returns an NSIndexSet containing only `.currentPage`). Page numbers start at 1 and are based on the `.displayedPages`, not a page's position in the PDF document, so if you are only showing pages 21-25 of a document `.currentPage` will report these as pages 1-5. Setting `.currentPage` changes the displayed page, as long as the new value is between 1 and `.displayedPageCount` inclusive. If you would like to track user interaction with the PDFView, `.currentPage` is KVO compliant (see the example app). The inset of a page from the edges of the PDFView can be set via `.pageInsets`. The background of this inset area can be set with `.pageBackgroundColour`. (Note that most PDFs with white backgrounds are effectively transparent.) The width and colour of the border drawn around this inset area can be specified with `.borderColour` and `.borderWidth`. All of these properties can be set in Interface Builder. ================================================ FILE: Sublime/Pods/SJCSimplePDFView/SJCSimplePDFView/SJCSimplePDFView.h ================================================ /* The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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 typedef NS_ENUM(NSUInteger, SJCPDFViewMode) { kSJCPDFViewModeContinuous, kSJCPDFViewModePageVertical, kSJCPDFViewModePageHorizontal, }; IB_DESIGNABLE @interface SJCSimplePDFView : UIScrollView // name of a file in the app's bundle to display @property (nonatomic,strong) IBInspectable NSString *PDFBundleFileName; // URL pointing to the file to display @property (nonatomic,strong) NSURL *PDFFileURL; // the raw PDF data @property (nonatomic,copy) NSData *PDFData; #if !TARGET_INTERFACE_BUILDER // defaults to kSJCPDFViewModeContinuous @property (nonatomic) SJCPDFViewMode viewMode; #else @property (nonatomic) IBInspectable NSUInteger viewMode; #endif // current visible page (topmost page for kSJCPDFViewModeContinuous) // KVO-able, in case you want to track user interaction with the view @property (nonatomic) NSUInteger currentPage; // a set containing details of the pages currently visible @property (nonatomic,readonly) NSIndexSet *currentPages; // number of pages in the PDF document @property (nonatomic,readonly) NSUInteger documentPageCount; // a set containing the pages which can be displayed. nil means display all @property (nonatomic,copy) NSIndexSet *displayPages; // number of pages from the PDF document which are available for display @property (nonatomic,readonly) NSUInteger displayedPageCount; // margin around each page @property (nonatomic) UIEdgeInsets pageInsets; // because IBDesignable needs a little more work @property (nonatomic) IBInspectable CGFloat topPageInset; @property (nonatomic) IBInspectable CGFloat bottomPageInset; @property (nonatomic) IBInspectable CGFloat leftPageInset; @property (nonatomic) IBInspectable CGFloat rightPageInset; @property (nonatomic,strong) IBInspectable UIColor *pageBackgroundColour; // these are only visible if edge insets are non-zero @property (nonatomic,strong) IBInspectable UIColor *borderColour; @property (nonatomic) IBInspectable CGFloat borderWidth; @end ================================================ FILE: Sublime/Pods/SJCSimplePDFView/SJCSimplePDFView/SJCSimplePDFView.m ================================================ /* The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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 "SJCSimplePDFView.h" // distance outside content view to add extra page views static CGFloat const PageCachingMargin = 100.f; static CGFloat const DoublePageCachingMargin = PageCachingMargin * 2.f; @interface SJCSimplePDFView () @property (nonatomic,assign) CGPDFDocumentRef document; @property (nonatomic) NSUInteger documentPageCount; @property (nonatomic) NSUInteger displayedPageCount; @property (nonatomic,strong) UIView *pagesContainer; @property (nonatomic,strong) NSArray *pages; @property (nonatomic,strong) NSArray *pageFrames; @property (nonatomic,strong) NSMutableDictionary *pageViews; @property (nonatomic) CGSize lastLaidOutSize; @property (nonatomic,assign) CGColorSpaceRef cs; @property (nonatomic,weak) NSObject *externalDelegate; @end @implementation SJCSimplePDFView #pragma mark - lifecycle - (instancetype)initWithFrame:(CGRect)frame { if((self = [super initWithFrame:frame])) { [self _setup]; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { if((self = [super initWithCoder:aDecoder])) { [self _setup]; } return self; } - (void)_setup { _pagesContainer = [[UIView alloc] initWithFrame:self.bounds]; [self addSubview:_pagesContainer]; super.delegate = self; _cs = CGColorSpaceCreateDeviceRGB(); } - (void)dealloc { if(_document) { CGPDFDocumentRelease(_document); _document = NULL; } if(_cs) { CGColorSpaceRelease(_cs); _cs = NULL; } } #pragma mark - setting the document - (void)setPDFBundleFileName:(NSString *)PDFBundleFileName { NSParameterAssert(PDFBundleFileName.length); #if TARGET_INTERFACE_BUILDER NSURL *fileURL = [[NSBundle bundleForClass:[self class]] URLForResource:[PDFBundleFileName stringByDeletingPathExtension] withExtension:[PDFBundleFileName pathExtension]]; #else NSURL *fileURL = [[NSBundle mainBundle] URLForResource:[PDFBundleFileName stringByDeletingPathExtension] withExtension:[PDFBundleFileName pathExtension]]; #endif if(!fileURL) { NSLog(@"error: unable to find '%@' in the main app bundle", PDFBundleFileName); return; } self.PDFFileURL = fileURL; _PDFBundleFileName = PDFBundleFileName; } - (void)setPDFFileURL:(NSURL *)PDFFileURL { NSParameterAssert(PDFFileURL.isFileURL); NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:PDFFileURL options:NSDataReadingMappedIfSafe error:&error]; if(!data) { NSLog(@"error loading data from URL %@: %@", PDFFileURL, error); return; } if(!data.length) { NSLog(@"error: loading %@ resulted in 0-length data", PDFFileURL); return; } self.PDFData = data; _PDFBundleFileName = nil; _PDFFileURL = PDFFileURL; } - (void)setPDFData:(NSData *)PDFData { NSParameterAssert(PDFData.length); CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)PDFData); CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(provider); CGDataProviderRelease(provider); if(!document) { NSLog(@"error creating PDF document from data"); return; } _PDFFileURL = nil; _PDFData = PDFData; _document = document; [self _configureForDocument]; } // setup values which are derived from the current PDF document - (void)_configureForDocument { _documentPageCount = CGPDFDocumentGetNumberOfPages(_document); if(!_documentPageCount) { NSLog(@"warning: document has no pages!"); return; // not much else we can do... } _currentPage = 1; NSMutableArray *pages = [NSMutableArray new]; if(_displayPages) { [_displayPages enumerateIndexesInRange:NSMakeRange(1, _documentPageCount) options:kNilOptions usingBlock:^(NSUInteger page, BOOL *stop) { [pages addObject:(__bridge id)CGPDFDocumentGetPage(_document, page)]; }]; } else { NSUInteger page = 1; while(page <= _documentPageCount) { [pages addObject:(__bridge id)CGPDFDocumentGetPage(_document, page++)]; } } _pages = [pages copy]; _displayedPageCount = _pages.count; [self _resetPageViews]; self.contentOffset = CGPointZero; } - (void)_resetPageViews { [_pageViews.allValues enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { [view removeFromSuperview]; }]; _pageViews = [NSMutableDictionary new]; _pageFrames = nil; } #pragma mark - IB_DESIGNABLE #if TARGET_INTERFACE_BUILDER - (void)prepareForInterfaceBuilder { if(!_PDFData.length) { // create a blank A4 PDF page to display as example content self.PDFData = ({ NSMutableData *data = [NSMutableData new]; CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data); CGRect box = (CGRect){ CGPointZero, CGSizeMake(210.f * 72.0f * 0.393700787f, 297.f * 72.0f * 0.393700787f) }; CGContextRef context = CGPDFContextCreate(consumer, &box, NULL); CGPDFContextBeginPage(context, NULL); CGPDFContextEndPage(context); CGPDFContextClose(context); CGContextRelease(context); CGDataConsumerRelease(consumer); data; }); } } #endif #pragma mark - - (void)setDisplayPages:(NSIndexSet *)displayPages { _displayPages = [displayPages copy]; [self _resetPageViews]; [self setNeedsLayout]; } - (void)setViewMode:(SJCPDFViewMode)viewMode { // sanity check because of the hoops we're jumping through to make this IBInspectable if(viewMode < kSJCPDFViewModeContinuous || viewMode > kSJCPDFViewModePageHorizontal) { return; } if(_viewMode != viewMode) { // do basic configuration for the new mode switch((_viewMode = viewMode)) { case kSJCPDFViewModeContinuous: self.pagingEnabled = NO; break; case kSJCPDFViewModePageHorizontal: case kSJCPDFViewModePageVertical: self.pagingEnabled = YES; break; } // most other view configuration happens in -didLayoutSubviews [self _resetPageViews]; [self setNeedsLayout]; } } - (void)setCurrentPage:(NSUInteger)currentPage { if(_currentPage != currentPage && (_displayPages == nil || [_displayPages containsIndex:currentPage])) { _currentPage = currentPage; self.contentOffset = ({ CGSize size = UIEdgeInsetsInsetRect(self.bounds, self.contentInset).size; CGPoint offset; switch(_viewMode) { case kSJCPDFViewModeContinuous: offset = [_pageFrames[currentPage - 1] CGRectValue].origin; offset.x = 0.f; offset.y = offset.y - _pageInsets.right - self.contentInset.top; break; case kSJCPDFViewModePageVertical: offset = CGPointMake(0.f, size.height * currentPage); break; case kSJCPDFViewModePageHorizontal: offset = CGPointMake(size.width * currentPage, 0.f); break; } offset; }); [self _configureVisiblePages]; } } // the pages which are (should be) visible - (NSIndexSet *)currentPages { NSMutableIndexSet *indexSet = [NSMutableIndexSet new]; CGRect visibleRect = UIEdgeInsetsInsetRect((CGRect){ self.contentOffset, self.bounds.size }, self.contentInset); [_pageViews enumerateKeysAndObjectsUsingBlock:^(NSNumber *index, UIView *view, BOOL *stop) { if(CGRectIntersectsRect(visibleRect, view.frame)) { [indexSet addIndex:view.tag]; } }]; return [indexSet copy]; } #pragma mark - view layout - (void)setNeedsLayout { _lastLaidOutSize = CGSizeZero; [super setNeedsLayout]; } - (void)layoutSubviews { [super layoutSubviews]; CGRect bounds = UIEdgeInsetsInsetRect((CGRect){ CGPointZero, self.bounds.size }, self.contentInset); if(CGSizeEqualToSize(_lastLaidOutSize, bounds.size)) { return; // we've already laid out for this view size } _lastLaidOutSize = bounds.size; CGSize __block contentSize; CGPoint __block contentOffset; NSMutableArray *pageFrames = [NSMutableArray new]; switch(_viewMode) { case kSJCPDFViewModeContinuous: { // scrollable content will be as wide as the view contentSize = CGSizeMake(bounds.size.width, 0.f); // calculate what we can about the size of the first page: its width and x position CGRect __block pageFrame = CGRectMake(_pageInsets.left, 0.f, contentSize.width - _pageInsets.left - _pageInsets.right, 0.f); [_pages enumerateObjectsUsingBlock:^(id page, NSUInteger index, BOOL *stop) { CGSize pageSize = CGPDFPageGetBoxRect((__bridge CGPDFPageRef)page, kCGPDFMediaBox).size; int rotation = CGPDFPageGetRotationAngle((__bridge CGPDFPageRef)page); if(rotation == 90 || rotation == 270) { pageSize = CGSizeMake(pageSize.height, pageSize.width); } pageFrame.origin.y += _pageInsets.top; pageFrame.size.height = roundf(pageFrame.size.width * (pageSize.height / pageSize.width)); [pageFrames addObject:[NSValue valueWithCGRect:pageFrame]]; UIView *view = _pageViews[@(index)]; if(view) { view.frame = pageFrame; } if(_currentPage - 1 == index) { contentOffset = CGPointMake(0.f, pageFrame.origin.y - _pageInsets.top); } // advance to the next page frame position pageFrame.origin.y += pageFrame.size.height + _pageInsets.bottom; }]; contentSize.height = pageFrame.origin.y; } break; case kSJCPDFViewModePageVertical: case kSJCPDFViewModePageHorizontal: { CGFloat xd = 0.f; CGFloat yd = 0.f; // code paths for these modes are mostly the same, except for this bit if(_viewMode == kSJCPDFViewModePageHorizontal) { xd = bounds.size.width; contentSize = CGSizeMake(bounds.size.width * _displayedPageCount, bounds.size.height); contentOffset = CGPointMake(bounds.size.width * (_currentPage - 1), 0.f); } else { yd = bounds.size.height; contentSize = CGSizeMake(bounds.size.width, bounds.size.height * _displayedPageCount); contentOffset = CGPointMake(0.f, bounds.size.height * (_currentPage - 1)); } CGRect __block pageFrame = UIEdgeInsetsInsetRect(bounds, _pageInsets); [_pages enumerateObjectsUsingBlock:^(id page, NSUInteger index, BOOL *stop) { CGSize pageSize = CGPDFPageGetBoxRect((__bridge CGPDFPageRef)page, kCGPDFMediaBox).size; // calculate the page frame which fits -- attempt to fit full height first CGRect frame; CGFloat width = roundf(pageFrame.size.height * (pageSize.width / pageSize.height)); if(width <= pageFrame.size.width) { // fits, so adjust x offsets frame = CGRectMake(pageFrame.origin.x + roundf((pageFrame.size.width - width) / 2.f), pageFrame.origin.y, width, pageFrame.size.height); } else { // doesn't fit, so assume we're fitting across full width CGFloat height = roundf(pageFrame.size.width * (pageSize.height / pageSize.width)); frame = CGRectMake(pageFrame.origin.x, pageFrame.origin.y + roundf((pageFrame.size.height - height) / 2.f), pageFrame.size.width, height); } [pageFrames addObject:[NSValue valueWithCGRect:frame]]; UIView *view = _pageViews[@(index)]; if(view) { view.frame = frame; } // advance to the next page frame position pageFrame.origin.x += xd; pageFrame.origin.y += yd; }]; } break; default: return; break; } _pageFrames = [pageFrames copy]; _pagesContainer.frame = (CGRect){ CGPointZero, contentSize }; self.contentSize = contentSize; //self.contentOffset = contentOffset; [self _configureVisiblePages]; } - (void)_configureVisiblePages { // calculate the visible part of the scrollview, plus an overlap which will cache the neighbouring views CGFloat zoom = self.zoomScale; CGPoint offset = ({ CGPoint offset = self.contentOffset; UIEdgeInsets insets = self.contentInset; offset.x += insets.left; offset.y += insets.top; offset; }); CGSize visible = UIEdgeInsetsInsetRect(self.bounds, self.contentInset).size; CGRect visibleRect = CGRectMake(offset.x / zoom, offset.y / zoom, visible.width / zoom, visible.height / zoom); if(_viewMode == kSJCPDFViewModePageHorizontal) { visibleRect.origin.x -= PageCachingMargin; visibleRect.size.width += DoublePageCachingMargin; } else { visibleRect.origin.y -= PageCachingMargin; visibleRect.size.height += DoublePageCachingMargin; } // calculate which views should be visible and add them to the scrollview NSMutableIndexSet *visibleViewIdexes = [NSMutableIndexSet new]; [_pageFrames enumerateObjectsUsingBlock:^(NSValue *value, NSUInteger index, BOOL *stop) { if(CGRectIntersectsRect(visibleRect, value.CGRectValue)) { [visibleViewIdexes addIndex:index]; [self _displayPageAtIndex:index]; } }]; // remove the views which should no longer be visible NSMutableIndexSet *removableViewIndexes = [NSMutableIndexSet new]; [_pageViews enumerateKeysAndObjectsUsingBlock:^(NSNumber *index, UIView *view, BOOL *stop) { NSUInteger i = index.integerValue; if(![visibleViewIdexes containsIndex:i]) { [removableViewIndexes addIndex:i]; [view removeFromSuperview]; } }]; [removableViewIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { [_pageViews removeObjectForKey:@(index)]; }]; // work out what the current visible page is NSUInteger currentPage = self.currentPages.firstIndex; if(currentPage != _currentPage) { [self willChangeValueForKey:@"currentPage"]; _currentPage = currentPage; [self didChangeValueForKey:@"currentPage"]; } } // index is 0-based and describes the page's position within the scrollview. it // is not necessarily directly related to the PDF page number - (void)_displayPageAtIndex:(NSUInteger)index { if(index >= _pages.count) { return; // no such page } // the .pageViews dictionary stores using the index, to make this easier if(_pageViews[@(index)]) { return; // view already exists } // get details about the page we'll be displaying CGPDFPageRef page = (__bridge CGPDFPageRef)_pages[index]; CGRect pageFrame = [_pageFrames[index] CGRectValue]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:pageFrame]; imageView.backgroundColor = _pageBackgroundColour; imageView.contentMode = UIViewContentModeScaleToFill; imageView.tag = CGPDFPageGetPageNumber(page);; // makes -visiblePages a bit easier [self configureLayerBorderForView:imageView]; [_pagesContainer addSubview:imageView]; _pageViews[@(index)] = imageView; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // calculate pixel size, taking into account how far in we could zoom CGFloat scale = [UIScreen mainScreen].scale * self.maximumZoomScale; CGSize size = CGSizeMake(pageFrame.size.width * scale, pageFrame.size.height * scale); CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width * 4, _cs, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big); CGSize mediaSize = CGPDFPageGetBoxRect(page, kCGPDFMediaBox).size; int rotation = CGPDFPageGetRotationAngle(page); if(rotation == 90 || rotation == 270) { mediaSize = CGSizeMake(mediaSize.height, mediaSize.width); } CGContextScaleCTM(context, size.width / mediaSize.width, size.height / mediaSize.height ); CGContextTranslateCTM(context, (mediaSize.width - size.width) / 2.f, (mediaSize.height - size.height) / 2.f); CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, (CGRect){ CGPointZero, size }, 0, true)); CGContextDrawPDFPage(context, page); CGImageRef cgImage = CGBitmapContextCreateImage(context); UIImage *image = [UIImage imageWithCGImage:cgImage]; CGImageRelease(cgImage); CGContextRelease(context); dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = image; }); }); } #pragma mark - page view attributes - (void)setPageInsets:(UIEdgeInsets)pageInsets { if(!UIEdgeInsetsEqualToEdgeInsets(_pageInsets, pageInsets)) { _pageInsets = pageInsets; [self setNeedsLayout]; } } // because UIEdgeInsets cannot be IBInspectable // TODO: radar this - (void)setTopPageInset:(CGFloat)topPageInset { if(_pageInsets.top != topPageInset) { _pageInsets.top = topPageInset; [self setNeedsLayout]; } } - (CGFloat)topPageInset { return _pageInsets.top; } - (void)setBottomPageInset:(CGFloat)bottomPageInset { if(_pageInsets.bottom != bottomPageInset) { _pageInsets.bottom = bottomPageInset; [self setNeedsLayout]; } } - (CGFloat)bottomPageInset { return _pageInsets.bottom; } - (void)setLeftPageInset:(CGFloat)leftPageInset { if(_pageInsets.left != leftPageInset) { _pageInsets.left = leftPageInset; [self setNeedsLayout]; } } - (CGFloat)leftPageInset { return _pageInsets.left; } - (void)setRightPageInset:(CGFloat)rightPageInset { if(_pageInsets.right != rightPageInset) { _pageInsets.right = rightPageInset; [self setNeedsLayout]; } } - (CGFloat)rightPageInset { return _pageInsets.right; } - (void)setPageBackgroundColour:(UIColor *)pageBackgroundColour { _pageBackgroundColour = pageBackgroundColour; [_pageViews enumerateKeysAndObjectsUsingBlock:^(UIView *view, id obj, BOOL *stop) { view.backgroundColor = pageBackgroundColour; }]; } - (void)setBorderColour:(UIColor *)borderColour { _borderColour = borderColour; [_pageViews enumerateKeysAndObjectsUsingBlock:^(UIView *view, id obj, BOOL *stop) { [self configureLayerBorderForView:view]; }]; } - (void)setBorderWidth:(CGFloat)borderWidth { _borderWidth = borderWidth; [_pageViews enumerateKeysAndObjectsUsingBlock:^(UIView *view, id obj, BOOL *stop) { [self configureLayerBorderForView:view]; }]; } // apply the current border setting to the given view - (void)configureLayerBorderForView:(UIView *)view { CALayer *layer = view.layer; layer.borderColor = _borderColour.CGColor; layer.borderWidth = _borderWidth; } #pragma mark - UIScrollViewDelegate // allow another object to act as delegate to our scrollview - (void)setDelegate:(id)delegate { self.externalDelegate = delegate; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if(_viewMode == kSJCPDFViewModeContinuous) { [self _configureVisiblePages]; } if([_externalDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) { [_externalDelegate scrollViewDidScroll:scrollView]; } } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if(_viewMode != kSJCPDFViewModeContinuous) { [self _configureVisiblePages]; } if([_externalDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) { [_externalDelegate scrollViewDidEndScrollingAnimation:scrollView]; } } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { // don't allow an external delegate to over-ride this return _pagesContainer; } // TODO: there must be a better way than all this... ;) - (void)scrollViewDidZoom:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) { [_externalDelegate scrollViewDidZoom:self]; } } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) { [_externalDelegate scrollViewWillBeginDragging:self]; } } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { if([_externalDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { [_externalDelegate scrollViewWillEndDragging:self withVelocity:velocity targetContentOffset:targetContentOffset]; } } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if([_externalDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) { [_externalDelegate scrollViewDidEndDragging:self willDecelerate:decelerate]; } } - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) { [_externalDelegate scrollViewWillBeginDecelerating:self]; } } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) { [_externalDelegate scrollViewDidEndScrollingAnimation:self]; } } - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { if([_externalDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) { [_externalDelegate scrollViewWillBeginZooming:self withView:view]; } } - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { if([_externalDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) { [_externalDelegate scrollViewDidEndZooming:self withView:view atScale:scale]; } } - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) { return [_externalDelegate scrollViewShouldScrollToTop:self]; } return YES; } - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView { if([_externalDelegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) { [_externalDelegate scrollViewDidScrollToTop:self]; } } @end ================================================ FILE: Sublime/Pods/SSZipArchive/LICENSE.txt ================================================ Copyright (c) 2010-2015, Sam Soffes, http://soff.es 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/SSZipArchive/README.md ================================================ # SSZipArchive ZipArchive is a simple utility class for zipping and unzipping files on iOS and Mac. - Unzip zip files; - Unzip password protected zip files; - Create new zip files; - Append to existing zip files; - Zip files; - Zip-up NSData instances. (with a filename) ## Installation and Setup ### CocoaPods `pod install SSZipArchive` ### Carthage `github "ZipArchive/ZipArchive"` ### Manual 1. Add the `SSZipArchive` and `minizip` folders to your project. 2. Add the `libz` library to your target SSZipArchive requires ARC. ## Usage ### Objective-C ```objective-c // Create [SSZipArchive createZipFileAtPath: zipPath withContentsOfDirectory: sampleDataPath]; // Unzip [SSZipArchive unzipFileAtPath:zipPath toDestination: unzipPath]; ``` ### Swift ```swift // Create SSZipArchive.createZipFileAtPath(zipPath, withContentsOfDirectory: sampleDataPath) // Unzip SSZipArchive.unzipFileAtPath(zipPath, toDestination: unzipPath) ``` ## License SSZipArchive is protected under the [MIT license](https://github.com/samsoffes/ssziparchive/raw/master/LICENSE) and our slightly modified version of [Minizip](http://www.winimage.com/zLibDll/minizip.html) 1.1 is licensed under the [Zlib license](http://www.zlib.net/zlib_license.html). ## Acknowledgments Big thanks to [aish](http://code.google.com/p/ziparchive) for creating [ZipArchive](http://code.google.com/p/ziparchive). The project that inspired SSZipArchive. Thank you [@randomsequence](https://github.com/randomsequence) for implementing the creation support tech and to [@johnezang](https://github.com/johnezang) for all his amazing help along the way. ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/Common.h ================================================ #ifndef SSZipCommon #define SSZipCommon /* tm_unz contain date/time info */ typedef struct tm_unz_s { unsigned int tm_sec; /* seconds after the minute - [0,59] */ unsigned int tm_min; /* minutes after the hour - [0,59] */ unsigned int tm_hour; /* hours since midnight - [0,23] */ unsigned int tm_mday; /* day of the month - [1,31] */ unsigned int tm_mon; /* months since January - [0,11] */ unsigned int tm_year; /* years - [1980..2044] */ } tm_unz; typedef struct unz_file_info_s { unsigned long version; /* version made by 2 bytes */ unsigned long version_needed; /* version needed to extract 2 bytes */ unsigned long flag; /* general purpose bit flag 2 bytes */ unsigned long compression_method; /* compression method 2 bytes */ unsigned long dosDate; /* last mod file date in Dos fmt 4 bytes */ unsigned long crc; /* crc-32 4 bytes */ unsigned long compressed_size; /* compressed size 4 bytes */ unsigned long uncompressed_size; /* uncompressed size 4 bytes */ unsigned long size_filename; /* filename length 2 bytes */ unsigned long size_file_extra; /* extra field length 2 bytes */ unsigned long size_file_comment; /* file comment length 2 bytes */ unsigned long disk_num_start; /* disk number start 2 bytes */ unsigned long internal_fa; /* internal file attributes 2 bytes */ unsigned long external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info64_s { unsigned long version; /* version made by 2 bytes */ unsigned long version_needed; /* version needed to extract 2 bytes */ unsigned long flag; /* general purpose bit flag 2 bytes */ unsigned long compression_method; /* compression method 2 bytes */ unsigned long dosDate; /* last mod file date in Dos fmt 4 bytes */ unsigned long crc; /* crc-32 4 bytes */ unsigned long long compressed_size; /* compressed size 8 bytes */ unsigned long long uncompressed_size; /* uncompressed size 8 bytes */ unsigned long size_filename; /* filename length 2 bytes */ unsigned long size_file_extra; /* extra field length 2 bytes */ unsigned long size_file_comment; /* file comment length 2 bytes */ unsigned long disk_num_start; /* disk number start 2 bytes */ unsigned long internal_fa; /* internal file attributes 2 bytes */ unsigned long external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; unsigned long long disk_offset; unsigned long size_file_extra_internal; } unz_file_info64; typedef struct unz_global_info_s { unsigned long number_entry; /* total number of entries in the central dir on this disk */ unsigned long number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ unsigned long size_comment; /* size of the global comment of the zipfile */ } unz_global_info; typedef struct unz_global_info64 { unsigned long long number_entry; /* total number of entries in the central dir on this disk */ unsigned long number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ unsigned long size_comment; /* size of the global comment of the zipfile */ } unz_global_info64; #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/SSZipArchive.h ================================================ // // SSZipArchive.h // SSZipArchive // // Created by Sam Soffes on 7/21/10. // Copyright (c) Sam Soffes 2010-2015. All rights reserved. // #ifndef _SSZIPARCHIVE_H #define _SSZIPARCHIVE_H #import #include "Common.h" @protocol SSZipArchiveDelegate; @interface SSZipArchive : NSObject // Unzip + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination; + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id)delegate; + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError * *)error; + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError * *)error delegate:(id)delegate; + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler; + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler; // Zip // without password + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths; + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath; + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirector; // with password, password could be nil + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths withPassword:(NSString *)password; + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(NSString *)password; + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(NSString *)password; - (instancetype)initWithPath:(NSString *)path; @property (NS_NONATOMIC_IOSONLY, readonly, getter = isOpen) BOOL open; - (BOOL)writeFile:(NSString *)path withPassword:(NSString *)password; - (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(NSString *)password; - (BOOL)writeFileAtPath:(NSString *)path withFileName:(NSString *)fileName withPassword:(NSString *)password; - (BOOL)writeData:(NSData *)data filename:(NSString *)filename withPassword:(NSString *)password; @property (NS_NONATOMIC_IOSONLY, readonly, getter = isClosed) BOOL close; @end @protocol SSZipArchiveDelegate @optional - (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo; - (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath; - (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; - (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; - (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; - (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath unzippedFilePath:(NSString *)unzippedFilePath; - (void)zipArchiveProgressEvent:(unsigned long long)loaded total:(unsigned long long)total; - (void)zipArchiveDidUnzipArchiveFile:(NSString *)zipFile entryPath:(NSString *)entryPath destPath:(NSString *)destPath; @end #endif /* _SSZIPARCHIVE_H */ ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/SSZipArchive.m ================================================ // // SSZipArchive.m // SSZipArchive // // Created by Sam Soffes on 7/21/10. // Copyright (c) Sam Soffes 2010-2015. All rights reserved. // #import "SSZipArchive.h" #include "unzip.h" #include "zip.h" #import "zlib.h" #import "zconf.h" #include #define CHUNK 16384 @interface SSZipArchive () + (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime; @end @implementation SSZipArchive { NSString *_path; NSString *_filename; zipFile _zip; } #pragma mark - Unzipping + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination { return [self unzipFileAtPath:path toDestination:destination delegate:nil]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error { return [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:error delegate:nil progressHandler:nil completionHandler:nil]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id)delegate { return [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil delegate:delegate progressHandler:nil completionHandler:nil]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id)delegate { return [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler { return [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler { return [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler]; } + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id)delegate progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler { // Begin opening zipFile zip = unzOpen((const char*)[path UTF8String]); if (zip == NULL) { NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open zip file"}; NSError *err = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:-1 userInfo:userInfo]; if (error) { *error = err; } if (completionHandler) { completionHandler(nil, NO, err); } return NO; } NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; unsigned long long fileSize = [fileAttributes[NSFileSize] unsignedLongLongValue]; unsigned long long currentPosition = 0; unz_global_info globalInfo = {0ul, 0ul}; unzGetGlobalInfo(zip, &globalInfo); // Begin unzipping if (unzGoToFirstFile(zip) != UNZ_OK) { NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open first file in zip file"}; NSError *err = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:-2 userInfo:userInfo]; if (error) { *error = err; } if (completionHandler) { completionHandler(nil, NO, err); } return NO; } BOOL success = YES; BOOL canceled = NO; int ret = 0; int crc_ret =0; unsigned char buffer[4096] = {0}; NSFileManager *fileManager = [NSFileManager defaultManager]; NSMutableSet *directoriesModificationDates = [[NSMutableSet alloc] init]; // Message delegate if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) { [delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo]; } if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { [delegate zipArchiveProgressEvent:currentPosition total:fileSize]; } NSInteger currentFileNumber = 0; do { @autoreleasepool { if ([password length] == 0) { ret = unzOpenCurrentFile(zip); } else { ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]); } if (ret != UNZ_OK) { success = NO; break; } // Reading data and write to file unz_file_info fileInfo; memset(&fileInfo, 0, sizeof(unz_file_info)); ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0); if (ret != UNZ_OK) { success = NO; unzCloseCurrentFile(zip); break; } currentPosition += fileInfo.compressed_size; // Message delegate if ([delegate respondsToSelector:@selector(zipArchiveShouldUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { if (![delegate zipArchiveShouldUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry archivePath:path fileInfo:fileInfo]) { success = NO; canceled = YES; break; } } if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { [delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry archivePath:path fileInfo:fileInfo]; } if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { [delegate zipArchiveProgressEvent:(NSInteger)currentPosition total:(NSInteger)fileSize]; } char *filename = (char *)malloc(fileInfo.size_filename + 1); if (filename == NULL) { return NO; } unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); filename[fileInfo.size_filename] = '\0'; // // Determine whether this is a symbolic link: // - File is stored with 'version made by' value of UNIX (3), // as per http://www.pkware.com/documents/casestudies/APPNOTE.TXT // in the upper byte of the version field. // - BSD4.4 st_mode constants are stored in the high 16 bits of the // external file attributes (defacto standard, verified against libarchive) // // The original constants can be found here: // http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/stat.h // const uLong ZipUNIXVersion = 3; const uLong BSD_SFMT = 0170000; const uLong BSD_IFLNK = 0120000; BOOL fileIsSymbolicLink = NO; if (((fileInfo.version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo.external_fa >> 16))) { fileIsSymbolicLink = NO; } // Check if it contains directory NSString *strPath = @(filename); BOOL isDirectory = NO; if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') { isDirectory = YES; } free(filename); // Contains a path if ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location != NSNotFound) { strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; } NSString *fullPath = [destination stringByAppendingPathComponent:strPath]; NSError *err = nil; NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate]; NSDictionary *directoryAttr = @{NSFileCreationDate: modDate, NSFileModificationDate: modDate}; if (isDirectory) { [fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err]; } else { [fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err]; } if (nil != err) { NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription); } if(!fileIsSymbolicLink) [directoriesModificationDates addObject: @{@"path": fullPath, @"modDate": modDate}]; if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) { //FIXME: couldBe CRC Check? unzCloseCurrentFile(zip); ret = unzGoToNextFile(zip); continue; } if (!fileIsSymbolicLink) { FILE *fp = fopen((const char*)[fullPath UTF8String], "wb"); while (fp) { int readBytes = unzReadCurrentFile(zip, buffer, 4096); if (readBytes > 0) { fwrite(buffer, readBytes, 1, fp ); } else { break; } } if (fp) { if ([[[fullPath pathExtension] lowercaseString] isEqualToString:@"zip"]) { NSLog(@"Unzipping nested .zip file: %@", [fullPath lastPathComponent]); if ([self unzipFileAtPath:fullPath toDestination:[fullPath stringByDeletingLastPathComponent] overwrite:overwrite password:password error:nil delegate:nil]) { [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil]; } } fclose(fp); // Set the original datetime property if (fileInfo.dosDate != 0) { NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate]; NSDictionary *attr = @{NSFileModificationDate: orgDate}; if (attr) { if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) { // Can't set attributes NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date"); } } } // Set the original permissions on the file uLong permissions = fileInfo.external_fa >> 16; if (permissions != 0) { // Store it into a NSNumber NSNumber *permissionsValue = @(permissions); // Retrieve any existing attributes NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]]; // Set the value in the attributes dict attrs[NSFilePosixPermissions] = permissionsValue; // Update attributes if ([fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil] == NO) { // Unable to set the permissions attribute NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions"); } #if !__has_feature(objc_arc) [attrs release]; #endif } } } else { // Assemble the path for the symbolic link NSMutableString* destinationPath = [NSMutableString string]; int bytesRead = 0; while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0) { buffer[bytesRead] = (int)0; [destinationPath appendString:@((const char*)buffer)]; } // Create the symbolic link (making sure it stays relative if it was relative before) int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding], [fullPath cStringUsingEncoding:NSUTF8StringEncoding]); if(symlinkError != 0) { NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". symlink() error code: %d", fullPath, destinationPath, errno); } } crc_ret = unzCloseCurrentFile( zip ); if (crc_ret == UNZ_CRCERROR) { //CRC ERROR success = NO; break; } ret = unzGoToNextFile( zip ); // Message delegate if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { [delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry archivePath:path fileInfo:fileInfo]; } else if ([delegate respondsToSelector: @selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:)]) { [delegate zipArchiveDidUnzipFileAtIndex: currentFileNumber totalFiles: (NSInteger)globalInfo.number_entry archivePath:path unzippedFilePath: fullPath]; } currentFileNumber++; if (progressHandler) { progressHandler(strPath, fileInfo, currentFileNumber, globalInfo.number_entry); } } } while(ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE); // Close unzClose(zip); // The process of decompressing the .zip archive causes the modification times on the folders // to be set to the present time. So, when we are done, they need to be explicitly set. // set the modification date on all of the directories. NSError * err = nil; for (NSDictionary * d in directoriesModificationDates) { if (![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: d[@"modDate"]} ofItemAtPath:d[@"path"] error:&err]) { NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", d[@"path"]); } if (err) { NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@",err.localizedDescription); } } #if !__has_feature(objc_arc) [directoriesModificationDates release]; #endif // Message delegate if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) { [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination]; } // final progress event = 100% if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { [delegate zipArchiveProgressEvent:fileSize total:fileSize]; } NSError *retErr = nil; if (crc_ret == UNZ_CRCERROR) { NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"crc check failed for file"}; retErr = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:-3 userInfo:userInfo]; } if (error) { *error = retErr; } if (completionHandler) { completionHandler(path, success, retErr); } return success; } #pragma mark - Zipping + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths { return [SSZipArchive createZipFileAtPath:path withFilesAtPaths:paths withPassword:nil]; } + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath{ return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath withPassword:nil]; } + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirector{ return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirector withPassword:nil]; } + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths withPassword:(NSString *)password { BOOL success = NO; SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path]; if ([zipArchive open]) { for (NSString *filePath in paths) { [zipArchive writeFile:filePath withPassword:password]; } success = [zipArchive close]; } #if !__has_feature(objc_arc) [zipArchive release]; #endif return success; } + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(NSString *)password{ return [self createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:NO withPassword:password]; } + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(NSString *)password{ BOOL success = NO; NSFileManager *fileManager = nil; SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path]; if ([zipArchive open]) { // use a local filemanager (queue/thread compatibility) fileManager = [[NSFileManager alloc] init]; NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath]; NSString *fileName; while ((fileName = [dirEnumerator nextObject])) { BOOL isDir; NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName]; [fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir]; if (!isDir) { if (keepParentDirectory) { fileName = [[directoryPath lastPathComponent] stringByAppendingPathComponent:fileName]; } [zipArchive writeFileAtPath:fullFilePath withFileName:fileName withPassword:password]; } else { if([[NSFileManager defaultManager] subpathsOfDirectoryAtPath:fullFilePath error:nil].count == 0) { NSString *tempName = [fullFilePath stringByAppendingPathComponent:@".DS_Store"]; [@"" writeToFile:tempName atomically:YES encoding:NSUTF8StringEncoding error:nil]; [zipArchive writeFileAtPath:tempName withFileName:[fileName stringByAppendingPathComponent:@".DS_Store"] withPassword:password]; [[NSFileManager defaultManager] removeItemAtPath:tempName error:nil]; } } } success = [zipArchive close]; } #if !__has_feature(objc_arc) [fileManager release]; [zipArchive release]; #endif return success; } - (instancetype)initWithPath:(NSString *)path { if ((self = [super init])) { _path = [path copy]; } return self; } #if !__has_feature(objc_arc) - (void)dealloc { [_path release]; [super dealloc]; } #endif - (BOOL)open { NSAssert((_zip == NULL), @"Attempting open an archive which is already open"); _zip = zipOpen([_path UTF8String], APPEND_STATUS_CREATE); return (NULL != _zip); } - (void)zipInfo:(zip_fileinfo*)zipInfo setDate:(NSDate*)date { NSCalendar *currentCalendar = [NSCalendar currentCalendar]; #if defined(__IPHONE_8_0) || defined(__MAC_10_10) uint flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; #else uint flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; #endif NSDateComponents *components = [currentCalendar components:flags fromDate:date]; zipInfo->tmz_date.tm_sec = (unsigned int)components.second; zipInfo->tmz_date.tm_min = (unsigned int)components.minute; zipInfo->tmz_date.tm_hour = (unsigned int)components.hour; zipInfo->tmz_date.tm_mday = (unsigned int)components.day; zipInfo->tmz_date.tm_mon = (unsigned int)components.month - 1; zipInfo->tmz_date.tm_year = (unsigned int)components.year; } - (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(NSString *)password { NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened"); zip_fileinfo zipInfo = {{0}}; NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil]; if( attr ) { NSDate *fileDate = (NSDate *)attr[NSFileModificationDate]; if( fileDate ) { [self zipInfo:&zipInfo setDate: fileDate ]; } // Write permissions into the external attributes, for details on this see here: http://unix.stackexchange.com/a/14727 // Get the permissions value from the files attributes NSNumber *permissionsValue = (NSNumber *)attr[NSFilePosixPermissions]; if (permissionsValue) { // Get the short value for the permissions short permissionsShort = permissionsValue.shortValue; // Convert this into an octal by adding 010000, 010000 being the flag for a regular file NSInteger permissionsOctal = 0100000 + permissionsShort; // Convert this into a long value uLong permissionsLong = @(permissionsOctal).unsignedLongValue; // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte zipInfo.external_fa = permissionsLong << 16L; } } unsigned int len = 0; zipOpenNewFileInZip3(_zip, [[folderName stringByAppendingString:@"/"] UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_NO_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, [password UTF8String], 0); zipWriteInFileInZip(_zip, &len, 0); zipCloseFileInZip(_zip); return YES; } - (BOOL)writeFile:(NSString *)path withPassword:(NSString *)password; { return [self writeFileAtPath:path withFileName:nil withPassword:password]; } // supports writing files with logical folder/directory structure // *path* is the absolute path of the file that will be compressed // *fileName* is the relative name of the file how it is stored within the zip e.g. /folder/subfolder/text1.txt - (BOOL)writeFileAtPath:(NSString *)path withFileName:(NSString *)fileName withPassword:(NSString *)password { NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened"); FILE *input = fopen([path UTF8String], "r"); if (NULL == input) { return NO; } const char *afileName; if (!fileName) { afileName = [path.lastPathComponent UTF8String]; } else { afileName = [fileName UTF8String]; } zip_fileinfo zipInfo = {{0}}; NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil]; if( attr ) { NSDate *fileDate = (NSDate *)attr[NSFileModificationDate]; if( fileDate ) { [self zipInfo:&zipInfo setDate: fileDate ]; } // Write permissions into the external attributes, for details on this see here: http://unix.stackexchange.com/a/14727 // Get the permissions value from the files attributes NSNumber *permissionsValue = (NSNumber *)attr[NSFilePosixPermissions]; if (permissionsValue) { // Get the short value for the permissions short permissionsShort = permissionsValue.shortValue; // Convert this into an octal by adding 010000, 010000 being the flag for a regular file NSInteger permissionsOctal = 0100000 + permissionsShort; // Convert this into a long value uLong permissionsLong = @(permissionsOctal).unsignedLongValue; // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte zipInfo.external_fa = permissionsLong << 16L; } } void *buffer = malloc(CHUNK); if (buffer == NULL) { return NO; } zipOpenNewFileInZip3(_zip, afileName, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, [password UTF8String], 0); unsigned int len = 0; while (!feof(input)) { len = (unsigned int) fread(buffer, 1, CHUNK, input); zipWriteInFileInZip(_zip, buffer, len); } zipCloseFileInZip(_zip); free(buffer); fclose(input); return YES; } - (BOOL)writeData:(NSData *)data filename:(NSString *)filename withPassword:(NSString *)password; { if (!_zip) { return NO; } if (!data) { return NO; } zip_fileinfo zipInfo = {{0,0,0,0,0,0},0,0,0}; [self zipInfo:&zipInfo setDate:[NSDate date]]; zipOpenNewFileInZip3(_zip, [filename UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, [password UTF8String], 0); zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length); zipCloseFileInZip(_zip); return YES; } - (BOOL)close { NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened"); zipClose(_zip, NULL); return YES; } #pragma mark - Private // Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html // Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss // YYYYYYY is years from 1980 = 0 // sssss is (seconds/2). // // 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24 // 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 3 = 14:33:06 + (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime { static const UInt32 kYearMask = 0xFE000000; static const UInt32 kMonthMask = 0x1E00000; static const UInt32 kDayMask = 0x1F0000; static const UInt32 kHourMask = 0xF800; static const UInt32 kMinuteMask = 0x7E0; static const UInt32 kSecondMask = 0x1F; static NSCalendar *gregorian; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ #if defined(__IPHONE_8_0) || defined(__MAC_10_10) gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; #else gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; #endif }); NSDateComponents *components = [[NSDateComponents alloc] init]; NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @"[SSZipArchive] MSDOS date masks don't add up"); [components setYear:1980 + ((msdosDateTime & kYearMask) >> 25)]; [components setMonth:(msdosDateTime & kMonthMask) >> 21]; [components setDay:(msdosDateTime & kDayMask) >> 16]; [components setHour:(msdosDateTime & kHourMask) >> 11]; [components setMinute:(msdosDateTime & kMinuteMask) >> 5]; [components setSecond:(msdosDateTime & kSecondMask) * 2]; NSDate *date = [NSDate dateWithTimeInterval:0 sinceDate:[gregorian dateFromComponents:components]]; #if !__has_feature(objc_arc) [components release]; #endif return date; } @end ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/ZipArchive.h ================================================ // // ZipArchive.h // ZipArchive // // Created by Serhii Mumriak on 12/1/15. // Copyright © 2015 smumryak. All rights reserved. // #import //! Project version number for ZipArchive. FOUNDATION_EXPORT double ZipArchiveVersionNumber; //! Project version string for ZipArchive. FOUNDATION_EXPORT const unsigned char ZipArchiveVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import #import "SSZipArchive.h" ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aes.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the definitions required to use AES in C. See aesopt.h for optimisation details. */ #ifndef _AES_H #define _AES_H #include /* This include is used to find 8 & 32 bit unsigned integer types */ #include "brg_types.h" #if defined(__cplusplus) extern "C" { #endif #define AES_128 /* if a fast 128 bit key scheduler is needed */ #define AES_192 /* if a fast 192 bit key scheduler is needed */ #define AES_256 /* if a fast 256 bit key scheduler is needed */ #define AES_VAR /* if variable key size scheduler is needed */ #define AES_MODES /* if support is needed for modes */ /* The following must also be set in assembler files if being used */ #define AES_ENCRYPT /* if support for encryption is needed */ #define AES_DECRYPT /* if support for decryption is needed */ #define AES_REV_DKS /* define to reverse decryption key schedule */ #define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ #define N_COLS 4 /* the number of columns in the state */ /* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ /* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ /* or 44, 52 or 60 32-bit words. */ #if defined( AES_VAR ) || defined( AES_256 ) #define KS_LENGTH 60 #elif defined( AES_192 ) #define KS_LENGTH 52 #else #define KS_LENGTH 44 #endif #define AES_RETURN INT_RETURN /* the character array 'inf' in the following structures is used */ /* to hold AES context information. This AES code uses cx->inf.b[0] */ /* to hold the number of rounds multiplied by 16. The other three */ /* elements can be used by code that implements additional modes */ typedef union { uint_32t l; uint_8t b[4]; } aes_inf; typedef struct { uint_32t ks[KS_LENGTH]; aes_inf inf; } aes_encrypt_ctx; typedef struct { uint_32t ks[KS_LENGTH]; aes_inf inf; } aes_decrypt_ctx; /* This routine must be called before first use if non-static */ /* tables are being used */ AES_RETURN aes_init(void); /* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ /* those in the range 128 <= key_len <= 256 are given in bits */ #if defined( AES_ENCRYPT ) #if defined( AES_128 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_192 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_256 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_VAR ) AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); #endif AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); #endif #if defined( AES_DECRYPT ) #if defined( AES_128 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_192 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_256 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_VAR ) AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); #endif AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); #endif #if defined( AES_MODES ) /* Multiple calls to the following subroutines for multiple block */ /* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ /* long messages incremantally provided that the context AND the iv */ /* are preserved between all such calls. For the ECB and CBC modes */ /* each individual call within a series of incremental calls must */ /* process only full blocks (i.e. len must be a multiple of 16) but */ /* the CFB, OFB and CTR mode calls can handle multiple incremental */ /* calls of any length. Each mode is reset when a new AES key is */ /* set but ECB and CBC operations can be reset without setting a */ /* new key by setting a new IV value. To reset CFB, OFB and CTR */ /* without setting the key, aes_mode_reset() must be called and the */ /* IV must be set. NOTE: All these calls update the IV on exit so */ /* this has to be reset if a new operation with the same IV as the */ /* previous one is required (or decryption follows encryption with */ /* the same IV array). */ AES_RETURN aes_test_alignment_detection(unsigned int n); AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_encrypt_ctx cx[1]); AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_decrypt_ctx cx[1]); AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); #define aes_ofb_encrypt aes_ofb_crypt #define aes_ofb_decrypt aes_ofb_crypt AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); typedef void cbuf_inc(unsigned char *cbuf); #define aes_ctr_encrypt aes_ctr_crypt #define aes_ctr_decrypt aes_ctr_crypt AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); #endif #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aes_via_ace.h ================================================ /* Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #ifndef AES_VIA_ACE_H #define AES_VIA_ACE_H #if defined( _MSC_VER ) # define INLINE __inline #elif defined( __GNUC__ ) # define INLINE static inline #else # error VIA ACE requires Microsoft or GNU C #endif #define NEH_GENERATE 1 #define NEH_LOAD 2 #define NEH_HYBRID 3 #define MAX_READ_ATTEMPTS 1000 /* VIA Nehemiah RNG and ACE Feature Mask Values */ #define NEH_CPU_IS_VIA 0x00000001 #define NEH_CPU_READ 0x00000010 #define NEH_CPU_MASK 0x00000011 #define NEH_RNG_PRESENT 0x00000004 #define NEH_RNG_ENABLED 0x00000008 #define NEH_ACE_PRESENT 0x00000040 #define NEH_ACE_ENABLED 0x00000080 #define NEH_RNG_FLAGS (NEH_RNG_PRESENT | NEH_RNG_ENABLED) #define NEH_ACE_FLAGS (NEH_ACE_PRESENT | NEH_ACE_ENABLED) #define NEH_FLAGS_MASK (NEH_RNG_FLAGS | NEH_ACE_FLAGS) /* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values */ #define NEH_GEN_KEY 0x00000000 /* generate key schedule */ #define NEH_LOAD_KEY 0x00000080 /* load schedule from memory */ #define NEH_ENCRYPT 0x00000000 /* encryption */ #define NEH_DECRYPT 0x00000200 /* decryption */ #define NEH_KEY128 0x00000000+0x0a /* 128 bit key */ #define NEH_KEY192 0x00000400+0x0c /* 192 bit key */ #define NEH_KEY256 0x00000800+0x0e /* 256 bit key */ #define NEH_ENC_GEN (NEH_ENCRYPT | NEH_GEN_KEY) #define NEH_DEC_GEN (NEH_DECRYPT | NEH_GEN_KEY) #define NEH_ENC_LOAD (NEH_ENCRYPT | NEH_LOAD_KEY) #define NEH_DEC_LOAD (NEH_DECRYPT | NEH_LOAD_KEY) #define NEH_ENC_GEN_DATA {\ NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\ NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 } #define NEH_ENC_LOAD_DATA {\ NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\ NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } #define NEH_ENC_HYBRID_DATA {\ NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } #define NEH_DEC_GEN_DATA {\ NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\ NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 } #define NEH_DEC_LOAD_DATA {\ NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\ NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } #define NEH_DEC_HYBRID_DATA {\ NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } #define neh_enc_gen_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256)) #define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) : \ (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) #define neh_enc_hybrid_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) #define neh_dec_gen_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256)) #define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) : \ (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) #define neh_dec_hybrid_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) #if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) #define aligned_auto(type, name, no, stride) __declspec(align(stride)) type name[no] #else #define aligned_auto(type, name, no, stride) \ unsigned char _##name[no * sizeof(type) + stride]; \ type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride)) #endif #if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) #define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no] #elif defined( __GNUC__ ) #define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride))) #else #define aligned_array(type, name, no, stride) type name[no] #endif /* VIA ACE codeword */ static unsigned char via_flags = 0; #if defined ( _MSC_VER ) && ( _MSC_VER > 800 ) #define NEH_REKEY __asm pushfd __asm popfd #define NEH_AES __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7 #define NEH_ECB NEH_AES __asm _emit 0xc8 #define NEH_CBC NEH_AES __asm _emit 0xd0 #define NEH_CFB NEH_AES __asm _emit 0xe0 #define NEH_OFB NEH_AES __asm _emit 0xe8 #define NEH_RNG __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0 INLINE int has_cpuid(void) { char ret_value; __asm { pushfd /* save EFLAGS register */ mov eax,[esp] /* copy it to eax */ mov edx,0x00200000 /* CPUID bit position */ xor eax,edx /* toggle the CPUID bit */ push eax /* attempt to set EFLAGS to */ popfd /* the new value */ pushfd /* get the new EFLAGS value */ pop eax /* into eax */ xor eax,[esp] /* xor with original value */ and eax,edx /* has CPUID bit changed? */ setne al /* set to 1 if we have been */ mov ret_value,al /* able to change it */ popfd /* restore original EFLAGS */ } return (int)ret_value; } INLINE int is_via_cpu(void) { char ret_value; __asm { push ebx xor eax,eax /* use CPUID to get vendor */ cpuid /* identity string */ xor eax,eax /* is it "CentaurHauls" ? */ sub ebx,0x746e6543 /* 'Cent' */ or eax,ebx sub edx,0x48727561 /* 'aurH' */ or eax,edx sub ecx,0x736c7561 /* 'auls' */ or eax,ecx sete al /* set to 1 if it is VIA ID */ mov dl,NEH_CPU_READ /* mark CPU type as read */ or dl,al /* & store result in flags */ mov [via_flags],dl /* set VIA detected flag */ mov ret_value,al /* able to change it */ pop ebx } return (int)ret_value; } INLINE int read_via_flags(void) { char ret_value = 0; __asm { mov eax,0xC0000000 /* Centaur extended CPUID */ cpuid mov edx,0xc0000001 /* >= 0xc0000001 if support */ cmp eax,edx /* for VIA extended feature */ jnae no_rng /* flags is available */ mov eax,edx /* read Centaur extended */ cpuid /* feature flags */ mov eax,NEH_FLAGS_MASK /* mask out and save */ and eax,edx /* the RNG and ACE flags */ or [via_flags],al /* present & enabled flags */ mov ret_value,al /* able to change it */ no_rng: } return (int)ret_value; } INLINE unsigned int via_rng_in(void *buf) { char ret_value = 0x1f; __asm { push edi mov edi,buf /* input buffer address */ xor edx,edx /* try to fetch 8 bytes */ NEH_RNG /* do RNG read operation */ and ret_value,al /* count of bytes returned */ pop edi } return (int)ret_value; } INLINE void via_ecb_op5( const void *k, const void *c, const void *s, void *d, int l) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) NEH_ECB pop ebx } } INLINE void via_cbc_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) mov eax, (v) NEH_CBC pop ebx } } INLINE void via_cbc_op7( const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) mov eax, (v) NEH_CBC mov esi, eax mov edi, (w) movsd movsd movsd movsd pop ebx } } INLINE void via_cfb_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) mov eax, (v) NEH_CFB pop ebx } } INLINE void via_cfb_op7( const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) mov eax, (v) NEH_CFB mov esi, eax mov edi, (w) movsd movsd movsd movsd pop ebx } } INLINE void via_ofb_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { __asm { push ebx NEH_REKEY mov ebx, (k) mov edx, (c) mov esi, (s) mov edi, (d) mov ecx, (l) mov eax, (v) NEH_OFB pop ebx } } #elif defined( __GNUC__ ) #define NEH_REKEY asm("pushfl\n popfl\n\t") #define NEH_ECB asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t") #define NEH_CBC asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t") #define NEH_CFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t") #define NEH_OFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t") #define NEH_RNG asm(".byte 0x0f, 0xa7, 0xc0\n\t"); INLINE int has_cpuid(void) { int val; asm("pushfl\n\t"); asm("movl 0(%esp),%eax\n\t"); asm("xor $0x00200000,%eax\n\t"); asm("pushl %eax\n\t"); asm("popfl\n\t"); asm("pushfl\n\t"); asm("popl %eax\n\t"); asm("xorl 0(%esp),%edx\n\t"); asm("andl $0x00200000,%eax\n\t"); asm("movl %%eax,%0\n\t" : "=m" (val)); asm("popfl\n\t"); return val ? 1 : 0; } INLINE int is_via_cpu(void) { int val; asm("pushl %ebx\n\t"); asm("xorl %eax,%eax\n\t"); asm("cpuid\n\t"); asm("xorl %eax,%eax\n\t"); asm("subl $0x746e6543,%ebx\n\t"); asm("orl %ebx,%eax\n\t"); asm("subl $0x48727561,%edx\n\t"); asm("orl %edx,%eax\n\t"); asm("subl $0x736c7561,%ecx\n\t"); asm("orl %ecx,%eax\n\t"); asm("movl %%eax,%0\n\t" : "=m" (val)); asm("popl %ebx\n\t"); val = (val ? 0 : 1); via_flags = (val | NEH_CPU_READ); return val; } INLINE int read_via_flags(void) { unsigned char val; asm("movl $0xc0000000,%eax\n\t"); asm("cpuid\n\t"); asm("movl $0xc0000001,%edx\n\t"); asm("cmpl %edx,%eax\n\t"); asm("setae %al\n\t"); asm("movb %%al,%0\n\t" : "=m" (val)); if(!val) return 0; asm("movl $0xc0000001,%eax\n\t"); asm("cpuid\n\t"); asm("movb %%dl,%0\n\t" : "=m" (val)); val &= NEH_FLAGS_MASK; via_flags |= val; return (int) val; } INLINE int via_rng_in(void *buf) { int val; asm("pushl %edi\n\t"); asm("movl %0,%%edi\n\t" : : "m" (buf)); asm("xorl %edx,%edx\n\t"); NEH_RNG asm("andl $0x0000001f,%eax\n\t"); asm("movl %%eax,%0\n\t" : "=m" (val)); asm("popl %edi\n\t"); return val; } INLINE volatile void via_ecb_op5( const void *k, const void *c, const void *s, void *d, int l) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); NEH_ECB; asm("popl %ebx\n\t"); } INLINE volatile void via_cbc_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); asm("movl %0, %%eax\n\t" : : "m" (v)); NEH_CBC; asm("popl %ebx\n\t"); } INLINE volatile void via_cbc_op7( const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); asm("movl %0, %%eax\n\t" : : "m" (v)); NEH_CBC; asm("movl %eax,%esi\n\t"); asm("movl %0, %%edi\n\t" : : "m" (w)); asm("movsl; movsl; movsl; movsl\n\t"); asm("popl %ebx\n\t"); } INLINE volatile void via_cfb_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); asm("movl %0, %%eax\n\t" : : "m" (v)); NEH_CFB; asm("popl %ebx\n\t"); } INLINE volatile void via_cfb_op7( const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); asm("movl %0, %%eax\n\t" : : "m" (v)); NEH_CFB; asm("movl %eax,%esi\n\t"); asm("movl %0, %%edi\n\t" : : "m" (w)); asm("movsl; movsl; movsl; movsl\n\t"); asm("popl %ebx\n\t"); } INLINE volatile void via_ofb_op6( const void *k, const void *c, const void *s, void *d, int l, void *v) { asm("pushl %ebx\n\t"); NEH_REKEY; asm("movl %0, %%ebx\n\t" : : "m" (k)); asm("movl %0, %%edx\n\t" : : "m" (c)); asm("movl %0, %%esi\n\t" : : "m" (s)); asm("movl %0, %%edi\n\t" : : "m" (d)); asm("movl %0, %%ecx\n\t" : : "m" (l)); asm("movl %0, %%eax\n\t" : : "m" (v)); NEH_OFB; asm("popl %ebx\n\t"); } #else #error VIA ACE is not available with this compiler #endif INLINE int via_ace_test(void) { return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS); } #define VIA_ACE_AVAILABLE (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS) \ || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test()) INLINE int via_rng_test(void) { return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS); } #define VIA_RNG_AVAILABLE (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS) \ || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test()) INLINE int read_via_rng(void *buf, int count) { int nbr, max_reads, lcnt = count; unsigned char *p, *q; aligned_auto(unsigned char, bp, 64, 16); if(!VIA_RNG_AVAILABLE) return 0; do { max_reads = MAX_READ_ATTEMPTS; do nbr = via_rng_in(bp); while (nbr == 0 && --max_reads); lcnt -= nbr; p = (unsigned char*)buf; q = bp; while(nbr--) *p++ = *q++; } while (lcnt && max_reads); return count - lcnt; } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aescrypt.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #include "aesopt.h" #include "aestab.h" #if defined(__cplusplus) extern "C" { #endif #define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) #define so(y,x,c) word_out(y, c, s(x,c)) #if defined(ARRAYS) #define locals(y,x) x[4],y[4] #else #define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 #endif #define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ s(y,2) = s(x,2); s(y,3) = s(x,3); #define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) #define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) #define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) #if ( FUNCS_IN_C & ENCRYPTION_IN_C ) /* Visual C++ .Net v7.1 provides the fastest encryption code when using Pentium optimiation with small code but this is poor for decryption so we need to control this with the following VC++ pragmas */ #if defined( _MSC_VER ) && !defined( _WIN64 ) #pragma optimize( "s", on ) #endif /* Given the column (c) of the output state variable, the following macros give the input state variables which are needed in its computation for each row (r) of the state. All the alternative macros give the same end values but expand into different ways of calculating these values. In particular the complex macro used for dynamically variable block sizes is designed to expand to a compile time constant whenever possible but will expand to conditional clauses on some branches (I am grateful to Frank Yellin for this construction) */ #define fwd_var(x,r,c)\ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) #if defined(FT4_SET) #undef dec_fmvars #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) #elif defined(FT1_SET) #undef dec_fmvars #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) #else #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) #endif #if defined(FL4_SET) #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) #elif defined(FL1_SET) #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) #else #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) #endif AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) { uint_32t locals(b0, b1); const uint_32t *kp; #if defined( dec_fmvars ) dec_fmvars; /* declare variables for fwd_mcol() if needed */ #endif if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) return EXIT_FAILURE; kp = cx->ks; state_in(b0, in, kp); #if (ENC_UNROLL == FULL) switch(cx->inf.b[0]) { case 14 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; case 12 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; case 10 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); round(fwd_rnd, b1, b0, kp + 3 * N_COLS); round(fwd_rnd, b0, b1, kp + 4 * N_COLS); round(fwd_rnd, b1, b0, kp + 5 * N_COLS); round(fwd_rnd, b0, b1, kp + 6 * N_COLS); round(fwd_rnd, b1, b0, kp + 7 * N_COLS); round(fwd_rnd, b0, b1, kp + 8 * N_COLS); round(fwd_rnd, b1, b0, kp + 9 * N_COLS); round(fwd_lrnd, b0, b1, kp +10 * N_COLS); } #else #if (ENC_UNROLL == PARTIAL) { uint_32t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { kp += N_COLS; round(fwd_rnd, b1, b0, kp); kp += N_COLS; round(fwd_rnd, b0, b1, kp); } kp += N_COLS; round(fwd_rnd, b1, b0, kp); #else { uint_32t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { kp += N_COLS; round(fwd_rnd, b1, b0, kp); l_copy(b0, b1); } #endif kp += N_COLS; round(fwd_lrnd, b0, b1, kp); } #endif state_out(out, b0); return EXIT_SUCCESS; } #endif #if ( FUNCS_IN_C & DECRYPTION_IN_C) /* Visual C++ .Net v7.1 provides the fastest encryption code when using Pentium optimiation with small code but this is poor for decryption so we need to control this with the following VC++ pragmas */ #if defined( _MSC_VER ) && !defined( _WIN64 ) #pragma optimize( "t", on ) #endif /* Given the column (c) of the output state variable, the following macros give the input state variables which are needed in its computation for each row (r) of the state. All the alternative macros give the same end values but expand into different ways of calculating these values. In particular the complex macro used for dynamically variable block sizes is designed to expand to a compile time constant whenever possible but will expand to conditional clauses on some branches (I am grateful to Frank Yellin for this construction) */ #define inv_var(x,r,c)\ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) #if defined(IT4_SET) #undef dec_imvars #define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) #elif defined(IT1_SET) #undef dec_imvars #define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) #else #define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) #endif #if defined(IL4_SET) #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) #elif defined(IL1_SET) #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) #else #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) #endif /* This code can work with the decryption key schedule in the */ /* order that is used for encrytpion (where the 1st decryption */ /* round key is at the high end ot the schedule) or with a key */ /* schedule that has been reversed to put the 1st decryption */ /* round key at the low end of the schedule in memory (when */ /* AES_REV_DKS is defined) */ #ifdef AES_REV_DKS #define key_ofs 0 #define rnd_key(n) (kp + n * N_COLS) #else #define key_ofs 1 #define rnd_key(n) (kp - n * N_COLS) #endif AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) { uint_32t locals(b0, b1); #if defined( dec_imvars ) dec_imvars; /* declare variables for inv_mcol() if needed */ #endif const uint_32t *kp; if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) return EXIT_FAILURE; kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); state_in(b0, in, kp); #if (DEC_UNROLL == FULL) kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); switch(cx->inf.b[0]) { case 14 * 16: round(inv_rnd, b1, b0, rnd_key(-13)); round(inv_rnd, b0, b1, rnd_key(-12)); case 12 * 16: round(inv_rnd, b1, b0, rnd_key(-11)); round(inv_rnd, b0, b1, rnd_key(-10)); case 10 * 16: round(inv_rnd, b1, b0, rnd_key(-9)); round(inv_rnd, b0, b1, rnd_key(-8)); round(inv_rnd, b1, b0, rnd_key(-7)); round(inv_rnd, b0, b1, rnd_key(-6)); round(inv_rnd, b1, b0, rnd_key(-5)); round(inv_rnd, b0, b1, rnd_key(-4)); round(inv_rnd, b1, b0, rnd_key(-3)); round(inv_rnd, b0, b1, rnd_key(-2)); round(inv_rnd, b1, b0, rnd_key(-1)); round(inv_lrnd, b0, b1, rnd_key( 0)); } #else #if (DEC_UNROLL == PARTIAL) { uint_32t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { kp = rnd_key(1); round(inv_rnd, b1, b0, kp); kp = rnd_key(1); round(inv_rnd, b0, b1, kp); } kp = rnd_key(1); round(inv_rnd, b1, b0, kp); #else { uint_32t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { kp = rnd_key(1); round(inv_rnd, b1, b0, kp); l_copy(b0, b1); } #endif kp = rnd_key(1); round(inv_lrnd, b0, b1, kp); } #endif state_out(out, b0); return EXIT_SUCCESS; } #endif #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aeskey.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #include "aesopt.h" #include "aestab.h" #ifdef USE_VIA_ACE_IF_PRESENT # include "aes_via_ace.h" #endif #if defined(__cplusplus) extern "C" { #endif /* Initialise the key schedule from the user supplied key. The key length can be specified in bytes, with legal values of 16, 24 and 32, or in bits, with legal values of 128, 192 and 256. These values correspond with Nk values of 4, 6 and 8 respectively. The following macros implement a single cycle in the key schedule generation process. The number of cycles needed for each cx->n_col and nk value is: nk = 4 5 6 7 8 ------------------------------ cx->n_col = 4 10 9 8 7 7 cx->n_col = 5 14 11 10 9 9 cx->n_col = 6 19 15 12 11 11 cx->n_col = 7 21 19 16 13 14 cx->n_col = 8 29 23 19 17 14 */ #if defined( REDUCE_CODE_SIZE ) # define ls_box ls_sub uint_32t ls_sub(const uint_32t t, const uint_32t n); # define inv_mcol im_sub uint_32t im_sub(const uint_32t x); # ifdef ENC_KS_UNROLL # undef ENC_KS_UNROLL # endif # ifdef DEC_KS_UNROLL # undef DEC_KS_UNROLL # endif #endif #if (FUNCS_IN_C & ENC_KEYING_IN_C) #if defined(AES_128) || defined( AES_VAR ) #define ke4(k,i) \ { k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ k[4*(i)+5] = ss[1] ^= ss[0]; \ k[4*(i)+6] = ss[2] ^= ss[1]; \ k[4*(i)+7] = ss[3] ^= ss[2]; \ } AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint_32t ss[4]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); #ifdef ENC_KS_UNROLL ke4(cx->ks, 0); ke4(cx->ks, 1); ke4(cx->ks, 2); ke4(cx->ks, 3); ke4(cx->ks, 4); ke4(cx->ks, 5); ke4(cx->ks, 6); ke4(cx->ks, 7); ke4(cx->ks, 8); #else { uint_32t i; for(i = 0; i < 9; ++i) ke4(cx->ks, i); } #endif ke4(cx->ks, 9); cx->inf.l = 0; cx->inf.b[0] = 10 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_192) || defined( AES_VAR ) #define kef6(k,i) \ { k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ k[6*(i)+ 7] = ss[1] ^= ss[0]; \ k[6*(i)+ 8] = ss[2] ^= ss[1]; \ k[6*(i)+ 9] = ss[3] ^= ss[2]; \ } #define ke6(k,i) \ { kef6(k,i); \ k[6*(i)+10] = ss[4] ^= ss[3]; \ k[6*(i)+11] = ss[5] ^= ss[4]; \ } AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint_32t ss[6]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); cx->ks[4] = ss[4] = word_in(key, 4); cx->ks[5] = ss[5] = word_in(key, 5); #ifdef ENC_KS_UNROLL ke6(cx->ks, 0); ke6(cx->ks, 1); ke6(cx->ks, 2); ke6(cx->ks, 3); ke6(cx->ks, 4); ke6(cx->ks, 5); ke6(cx->ks, 6); #else { uint_32t i; for(i = 0; i < 7; ++i) ke6(cx->ks, i); } #endif kef6(cx->ks, 7); cx->inf.l = 0; cx->inf.b[0] = 12 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_256) || defined( AES_VAR ) #define kef8(k,i) \ { k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ k[8*(i)+ 9] = ss[1] ^= ss[0]; \ k[8*(i)+10] = ss[2] ^= ss[1]; \ k[8*(i)+11] = ss[3] ^= ss[2]; \ } #define ke8(k,i) \ { kef8(k,i); \ k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ k[8*(i)+13] = ss[5] ^= ss[4]; \ k[8*(i)+14] = ss[6] ^= ss[5]; \ k[8*(i)+15] = ss[7] ^= ss[6]; \ } AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint_32t ss[8]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); cx->ks[4] = ss[4] = word_in(key, 4); cx->ks[5] = ss[5] = word_in(key, 5); cx->ks[6] = ss[6] = word_in(key, 6); cx->ks[7] = ss[7] = word_in(key, 7); #ifdef ENC_KS_UNROLL ke8(cx->ks, 0); ke8(cx->ks, 1); ke8(cx->ks, 2); ke8(cx->ks, 3); ke8(cx->ks, 4); ke8(cx->ks, 5); #else { uint_32t i; for(i = 0; i < 6; ++i) ke8(cx->ks, i); } #endif kef8(cx->ks, 6); cx->inf.l = 0; cx->inf.b[0] = 14 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined( AES_VAR ) AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) { switch(key_len) { case 16: case 128: return aes_encrypt_key128(key, cx); case 24: case 192: return aes_encrypt_key192(key, cx); case 32: case 256: return aes_encrypt_key256(key, cx); default: return EXIT_FAILURE; } } #endif #endif #if (FUNCS_IN_C & DEC_KEYING_IN_C) /* this is used to store the decryption round keys */ /* in forward or reverse order */ #ifdef AES_REV_DKS #define v(n,i) ((n) - (i) + 2 * ((i) & 3)) #else #define v(n,i) (i) #endif #if DEC_ROUND == NO_TABLES #define ff(x) (x) #else #define ff(x) inv_mcol(x) #if defined( dec_imvars ) #define d_vars dec_imvars #endif #endif #if defined(AES_128) || defined( AES_VAR ) #define k4e(k,i) \ { k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ } #if 1 #define kdf4(k,i) \ { ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ ss[1] = ss[1] ^ ss[3]; \ ss[2] = ss[2] ^ ss[3]; \ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ ss[i % 4] ^= ss[4]; \ ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ } #define kd4(k,i) \ { ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ } #define kdl4(k,i) \ { ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ k[v(40,(4*(i))+6)] = ss[0]; \ k[v(40,(4*(i))+7)] = ss[1]; \ } #else #define kdf4(k,i) \ { ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ } #define kd4(k,i) \ { ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ } #define kdl4(k,i) \ { ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ } #endif AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint_32t ss[5]; #if defined( d_vars ) d_vars; #endif cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL kdf4(cx->ks, 0); kd4(cx->ks, 1); kd4(cx->ks, 2); kd4(cx->ks, 3); kd4(cx->ks, 4); kd4(cx->ks, 5); kd4(cx->ks, 6); kd4(cx->ks, 7); kd4(cx->ks, 8); kdl4(cx->ks, 9); #else { uint_32t i; for(i = 0; i < 10; ++i) k4e(cx->ks, i); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 10 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 10 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_192) || defined( AES_VAR ) #define k6ef(k,i) \ { k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ } #define k6e(k,i) \ { k6ef(k,i); \ k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ } #define kdf6(k,i) \ { ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ } #define kd6(k,i) \ { ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ } #define kdl6(k,i) \ { ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ } AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint_32t ss[7]; #if defined( d_vars ) d_vars; #endif cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); kdf6(cx->ks, 0); kd6(cx->ks, 1); kd6(cx->ks, 2); kd6(cx->ks, 3); kd6(cx->ks, 4); kd6(cx->ks, 5); kd6(cx->ks, 6); kdl6(cx->ks, 7); #else cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); { uint_32t i; for(i = 0; i < 7; ++i) k6e(cx->ks, i); k6ef(cx->ks, 7); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 12 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 12 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_256) || defined( AES_VAR ) #define k8ef(k,i) \ { k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ } #define k8e(k,i) \ { k8ef(k,i); \ k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ } #define kdf8(k,i) \ { ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ } #define kd8(k,i) \ { ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ ss[8] = ls_box(ss[3],0); \ ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ } #define kdl8(k,i) \ { ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ } AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint_32t ss[9]; #if defined( d_vars ) d_vars; #endif cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); kdf8(cx->ks, 0); kd8(cx->ks, 1); kd8(cx->ks, 2); kd8(cx->ks, 3); kd8(cx->ks, 4); kd8(cx->ks, 5); kdl8(cx->ks, 6); #else cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); { uint_32t i; for(i = 0; i < 6; ++i) k8e(cx->ks, i); k8ef(cx->ks, 6); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 14 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 14 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined( AES_VAR ) AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) { switch(key_len) { case 16: case 128: return aes_decrypt_key128(key, cx); case 24: case 192: return aes_decrypt_key192(key, cx); case 32: case 256: return aes_decrypt_key256(key, cx); default: return EXIT_FAILURE; } } #endif #endif #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aesopt.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the compilation options for AES (Rijndael) and code that is common across encryption, key scheduling and table generation. OPERATION These source code files implement the AES algorithm Rijndael designed by Joan Daemen and Vincent Rijmen. This version is designed for the standard block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 and 32 bytes). This version is designed for flexibility and speed using operations on 32-bit words rather than operations on bytes. It can be compiled with either big or little endian internal byte order but is faster when the native byte order for the processor is used. THE CIPHER INTERFACE The cipher interface is implemented as an array of bytes in which lower AES bit sequence indexes map to higher numeric significance within bytes. uint_8t (an unsigned 8-bit type) uint_32t (an unsigned 32-bit type) struct aes_encrypt_ctx (structure for the cipher encryption context) struct aes_decrypt_ctx (structure for the cipher decryption context) AES_RETURN the function return type C subroutine calls: AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that you call aes_init() before AES is used so that the tables are initialised. C++ aes class subroutines: Class AESencrypt for encryption Construtors: AESencrypt(void) AESencrypt(const unsigned char *key) - 128 bit key Members: AES_RETURN key128(const unsigned char *key) AES_RETURN key192(const unsigned char *key) AES_RETURN key256(const unsigned char *key) AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const Class AESdecrypt for encryption Construtors: AESdecrypt(void) AESdecrypt(const unsigned char *key) - 128 bit key Members: AES_RETURN key128(const unsigned char *key) AES_RETURN key192(const unsigned char *key) AES_RETURN key256(const unsigned char *key) AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const */ #if !defined( _AESOPT_H ) #define _AESOPT_H #if defined( __cplusplus ) #include "aescpp.h" #else #include "aes.h" #endif /* PLATFORM SPECIFIC INCLUDES */ #include "brg_endian.h" /* CONFIGURATION - THE USE OF DEFINES Later in this section there are a number of defines that control the operation of the code. In each section, the purpose of each define is explained so that the relevant form can be included or excluded by setting either 1's or 0's respectively on the branches of the related #if clauses. The following local defines should not be changed. */ #define ENCRYPTION_IN_C 1 #define DECRYPTION_IN_C 2 #define ENC_KEYING_IN_C 4 #define DEC_KEYING_IN_C 8 #define NO_TABLES 0 #define ONE_TABLE 1 #define FOUR_TABLES 4 #define NONE 0 #define PARTIAL 1 #define FULL 2 /* --- START OF USER CONFIGURED OPTIONS --- */ /* 1. BYTE ORDER WITHIN 32 BIT WORDS The fundamental data processing units in Rijndael are 8-bit bytes. The input, output and key input are all enumerated arrays of bytes in which bytes are numbered starting at zero and increasing to one less than the number of bytes in the array in question. This enumeration is only used for naming bytes and does not imply any adjacency or order relationship from one byte to another. When these inputs and outputs are considered as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. In this implementation bits are numbered from 0 to 7 starting at the numerically least significant end of each byte (bit n represents 2^n). However, Rijndael can be implemented more efficiently using 32-bit words by packing bytes into words so that bytes 4*n to 4*n+3 are placed into word[n]. While in principle these bytes can be assembled into words in any positions, this implementation only supports the two formats in which bytes in adjacent positions within words also have adjacent byte numbers. This order is called big-endian if the lowest numbered bytes in words have the highest numeric significance and little-endian if the opposite applies. This code can work in either order irrespective of the order used by the machine on which it runs. Normally the internal byte order will be set to the order of the processor on which the code is to be run but this define can be used to reverse this in special situations WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. This define will hence be redefined later (in section 4) if necessary */ #if 1 # define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER #elif 0 # define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN #elif 0 # define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN #else # error The algorithm byte order is not defined #endif /* 2. VIA ACE SUPPORT */ #if !defined(__APPLE__) && defined( __GNUC__ ) && defined( __i386__ ) \ || defined( _WIN32 ) && defined( _M_IX86 ) \ && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) # define VIA_ACE_POSSIBLE #endif /* Define this option if support for the VIA ACE is required. This uses inline assembler instructions and is only implemented for the Microsoft, Intel and GCC compilers. If VIA ACE is known to be present, then defining ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if it is detected (both present and enabled) but the normal AES code will also be present. When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte aligned; other input/output buffers do not need to be 16 byte aligned but there are very large performance gains if this can be arranged. VIA ACE also requires the decryption key schedule to be in reverse order (which later checks below ensure). */ #if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) # define USE_VIA_ACE_IF_PRESENT #endif #if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) # define ASSUME_VIA_ACE_PRESENT # endif /* 3. ASSEMBLER SUPPORT This define (which can be on the command line) enables the use of the assembler code routines for encryption, decryption and key scheduling as follows: ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for encryption and decryption and but with key scheduling in C ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for encryption, decryption and key scheduling ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for encryption and decryption and but with key scheduling in C ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for encryption and decryption and but with key scheduling in C Change one 'if 0' below to 'if 1' to select the version or define as a compilation option. */ #if 0 && !defined( ASM_X86_V1C ) # define ASM_X86_V1C #elif 0 && !defined( ASM_X86_V2 ) # define ASM_X86_V2 #elif 0 && !defined( ASM_X86_V2C ) # define ASM_X86_V2C #elif 0 && !defined( ASM_AMD64_C ) # define ASM_AMD64_C #endif #if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) # error Assembler code is only available for x86 and AMD64 systems #endif /* 4. FAST INPUT/OUTPUT OPERATIONS. On some machines it is possible to improve speed by transferring the bytes in the input and output arrays to and from the internal 32-bit variables by addressing these arrays as if they are arrays of 32-bit words. On some machines this will always be possible but there may be a large performance penalty if the byte arrays are not aligned on the normal word boundaries. On other machines this technique will lead to memory access errors when such 32-bit word accesses are not properly aligned. The option SAFE_IO avoids such problems but will often be slower on those machines that support misaligned access (especially so if care is taken to align the input and output byte arrays on 32-bit word boundaries). If SAFE_IO is not defined it is assumed that access to byte arrays as if they are arrays of 32-bit words will not cause problems when such accesses are misaligned. */ #if 1 && !defined( _MSC_VER ) # define SAFE_IO #endif /* 5. LOOP UNROLLING The code for encryption and decrytpion cycles through a number of rounds that can be implemented either in a loop or by expanding the code into a long sequence of instructions, the latter producing a larger program but one that will often be much faster. The latter is called loop unrolling. There are also potential speed advantages in expanding two iterations in a loop with half the number of iterations, which is called partial loop unrolling. The following options allow partial or full loop unrolling to be set independently for encryption and decryption */ #if 1 # define ENC_UNROLL FULL #elif 0 # define ENC_UNROLL PARTIAL #else # define ENC_UNROLL NONE #endif #if 1 # define DEC_UNROLL FULL #elif 0 # define DEC_UNROLL PARTIAL #else # define DEC_UNROLL NONE #endif #if 1 # define ENC_KS_UNROLL #endif #if 1 # define DEC_KS_UNROLL #endif /* 6. FAST FINITE FIELD OPERATIONS If this section is included, tables are used to provide faster finite field arithmetic (this has no effect if FIXED_TABLES is defined). */ #if 1 # define FF_TABLES #endif /* 7. INTERNAL STATE VARIABLE FORMAT The internal state of Rijndael is stored in a number of local 32-bit word varaibles which can be defined either as an array or as individual names variables. Include this section if you want to store these local varaibles in arrays. Otherwise individual local variables will be used. */ #if 1 # define ARRAYS #endif /* 8. FIXED OR DYNAMIC TABLES When this section is included the tables used by the code are compiled statically into the binary file. Otherwise the subroutine aes_init() must be called to compute them before the code is first used. */ #if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) # define FIXED_TABLES #endif /* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES In some systems it is better to mask longer values to extract bytes rather than using a cast. This option allows this choice. */ #if 0 # define to_byte(x) ((uint_8t)(x)) #else # define to_byte(x) ((x) & 0xff) #endif /* 10. TABLE ALIGNMENT On some sytsems speed will be improved by aligning the AES large lookup tables on particular boundaries. This define should be set to a power of two giving the desired alignment. It can be left undefined if alignment is not needed. This option is specific to the Microsft VC++ compiler - it seems to sometimes cause trouble for the VC++ version 6 compiler. */ #if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) # define TABLE_ALIGN 32 #endif /* 11. REDUCE CODE AND TABLE SIZE This replaces some expanded macros with function calls if AES_ASM_V2 or AES_ASM_V2C are defined */ #if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) # define REDUCE_CODE_SIZE #endif /* 12. TABLE OPTIONS This cipher proceeds by repeating in a number of cycles known as 'rounds' which are implemented by a round function which can optionally be speeded up using tables. The basic tables are each 256 32-bit words, with either one or four tables being required for each round function depending on how much speed is required. The encryption and decryption round functions are different and the last encryption and decrytpion round functions are different again making four different round functions in all. This means that: 1. Normal encryption and decryption rounds can each use either 0, 1 or 4 tables and table spaces of 0, 1024 or 4096 bytes each. 2. The last encryption and decryption rounds can also use either 0, 1 or 4 tables and table spaces of 0, 1024 or 4096 bytes each. Include or exclude the appropriate definitions below to set the number of tables used by this implementation. */ #if 1 /* set tables for the normal encryption round */ # define ENC_ROUND FOUR_TABLES #elif 0 # define ENC_ROUND ONE_TABLE #else # define ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the last encryption round */ # define LAST_ENC_ROUND FOUR_TABLES #elif 0 # define LAST_ENC_ROUND ONE_TABLE #else # define LAST_ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the normal decryption round */ # define DEC_ROUND FOUR_TABLES #elif 0 # define DEC_ROUND ONE_TABLE #else # define DEC_ROUND NO_TABLES #endif #if 1 /* set tables for the last decryption round */ # define LAST_DEC_ROUND FOUR_TABLES #elif 0 # define LAST_DEC_ROUND ONE_TABLE #else # define LAST_DEC_ROUND NO_TABLES #endif /* The decryption key schedule can be speeded up with tables in the same way that the round functions can. Include or exclude the following defines to set this requirement. */ #if 1 # define KEY_SCHED FOUR_TABLES #elif 0 # define KEY_SCHED ONE_TABLE #else # define KEY_SCHED NO_TABLES #endif /* ---- END OF USER CONFIGURED OPTIONS ---- */ /* VIA ACE support is only available for VC++ and GCC */ #if !defined( _MSC_VER ) && !defined( __GNUC__ ) # if defined( ASSUME_VIA_ACE_PRESENT ) # undef ASSUME_VIA_ACE_PRESENT # endif # if defined( USE_VIA_ACE_IF_PRESENT ) # undef USE_VIA_ACE_IF_PRESENT # endif #endif #if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) # define USE_VIA_ACE_IF_PRESENT #endif #if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) # define AES_REV_DKS #endif /* Assembler support requires the use of platform byte order */ #if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) # undef ALGORITHM_BYTE_ORDER # define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER #endif /* In this implementation the columns of the state array are each held in 32-bit words. The state array can be held in various ways: in an array of words, in a number of individual word variables or in a number of processor registers. The following define maps a variable name x and a column number c to the way the state array variable is to be held. The first define below maps the state into an array x[c] whereas the second form maps the state into a number of individual variables x0, x1, etc. Another form could map individual state colums to machine register names. */ #if defined( ARRAYS ) # define s(x,c) x[c] #else # define s(x,c) x##c #endif /* This implementation provides subroutines for encryption, decryption and for setting the three key lengths (separately) for encryption and decryption. Since not all functions are needed, masks are set up here to determine which will be implemented in C */ #if !defined( AES_ENCRYPT ) # define EFUNCS_IN_C 0 #elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) # define EFUNCS_IN_C ENC_KEYING_IN_C #elif !defined( ASM_X86_V2 ) # define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) #else # define EFUNCS_IN_C 0 #endif #if !defined( AES_DECRYPT ) # define DFUNCS_IN_C 0 #elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) # define DFUNCS_IN_C DEC_KEYING_IN_C #elif !defined( ASM_X86_V2 ) # define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) #else # define DFUNCS_IN_C 0 #endif #define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) /* END OF CONFIGURATION OPTIONS */ #define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) /* Disable or report errors on some combinations of options */ #if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES # undef LAST_ENC_ROUND # define LAST_ENC_ROUND NO_TABLES #elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES # undef LAST_ENC_ROUND # define LAST_ENC_ROUND ONE_TABLE #endif #if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE # undef ENC_UNROLL # define ENC_UNROLL NONE #endif #if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES # undef LAST_DEC_ROUND # define LAST_DEC_ROUND NO_TABLES #elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES # undef LAST_DEC_ROUND # define LAST_DEC_ROUND ONE_TABLE #endif #if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE # undef DEC_UNROLL # define DEC_UNROLL NONE #endif #if defined( bswap32 ) # define aes_sw32 bswap32 #elif defined( bswap_32 ) # define aes_sw32 bswap_32 #else # define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n))) # define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) #endif /* upr(x,n): rotates bytes within words by n positions, moving bytes to higher index positions with wrap around into low positions ups(x,n): moves bytes by n positions to higher index positions in words but without wrap around bval(x,n): extracts a byte from a word WARNING: The definitions given here are intended only for use with unsigned variables and with shift counts that are compile time constants */ #if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) # define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n)))) # define ups(x,n) ((uint_32t) (x) << (8 * (n))) # define bval(x,n) to_byte((x) >> (8 * (n))) # define bytes2word(b0, b1, b2, b3) \ (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0)) #endif #if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) # define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n)))) # define ups(x,n) ((uint_32t) (x) >> (8 * (n))) # define bval(x,n) to_byte((x) >> (24 - 8 * (n))) # define bytes2word(b0, b1, b2, b3) \ (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3)) #endif #if defined( SAFE_IO ) # define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \ ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3]) # define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \ ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); } #elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) # define word_in(x,c) (*((uint_32t*)(x)+(c))) # define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v)) #else # define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c))) # define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v)) #endif /* the finite field modular polynomial and elements */ #define WPOLY 0x011b #define BPOLY 0x1b /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ #define gf_c1 0x80808080 #define gf_c2 0x7f7f7f7f #define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) /* The following defines provide alternative definitions of gf_mulx that might give improved performance if a fast 32-bit multiply is not available. Note that a temporary variable u needs to be defined where gf_mulx is used. #define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) #define gf_c4 (0x01010101 * BPOLY) #define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) */ /* Work out which tables are needed for the different options */ #if defined( ASM_X86_V1C ) # if defined( ENC_ROUND ) # undef ENC_ROUND # endif # define ENC_ROUND FOUR_TABLES # if defined( LAST_ENC_ROUND ) # undef LAST_ENC_ROUND # endif # define LAST_ENC_ROUND FOUR_TABLES # if defined( DEC_ROUND ) # undef DEC_ROUND # endif # define DEC_ROUND FOUR_TABLES # if defined( LAST_DEC_ROUND ) # undef LAST_DEC_ROUND # endif # define LAST_DEC_ROUND FOUR_TABLES # if defined( KEY_SCHED ) # undef KEY_SCHED # define KEY_SCHED FOUR_TABLES # endif #endif #if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) # if ENC_ROUND == ONE_TABLE # define FT1_SET # elif ENC_ROUND == FOUR_TABLES # define FT4_SET # else # define SBX_SET # endif # if LAST_ENC_ROUND == ONE_TABLE # define FL1_SET # elif LAST_ENC_ROUND == FOUR_TABLES # define FL4_SET # elif !defined( SBX_SET ) # define SBX_SET # endif #endif #if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) # if DEC_ROUND == ONE_TABLE # define IT1_SET # elif DEC_ROUND == FOUR_TABLES # define IT4_SET # else # define ISB_SET # endif # if LAST_DEC_ROUND == ONE_TABLE # define IL1_SET # elif LAST_DEC_ROUND == FOUR_TABLES # define IL4_SET # elif !defined(ISB_SET) # define ISB_SET # endif #endif #if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) # if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) # if KEY_SCHED == ONE_TABLE # if !defined( FL1_SET ) && !defined( FL4_SET ) # define LS1_SET # endif # elif KEY_SCHED == FOUR_TABLES # if !defined( FL4_SET ) # define LS4_SET # endif # elif !defined( SBX_SET ) # define SBX_SET # endif # endif # if (FUNCS_IN_C & DEC_KEYING_IN_C) # if KEY_SCHED == ONE_TABLE # define IM1_SET # elif KEY_SCHED == FOUR_TABLES # define IM4_SET # elif !defined( SBX_SET ) # define SBX_SET # endif # endif #endif /* generic definitions of Rijndael macros that use tables */ #define no_table(x,box,vf,rf,c) bytes2word( \ box[bval(vf(x,0,c),rf(0,c))], \ box[bval(vf(x,1,c),rf(1,c))], \ box[bval(vf(x,2,c),rf(2,c))], \ box[bval(vf(x,3,c),rf(3,c))]) #define one_table(x,op,tab,vf,rf,c) \ ( tab[bval(vf(x,0,c),rf(0,c))] \ ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) #define four_tables(x,tab,vf,rf,c) \ ( tab[0][bval(vf(x,0,c),rf(0,c))] \ ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ ^ tab[3][bval(vf(x,3,c),rf(3,c))]) #define vf1(x,r,c) (x) #define rf1(r,c) (r) #define rf2(r,c) ((8+r-c)&3) /* perform forward and inverse column mix operation on four bytes in long word x in */ /* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ #if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) #if defined( FM4_SET ) /* not currently used */ # define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) #elif defined( FM1_SET ) /* not currently used */ # define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) #else # define dec_fmvars uint_32t g2 # define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) #endif #if defined( IM4_SET ) # define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) #elif defined( IM1_SET ) # define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) #else # define dec_imvars uint_32t g2, g4, g9 # define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) #endif #if defined( FL4_SET ) # define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) #elif defined( LS4_SET ) # define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) #elif defined( FL1_SET ) # define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) #elif defined( LS1_SET ) # define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) #else # define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) #endif #endif #if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) # define ISB_SET #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aestab.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #define DO_TABLES #include "aes.h" #include "aesopt.h" #if defined(FIXED_TABLES) #define sb_data(w) {\ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } #define isb_data(w) {\ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } #define mm_data(w) {\ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } #define rc_data(w) {\ w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ w(0x1b), w(0x36) } #define h0(x) (x) #define w0(p) bytes2word(p, 0, 0, 0) #define w1(p) bytes2word(0, p, 0, 0) #define w2(p) bytes2word(0, 0, p, 0) #define w3(p) bytes2word(0, 0, 0, p) #define u0(p) bytes2word(f2(p), p, p, f3(p)) #define u1(p) bytes2word(f3(p), f2(p), p, p) #define u2(p) bytes2word(p, f3(p), f2(p), p) #define u3(p) bytes2word(p, p, f3(p), f2(p)) #define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) #define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) #define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) #define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) #endif #if defined(FIXED_TABLES) || !defined(FF_TABLES) #define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) #define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) #define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ ^ (((x>>5) & 4) * WPOLY)) #define f3(x) (f2(x) ^ x) #define f9(x) (f8(x) ^ x) #define fb(x) (f8(x) ^ f2(x) ^ x) #define fd(x) (f8(x) ^ f4(x) ^ x) #define fe(x) (f8(x) ^ f4(x) ^ f2(x)) #else #define f2(x) ((x) ? pow[log[x] + 0x19] : 0) #define f3(x) ((x) ? pow[log[x] + 0x01] : 0) #define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) #define fb(x) ((x) ? pow[log[x] + 0x68] : 0) #define fd(x) ((x) ? pow[log[x] + 0xee] : 0) #define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) #endif #include "aestab.h" #if defined(__cplusplus) extern "C" { #endif #if defined(FIXED_TABLES) /* implemented in case of wrong call for fixed tables */ AES_RETURN aes_init(void) { return EXIT_SUCCESS; } #else /* Generate the tables for the dynamic table option */ #if defined(FF_TABLES) #define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) #else /* It will generally be sensible to use tables to compute finite field multiplies and inverses but where memory is scarse this code might sometimes be better. But it only has effect during initialisation so its pretty unimportant in overall terms. */ /* return 2 ^ (n - 1) where n is the bit number of the highest bit set in x with x in the range 1 < x < 0x00000200. This form is used so that locals within fi can be bytes rather than words */ static uint_8t hibit(const uint_32t x) { uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); r |= (r >> 2); r |= (r >> 4); return (r + 1) >> 1; } /* return the inverse of the finite field element x */ static uint_8t gf_inv(const uint_8t x) { uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; if(x < 2) return x; for( ; ; ) { if(n1) while(n2 >= n1) /* divide polynomial p2 by p1 */ { n2 /= n1; /* shift smaller polynomial left */ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ v2 ^= v1 * n2; /* shift accumulated value and */ n2 = hibit(p2); /* add into result */ } else return v1; if(n2) /* repeat with values swapped */ while(n1 >= n2) { n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); } else return v2; } } #endif /* The forward and inverse affine transformations used in the S-box */ uint_8t fwd_affine(const uint_8t x) { uint_32t w = x; w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); return 0x63 ^ ((w ^ (w >> 8)) & 0xff); } uint_8t inv_affine(const uint_8t x) { uint_32t w = x; w = (w << 1) ^ (w << 3) ^ (w << 6); return 0x05 ^ ((w ^ (w >> 8)) & 0xff); } static int init = 0; AES_RETURN aes_init(void) { uint_32t i, w; #if defined(FF_TABLES) uint_8t pow[512], log[256]; if(init) return EXIT_SUCCESS; /* log and power tables for GF(2^8) finite field with WPOLY as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ i = 0; w = 1; do { pow[i] = (uint_8t)w; pow[i + 255] = (uint_8t)w; log[w] = (uint_8t)i++; w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); } while (w != 1); #else if(init) return EXIT_SUCCESS; #endif for(i = 0, w = 1; i < RC_LENGTH; ++i) { t_set(r,c)[i] = bytes2word(w, 0, 0, 0); w = f2(w); } for(i = 0; i < 256; ++i) { uint_8t b; b = fwd_affine(gf_inv((uint_8t)i)); w = bytes2word(f2(b), b, b, f3(b)); #if defined( SBX_SET ) t_set(s,box)[i] = b; #endif #if defined( FT1_SET ) /* tables for a normal encryption round */ t_set(f,n)[i] = w; #endif #if defined( FT4_SET ) t_set(f,n)[0][i] = w; t_set(f,n)[1][i] = upr(w,1); t_set(f,n)[2][i] = upr(w,2); t_set(f,n)[3][i] = upr(w,3); #endif w = bytes2word(b, 0, 0, 0); #if defined( FL1_SET ) /* tables for last encryption round (may also */ t_set(f,l)[i] = w; /* be used in the key schedule) */ #endif #if defined( FL4_SET ) t_set(f,l)[0][i] = w; t_set(f,l)[1][i] = upr(w,1); t_set(f,l)[2][i] = upr(w,2); t_set(f,l)[3][i] = upr(w,3); #endif #if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ t_set(l,s)[i] = w; /* not of the required form */ #endif #if defined( LS4_SET ) t_set(l,s)[0][i] = w; t_set(l,s)[1][i] = upr(w,1); t_set(l,s)[2][i] = upr(w,2); t_set(l,s)[3][i] = upr(w,3); #endif b = gf_inv(inv_affine((uint_8t)i)); w = bytes2word(fe(b), f9(b), fd(b), fb(b)); #if defined( IM1_SET ) /* tables for the inverse mix column operation */ t_set(i,m)[b] = w; #endif #if defined( IM4_SET ) t_set(i,m)[0][b] = w; t_set(i,m)[1][b] = upr(w,1); t_set(i,m)[2][b] = upr(w,2); t_set(i,m)[3][b] = upr(w,3); #endif #if defined( ISB_SET ) t_set(i,box)[i] = b; #endif #if defined( IT1_SET ) /* tables for a normal decryption round */ t_set(i,n)[i] = w; #endif #if defined( IT4_SET ) t_set(i,n)[0][i] = w; t_set(i,n)[1][i] = upr(w,1); t_set(i,n)[2][i] = upr(w,2); t_set(i,n)[3][i] = upr(w,3); #endif w = bytes2word(b, 0, 0, 0); #if defined( IL1_SET ) /* tables for last decryption round */ t_set(i,l)[i] = w; #endif #if defined( IL4_SET ) t_set(i,l)[0][i] = w; t_set(i,l)[1][i] = upr(w,1); t_set(i,l)[2][i] = upr(w,2); t_set(i,l)[3][i] = upr(w,3); #endif } init = 1; return EXIT_SUCCESS; } #endif #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/aestab.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the code for declaring the tables needed to implement AES. The file aesopt.h is assumed to be included before this header file. If there are no global variables, the definitions here can be used to put the AES tables in a structure so that a pointer can then be added to the AES context to pass them to the AES routines that need them. If this facility is used, the calling program has to ensure that this pointer is managed appropriately. In particular, the value of the t_dec(in,it) item in the table structure must be set to zero in order to ensure that the tables are initialised. In practice the three code sequences in aeskey.c that control the calls to aes_init() and the aes_init() routine itself will have to be changed for a specific implementation. If global variables are available it will generally be preferable to use them with the precomputed FIXED_TABLES option that uses static global tables. The following defines can be used to control the way the tables are defined, initialised and used in embedded environments that require special features for these purposes the 't_dec' construction is used to declare fixed table arrays the 't_set' construction is used to set fixed table values the 't_use' construction is used to access fixed table values 256 byte tables: t_xxx(s,box) => forward S box t_xxx(i,box) => inverse S box 256 32-bit word OR 4 x 256 32-bit word tables: t_xxx(f,n) => forward normal round t_xxx(f,l) => forward last round t_xxx(i,n) => inverse normal round t_xxx(i,l) => inverse last round t_xxx(l,s) => key schedule table t_xxx(i,m) => key schedule table Other variables and tables: t_xxx(r,c) => the rcon table */ #if !defined( _AESTAB_H ) #define _AESTAB_H #if defined(__cplusplus) extern "C" { #endif #define t_dec(m,n) t_##m##n #define t_set(m,n) t_##m##n #define t_use(m,n) t_##m##n #if defined(FIXED_TABLES) # if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) /* make tables far data to avoid using too much DGROUP space (PG) */ # define CONST const far # else # define CONST const # endif #else # define CONST #endif #if defined(DO_TABLES) # define EXTERN #else # define EXTERN extern #endif #if defined(_MSC_VER) && defined(TABLE_ALIGN) #define ALIGN __declspec(align(TABLE_ALIGN)) #else #define ALIGN #endif #if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) # define XP_DIR __cdecl #else # define XP_DIR #endif #if defined(DO_TABLES) && defined(FIXED_TABLES) #define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) #define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0); #else #define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] #define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH]; #endif #if defined( SBX_SET ) d_1(uint_8t, t_dec(s,box), sb_data, h0); #endif #if defined( ISB_SET ) d_1(uint_8t, t_dec(i,box), isb_data, h0); #endif #if defined( FT1_SET ) d_1(uint_32t, t_dec(f,n), sb_data, u0); #endif #if defined( FT4_SET ) d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3); #endif #if defined( FL1_SET ) d_1(uint_32t, t_dec(f,l), sb_data, w0); #endif #if defined( FL4_SET ) d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3); #endif #if defined( IT1_SET ) d_1(uint_32t, t_dec(i,n), isb_data, v0); #endif #if defined( IT4_SET ) d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3); #endif #if defined( IL1_SET ) d_1(uint_32t, t_dec(i,l), isb_data, w0); #endif #if defined( IL4_SET ) d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3); #endif #if defined( LS1_SET ) #if defined( FL1_SET ) #undef LS1_SET #else d_1(uint_32t, t_dec(l,s), sb_data, w0); #endif #endif #if defined( LS4_SET ) #if defined( FL4_SET ) #undef LS4_SET #else d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3); #endif #endif #if defined( IM1_SET ) d_1(uint_32t, t_dec(i,m), mm_data, v0); #endif #if defined( IM4_SET ) d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3); #endif #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/brg_endian.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #ifndef _BRG_ENDIAN_H #define _BRG_ENDIAN_H #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ /* Include files where endian defines and byteswap functions may reside */ #if defined( __sun ) # include #elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) # include #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) # include #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) # if !defined( __MINGW32__ ) && !defined( _AIX ) # include # if !defined( __BEOS__ ) # include # endif # endif #endif /* Now attempt to set the define for platform byte order using any */ /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ /* seem to encompass most endian symbol definitions */ #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) # if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) # if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( _BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( _LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) # if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) # if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif /* if the platform byte order could not be determined, then try to */ /* set this define using common machine defines */ #if !defined(PLATFORM_BYTE_ORDER) #if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ defined( vax ) || defined( vms ) || defined( VMS ) || \ defined( __VMS ) || defined( _M_X64 ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #else # error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order #endif #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/brg_types.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 The unsigned integer types defined here are of the form uint_t where is the length of the type; for example, the unsigned 32-bit type is 'uint_32t'. These are NOT the same as the 'C99 integer types' that are defined in the inttypes.h and stdint.h headers since attempts to use these types have shown that support for them is still highly variable. However, since the latter are of the form uint_t, a regular expression search and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') can be used to convert the types used here to the C99 standard types. */ #ifndef _BRG_TYPES_H #define _BRG_TYPES_H #if defined(__cplusplus) extern "C" { #endif #include #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) # include # define ptrint_t intptr_t #elif defined( __ECOS__ ) # define intptr_t unsigned int # define ptrint_t intptr_t #elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) # include # define ptrint_t intptr_t #else # define ptrint_t int #endif #ifndef BRG_UI8 # define BRG_UI8 # if UCHAR_MAX == 255u typedef unsigned char uint_8t; # else # error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h # endif #endif #ifndef BRG_UI16 # define BRG_UI16 # if USHRT_MAX == 65535u typedef unsigned short uint_16t; # else # error Please define uint_16t as a 16-bit unsigned short type in brg_types.h # endif #endif #ifndef BRG_UI32 # define BRG_UI32 # if UINT_MAX == 4294967295u # define li_32(h) 0x##h##u typedef unsigned int uint_32t; # elif ULONG_MAX == 4294967295u # define li_32(h) 0x##h##ul typedef unsigned long uint_32t; # elif defined( _CRAY ) # error This code needs 32-bit data types, which Cray machines do not provide # else # error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h # endif #endif #ifndef BRG_UI64 # if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) # define BRG_UI64 # define li_64(h) 0x##h##ui64 typedef unsigned __int64 uint_64t; # elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ # define BRG_UI64 # define li_64(h) 0x##h##ui64 typedef unsigned __int64 uint_64t; # elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # elif defined( __MVS__ ) # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned int long long uint_64t; # elif defined( UINT_MAX ) && UINT_MAX > 4294967295u # if UINT_MAX == 18446744073709551615u # define BRG_UI64 # define li_64(h) 0x##h##u typedef unsigned int uint_64t; # endif # elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u # if ULONG_MAX == 18446744073709551615ul # define BRG_UI64 # define li_64(h) 0x##h##ul typedef unsigned long uint_64t; # endif # elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u # if ULLONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # endif # elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u # if ULONG_LONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull typedef unsigned long long uint_64t; # endif # endif #endif #if !defined( BRG_UI64 ) # if defined( NEED_UINT_64T ) # error Please define uint_64t as an unsigned 64 bit type in brg_types.h # endif #endif #ifndef RETURN_VALUES # define RETURN_VALUES # if defined( DLL_EXPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllexport ) void __stdcall # define INT_RETURN __declspec( dllexport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllexport__ ) void # define INT_RETURN __declspec( __dllexport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( DLL_IMPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllimport ) void __stdcall # define INT_RETURN __declspec( dllimport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllimport__ ) void # define INT_RETURN __declspec( __dllimport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( __WATCOMC__ ) # define VOID_RETURN void __cdecl # define INT_RETURN int __cdecl # else # define VOID_RETURN void # define INT_RETURN int # endif #endif /* These defines are used to detect and set the memory alignment of pointers. Note that offsets are in bytes. ALIGN_OFFSET(x,n) return the positive or zero offset of the memory addressed by the pointer 'x' from an address that is aligned on an 'n' byte boundary ('n' is a power of 2) ALIGN_FLOOR(x,n) return a pointer that points to memory that is aligned on an 'n' byte boundary and is not higher than the memory address pointed to by 'x' ('n' is a power of 2) ALIGN_CEIL(x,n) return a pointer that points to memory that is aligned on an 'n' byte boundary and is not lower than the memory address pointed to by 'x' ('n' is a power of 2) */ #define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) #define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) #define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) /* These defines are used to declare buffers in a way that allows faster operations on longer variables to be used. In all these defines 'size' must be a power of 2 and >= 8. NOTE that the buffer size is in bytes but the type length is in bits UNIT_TYPEDEF(x,size) declares a variable 'x' of length 'size' bits BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' bytes defined as an array of variables each of 'size' bits (bsize must be a multiple of size / 8) UNIT_CAST(x,size) casts a variable to a type of length 'size' bits UPTR_CAST(x,size) casts a pointer to a pointer to a varaiable of length 'size' bits */ #define UI_TYPE(size) uint_##size##t #define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x #define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] #define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) #define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/entropy.c ================================================ #ifdef _WIN32 #include #else #include #include #include #endif #if defined(__cplusplus) extern "C" { #endif #ifdef _WIN32 int entropy_fun(unsigned char buf[], unsigned int len) { HCRYPTPROV provider; unsigned __int64 pentium_tsc[1]; unsigned int i; int result = 0; if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { result = CryptGenRandom(provider, len, buf); CryptReleaseContext(provider, 0); if (result) return len; } QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc); for(i = 0; i < 8 && i < len; ++i) buf[i] = ((unsigned char*)pentium_tsc)[i]; return i; } #else int entropy_fun(unsigned char buf[], unsigned int len) { int frand = open("/dev/random", O_RDONLY); int rlen = 0; if (frand != -1) { rlen = (int)read(frand, buf, len); close(frand); } return rlen; } #endif #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/entropy.h ================================================ #ifndef _ENTROPY_FUN_H #define _ENTROPY_FUN_H #if defined(__cplusplus) extern "C" { #endif int entropy_fun(unsigned char buf[], unsigned int len); #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/fileenc.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. ------------------------------------------------------------------------- Issue Date: 24/01/2003 This file implements password based file encryption and authentication using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password based key derivation. */ #include #include "fileenc.h" #if defined(__cplusplus) extern "C" { #endif /* subroutine for data encryption/decryption */ /* this could be speeded up a lot by aligning */ /* buffers and using 32 bit operations */ static void encr_data(unsigned char data[], unsigned long d_len, fcrypt_ctx cx[1]) { unsigned long i = 0, pos = cx->encr_pos; while (i < d_len) { if (pos == AES_BLOCK_SIZE) { unsigned int j = 0; /* increment encryption nonce */ while (j < 8 && !++cx->nonce[j]) ++j; /* encrypt the nonce to form next xor buffer */ aes_encrypt(cx->nonce, cx->encr_bfr, cx->encr_ctx); pos = 0; } data[i++] ^= cx->encr_bfr[pos++]; } cx->encr_pos = (unsigned int)pos; } int fcrypt_init( int mode, /* the mode to be used (input) */ const unsigned char pwd[], /* the user specified password (input) */ unsigned int pwd_len, /* the length of the password (input) */ const unsigned char salt[], /* the salt (input) */ #ifdef PASSWORD_VERIFIER unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ #endif fcrypt_ctx cx[1]) /* the file encryption context (output) */ { unsigned char kbuf[2 * MAX_KEY_LENGTH + PWD_VER_LENGTH]; if (pwd_len > MAX_PWD_LENGTH) return PASSWORD_TOO_LONG; if (mode < 1 || mode > 3) return BAD_MODE; cx->mode = mode; cx->pwd_len = pwd_len; /* derive the encryption and authentication keys and the password verifier */ derive_key(pwd, pwd_len, salt, SALT_LENGTH(mode), KEYING_ITERATIONS, kbuf, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH); /* initialise the encryption nonce and buffer pos */ cx->encr_pos = AES_BLOCK_SIZE; /* if we need a random component in the encryption */ /* nonce, this is where it would have to be set */ memset(cx->nonce, 0, AES_BLOCK_SIZE * sizeof(unsigned char)); /* initialise for encryption using key 1 */ aes_encrypt_key(kbuf, KEY_LENGTH(mode), cx->encr_ctx); /* initialise for authentication using key 2 */ hmac_sha_begin(cx->auth_ctx); hmac_sha_key(kbuf + KEY_LENGTH(mode), KEY_LENGTH(mode), cx->auth_ctx); #ifdef PASSWORD_VERIFIER memcpy(pwd_ver, kbuf + 2 * KEY_LENGTH(mode), PWD_VER_LENGTH); #endif return GOOD_RETURN; } /* perform 'in place' encryption and authentication */ void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) { encr_data(data, data_len, cx); hmac_sha_data(data, data_len, cx->auth_ctx); } /* perform 'in place' authentication and decryption */ void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) { hmac_sha_data(data, data_len, cx->auth_ctx); encr_data(data, data_len, cx); } /* close encryption/decryption and return the MAC value */ int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1]) { hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx); return MAC_LENGTH(cx->mode); /* return MAC length in bytes */ } #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/fileenc.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 24/01/2003 This file contains the header file for fileenc.c, which implements password based file encryption and authentication using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password based key derivation. */ #ifndef _FENC_H #define _FENC_H #include "aes.h" #include "hmac.h" #include "pwd2key.h" #define PASSWORD_VERIFIER #define MAX_KEY_LENGTH 32 #define MAX_PWD_LENGTH 128 #define MAX_SALT_LENGTH 16 #define KEYING_ITERATIONS 1000 #ifdef PASSWORD_VERIFIER #define PWD_VER_LENGTH 2 #else #define PWD_VER_LENGTH 0 #endif #define GOOD_RETURN 0 #define PASSWORD_TOO_LONG -100 #define BAD_MODE -101 /* Field lengths (in bytes) versus File Encryption Mode (0 < mode < 4) Mode Key Salt MAC Overhead 1 16 8 10 18 2 24 12 10 22 3 32 16 10 26 The following macros assume that the mode value is correct. */ #define KEY_LENGTH(mode) (8 * (mode & 3) + 8) #define SALT_LENGTH(mode) (4 * (mode & 3) + 4) #define MAC_LENGTH(mode) (10) /* the context for file encryption */ #if defined(__cplusplus) extern "C" { #endif typedef struct { unsigned char nonce[AES_BLOCK_SIZE]; /* the CTR nonce */ unsigned char encr_bfr[AES_BLOCK_SIZE]; /* encrypt buffer */ aes_encrypt_ctx encr_ctx[1]; /* encryption context */ hmac_ctx auth_ctx[1]; /* authentication context */ unsigned int encr_pos; /* block position (enc) */ unsigned int pwd_len; /* password length */ unsigned int mode; /* File encryption mode */ } fcrypt_ctx; /* initialise file encryption or decryption */ int fcrypt_init( int mode, /* the mode to be used (input) */ const unsigned char pwd[], /* the user specified password (input) */ unsigned int pwd_len, /* the length of the password (input) */ const unsigned char salt[], /* the salt (input) */ #ifdef PASSWORD_VERIFIER unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ #endif fcrypt_ctx cx[1]); /* the file encryption context (output) */ /* perform 'in place' encryption or decryption and authentication */ void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); /* close encryption/decryption and return the MAC value */ /* the return value is the length of the MAC */ int fcrypt_end(unsigned char mac[], /* the MAC value (output) */ fcrypt_ctx cx[1]); /* the context (input) */ #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/hmac.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 26/08/2003 This is an implementation of HMAC, the FIPS standard keyed hash function */ #include "hmac.h" #include "brg_types.h" #if defined(__cplusplus) extern "C" { #endif /* initialise the HMAC context to zero */ void hmac_sha_begin(hmac_ctx cx[1]) { memset(cx, 0, sizeof(hmac_ctx)); } /* input the HMAC key (can be called multiple times) */ int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]) { if(cx->klen == HMAC_IN_DATA) /* error if further key input */ return HMAC_BAD_MODE; /* is attempted in data mode */ if(cx->klen + key_len > HASH_INPUT_SIZE) /* if the key has to be hashed */ { if(cx->klen <= HASH_INPUT_SIZE) /* if the hash has not yet been */ { /* started, initialise it and */ sha_begin(cx->ctx); /* hash stored key characters */ sha_hash(cx->key, cx->klen, cx->ctx); } sha_hash(key, key_len, cx->ctx); /* hash long key data into hash */ } else /* otherwise store key data */ memcpy(cx->key + cx->klen, key, key_len); cx->klen += key_len; /* update the key length count */ return HMAC_OK; } /* input the HMAC data (can be called multiple times) - */ /* note that this call terminates the key input phase */ void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]) { unsigned int i; if(cx->klen != HMAC_IN_DATA) /* if not yet in data phase */ { if(cx->klen > HASH_INPUT_SIZE) /* if key is being hashed */ { /* complete the hash and */ sha_end(cx->key, cx->ctx); /* store the result as the */ cx->klen = HASH_OUTPUT_SIZE; /* key and set new length */ } /* pad the key if necessary */ memset(cx->key + cx->klen, 0, HASH_INPUT_SIZE - cx->klen); /* xor ipad into key value */ for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) ((uint_32t*)cx->key)[i] ^= 0x36363636; /* and start hash operation */ sha_begin(cx->ctx); sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); /* mark as now in data mode */ cx->klen = HMAC_IN_DATA; } /* hash the data (if any) */ if(data_len) sha_hash(data, data_len, cx->ctx); } /* compute and output the MAC value */ void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]) { unsigned char dig[HASH_OUTPUT_SIZE]; unsigned int i; /* if no data has been entered perform a null data phase */ if(cx->klen != HMAC_IN_DATA) hmac_sha_data((const unsigned char*)0, 0, cx); sha_end(dig, cx->ctx); /* complete the inner hash */ /* set outer key value using opad and removing ipad */ for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) ((uint_32t*)cx->key)[i] ^= 0x36363636 ^ 0x5c5c5c5c; /* perform the outer hash operation */ sha_begin(cx->ctx); sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); sha_hash(dig, HASH_OUTPUT_SIZE, cx->ctx); sha_end(dig, cx->ctx); /* output the hash value */ for(i = 0; i < mac_len; ++i) mac[i] = dig[i]; } /* 'do it all in one go' subroutine */ void hmac_sha(const unsigned char key[], unsigned long key_len, const unsigned char data[], unsigned long data_len, unsigned char mac[], unsigned long mac_len) { hmac_ctx cx[1]; hmac_sha_begin(cx); hmac_sha_key(key, key_len, cx); hmac_sha_data(data, data_len, cx); hmac_sha_end(mac, mac_len, cx); } #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/hmac.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 26/08/2003 This is an implementation of HMAC, the FIPS standard keyed hash function */ #ifndef _HMAC_H #define _HMAC_H #include #if defined(__cplusplus) extern "C" { #endif #define USE_SHA1 #if !defined(USE_SHA1) && !defined(USE_SHA256) #error define USE_SHA1 or USE_SHA256 to set the HMAC hash algorithm #endif #ifdef USE_SHA1 #include "sha1.h" #define HASH_INPUT_SIZE SHA1_BLOCK_SIZE #define HASH_OUTPUT_SIZE SHA1_DIGEST_SIZE #define sha_ctx sha1_ctx #define sha_begin sha1_begin #define sha_hash sha1_hash #define sha_end sha1_end #endif #ifdef USE_SHA256 #include "sha2.h" #define HASH_INPUT_SIZE SHA256_BLOCK_SIZE #define HASH_OUTPUT_SIZE SHA256_DIGEST_SIZE #define sha_ctx sha256_ctx #define sha_begin sha256_begin #define sha_hash sha256_hash #define sha_end sha256_end #endif #define HMAC_OK 0 #define HMAC_BAD_MODE -1 #define HMAC_IN_DATA 0xffffffff typedef struct { unsigned char key[HASH_INPUT_SIZE]; sha_ctx ctx[1]; unsigned long klen; } hmac_ctx; void hmac_sha_begin(hmac_ctx cx[1]); int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]); void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]); void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]); void hmac_sha(const unsigned char key[], unsigned long key_len, const unsigned char data[], unsigned long data_len, unsigned char mac[], unsigned long mac_len); #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/prng.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 24/01/2003 This file implements a random data pool based on the use of an external entropy function. It is based on the ideas advocated by Peter Gutmann in his work on pseudo random sequence generators. It is not a 'paranoid' random sequence generator and no attempt is made to protect the pool from prying eyes either by memory locking or by techniques to obscure its location in memory. */ #include #include "prng.h" #if defined(__cplusplus) extern "C" { #endif /* mix a random data pool using the SHA1 compression function (as */ /* suggested by Peter Gutmann in his paper on random pools) */ static void prng_mix(unsigned char buf[]) { unsigned int i, len; sha1_ctx ctx[1]; /*lint -e{663} unusual array to pointer conversion */ for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE) { /* copy digest size pool block into SHA1 hash block */ memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE) - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE); /* copy data from pool into the SHA1 data buffer */ len = PRNG_POOL_SIZE - i; memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len)); if(len < SHA1_BLOCK_SIZE) memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len); /* compress using the SHA1 compression function */ sha1_compile(ctx); /* put digest size block back into the random pool */ memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE); } } /* refresh the output buffer and update the random pool by adding */ /* entropy and remixing */ static void update_pool(prng_ctx ctx[1]) { unsigned int i = 0; /* transfer random pool data to the output buffer */ memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE); /* enter entropy data into the pool */ while(i < PRNG_POOL_SIZE) i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i); /* invert and xor the original pool data into the pool */ for(i = 0; i < PRNG_POOL_SIZE; ++i) ctx->rbuf[i] ^= ~ctx->obuf[i]; /* mix the pool and the output buffer */ prng_mix(ctx->rbuf); prng_mix(ctx->obuf); } void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]) { int i; /* clear the buffers and the counter in the context */ memset(ctx, 0, sizeof(prng_ctx)); /* set the pointer to the entropy collection function */ ctx->entropy = fun; /* initialise the random data pool */ update_pool(ctx); /* mix the pool a minimum number of times */ for(i = 0; i < PRNG_MIN_MIX; ++i) prng_mix(ctx->rbuf); /* update the pool to prime the pool output buffer */ update_pool(ctx); } /* provide random bytes from the random data pool */ void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]) { unsigned char *rp = data; unsigned int len, pos = ctx->pos; while(data_len) { /* transfer 'data_len' bytes (or the number of bytes remaining */ /* the pool output buffer if less) into the output */ len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos); memcpy(rp, ctx->obuf + pos, len); rp += len; /* update ouput buffer position pointer */ pos += len; /* update pool output buffer pointer */ data_len -= len; /* update the remaining data count */ /* refresh the random pool if necessary */ if(pos == PRNG_POOL_SIZE) { update_pool(ctx); pos = 0; } } ctx->pos = pos; } void prng_end(prng_ctx ctx[1]) { /* ensure the data in the context is destroyed */ memset(ctx, 0, sizeof(prng_ctx)); } #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/prng.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 24/01/2003 This is the header file for an implementation of a random data pool based on the use of an external entropy function (inspired by Peter Gutmann's work). */ #ifndef _PRNG_H #define _PRNG_H #include "sha1.h" #define PRNG_POOL_LEN 256 /* minimum random pool size */ #define PRNG_MIN_MIX 20 /* min initial pool mixing iterations */ /* ensure that pool length is a multiple of the SHA1 digest size */ #define PRNG_POOL_SIZE (SHA1_DIGEST_SIZE * (1 + (PRNG_POOL_LEN - 1) / SHA1_DIGEST_SIZE)) #if defined(__cplusplus) extern "C" { #endif /* A function for providing entropy is a parameter in the prng_init() */ /* call. This function has the following form and returns a maximum */ /* of 'len' bytes of pseudo random data in the buffer 'buf'. It can */ /* return less than 'len' bytes but will be repeatedly called for more */ /* data in this case. */ typedef int (*prng_entropy_fn)(unsigned char buf[], unsigned int len); typedef struct { unsigned char rbuf[PRNG_POOL_SIZE]; /* the random pool */ unsigned char obuf[PRNG_POOL_SIZE]; /* pool output buffer */ unsigned int pos; /* output buffer position */ prng_entropy_fn entropy; /* entropy function pointer */ } prng_ctx; /* initialise the random stream generator */ void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]); /* obtain random bytes from the generator */ void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]); /* close the random stream generator */ void prng_end(prng_ctx ctx[1]); #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/pwd2key.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 26/08/2003 This is an implementation of RFC2898, which specifies key derivation from a password and a salt value. */ #include #include "hmac.h" #if defined(__cplusplus) extern "C" { #endif void derive_key(const unsigned char pwd[], /* the PASSWORD */ unsigned int pwd_len, /* and its length */ const unsigned char salt[], /* the SALT and its */ unsigned int salt_len, /* length */ unsigned int iter, /* the number of iterations */ unsigned char key[], /* space for the output key */ unsigned int key_len)/* and its required length */ { unsigned int i, j, k, n_blk; unsigned char uu[HASH_OUTPUT_SIZE], ux[HASH_OUTPUT_SIZE]; hmac_ctx c1[1], c2[1], c3[1]; /* set HMAC context (c1) for password */ hmac_sha_begin(c1); hmac_sha_key(pwd, pwd_len, c1); /* set HMAC context (c2) for password and salt */ memcpy(c2, c1, sizeof(hmac_ctx)); hmac_sha_data(salt, salt_len, c2); /* find the number of SHA blocks in the key */ n_blk = 1 + (key_len - 1) / HASH_OUTPUT_SIZE; for(i = 0; i < n_blk; ++i) /* for each block in key */ { /* ux[] holds the running xor value */ memset(ux, 0, HASH_OUTPUT_SIZE); /* set HMAC context (c3) for password and salt */ memcpy(c3, c2, sizeof(hmac_ctx)); /* enter additional data for 1st block into uu */ uu[0] = (unsigned char)((i + 1) >> 24); uu[1] = (unsigned char)((i + 1) >> 16); uu[2] = (unsigned char)((i + 1) >> 8); uu[3] = (unsigned char)(i + 1); /* this is the key mixing iteration */ for(j = 0, k = 4; j < iter; ++j) { /* add previous round data to HMAC */ hmac_sha_data(uu, k, c3); /* obtain HMAC for uu[] */ hmac_sha_end(uu, HASH_OUTPUT_SIZE, c3); /* xor into the running xor block */ for(k = 0; k < HASH_OUTPUT_SIZE; ++k) ux[k] ^= uu[k]; /* set HMAC context (c3) for password */ memcpy(c3, c1, sizeof(hmac_ctx)); } /* compile key blocks into the key output */ j = 0; k = i * HASH_OUTPUT_SIZE; while(j < HASH_OUTPUT_SIZE && k < key_len) key[k++] = ux[j++]; } } #ifdef TEST #include struct { unsigned int pwd_len; unsigned int salt_len; unsigned int it_count; unsigned char *pwd; unsigned char salt[32]; unsigned char key[32]; } tests[] = { { 8, 4, 5, (unsigned char*)"password", { 0x12, 0x34, 0x56, 0x78 }, { 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7, 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5 } }, { 8, 8, 5, (unsigned char*)"password", { 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 }, { 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49 } }, { 8, 21, 1, (unsigned char*)"password", { "ATHENA.MIT.EDUraeburn" }, { 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15 } }, { 8, 21, 2, (unsigned char*)"password", { "ATHENA.MIT.EDUraeburn" }, { 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d } }, { 8, 21, 1200, (unsigned char*)"password", { "ATHENA.MIT.EDUraeburn" }, { 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b } } }; int main() { unsigned int i, j, key_len = 256; unsigned char key[256]; printf("\nTest of RFC2898 Password Based Key Derivation"); for(i = 0; i < 5; ++i) { derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt, tests[i].salt_len, tests[i].it_count, key, key_len); printf("\ntest %i: ", i + 1); printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good"); for(j = 0; j < key_len && j < 64; j += 4) { if(j % 16 == 0) printf("\n"); printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]); } printf(j < key_len ? " ... \n" : "\n"); } printf("\n"); return 0; } #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/pwd2key.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 26/08/2003 This is an implementation of RFC2898, which specifies key derivation from a password and a salt value. */ #ifndef PWD2KEY_H #define PWD2KEY_H #if defined(__cplusplus) extern "C" { #endif void derive_key( const unsigned char pwd[], /* the PASSWORD, and */ unsigned int pwd_len, /* its length */ const unsigned char salt[], /* the SALT and its */ unsigned int salt_len, /* length */ unsigned int iter, /* the number of iterations */ unsigned char key[], /* space for the output key */ unsigned int key_len); /* and its required length */ #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/sha1.c ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 01/08/2005 This is a byte oriented version of SHA1 that operates on arrays of bytes stored in memory. */ #include /* for memcpy() etc. */ #include "sha1.h" #include "brg_endian.h" #if defined(__cplusplus) extern "C" { #endif #if defined( _MSC_VER ) && ( _MSC_VER > 800 ) #pragma intrinsic(memcpy) #endif #if 0 && defined(_MSC_VER) #define rotl32 _lrotl #define rotr32 _lrotr #else #define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) #define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) #endif #if !defined(bswap_32) #define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) #endif #if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) #define SWAP_BYTES #else #undef SWAP_BYTES #endif #if defined(SWAP_BYTES) #define bsw_32(p,n) \ { int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); } #else #define bsw_32(p,n) #endif #define SHA1_MASK (SHA1_BLOCK_SIZE - 1) #if 0 #define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define parity(x,y,z) ((x) ^ (y) ^ (z)) #define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #else /* Discovered by Rich Schroeppel and Colin Plumb */ #define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define parity(x,y,z) ((x) ^ (y) ^ (z)) #define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) #endif /* Compile 64 bytes of hash data into SHA1 context. Note */ /* that this routine assumes that the byte order in the */ /* ctx->wbuf[] at this point is in such an order that low */ /* address bytes in the ORIGINAL byte stream will go in */ /* this buffer to the high end of 32-bit words on BOTH big */ /* and little endian systems */ #ifdef ARRAY #define q(v,n) v[n] #else #define q(v,n) v##n #endif #define one_cycle(v,a,b,c,d,e,f,k,h) \ q(v,e) += rotr32(q(v,a),27) + \ f(q(v,b),q(v,c),q(v,d)) + k + h; \ q(v,b) = rotr32(q(v,b), 2) #define five_cycle(v,f,k,i) \ one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \ one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \ one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \ one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \ one_cycle(v, 1,2,3,4,0, f,k,hf(i+4)) VOID_RETURN sha1_compile(sha1_ctx ctx[1]) { uint_32t *w = ctx->wbuf; #ifdef ARRAY uint_32t v[5]; memcpy(v, ctx->hash, 5 * sizeof(uint_32t)); #else uint_32t v0, v1, v2, v3, v4; v0 = ctx->hash[0]; v1 = ctx->hash[1]; v2 = ctx->hash[2]; v3 = ctx->hash[3]; v4 = ctx->hash[4]; #endif #define hf(i) w[i] five_cycle(v, ch, 0x5a827999, 0); five_cycle(v, ch, 0x5a827999, 5); five_cycle(v, ch, 0x5a827999, 10); one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \ #undef hf #define hf(i) (w[(i) & 15] = rotl32( \ w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \ ^ w[((i) + 2) & 15] ^ w[(i) & 15], 1)) one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16)); one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17)); one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18)); one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19)); five_cycle(v, parity, 0x6ed9eba1, 20); five_cycle(v, parity, 0x6ed9eba1, 25); five_cycle(v, parity, 0x6ed9eba1, 30); five_cycle(v, parity, 0x6ed9eba1, 35); five_cycle(v, maj, 0x8f1bbcdc, 40); five_cycle(v, maj, 0x8f1bbcdc, 45); five_cycle(v, maj, 0x8f1bbcdc, 50); five_cycle(v, maj, 0x8f1bbcdc, 55); five_cycle(v, parity, 0xca62c1d6, 60); five_cycle(v, parity, 0xca62c1d6, 65); five_cycle(v, parity, 0xca62c1d6, 70); five_cycle(v, parity, 0xca62c1d6, 75); #ifdef ARRAY ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; ctx->hash[4] += v[4]; #else ctx->hash[0] += v0; ctx->hash[1] += v1; ctx->hash[2] += v2; ctx->hash[3] += v3; ctx->hash[4] += v4; #endif } VOID_RETURN sha1_begin(sha1_ctx ctx[1]) { ctx->count[0] = ctx->count[1] = 0; ctx->hash[0] = 0x67452301; ctx->hash[1] = 0xefcdab89; ctx->hash[2] = 0x98badcfe; ctx->hash[3] = 0x10325476; ctx->hash[4] = 0xc3d2e1f0; } /* SHA1 hash data in an array of bytes into hash buffer and */ /* call the hash_compile function as required. */ VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]) { uint_32t pos = (uint_32t)(ctx->count[0] & SHA1_MASK), space = SHA1_BLOCK_SIZE - pos; const unsigned char *sp = data; if((ctx->count[0] += len) < len) ++(ctx->count[1]); while(len >= space) /* tranfer whole blocks if possible */ { memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0; bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2); sha1_compile(ctx); } memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); } /* SHA1 final padding and digest calculation */ VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]) { uint_32t i = (uint_32t)(ctx->count[0] & SHA1_MASK); /* put bytes in the buffer in an order in which references to */ /* 32-bit words will put bytes with lower addresses into the */ /* top of 32 bit words on BOTH big and little endian machines */ bsw_32(ctx->wbuf, (i + 3) >> 2); /* we now need to mask valid bytes and add the padding which is */ /* a single 1 bit and as many zero bits as necessary. Note that */ /* we can always add the first padding byte here because the */ /* buffer always has at least one empty slot */ ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3); ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3); /* we need 9 or more empty positions, one for the padding byte */ /* (above) and eight for the length count. If there is not */ /* enough space, pad and empty the buffer */ if(i > SHA1_BLOCK_SIZE - 9) { if(i < 60) ctx->wbuf[15] = 0; sha1_compile(ctx); i = 0; } else /* compute a word index for the empty buffer positions */ i = (i >> 2) + 1; while(i < 14) /* and zero pad all but last two positions */ ctx->wbuf[i++] = 0; /* the following 32-bit length fields are assembled in the */ /* wrong byte order on little endian machines but this is */ /* corrected later since they are only ever used as 32-bit */ /* word values. */ ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); ctx->wbuf[15] = ctx->count[0] << 3; sha1_compile(ctx); /* extract the hash value as bytes in case the hash buffer is */ /* misaligned for 32-bit words */ for(i = 0; i < SHA1_DIGEST_SIZE; ++i) hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); } VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len) { sha1_ctx cx[1]; sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx); } #if defined(__cplusplus) } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/aes/sha1.h ================================================ /* --------------------------------------------------------------------------- Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. LICENSE TERMS The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that: 1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer; 2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials; 3. the copyright holder's name is not used to endorse products built using this software without specific written permission. ALTERNATIVELY, provided that this notice is retained in full, this product may be distributed under the terms of the GNU General Public License (GPL), in which case the provisions of the GPL apply INSTEAD OF those given above. DISCLAIMER This software is provided 'as is' with no explicit or implied warranties in respect of its properties, including, but not limited to, correctness and/or fitness for purpose. --------------------------------------------------------------------------- Issue Date: 01/08/2005 */ #ifndef _SHA1_H #define _SHA1_H #include #include "brg_types.h" #define SHA1_BLOCK_SIZE 64 #define SHA1_DIGEST_SIZE 20 #if defined(__cplusplus) extern "C" { #endif /* type to hold the SHA256 context */ typedef struct { uint_32t count[2]; uint_32t hash[5]; uint_32t wbuf[16]; } sha1_ctx; /* Note that these prototypes are the same for both bit and */ /* byte oriented implementations. However the length fields */ /* are in bytes or bits as appropriate for the version used */ /* and bit sequences are input as arrays of bytes in which */ /* bit sequences run from the most to the least significant */ /* end of each byte */ VOID_RETURN sha1_compile(sha1_ctx ctx[1]); VOID_RETURN sha1_begin(sha1_ctx ctx[1]); VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]); VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]); VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len); #if defined(__cplusplus) } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/crypt.h ================================================ /* crypt.h -- base code for traditional PKWARE encryption Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Modifications for Info-ZIP crypting Copyright (C) 2003 Terry Thorsen This code is a modified version of crypting code in Info-ZIP distribution Copyright (C) 1990-2000 Info-ZIP. All rights reserved. See the Info-ZIP LICENSE file version 2000-Apr-09 or later for terms of use which also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != 0) { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, const unsigned long* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/ioapi.c ================================================ /* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson http://result42.com This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #include #include #include "ioapi.h" #if defined(_WIN32) # define snprintf _snprintf #endif #ifdef __APPLE__ /* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */ # define FOPEN_FUNC(filename, mode) fopen(filename, mode) # define FTELLO_FUNC(stream) ftello(stream) # define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else # define FOPEN_FUNC(filename, mode) fopen64(filename, mode) # define FTELLO_FUNC(stream) ftello64(stream) # define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) #endif /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR # define SEEK_CUR 1 #endif #ifndef SEEK_END # define SEEK_END 2 #endif #ifndef SEEK_SET # define SEEK_SET 0 #endif voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); } voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)) { if (pfilefunc->zfile_func64.zopendisk64_file != NULL) return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); } long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { uLong offsetTruncated; if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) { uLong tell_uLong; if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == 0xffffffff) return (ZPOS64_T)-1; return tell_uLong; } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zfile_func64.zopendisk64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); typedef struct { FILE *file; int filenameLength; void *filename; } FILE_IOPOSIX; static voidpf file_build_ioposix(FILE *file, const char *filename) { FILE_IOPOSIX *ioposix = NULL; if (file == NULL) return NULL; ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX)); ioposix->file = file; ioposix->filenameLength = (int)strlen(filename) + 1; ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char)); strncpy(ioposix->filename, filename, ioposix->filenameLength); return (voidpf)ioposix; } static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename != NULL) && (mode_fopen != NULL)) { file = fopen(filename, mode_fopen); return file_build_ioposix(file, filename); } return file; } static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename != NULL) && (mode_fopen != NULL)) { file = FOPEN_FUNC((const char*)filename, mode_fopen); return file_build_ioposix(file, (const char*)filename); } return file; } static voidpf ZCALLBACK fopendisk64_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) { FILE_IOPOSIX *ioposix = NULL; char *diskFilename = NULL; voidpf ret = NULL; int i = 0; if (stream == NULL) return NULL; ioposix = (FILE_IOPOSIX*)stream; diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) { if (diskFilename[i] != '.') continue; snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); break; } if (i >= 0) ret = fopen64_file_func(opaque, diskFilename, mode); free(diskFilename); return ret; } static voidpf ZCALLBACK fopendisk_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) { FILE_IOPOSIX *ioposix = NULL; char *diskFilename = NULL; voidpf ret = NULL; int i = 0; if (stream == NULL) return NULL; ioposix = (FILE_IOPOSIX*)stream; diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) { if (diskFilename[i] != '.') continue; snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); break; } if (i >= 0) ret = fopen_file_func(opaque, diskFilename, mode); free(diskFilename); return ret; } static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) { FILE_IOPOSIX *ioposix = NULL; uLong ret; if (stream == NULL) return -1; ioposix = (FILE_IOPOSIX*)stream; ret = (uLong)fread(buf, 1, (size_t)size, ioposix->file); return ret; } static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) { FILE_IOPOSIX *ioposix = NULL; uLong ret; if (stream == NULL) return -1; ioposix = (FILE_IOPOSIX*)stream; ret = (uLong)fwrite(buf, 1, (size_t)size, ioposix->file); return ret; } static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) { FILE_IOPOSIX *ioposix = NULL; long ret = -1; if (stream == NULL) return ret; ioposix = (FILE_IOPOSIX*)stream; ret = ftell(ioposix->file); return ret; } static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) { FILE_IOPOSIX *ioposix = NULL; ZPOS64_T ret = -1; if (stream == NULL) return ret; ioposix = (FILE_IOPOSIX*)stream; ret = FTELLO_FUNC(ioposix->file); return ret; } static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) { FILE_IOPOSIX *ioposix = NULL; int fseek_origin = 0; long ret = 0; if (stream == NULL) return -1; ioposix = (FILE_IOPOSIX*)stream; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END: fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET: fseek_origin = SEEK_SET; break; default: return -1; } if (fseek(ioposix->file, offset, fseek_origin) != 0) ret = -1; return ret; } static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { FILE_IOPOSIX *ioposix = NULL; int fseek_origin = 0; long ret = 0; if (stream == NULL) return -1; ioposix = (FILE_IOPOSIX*)stream; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END: fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET: fseek_origin = SEEK_SET; break; default: return -1; } if(FSEEKO_FUNC(ioposix->file, offset, fseek_origin) != 0) ret = -1; return ret; } static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) { FILE_IOPOSIX *ioposix = NULL; int ret = -1; if (stream == NULL) return ret; ioposix = (FILE_IOPOSIX*)stream; if (ioposix->filename != NULL) free(ioposix->filename); ret = fclose(ioposix->file); free(ioposix); return ret; } static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) { FILE_IOPOSIX *ioposix = NULL; int ret = -1; if (stream == NULL) return ret; ioposix = (FILE_IOPOSIX*)stream; ret = ferror(ioposix->file); return ret; } void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zopendisk_file = fopendisk_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell64_file = ftell64_file_func; pzlib_filefunc_def->zseek64_file = fseek64_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/ioapi.h ================================================ /* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson http://result42.com This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) # ifndef __USE_FILE_OFFSET64 # define __USE_FILE_OFFSET64 # endif # ifndef __USE_LARGEFILE64 # define __USE_LARGEFILE64 # endif # ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE # endif # ifndef _FILE_OFFSET_BIT # define _FILE_OFFSET_BIT 64 # endif #endif #include #include #include "zlib.h" #if defined(USE_FILE32API) # define fopen64 fopen # define ftello64 ftell # define fseeko64 fseek #else # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) # define fopen64 fopen # define ftello64 ftello # define fseeko64 fseeko # endif # ifdef _MSC_VER # define fopen64 fopen # if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) # define ftello64 _ftelli64 # define fseeko64 _fseeki64 # else /* old MSC */ # define ftello64 ftell # define fseeko64 fseek # endif # endif #endif /* a type choosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else # ifdef HAS_STDINT_H # include "stdint.h" typedef uint64_t ZPOS64_T; # else # if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; # else typedef unsigned long long int ZPOS64_T; # endif # endif #endif #ifdef __cplusplus extern "C" { #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK # if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \ defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) # define ZCALLBACK CALLBACK # else # define ZCALLBACK # endif #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef voidpf (ZCALLBACK *opendisk_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); /* here is the "old" 32 bits structure structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; opendisk_file_func zopendisk_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); typedef voidpf (ZCALLBACK *opendisk64_file_func)OF((voidpf opaque, voidpf stream, int number_disk, int mode)); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; opendisk64_file_func zopendisk64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; opendisk_file_func zopendisk32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) /*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/ /*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/ #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)); long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); void fill_zlib_filefunc64_32_def_from_filefunc32 OF((zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/mztools.c ================================================ /* Additional tools for Minizip Code: Xavier Roche '2004 License: Same as ZLIB (www.gzip.org) */ /* Code */ #include #include #include #include "zlib.h" #include "unzip.h" #include "mztools.h" #define READ_8(adr) ((unsigned char)*(adr)) #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) #define WRITE_8(buff, n) do { \ *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ } while(0) #define WRITE_16(buff, n) do { \ WRITE_8((unsigned char*)(buff), n); \ WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ } while(0) #define WRITE_32(buff, n) do { \ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ } while(0) extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) const char* file; const char* fileOut; const char* fileOutTmp; uLong* nRecovered; uLong* bytesRecovered; { int err = Z_OK; FILE* fpZip = fopen(file, "rb"); FILE* fpOut = fopen(fileOut, "wb"); FILE* fpOutCD = fopen(fileOutTmp, "wb"); if (fpZip != NULL && fpOut != NULL) { int entries = 0; uLong totalBytes = 0; char header[30]; char filename[256]; char extra[1024]; int offset = 0; int offsetCD = 0; while ( fread(header, 1, 30, fpZip) == 30 ) { int currentOffset = offset; /* File entry */ if (READ_32(header) == 0x04034b50) { unsigned int version = READ_16(header + 4); unsigned int gpflag = READ_16(header + 6); unsigned int method = READ_16(header + 8); unsigned int filetime = READ_16(header + 10); unsigned int filedate = READ_16(header + 12); unsigned int crc = READ_32(header + 14); /* crc */ unsigned int cpsize = READ_32(header + 18); /* compressed size */ unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ unsigned int fnsize = READ_16(header + 26); /* file name length */ unsigned int extsize = READ_16(header + 28); /* extra field length */ filename[0] = extra[0] = '\0'; /* Header */ if (fwrite(header, 1, 30, fpOut) == 30) { offset += 30; } else { err = Z_ERRNO; break; } /* Filename */ if (fnsize > 0) { if (fread(filename, 1, fnsize, fpZip) == fnsize) { if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { offset += fnsize; } else { err = Z_ERRNO; break; } } else { err = Z_ERRNO; break; } } else { err = Z_STREAM_ERROR; break; } /* Extra field */ if (extsize > 0) { if (fread(extra, 1, extsize, fpZip) == extsize) { if (fwrite(extra, 1, extsize, fpOut) == extsize) { offset += extsize; } else { err = Z_ERRNO; break; } } else { err = Z_ERRNO; break; } } /* Data */ { int dataSize = cpsize; if (dataSize == 0) { dataSize = uncpsize; } if (dataSize > 0) { char* data = malloc(dataSize); if (data != NULL) { if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { offset += dataSize; totalBytes += dataSize; } else { err = Z_ERRNO; } } else { err = Z_ERRNO; } free(data); if (err != Z_OK) { break; } } else { err = Z_MEM_ERROR; break; } } } /* Central directory entry */ { char centralDirectoryEntryHeader[46]; //char* comment = ""; //int comsize = (int) strlen(comment); WRITE_32(centralDirectoryEntryHeader, 0x02014b50); WRITE_16(centralDirectoryEntryHeader + 4, version); WRITE_16(centralDirectoryEntryHeader + 6, version); WRITE_16(centralDirectoryEntryHeader + 8, gpflag); WRITE_16(centralDirectoryEntryHeader + 10, method); WRITE_16(centralDirectoryEntryHeader + 12, filetime); WRITE_16(centralDirectoryEntryHeader + 14, filedate); WRITE_32(centralDirectoryEntryHeader + 16, crc); WRITE_32(centralDirectoryEntryHeader + 20, cpsize); WRITE_32(centralDirectoryEntryHeader + 24, uncpsize); WRITE_16(centralDirectoryEntryHeader + 28, fnsize); WRITE_16(centralDirectoryEntryHeader + 30, extsize); WRITE_16(centralDirectoryEntryHeader + 32, 0 /*comsize*/); WRITE_16(centralDirectoryEntryHeader + 34, 0); /* disk # */ WRITE_16(centralDirectoryEntryHeader + 36, 0); /* int attrb */ WRITE_32(centralDirectoryEntryHeader + 38, 0); /* ext attrb */ WRITE_32(centralDirectoryEntryHeader + 42, currentOffset); /* Header */ if (fwrite(centralDirectoryEntryHeader, 1, 46, fpOutCD) == 46) { offsetCD += 46; /* Filename */ if (fnsize > 0) { if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { offsetCD += fnsize; } else { err = Z_ERRNO; break; } } else { err = Z_STREAM_ERROR; break; } /* Extra field */ if (extsize > 0) { if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { offsetCD += extsize; } else { err = Z_ERRNO; break; } } /* Comment field */ /* if (comsize > 0) { if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { offsetCD += comsize; } else { err = Z_ERRNO; break; } } */ } else { err = Z_ERRNO; break; } } /* Success */ entries++; } else { break; } } /* Final central directory */ { int entriesZip = entries; char finalCentralDirectoryHeader[22]; //char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; //int comsize = (int) strlen(comment); if (entriesZip > 0xffff) { entriesZip = 0xffff; } WRITE_32(finalCentralDirectoryHeader, 0x06054b50); WRITE_16(finalCentralDirectoryHeader + 4, 0); /* disk # */ WRITE_16(finalCentralDirectoryHeader + 6, 0); /* disk # */ WRITE_16(finalCentralDirectoryHeader + 8, entriesZip); /* hack */ WRITE_16(finalCentralDirectoryHeader + 10, entriesZip); /* hack */ WRITE_32(finalCentralDirectoryHeader + 12, offsetCD); /* size of CD */ WRITE_32(finalCentralDirectoryHeader + 16, offset); /* offset to CD */ WRITE_16(finalCentralDirectoryHeader + 20, 0 /*comsize*/); /* comment */ /* Header */ if (fwrite(finalCentralDirectoryHeader, 1, 22, fpOutCD) == 22) { /* Comment field */ /* if (comsize > 0) { if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { err = Z_ERRNO; } } */ } else { err = Z_ERRNO; } } /* Final merge (file + central directory) */ fclose(fpOutCD); if (err == Z_OK) { fpOutCD = fopen(fileOutTmp, "rb"); if (fpOutCD != NULL) { int nRead; char buffer[8192]; while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { err = Z_ERRNO; break; } } fclose(fpOutCD); } } /* Close */ fclose(fpZip); fclose(fpOut); /* Wipe temporary file */ (void)remove(fileOutTmp); /* Number of recovered entries */ if (err == Z_OK) { if (nRecovered != NULL) { *nRecovered = entries; } if (bytesRecovered != NULL) { *bytesRecovered = totalBytes; } } } else { err = Z_STREAM_ERROR; } return err; } ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/mztools.h ================================================ /* Additional tools for Minizip Code: Xavier Roche '2004 License: Same as ZLIB (www.gzip.org) */ #ifndef _zip_tools_H #define _zip_tools_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #include "unzip.h" /* Repair a ZIP file (missing central directory) file: file to recover fileOut: output file after recovery fileOutTmp: temporary file name used for recovery */ extern int ZEXPORT unzRepair(const char* file, const char* fileOut, const char* fileOutTmp, uLong* nRecovered, uLong* bytesRecovered); #endif ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/unzip.c ================================================ /* unzip.c -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson http://result42.com Modifications for AES, PKWARE disk spanning Copyright (C) 2010-2014 Nathan Moinvaziri This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #include #include #include /*#ifndef NOUNCRYPT # define NOUNCRYPT #endif*/ #include "zlib.h" #include "unzip.h" #include "Common.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifdef HAVE_AES # define AES_METHOD (99) # define AES_PWVERIFYSIZE (2) # define AES_MAXSALTLENGTH (16) # define AES_AUTHCODESIZE (10) # define AES_HEADERSIZE (11) # define AES_KEYSIZE(mode) (64 + (mode * 64)) # include "aes.h" # include "fileenc.h" #endif #ifndef NOUNCRYPT # include "crypt.h" #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #define DISKHEADERMAGIC (0x08074b50) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define ZIP64ENDHEADERMAGIC (0x06064b50) #define ZIP64ENDLOCHEADERMAGIC (0x07064b50) #define SIZECENTRALDIRITEM (0x2e) #define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ #define SIZEZIPLOCALHEADER (0x1e) #ifndef BUFREADCOMMENT # define BUFREADCOMMENT (0x400) #endif #ifndef UNZ_BUFSIZE # define UNZ_BUFSIZE (64 * 1024) #endif #ifndef UNZ_MAXFILENAMEINZIP # define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p); } #endif const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile; /* relative offset of local header 8 bytes */ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ #ifdef HAVE_AES uLong aes_encryption_mode; uLong aes_compression_method; uLong aes_version; #endif } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile */ typedef struct { Bytef *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif #ifdef HAVE_AES fcrypt_ctx aes_ctx; #endif ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek */ uLong stream_initialised; /* flag set if stream structure is initialised */ ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read */ ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed; /* number of byte to be obtained after decomp */ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structure of the current zipfile */ voidpf filestream_with_CD; /* io structure of the disk with the central directory */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ uLong number_disk; /* number of the current disk, used for spanning ZIP*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info64 cur_file_info; /* public info about the current file in zip*/ unz_file_info64_internal cur_file_info_internal; /* private info about it*/ file_in_zip64_read_info_s *pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int isZip64; /* is the current file zip64 */ #ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long *pcrc_32_tab; #endif } unz64_s; /* Translate date/time from Dos format to tm_unz (readable more easily) */ local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz *ptm) { ZPOS64_T uDate = (ZPOS64_T)(ulDosDate >> 16); ptm->tm_mday = (uInt)(uDate & 0x1f); ptm->tm_mon = (uInt)((((uDate) & 0x1E0) / 0x20) - 1); ptm->tm_year = (uInt)(((uDate & 0x0FE00) / 0x0200) + 1980); ptm->tm_hour = (uInt)((ulDosDate & 0xF800) / 0x800); ptm->tm_min = (uInt)((ulDosDate & 0x7E0) / 0x20); ptm->tm_sec = (uInt)(2 * (ulDosDate & 0x1f)); #define unz64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) if (!unz64local_in_range(0, 11, ptm->tm_mon) || !unz64local_in_range(1, 31, ptm->tm_mday) || !unz64local_in_range(0, 23, ptm->tm_hour) || !unz64local_in_range(0, 59, ptm->tm_min) || !unz64local_in_range(0, 59, ptm->tm_sec)) /* Invalid date stored, so don't return it. */ memset(ptm, 0, sizeof(tm_unz)); #undef unz64local_in_range } /* Read a byte from a gz_stream; Return EOF for end of file. */ local int unz64local_getByte(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); if (err == 1) { *pi = (int)c; return UNZ_OK; } if (ZERROR64(*pzlib_filefunc_def, filestream)) return UNZ_ERRNO; return UNZ_EOF; } local int unz64local_getShort OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, uLong * pX)); local int unz64local_getShort(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x = (uLong)i; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((uLong)i) << 8; if (err == UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, uLong * pX)); local int unz64local_getLong(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x = (uLong)i; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((uLong)i) << 8; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((uLong)i) << 16; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((uLong)i) << 24; if (err == UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong64 OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, ZPOS64_T * pX)); local int unz64local_getLong64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x = (ZPOS64_T)i; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 8; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 16; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 24; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 32; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 40; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 48; if (err == UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); x |= ((ZPOS64_T)i) << 56; if (err == UNZ_OK) *pX = x; else *pX = 0; return err; } /* Locate the Central directory of a zip file (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream) { unsigned char *buf; ZPOS64_T file_size; ZPOS64_T back_read = 4; ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ ZPOS64_T pos_found = 0; uLong read_size; ZPOS64_T read_pos; int i; buf = (unsigned char *)ALLOC(BUFREADCOMMENT + 4); if (buf == NULL) return 0; if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) { TRYFREE(buf); return 0; } file_size = ZTELL64(*pzlib_filefunc_def, filestream); if (max_back > file_size) max_back = file_size; while (back_read < max_back) { if (back_read + BUFREADCOMMENT > max_back) back_read = max_back; else back_read += BUFREADCOMMENT; read_pos = file_size - back_read; read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) break; if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) break; for (i = (int)read_size - 3; (i--) > 0; ) if (((*(buf + i)) == (ENDHEADERMAGIC & 0xff)) && ((*(buf + i + 1)) == (ENDHEADERMAGIC >> 8 & 0xff)) && ((*(buf + i + 2)) == (ENDHEADERMAGIC >> 16 & 0xff)) && ((*(buf + i + 3)) == (ENDHEADERMAGIC >> 24 & 0xff))) { pos_found = read_pos + i; break; } if (pos_found != 0) break; } TRYFREE(buf); return pos_found; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset)); local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset) { ZPOS64_T offset; uLong uL; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) return 0; /* read locator signature */ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) return 0; if (uL != ZIP64ENDLOCHEADERMAGIC) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) return 0; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK) return 0; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) return 0; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) return 0; if (uL != ZIP64ENDHEADERMAGIC) return 0; return offset; } local unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; voidpf filestream = NULL; ZPOS64_T number_entry_CD; int err = UNZ_OK; if (unz_copyright[0] != ' ') return NULL; us.filestream = NULL; us.filestream_with_CD = NULL; us.z_filefunc.zseek32_file = NULL; us.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def == NULL) fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); else us.z_filefunc = *pzlib_filefunc64_32_def; us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream == NULL) return NULL; us.filestream_with_CD = us.filestream; us.isZip64 = 0; /* Use unz64local_SearchCentralDir first. Only based on the result is it necessary to locate the unz64local_SearchCentralDir64 */ central_pos = unz64local_SearchCentralDir(&us.z_filefunc, us.filestream); if (central_pos) { if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err = UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; /* number of this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; us.number_disk = uL; /* number of the disk with the start of the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; us.gi.number_disk_with_CD = uL; /* total number of entries in the central directory on this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; us.gi.number_entry = uL; /* total number of entries in the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; number_entry_CD = uL; if (number_entry_CD != us.gi.number_entry) err = UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; us.size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; us.offset_central_dir = uL; /* zipfile comment length */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK) err = UNZ_ERRNO; if ((err == UNZ_OK) && ((us.gi.number_entry == 0xffff) || (us.size_central_dir == 0xffff) || (us.offset_central_dir == 0xffffffff))) { /* Format should be Zip64, as the central directory or file size is too large */ central_pos = unz64local_SearchCentralDir64(&us.z_filefunc, us.filestream, central_pos); if (central_pos) { ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err = UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; /* size of zip64 end of central directory record */ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &uL64) != UNZ_OK) err = UNZ_ERRNO; /* version made by */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; /* version needed to extract */ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; /* number of this disk */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK) err = UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK) err = UNZ_ERRNO; /* total number of entries in the central directory on this disk */ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK) err = UNZ_ERRNO; /* total number of entries in the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK) err = UNZ_ERRNO; if (number_entry_CD != us.gi.number_entry) err = UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK) err = UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK) err = UNZ_ERRNO; } else err = UNZ_BADZIPFILE; } } else err = UNZ_ERRNO; if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir)) err = UNZ_BADZIPFILE; if (err != UNZ_OK) { ZCLOSE64(us.z_filefunc, us.filestream); return NULL; } if (us.gi.number_disk_with_CD == 0) { /* If there is only one disk open another stream so we don't have to seek between the CD and the file headers constantly */ filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (filestream != NULL) us.filestream = filestream; } /* Hack for zip files that have no respect for zip64 if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff)) us.offset_central_dir = central_pos - us.size_central_dir;*/ us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir); us.central_pos = central_pos; us.pfile_in_zip_read = NULL; s = (unz64_s *)ALLOC(sizeof(unz64_s)); if (s != NULL) { *s = us; unzGoToFirstFile((unzFile)s); } return (unzFile)s; } extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); } return unzOpenInternal(path, NULL); } extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); } return unzOpenInternal(path, NULL); } extern unzFile ZEXPORT unzOpen(const char *path) { return unzOpenInternal(path, NULL); } extern unzFile ZEXPORT unzOpen64(const void *path) { return unzOpenInternal(path, NULL); } extern int ZEXPORT unzClose(unzFile file) { unz64_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) ZCLOSE64(s->z_filefunc, s->filestream); if (s->filestream_with_CD != NULL) ZCLOSE64(s->z_filefunc, s->filestream_with_CD); s->filestream = NULL; s->filestream_with_CD = NULL; TRYFREE(s); return UNZ_OK; } /* Goto to the next available disk for spanned archives */ local int unzGoToNextDisk OF((unzFile file)); local int unzGoToNextDisk(unzFile file) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; uLong number_disk_next = 0; s = (unz64_s *)file; if (s == NULL) return UNZ_PARAMERROR; pfile_in_zip_read_info = s->pfile_in_zip_read; number_disk_next = s->number_disk; if ((pfile_in_zip_read_info != NULL) && (pfile_in_zip_read_info->rest_read_uncompressed > 0)) /* We are currently reading a file and we need the next sequential disk */ number_disk_next += 1; else /* Goto the disk for the current file */ number_disk_next = s->cur_file_info.disk_num_start; if (number_disk_next != s->number_disk) { /* Switch disks */ if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) ZCLOSE64(s->z_filefunc, s->filestream); if (number_disk_next == s->gi.number_disk_with_CD) { s->filestream = s->filestream_with_CD; } else { s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, (unsigned int)number_disk_next, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); } if (s->filestream == NULL) return UNZ_ERRNO; s->number_disk = number_disk_next; } return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info32) { unz64_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info) { unz64_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; *pglobal_info = s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uLong comment_size) { unz64_s *s; uLong bytes_to_read = comment_size; if (file == NULL) return (int)UNZ_PARAMERROR; s = (unz64_s *)file; if (bytes_to_read > s->gi.size_comment) bytes_to_read = s->gi.size_comment; if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0) return UNZ_ERRNO; if (bytes_to_read > 0) { *comment = 0; if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read) return UNZ_ERRNO; } if ((comment != NULL) && (comment_size > s->gi.size_comment)) *(comment + s->gi.size_comment) = 0; return (int)bytes_to_read; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) { unz64_s *s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; ZPOS64_T bytes_to_read; int err = UNZ_OK; uLong uMagic; long lSeek = 0; ZPOS64_T current_pos = 0; uLong acc = 0; uLong uL; ZPOS64_T uL64; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err = UNZ_ERRNO; /* Check the magic */ if (err == UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uMagic) != UNZ_OK) err = UNZ_ERRNO; else if (uMagic != CENTRALHEADERMAGIC) err = UNZ_BADZIPFILE; } /* Read central directory header */ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.dosDate) != UNZ_OK) err = UNZ_ERRNO; unz64local_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) err = UNZ_ERRNO; file_info.compressed_size = uL; if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) err = UNZ_ERRNO; file_info.uncompressed_size = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK) err = UNZ_ERRNO; /* Relative offset of local header */ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) err = UNZ_ERRNO; file_info.size_file_extra_internal = 0; file_info.disk_offset = uL; file_info_internal.offset_curfile = uL; #ifdef HAVE_AES file_info_internal.aes_compression_method = 0; file_info_internal.aes_encryption_mode = 0; file_info_internal.aes_version = 0; #endif lSeek += file_info.size_filename; if ((err == UNZ_OK) && (filename != NULL)) { if (file_info.size_filename < filename_size) { *(filename + file_info.size_filename) = 0; bytes_to_read = file_info.size_filename; } else bytes_to_read = filename_size; if ((file_info.size_filename > 0) && (filename_size > 0)) if (ZREAD64(s->z_filefunc, s->filestream_with_CD, filename, (uLong)bytes_to_read) != bytes_to_read) err = UNZ_ERRNO; lSeek -= (uLong)bytes_to_read; } /* Read extrafield */ if ((err == UNZ_OK) && (extrafield != NULL)) { if (file_info.size_file_extra < extrafield_size) bytes_to_read = file_info.size_file_extra; else bytes_to_read = extrafield_size; if (lSeek != 0) { if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) lSeek = 0; else err = UNZ_ERRNO; } if ((file_info.size_file_extra > 0) && (extrafield_size > 0)) if (ZREAD64(s->z_filefunc, s->filestream_with_CD, extrafield, (uLong)bytes_to_read) != bytes_to_read) err = UNZ_ERRNO; lSeek += file_info.size_file_extra - (uLong)bytes_to_read; } else lSeek += file_info.size_file_extra; if ((err == UNZ_OK) && (file_info.size_file_extra != 0)) { if (lSeek != 0) { if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) lSeek = 0; else err = UNZ_ERRNO; } /* We are going to parse the extra field so we need to move back */ current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD); if (current_pos < file_info.size_file_extra) err = UNZ_ERRNO; current_pos -= file_info.size_file_extra; if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err = UNZ_ERRNO; while ((err != UNZ_ERRNO) && (acc < file_info.size_file_extra)) { uLong headerid; uLong datasize; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &headerid) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &datasize) != UNZ_OK) err = UNZ_ERRNO; /* ZIP64 extra fields */ if (headerid == 0x0001) { /* Subtract size of ZIP64 field, since ZIP64 is handled internally */ file_info.size_file_extra_internal += 2 + 2 + datasize; if (file_info.uncompressed_size == 0xffffffff) { if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK) err = UNZ_ERRNO; } if (file_info.compressed_size == 0xffffffff) { if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK) err = UNZ_ERRNO; } if (file_info_internal.offset_curfile == 0xffffffff) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &uL64) != UNZ_OK) err = UNZ_ERRNO; file_info_internal.offset_curfile = uL64; file_info.disk_offset = uL64; } if (file_info.disk_num_start == 0xffffffff) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) err = UNZ_ERRNO; } } #ifdef HAVE_AES /* AES header */ else if (headerid == 0x9901) { /* Subtract size of AES field, since AES is handled internally */ file_info.size_file_extra_internal += 2 + 2 + datasize; /* Verify version info */ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) err = UNZ_ERRNO; /* Support AE-1 and AE-2 */ if (uL != 1 && uL != 2) err = UNZ_ERRNO; file_info_internal.aes_version = uL; if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, (int *)&uL) != UNZ_OK) err = UNZ_ERRNO; if ((char)uL != 'A') err = UNZ_ERRNO; if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, (int *)&uL) != UNZ_OK) err = UNZ_ERRNO; if ((char)uL != 'E') err = UNZ_ERRNO; /* Get AES encryption strength and actual compression method */ if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, (int *)&uL) != UNZ_OK) err = UNZ_ERRNO; file_info_internal.aes_encryption_mode = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) err = UNZ_ERRNO; file_info_internal.aes_compression_method = uL; } #endif else { if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, datasize, ZLIB_FILEFUNC_SEEK_CUR) != 0) err = UNZ_ERRNO; } acc += 2 + 2 + datasize; } } if (file_info.disk_num_start == s->gi.number_disk_with_CD) file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile; else file_info_internal.byte_before_the_zipfile = 0; if ((err == UNZ_OK) && (comment != NULL)) { if (file_info.size_file_comment < comment_size) { *(comment + file_info.size_file_comment) = 0; bytes_to_read = file_info.size_file_comment; } else bytes_to_read = comment_size; if (lSeek != 0) { if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) != 0) err = UNZ_ERRNO; } if ((file_info.size_file_comment > 0) && (comment_size > 0)) if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, (uLong)bytes_to_read) != bytes_to_read) err = UNZ_ERRNO; lSeek += file_info.size_file_comment - (uLong)bytes_to_read; } else lSeek += file_info.size_file_comment; if ((err == UNZ_OK) && (pfile_info != NULL)) *pfile_info = file_info; if ((err == UNZ_OK) && (pfile_info_internal != NULL)) *pfile_info_internal = file_info_internal; return err; } extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) { unz_file_info64 file_info64; int err; err = unz64local_GetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size, extrafield, extrafield_size, comment, comment_size); if ((err == UNZ_OK) && (pfile_info != NULL)) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; pfile_info->flag = file_info64.flag; pfile_info->compression_method = file_info64.compression_method; pfile_info->dosDate = file_info64.dosDate; pfile_info->crc = file_info64.crc; pfile_info->size_filename = file_info64.size_filename; pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date, pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) { return unz64local_GetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size, extrafield, extrafield_size, comment, comment_size); } /* Read the local header of the current zipfile. Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s *s, uInt *piSizeVar, ZPOS64_T *poffset_local_extrafield, uInt *psize_local_extrafield) { uLong uMagic, uL, uFlags; uLong size_filename; uLong size_extra_field; int err = UNZ_OK; int compression_method = 0; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; err = unzGoToNextDisk((unzFile)s); if (err != UNZ_OK) return err; if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile + s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) return UNZ_ERRNO; if (err == UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) err = UNZ_ERRNO; else if (uMagic != LOCALHEADERMAGIC) err = UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK) err = UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uL != s->cur_file_info.compression_method)) err = UNZ_BADZIPFILE; compression_method = (int)s->cur_file_info.compression_method; #ifdef HAVE_AES if (compression_method == AES_METHOD) compression_method = (int)s->cur_file_info_internal.aes_compression_method; #endif if ((err == UNZ_OK) && (compression_method != 0) && #ifdef HAVE_BZIP2 (compression_method != Z_BZIP2ED) && #endif (compression_method != Z_DEFLATED)) err = UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* date/time */ err = UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* crc */ err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uL != s->cur_file_info.crc) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size compr */ err = UNZ_ERRNO; else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size uncompr */ err = UNZ_ERRNO; else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK) err = UNZ_ERRNO; else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) err = UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK) err = UNZ_ERRNO; *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password) { int err = UNZ_OK; int compression_method; uInt iSizeVar; unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; uInt size_local_extrafield; #ifndef NOUNCRYPT char source[12]; #else if (password != NULL) return UNZ_PARAMERROR; #endif if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unz64local_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip64_read_info_s *)ALLOC(sizeof(file_in_zip64_read_info_s)); if (pfile_in_zip_read_info == NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer = (Bytef *)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield = 0; pfile_in_zip_read_info->raw = raw; if (pfile_in_zip_read_info->read_buffer == NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised = 0; compression_method = (int)s->cur_file_info.compression_method; #ifdef HAVE_AES if (compression_method == AES_METHOD) compression_method = (int)s->cur_file_info_internal.aes_compression_method; #endif if (method != NULL) *method = compression_method; if (level != NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6: *level = 1; break; case 4: *level = 2; break; case 2: *level = 9; break; } } if ((compression_method != 0) && #ifdef HAVE_BZIP2 (compression_method != Z_BZIP2ED) && #endif (compression_method != Z_DEFLATED)) err = UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; pfile_in_zip_read_info->crc32 = 0; pfile_in_zip_read_info->total_out_64 = 0; pfile_in_zip_read_info->compression_method = compression_method; pfile_in_zip_read_info->filestream = s->filestream; pfile_in_zip_read_info->z_filefunc = s->z_filefunc; if (s->number_disk == s->gi.number_disk_with_CD) pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; else pfile_in_zip_read_info->byte_before_the_zipfile = 0; pfile_in_zip_read_info->stream.total_out = 0; pfile_in_zip_read_info->stream.total_in = 0; pfile_in_zip_read_info->stream.next_in = NULL; if (!raw) { if (compression_method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*)(void *, int, int)) 0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; pfile_in_zip_read_info->bstream.state = (voidpf)0; pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED; else { TRYFREE(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw = 1; #endif } else if (compression_method == Z_DEFLATED) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)s; pfile_in_zip_read_info->stream.next_in = 0; pfile_in_zip_read_info->stream.avail_in = 0; err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised = Z_DEFLATED; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; #ifndef NOUNCRYPT if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0)) { if (ZSEEK64(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) return UNZ_INTERNALERROR; #ifdef HAVE_AES if (s->cur_file_info.compression_method == AES_METHOD) { unsigned char passverify[AES_PWVERIFYSIZE]; unsigned char saltvalue[AES_MAXSALTLENGTH]; uInt saltlength; if ((s->cur_file_info_internal.aes_encryption_mode < 1) || (s->cur_file_info_internal.aes_encryption_mode > 3)) return UNZ_INTERNALERROR; saltlength = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode); if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength) return UNZ_INTERNALERROR; if (ZREAD64(s->z_filefunc, s->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) return UNZ_INTERNALERROR; fcrypt_init((int)s->cur_file_info_internal.aes_encryption_mode, (unsigned char *)password, (unsigned int)strlen(password), saltvalue, passverify, &s->pfile_in_zip_read->aes_ctx); pfile_in_zip_read_info->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE; pfile_in_zip_read_info->rest_read_compressed -= AES_AUTHCODESIZE; s->pfile_in_zip_read->pos_in_zipfile += saltlength + AES_PWVERIFYSIZE; } else #endif { int i; s->pcrc_32_tab = (const unsigned long *)get_crc_table(); init_keys(password, s->keys, s->pcrc_32_tab); if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12) return UNZ_INTERNALERROR; for (i = 0; i < 12; i++) zdecode(s->keys, s->pcrc_32_tab, source[i]); pfile_in_zip_read_info->rest_read_compressed -= 12; s->pfile_in_zip_read->pos_in_zipfile += 12; } } #endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile(unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) { int err = UNZ_OK; uInt read = 0; unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len == 0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef *)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if (pfile_in_zip_read_info->raw) { if (len > pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in; } else { // NOTE: // This bit of code seems to try to set the amount of space in the output buffer based on the // value stored in the headers stored in the .zip file. However, if those values are incorrect // it may result in a loss of data when uncompresssing that file. The compressed data is still // legit and will deflate without knowing the uncompressed code so this tidbit is unnecessary and // may cause issues for some .zip files. // // It's removed in here to fix those issues. // // See: https://github.com/ZipArchive/ziparchive/issues/16 // /* FIXME: Upgrading to minizip 1.1 caused issues here, Uncommented the code that was commented before. 11/24/2015 */ if (len > pfile_in_zip_read_info->rest_read_uncompressed) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; } while (pfile_in_zip_read_info->stream.avail_out > 0) { if (pfile_in_zip_read_info->stream.avail_in == 0) { uInt bytes_to_read = UNZ_BUFSIZE; uInt bytes_not_read = 0; uInt bytes_read = 0; uInt total_bytes_read = 0; if (pfile_in_zip_read_info->stream.next_in != NULL) bytes_not_read = (uInt)(pfile_in_zip_read_info->read_buffer + UNZ_BUFSIZE - pfile_in_zip_read_info->stream.next_in); bytes_to_read -= bytes_not_read; if (bytes_not_read > 0) memcpy(pfile_in_zip_read_info->read_buffer, pfile_in_zip_read_info->stream.next_in, bytes_not_read); if (pfile_in_zip_read_info->rest_read_compressed < bytes_to_read) bytes_to_read = (uInt)pfile_in_zip_read_info->rest_read_compressed; while (total_bytes_read != bytes_to_read) { if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) return UNZ_ERRNO; bytes_read = (int)ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer + bytes_not_read + total_bytes_read, bytes_to_read - total_bytes_read); total_bytes_read += bytes_read; pfile_in_zip_read_info->pos_in_zipfile += bytes_read; if (bytes_read == 0) { if (ZERROR64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream)) return UNZ_ERRNO; err = unzGoToNextDisk(file); if (err != UNZ_OK) return err; pfile_in_zip_read_info->pos_in_zipfile = 0; pfile_in_zip_read_info->filestream = s->filestream; } } #ifndef NOUNCRYPT if ((s->cur_file_info.flag & 1) != 0) { #ifdef HAVE_AES if (s->cur_file_info.compression_method == AES_METHOD) { fcrypt_decrypt(pfile_in_zip_read_info->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx); } else #endif { uInt i; for (i = 0; i < total_bytes_read; i++) pfile_in_zip_read_info->read_buffer[i] = zdecode(s->keys, s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } } #endif pfile_in_zip_read_info->rest_read_compressed -= total_bytes_read; pfile_in_zip_read_info->stream.next_in = (Bytef *)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)bytes_not_read + total_bytes_read; } if ((pfile_in_zip_read_info->compression_method == 0) || (pfile_in_zip_read_info->raw)) { uInt copy, i; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (read == 0) ? UNZ_EOF : read; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) copy = pfile_in_zip_read_info->stream.avail_out; else copy = pfile_in_zip_read_info->stream.avail_in; for (i = 0; i < copy; i++) *(pfile_in_zip_read_info->stream.next_out + i) = *(pfile_in_zip_read_info->stream.next_in + i); pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + copy; pfile_in_zip_read_info->rest_read_uncompressed -= copy; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, copy); pfile_in_zip_read_info->stream.avail_in -= copy; pfile_in_zip_read_info->stream.avail_out -= copy; pfile_in_zip_read_info->stream.next_out += copy; pfile_in_zip_read_info->stream.next_in += copy; pfile_in_zip_read_info->stream.total_out += copy; read += copy; } else if (pfile_in_zip_read_info->compression_method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 uLong total_out_before, total_out_after; const Bytef *buf_before; uLong out_bytes; pfile_in_zip_read_info->bstream.next_in = (char *)pfile_in_zip_read_info->stream.next_in; pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; pfile_in_zip_read_info->bstream.total_in_hi32 = 0; pfile_in_zip_read_info->bstream.next_out = (char *)pfile_in_zip_read_info->stream.next_out; pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; pfile_in_zip_read_info->bstream.total_out_hi32 = 0; total_out_before = pfile_in_zip_read_info->bstream.total_out_lo32; buf_before = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; err = BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); total_out_after = pfile_in_zip_read_info->bstream.total_out_lo32; out_bytes = total_out_after - total_out_before; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + out_bytes; pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, buf_before, (uInt)(out_bytes)); read += (uInt)(total_out_after - total_out_before); pfile_in_zip_read_info->stream.next_in = (Bytef *)pfile_in_zip_read_info->bstream.next_in; pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; pfile_in_zip_read_info->stream.next_out = (Bytef *)pfile_in_zip_read_info->bstream.next_out; pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; if (err == BZ_STREAM_END) return (read == 0) ? UNZ_EOF : read; if (err != BZ_OK) break; #endif } else { ZPOS64_T total_out_before, total_out_after; const Bytef *buf_before; ZPOS64_T out_bytes; int flush = Z_SYNC_FLUSH; total_out_before = pfile_in_zip_read_info->stream.total_out; buf_before = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err = inflate(&pfile_in_zip_read_info->stream, flush); if ((err >= 0) && (pfile_in_zip_read_info->stream.msg != NULL)) err = Z_DATA_ERROR; total_out_after = pfile_in_zip_read_info->stream.total_out; out_bytes = total_out_after - total_out_before; pfile_in_zip_read_info->total_out_64 += out_bytes; pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, buf_before, (uInt)(out_bytes)); read += (uInt)(total_out_after - total_out_before); if (err == Z_STREAM_END) return (read == 0) ? UNZ_EOF : read; if (err != Z_OK) break; } } if (err == Z_OK) return read; return err; } extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; s = (unz64_s *)file; if (file == NULL) return 0; /* UNZ_PARAMERROR */ pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return 0; /* UNZ_PARAMERROR */ return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; size_to_read = pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield; if (buf == NULL) return (int)size_to_read; if (len > size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len; if (read_now == 0) return 0; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET) != 0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf, read_now) != read_now) return UNZ_ERRNO; return (int)read_now; } extern int ZEXPORT unzCloseCurrentFile(unzFile file) { int err = UNZ_OK; unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; #ifdef HAVE_AES if (s->cur_file_info.compression_method == AES_METHOD) { unsigned char authcode[AES_AUTHCODESIZE]; unsigned char rauthcode[AES_AUTHCODESIZE]; if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) return UNZ_ERRNO; if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE) err = UNZ_CRCERROR; if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0) err = UNZ_CRCERROR; } /* AES zip version AE-1 will expect a valid crc as well */ if ((s->cur_file_info.compression_method != AES_METHOD) || (s->cur_file_info_internal.aes_version == 0x0001)) #endif { if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err = UNZ_CRCERROR; } } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read = NULL; return err; } extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) { int err = UNZ_OK; unz64_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; s->pos_in_central_dir = s->offset_central_dir; s->num_file = 0; err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, filename, filename_size, extrafield, extrafield_size, comment, comment_size); s->current_file_ok = (err == UNZ_OK); if ((err == UNZ_OK) && (pfile_info != NULL)) memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); return err; } extern int ZEXPORT unzGoToFirstFile(unzFile file) { return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); } extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) { unz64_s *s; int err; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file + 1 == s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment; s->num_file++; err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, filename, filename_size, extrafield, extrafield_size, comment, comment_size); s->current_file_ok = (err == UNZ_OK); if ((err == UNZ_OK) && (pfile_info != NULL)) memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); return err; } extern int ZEXPORT unzGoToNextFile(unzFile file) { return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); } extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) { unz64_s *s; int err; unz_file_info64 cur_file_info_saved; unz_file_info64_internal cur_file_info_internal_saved; ZPOS64_T num_file_saved; ZPOS64_T pos_in_central_dir_saved; char current_filename[UNZ_MAXFILENAMEINZIP + 1]; if (file == NULL) return UNZ_PARAMERROR; if (strlen(filename) >= UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s = (unz64_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_file_saved = s->num_file; pos_in_central_dir_saved = s->pos_in_central_dir; cur_file_info_saved = s->cur_file_info; cur_file_info_internal_saved = s->cur_file_info_internal; err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename) - 1, NULL, 0, NULL, 0); while (err == UNZ_OK) { if (filename_compare_func != NULL) err = filename_compare_func(file, current_filename, filename); else err = strcmp(current_filename, filename); if (err == 0) return UNZ_OK; err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename) - 1, NULL, 0, NULL, 0); } /* We failed, so restore the state of the 'current file' to where we were. */ s->num_file = num_file_saved; s->pos_in_central_dir = pos_in_central_dir_saved; s->cur_file_info = cur_file_info_saved; s->cur_file_info_internal = cur_file_info_internal_saved; return err; } extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file, &file_pos64); if (err == UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file, &file_pos64); } extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos) { unz64_s *s; if (file == NULL || file_pos == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos) { unz64_s *s; int err; if (file == NULL || file_pos == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern uLong ZEXPORT unzGetOffset(unzFile file) { ZPOS64_T offset64; if (file == NULL) return 0; /* UNZ_PARAMERROR; */ offset64 = unzGetOffset64(file); return (uLong)offset64; } extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s *s; if (file == NULL) return 0; /* UNZ_PARAMERROR; */ s = (unz64_s *)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file == s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern int ZEXPORT unzSetOffset(unzFile file, uLong pos) { return unzSetOffset64(file, pos); } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s *s; int err; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); s->current_file_ok = (err == UNZ_OK); return err; } extern z_off_t ZEXPORT unztell(unzFile file) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64(unzFile file) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; if (file == NULL) return (ZPOS64_T)-1; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } extern int ZEXPORT unzeof(unzFile file) { unz64_s *s; file_in_zip64_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz64_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; return 0; } ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/unzip.h ================================================ /* unzip.h -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson http://result42.com This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #include "Common.h" #ifndef _UNZ_H #define _UNZ_H #define HAVE_AES #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /***************************************************************************/ /* Opening and close a zip file */ extern unzFile ZEXPORT unzOpen OF((const char *path)); extern unzFile ZEXPORT unzOpen64 OF((const void *path)); /* Open a Zip file. path should contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". return NULL if zipfile cannot be opened or doesn't exist return unzFile handle if no error NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile, these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no error */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. return UNZ_OK if no error */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *comment, uLong comment_size)); /* Get the global comment string of the ZipFile, in the comment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. return UNZ_OK if no error */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password return UNZ_OK if no error */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression NOTE: you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); /* Get Info about the current file pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file filename if != NULL, the file name string will be copied in filename filename_size is the size of the filename buffer extrafield if != NULL, the extra field information from the central header will be copied in to extrafield_size is the size of the extraField buffer comment if != NULL, the comment string of the file will be copied in to comment_size is the size of the comment buffer */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf == NULL, it return the size of the local extra field if buf != NULL, len is the size of the buffer, the extra header is copied in buf. return number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile return UNZ_CRCERROR if all the file was read but the CRC is not good */ /***************************************************************************/ /* Browse the directory of the zipfile */ typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2); typedef int (*unzIteratorFunction)(unzFile file); typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size); extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if no error */ extern int ZEXPORT unzGoToFirstFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); /* Set the current file of the zipfile to the first file and retrieves the current info on success. Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo. return UNZ_OK if no error */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if no error return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ extern int ZEXPORT unzGoToNextFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); /* Set the current file of the zipfile to the next file and retrieves the current info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo. return UNZ_OK if no error return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *filename, unzFileNameComparer filename_compare_func)); /* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function. return UNZ_OK if the file is found (it becomes the current file) return UNZ_END_OF_LIST_OF_FILE if the file is not found */ /***************************************************************************/ /* Raw access to zip file */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos)); extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos)); typedef struct unz64_file_pos_s { ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ ZPOS64_T num_of_file; /* # of file */ } unz64_file_pos; extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos)); extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos)); extern uLong ZEXPORT unzGetOffset OF((unzFile file)); extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file)); /* Get the current file offset */ extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos)); extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos)); /* Set the current file offset */ extern z_off_t ZEXPORT unztell OF((unzFile file)); extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); /* return current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ /***************************************************************************/ #ifdef __cplusplus } #endif #endif /* _UNZ_H */ ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/zip.c ================================================ /* zip.c -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson http://result42.com Modifications for AES, PKWARE disk spanning Copyright (C) 2010-2014 Nathan Moinvaziri This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #include #include #include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifdef HAVE_AES # define AES_METHOD (99) # define AES_PWVERIFYSIZE (2) # define AES_AUTHCODESIZE (10) # define AES_MAXSALTLENGTH (16) # define AES_VERSION (0x0001) # define AES_ENCRYPTIONMODE (0x03) # include "aes.h" # include "fileenc.h" # include "prng.h" # include "entropy.h" #endif #ifndef NOCRYPT # define INCLUDECRYPTINGCODE_IFCRYPTALLOWED # include "crypt.h" #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #define SIZEDATA_INDATABLOCK (4096 - (4 * 4)) #define DISKHEADERMAGIC (0x08074b50) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define ZIP64ENDHEADERMAGIC (0x06064b50) #define ZIP64ENDLOCHEADERMAGIC (0x07064b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ #define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) #ifndef BUFREADCOMMENT # define BUFREADCOMMENT (0x400) #endif #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform dependent */ #endif #ifndef Z_BUFSIZE # define Z_BUFSIZE (64 * 1024) #endif #ifndef Z_MAXFILENAMEINZIP # define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p); } #endif /* NOT sure that this work on ALL platform */ #define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s *next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignment */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal *first_block; linkedlist_datablock_internal *last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif #ifdef HAVE_AES fcrypt_ctx aes_ctx; prng_ctx aes_rng[1]; #endif int stream_initialised; /* 1 is stream is initialized */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file currently writing */ char *central_header; /* central header data for the current file */ uLong size_centralextra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralextrafree; /* Extra bytes allocated to the central header but that are not used */ uLong size_comment; uLong flag; /* flag of the file currently writing */ int method; /* compression method written to file.*/ int compression_method; /* compression method to use */ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int zip64; /* Add ZIP64 extended information in the extra field */ uLong number_disk; /* number of current disk used for spanning ZIP */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T total_compressed; ZPOS64_T total_uncompressed; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long *pcrc_32_tab; int crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structure of the zipfile */ voidpf filestream_with_CD; /* io structure of the zipfile with the central dir */ linkedlist_data central_dir; /* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ int append; /* append mode */ curfile64_info ci; /* info on the file currently writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writting_offset; ZPOS64_T number_entry; ZPOS64_T disk_size; /* size of each disk */ uLong number_disk; /* number of the current disk, used for spanning ZIP */ uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif } zip64_internal; /* Allocate a new data block */ local linkedlist_datablock_internal *allocate_new_datablock OF(()); local linkedlist_datablock_internal *allocate_new_datablock() { linkedlist_datablock_internal *ldi; ldi = (linkedlist_datablock_internal *)ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi != NULL) { ldi->next_datablock = NULL; ldi->filled_in_this_block = 0; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK; } return ldi; } /* Free data block in linked list */ local void free_datablock OF((linkedlist_datablock_internal * ldi)); local void free_datablock(linkedlist_datablock_internal *ldi) { while (ldi != NULL) { linkedlist_datablock_internal *ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } /* Initialize linked list */ local void init_linkedlist OF((linkedlist_data * ll)); local void init_linkedlist(linkedlist_data *ll) { ll->first_block = ll->last_block = NULL; } /* Free entire linked list and all data blocks */ local void free_linkedlist OF((linkedlist_data * ll)); local void free_linkedlist(linkedlist_data *ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } /* Add data to linked list data block */ local int add_data_in_datablock OF((linkedlist_data * ll, const void *buf, uLong len)); local int add_data_in_datablock(linkedlist_data *ll, const void *buf, uLong len) { linkedlist_datablock_internal *ldi; const unsigned char *from_copy; if (ll == NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char *)buf; while (len > 0) { uInt copy_this; uInt i; unsigned char *to_copy; if (ldi->avail_in_this_block == 0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i = 0; i < copy_this; i++) *(to_copy + i) = *(from_copy + i); ldi->filled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this; len -= copy_this; } return ZIP_OK; } local uLong zip64local_TmzDateToDosDate OF((const tm_zip * ptm)); local uLong zip64local_TmzDateToDosDate(const tm_zip *ptm) { uLong year; #define zip64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) /* Years supported: * [00, 79] (assumed to be between 2000 and 2079) * [80, 207] (assumed to be between 1980 and 2107, typical output of old software that does 'year-1900' to get a double digit year) * [1980, 2107] Due to the date format limitations, only years between 1980 and 2107 can be stored. */ if (!(zip64local_in_range(1980, 2107, ptm->tm_year) || zip64local_in_range(0, 207, ptm->tm_year)) || !zip64local_in_range(0, 11, ptm->tm_mon) || !zip64local_in_range(1, 31, ptm->tm_mday) || !zip64local_in_range(0, 23, ptm->tm_hour) || !zip64local_in_range(0, 59, ptm->tm_min) || !zip64local_in_range(0, 59, ptm->tm_sec)) return 0; #undef zip64local_in_range year = (uLong)ptm->tm_year; if (year >= 1980) /* range [1980, 2107] */ year -= 1980; else if (year >= 80) /* range [80, 99] */ year -= 80; else /* range [00, 79] */ year += 20; return (uLong)(((ptm->tm_mday) + (32 * (ptm->tm_mon + 1)) + (512 * year)) << 16) | ((ptm->tm_sec / 2) + (32 * ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /* Inputs a long in LSB order to the given file: nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ local int zip64local_putValue OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); local int zip64local_putValue(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE64(*pzlib_filefunc_def, filestream, buf, nbByte) != (uLong)nbByte) return ZIP_ERRNO; return ZIP_OK; } local void zip64local_putValue_inmemory OF((void *dest, ZPOS64_T x, int nbByte)); local void zip64local_putValue_inmemory(void *dest, ZPOS64_T x, int nbByte) { unsigned char *buf = (unsigned char *)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } local int zip64local_getByte OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, int *pi)); local int zip64local_getByte(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); if (err == 1) { *pi = (int)c; return ZIP_OK; } if (ZERROR64(*pzlib_filefunc_def, filestream)) return ZIP_ERRNO; return ZIP_EOF; } local int zip64local_getShort OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, uLong * pX)); local int zip64local_getShort(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x = (uLong)i; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((uLong)i) << 8; if (err == ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, uLong * pX)); local int zip64local_getLong(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x = (uLong)i; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((uLong)i) << 8; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((uLong)i) << 16; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((uLong)i) << 24; if (err == ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong64 OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, ZPOS64_T * pX)); local int zip64local_getLong64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x = (ZPOS64_T)i; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 8; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 16; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 24; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 32; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 40; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 48; if (err == ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); x += ((ZPOS64_T)i) << 56; if (err == ZIP_OK) *pX = x; else *pX = 0; return err; } /* Gets the amount of bytes left to write to the current disk for spanning archives */ local int zipGetDiskSizeAvailable OF((zipFile file, ZPOS64_T * size_available)); local int zipGetDiskSizeAvailable(zipFile file, ZPOS64_T *size_available) { zip64_internal *zi; ZPOS64_T current_disk_size; zi = (zip64_internal *)file; ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); current_disk_size = ZTELL64(zi->z_filefunc, zi->filestream); *size_available = zi->disk_size - current_disk_size; return ZIP_OK; } /* Goes to a specific disk number for spanning archives */ local int zipGoToSpecificDisk OF((zipFile file, int number_disk, int open_existing)); local int zipGoToSpecificDisk(zipFile file, int number_disk, int open_existing) { zip64_internal *zi; int err = ZIP_OK; zi = (zip64_internal *)file; if (zi->disk_size == 0) return err; if ((zi->filestream != NULL) && (zi->filestream != zi->filestream_with_CD)) ZCLOSE64(zi->z_filefunc, zi->filestream); zi->filestream = ZOPENDISK64(zi->z_filefunc, zi->filestream_with_CD, number_disk, (open_existing == 1) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE)); if (zi->filestream == NULL) err = ZIP_ERRNO; return err; } /* Goes to the first disk in a spanned archive */ local int zipGoToFirstDisk OF((zipFile file)); local int zipGoToFirstDisk(zipFile file) { zip64_internal *zi; int number_disk_next; int err = ZIP_OK; zi = (zip64_internal *)file; if (zi->disk_size == 0) return err; number_disk_next = 0; if (zi->number_disk_with_CD > 0) number_disk_next = (int)zi->number_disk_with_CD - 1; err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) err = zipGoToSpecificDisk(file, number_disk_next, 0); if (err == ZIP_OK) zi->number_disk = number_disk_next; ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); return err; } /* Goes to the next disk in a spanned archive */ local int zipGoToNextDisk OF((zipFile file)); local int zipGoToNextDisk(zipFile file) { zip64_internal *zi; ZPOS64_T size_available_in_disk; int err = ZIP_OK; int number_disk_next; zi = (zip64_internal *)file; if (zi->disk_size == 0) return err; number_disk_next = (int)zi->number_disk + 1; do { err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) err = zipGoToSpecificDisk(file, number_disk_next, 0); if (err != ZIP_OK) break; err = zipGetDiskSizeAvailable(file, &size_available_in_disk); if (err != ZIP_OK) break; zi->number_disk = number_disk_next; zi->number_disk_with_CD = zi->number_disk + 1; number_disk_next += 1; } while (size_available_in_disk <= 0); return err; } /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream) { unsigned char *buf; ZPOS64_T file_size; ZPOS64_T back_read = 4; ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ ZPOS64_T pos_found = 0; uLong read_size; ZPOS64_T read_pos; int i; buf = (unsigned char *)ALLOC(BUFREADCOMMENT + 4); if (buf == NULL) return 0; if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) { TRYFREE(buf); return 0; } file_size = ZTELL64(*pzlib_filefunc_def, filestream); if (max_back > file_size) max_back = file_size; while (back_read < max_back) { if (back_read + BUFREADCOMMENT > max_back) back_read = max_back; else back_read += BUFREADCOMMENT; read_pos = file_size - back_read; read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) break; if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) break; for (i = (int)read_size - 3; (i--) > 0; ) if ((*(buf + i)) == (ENDHEADERMAGIC & 0xff) && (*(buf + i + 1)) == (ENDHEADERMAGIC >> 8 & 0xff) && (*(buf + i + 2)) == (ENDHEADERMAGIC >> 16 & 0xff) && (*(buf + i + 3)) == (ENDHEADERMAGIC >> 24 & 0xff)) { pos_found = read_pos + i; break; } if (pos_found != 0) break; } TRYFREE(buf); return pos_found; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def * pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset)); local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset) { ZPOS64_T offset; uLong uL; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) return 0; /* read locator signature */ if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) return 0; if (uL != ZIP64ENDLOCHEADERMAGIC) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) return 0; /* relative offset of the zip64 end of central directory record */ if (zip64local_getLong64(pzlib_filefunc_def, filestream, &offset) != ZIP_OK) return 0; /* total number of disks */ if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) return 0; /* the signature */ if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) return 0; if (uL != ZIP64ENDHEADERMAGIC) return 0; return offset; } extern zipFile ZEXPORT zipOpen4(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc *globalcomment, zlib_filefunc64_32_def *pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal *zi; #ifndef NO_ADDFILEINEXISTINGZIP ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T size_central_dir = 0; /* size of the central directory */ ZPOS64_T offset_central_dir = 0; /* offset of start of central directory */ ZPOS64_T number_entry_CD = 0; /* total number of entries in the central dir */ ZPOS64_T number_entry; ZPOS64_T central_pos; ZPOS64_T size_central_dir_to_read; uLong uL; uLong size_comment = 0; size_t buf_size = SIZEDATA_INDATABLOCK; void *buf_read; #endif int err = ZIP_OK; int mode; ziinit.z_filefunc.zseek32_file = NULL; ziinit.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def == NULL) fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); else ziinit.z_filefunc = *pzlib_filefunc64_32_def; if (append == APPEND_STATUS_CREATE) mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE); else mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING); ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, mode); if (ziinit.filestream == NULL) return NULL; if (append == APPEND_STATUS_CREATEAFTER) { /* Don't support spanning ZIP with APPEND_STATUS_CREATEAFTER */ if (disk_size > 0) return NULL; ZSEEK64(ziinit.z_filefunc, ziinit.filestream, 0, SEEK_END); } ziinit.filestream_with_CD = ziinit.filestream; ziinit.append = append; ziinit.number_disk = 0; ziinit.number_disk_with_CD = 0; ziinit.disk_size = disk_size; ziinit.begin_pos = ZTELL64(ziinit.z_filefunc, ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writting_offset = 0; init_linkedlist(&(ziinit.central_dir)); zi = (zip64_internal *)ALLOC(sizeof(zip64_internal)); if (zi == NULL) { ZCLOSE64(ziinit.z_filefunc, ziinit.filestream); return NULL; } #ifndef NO_ADDFILEINEXISTINGZIP /* Add file in a zipfile */ ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { /* Read and Cache Central Directory Records */ central_pos = zip64local_SearchCentralDir(&ziinit.z_filefunc, ziinit.filestream); /* disable to allow appending to empty ZIP archive (must be standard zip, not zip64) if (central_pos == 0) err = ZIP_ERRNO; */ if (err == ZIP_OK) { /* read end of central directory info */ if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; /* number of this disk */ if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) err = ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) err = ZIP_ERRNO; /* total number of entries in the central dir on this disk */ number_entry = 0; if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; else number_entry = uL; /* total number of entries in the central dir */ number_entry_CD = 0; if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; else number_entry_CD = uL; if (number_entry_CD != number_entry) err = ZIP_BADZIPFILE; /* size of the central directory */ size_central_dir = 0; if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; else size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ offset_central_dir = 0; if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; else offset_central_dir = uL; /* zipfile global comment length */ if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &size_comment) != ZIP_OK) err = ZIP_ERRNO; if ((err == ZIP_OK) && ((number_entry_CD == 0xffff) || (offset_central_dir == 0xffffffff))) { /* Format should be Zip64, as the central directory or file size is too large */ central_pos = zip64local_SearchCentralDir64(&ziinit.z_filefunc, ziinit.filestream, central_pos); if (central_pos) { ZPOS64_T sizeEndOfCentralDirectory; if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; /* size of zip64 end of central directory record */ if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &sizeEndOfCentralDirectory) != ZIP_OK) err = ZIP_ERRNO; /* version made by */ if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; /* version needed to extract */ if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) err = ZIP_ERRNO; /* number of this disk */ if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) err = ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) err = ZIP_ERRNO; /* total number of entries in the central directory on this disk */ if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry) != ZIP_OK) err = ZIP_ERRNO; /* total number of entries in the central directory */ if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry_CD) != ZIP_OK) err = ZIP_ERRNO; if (number_entry_CD != number_entry) err = ZIP_BADZIPFILE; /* size of the central directory */ if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &size_central_dir) != ZIP_OK) err = ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &offset_central_dir) != ZIP_OK) err = ZIP_ERRNO; } else err = ZIP_BADZIPFILE; } } if ((err == ZIP_OK) && (central_pos < offset_central_dir + size_central_dir)) err = ZIP_BADZIPFILE; if (err != ZIP_OK) { ZCLOSE64(ziinit.z_filefunc, ziinit.filestream); TRYFREE(zi); return NULL; } if (size_comment > 0) { ziinit.globalcomment = (char *)ALLOC(size_comment + 1); if (ziinit.globalcomment) { size_comment = ZREAD64(ziinit.z_filefunc, ziinit.filestream, ziinit.globalcomment, size_comment); ziinit.globalcomment[size_comment] = 0; } } byte_before_the_zipfile = central_pos - (offset_central_dir + size_central_dir); ziinit.add_position_when_writting_offset = byte_before_the_zipfile; /* Store central directory in memory */ size_central_dir_to_read = size_central_dir; buf_size = SIZEDATA_INDATABLOCK; buf_read = (void *)ALLOC(buf_size); if (buf_read == NULL) err = ZIP_INTERNALERROR; if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; while ((size_central_dir_to_read > 0) && (err == ZIP_OK)) { ZPOS64_T read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, buf_read, (uLong)read_this) != read_this) err = ZIP_ERRNO; if (err == ZIP_OK) err = add_data_in_datablock(&ziinit.central_dir, buf_read, (uLong)read_this); size_central_dir_to_read -= read_this; } TRYFREE(buf_read); ziinit.begin_pos = byte_before_the_zipfile; ziinit.number_entry = number_entry_CD; if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; } if (globalcomment) *globalcomment = ziinit.globalcomment; #endif if (err != ZIP_OK) { #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); #endif TRYFREE(zi); return NULL; } *zi = ziinit; zipGoToFirstDisk((zipFile)zi); return (zipFile)zi; } extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc *globalcomment, zlib_filefunc_def *pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); } return zipOpen4(pathname, append, 0, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc *globalcomment, zlib_filefunc64_def *pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); } return zipOpen4(pathname, append, 0, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen3(const char *pathname, int append, ZPOS64_T disk_size, zipcharpc *globalcomment, zlib_filefunc_def *pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); } return zipOpen4(pathname, append, disk_size, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen3_64(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc *globalcomment, zlib_filefunc64_def *pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); } return zipOpen4(pathname, append, disk_size, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen(const char *pathname, int append) { return zipOpen3((const void *)pathname, append, 0, NULL, NULL); } extern zipFile ZEXPORT zipOpen64(const void *pathname, int append) { return zipOpen3(pathname, append, 0, NULL, NULL); } extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char *password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal *zi; uInt size_filename; uInt size_comment = 0; uInt i; int err = ZIP_OK; ZPOS64_T size_available; ZPOS64_T size_needed; #ifdef NOCRYPT (crcForCrypting); if (password != NULL) return ZIP_PARAMERROR; #endif if (file == NULL) return ZIP_PARAMERROR; if ((method != 0) && #ifdef HAVE_BZIP2 (method != Z_BZIP2ED) && #endif (method != Z_DEFLATED)) return ZIP_PARAMERROR; zi = (zip64_internal *)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip(file); if (err != ZIP_OK) return err; } if (filename == NULL) filename = "-"; if (comment != NULL) size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); } zi->ci.method = method; zi->ci.compression_method = method; zi->ci.crc32 = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.flag = flagBase; if ((level == 8) || (level == 9)) zi->ci.flag |= 2; if (level == 2) zi->ci.flag |= 4; if (level == 1) zi->ci.flag |= 6; if (password != NULL) { zi->ci.flag |= 1; #ifdef HAVE_AES zi->ci.method = AES_METHOD; #endif } if (zi->disk_size > 0) { if ((zi->number_disk == 0) && (zi->number_entry == 0)) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)DISKHEADERMAGIC, 4); /* Make sure enough space available on current disk for local header */ zipGetDiskSizeAvailable((zipFile)zi, &size_available); size_needed = 30 + size_filename + size_extrafield_local; if (zi->ci.zip64) size_needed += 20; #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) size_needed += 11; #endif if (size_available < size_needed) zipGoToNextDisk((zipFile)zi); } zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream); zi->ci.size_comment = size_comment; zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global; zi->ci.size_centralextra = size_extrafield_global; zi->ci.size_centralextrafree = 32; /* Extra space reserved for ZIP64 extra info */ #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) zi->ci.size_centralextrafree += 11; /* Extra space reserved for AES extra info */ #endif zi->ci.central_header = (char *)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralextrafree + size_comment); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; zi->ci.number_disk = zi->number_disk; /* Write central directory header */ zip64local_putValue_inmemory(zi->ci.central_header, (uLong)CENTRALHEADERMAGIC, 4); zip64local_putValue_inmemory(zi->ci.central_header + 4, (uLong)versionMadeBy, 2); zip64local_putValue_inmemory(zi->ci.central_header + 6, (uLong)20, 2); zip64local_putValue_inmemory(zi->ci.central_header + 8, (uLong)zi->ci.flag, 2); zip64local_putValue_inmemory(zi->ci.central_header + 10, (uLong)zi->ci.method, 2); zip64local_putValue_inmemory(zi->ci.central_header + 12, (uLong)zi->ci.dosDate, 4); zip64local_putValue_inmemory(zi->ci.central_header + 16, (uLong)0, 4); /*crc*/ zip64local_putValue_inmemory(zi->ci.central_header + 20, (uLong)0, 4); /*compr size*/ zip64local_putValue_inmemory(zi->ci.central_header + 24, (uLong)0, 4); /*uncompr size*/ zip64local_putValue_inmemory(zi->ci.central_header + 28, (uLong)size_filename, 2); zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)size_extrafield_global, 2); zip64local_putValue_inmemory(zi->ci.central_header + 32, (uLong)size_comment, 2); zip64local_putValue_inmemory(zi->ci.central_header + 34, (uLong)zi->ci.number_disk, 2); /*disk nm start*/ if (zipfi == NULL) zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)0, 2); else zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)zipfi->internal_fa, 2); if (zipfi == NULL) zip64local_putValue_inmemory(zi->ci.central_header + 38, (uLong)0, 4); else zip64local_putValue_inmemory(zi->ci.central_header + 38, (uLong)zipfi->external_fa, 4); if (zi->ci.pos_local_header >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header + 42, (uLong)0xffffffff, 4); else zip64local_putValue_inmemory(zi->ci.central_header + 42, (uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset, 4); for (i = 0; i < size_filename; i++) zi->ci.central_header[SIZECENTRALHEADER + i] = filename[i]; for (i = 0; i < size_extrafield_global; i++) zi->ci.central_header[SIZECENTRALHEADER + size_filename + i] = ((const char *)extrafield_global)[i]; /* Store comment at the end for later repositioning */ for (i = 0; i < size_comment; i++) zi->ci.central_header[zi->ci.size_centralheader + zi->ci.size_centralextrafree + i] = comment[i]; if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; zi->ci.zip64 = zip64; zi->ci.total_compressed = 0; zi->ci.total_uncompressed = 0; zi->ci.pos_zip64extrainfo = 0; /* Write the local header */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)LOCALHEADERMAGIC, 4); if (err == ZIP_OK) { if (zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* version needed to extract */ else err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)20, 2); /* version needed to extract */ } if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.flag, 2); if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.method, 2); if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.dosDate, 4); /* CRC & compressed size & uncompressed size will be filled in later and rewritten later */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* crc 32, unknown */ if (err == ZIP_OK) { if (zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); /* compressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* compressed size, unknown */ } if (err == ZIP_OK) { if (zi->ci.zip64) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); else /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); } if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_filename, 2); if (err == ZIP_OK) { ZPOS64_T size_extrafield = size_extrafield_local; if (zi->ci.zip64) size_extrafield += 20; #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) size_extrafield += 11; #endif err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_extrafield, 2); } if ((err == ZIP_OK) && (size_filename > 0)) { if (ZWRITE64(zi->z_filefunc, zi->filestream, filename, size_filename) != size_filename) err = ZIP_ERRNO; } if ((err == ZIP_OK) && (size_extrafield_local > 0)) { if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) err = ZIP_ERRNO; } /* Write the Zip64 extended info */ if ((err == ZIP_OK) && (zi->ci.zip64)) { short headerid = 1; short datasize = 16; ZPOS64_T compressed_size = 0; ZPOS64_T uncompressed_size = 0; /* Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) */ zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc, zi->filestream); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)headerid, 2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)datasize, 2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)uncompressed_size, 8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)compressed_size, 8); } #ifdef HAVE_AES /* Write the AES extended info */ if ((err == ZIP_OK) && (zi->ci.method == AES_METHOD)) { int headerid = 0x9901; short datasize = 7; err = zip64local_putValue(&zi->z_filefunc, zi->filestream, headerid, 2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, datasize, 2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_VERSION, 2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'A', 1); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'E', 1); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_ENCRYPTIONMODE, 1); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->ci.compression_method, 2); } #endif #ifdef HAVE_BZIP2 zi->ci.bstream.avail_in = (uInt)0; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char *)zi->ci.buffered_data; zi->ci.bstream.total_in_hi32 = 0; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_out_hi32 = 0; zi->ci.bstream.total_out_lo32 = 0; #endif zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; zi->ci.stream.data_type = Z_BINARY; if ((err == ZIP_OK) && (!zi->ci.raw)) { if (method == Z_DEFLATED) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)zi; if (windowBits > 0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err == Z_OK) zi->ci.stream_initialised = Z_DEFLATED; } else if (method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 zi->ci.bstream.bzalloc = 0; zi->ci.bstream.bzfree = 0; zi->ci.bstream.opaque = (voidpf)0; err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0, 35); if (err == BZ_OK) zi->ci.stream_initialised = Z_BZIP2ED; #endif } } #ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err == Z_OK) && ((zi->ci.flag & 1) != 0)) { #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) { unsigned char passverify[AES_PWVERIFYSIZE]; unsigned char saltvalue[AES_MAXSALTLENGTH]; uInt saltlength; if ((AES_ENCRYPTIONMODE < 1) || (AES_ENCRYPTIONMODE > 3)) return Z_ERRNO; saltlength = SALT_LENGTH(AES_ENCRYPTIONMODE); prng_init(entropy_fun, zi->ci.aes_rng); prng_rand(saltvalue, saltlength, zi->ci.aes_rng); prng_end(zi->ci.aes_rng); fcrypt_init(AES_ENCRYPTIONMODE, (unsigned char *)password, (unsigned int)strlen(password), saltvalue, passverify, &zi->ci.aes_ctx); if (ZWRITE64(zi->z_filefunc, zi->filestream, saltvalue, saltlength) != saltlength) err = ZIP_ERRNO; if (ZWRITE64(zi->z_filefunc, zi->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) err = ZIP_ERRNO; zi->ci.crypt_header_size = saltlength + AES_PWVERIFYSIZE + AES_AUTHCODESIZE; } else #endif { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.pcrc_32_tab = (const unsigned long *)get_crc_table(); /*init_keys(password, zi->ci.keys, zi->ci.pcrc_32_tab);*/ sizeHead = crypthead(password, bufHead, RAND_HEAD_LEN, zi->ci.keys, zi->ci.pcrc_32_tab, crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE64(zi->z_filefunc, zi->filestream, bufHead, sizeHead) != sizeHead) err = ZIP_ERRNO; } } #endif if (err == Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char *password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); } extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char *password, uLong crcForCrypting) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char *password, uLong crcForCrypting, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int raw, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, const char *comment, int method, int level) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } /* Flushes the write buffer to disk */ local int zip64FlushWriteBuffer OF((zip64_internal * zi)); local int zip64FlushWriteBuffer(zip64_internal *zi) { int err = ZIP_OK; uInt written = 0; uInt total_written = 0; uInt write = 0; uInt max_write = 0; ZPOS64_T size_available = 0; if ((zi->ci.flag & 1) != 0) { #ifndef NOCRYPT #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) { fcrypt_encrypt(zi->ci.buffered_data, zi->ci.pos_in_buffered_data, &zi->ci.aes_ctx); } else #endif { uInt i; int t; for (i = 0; i < zi->ci.pos_in_buffered_data; i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i], t); } #endif } write = zi->ci.pos_in_buffered_data; do { max_write = write; if (zi->disk_size > 0) { err = zipGetDiskSizeAvailable((zipFile)zi, &size_available); if (err != ZIP_OK) return err; if (size_available == 0) { err = zipGoToNextDisk((zipFile)zi); if (err != ZIP_OK) return err; } if (size_available < (ZPOS64_T)max_write) max_write = (uInt)size_available; } written = (unsigned int)ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data + total_written, max_write); if (ZERROR64(zi->z_filefunc, zi->filestream)) { err = ZIP_ERRNO; break; } total_written += written; write -= written; } while (write > 0); zi->ci.total_compressed += zi->ci.pos_in_buffered_data; #ifdef HAVE_BZIP2 if (zi->ci.compression_method == Z_BZIP2ED) { zi->ci.total_uncompressed += zi->ci.bstream.total_in_lo32; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_in_hi32 = 0; } else #endif { zi->ci.total_uncompressed += zi->ci.stream.total_in; zi->ci.stream.total_in = 0; } zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void *buf, unsigned int len) { zip64_internal *zi; int err = ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal *)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.crc32 = crc32(zi->ci.crc32, buf, (uInt)len); #ifdef HAVE_BZIP2 if ((zi->ci.compression_method == Z_BZIP2ED) && (!zi->ci.raw)) { zi->ci.bstream.next_in = (void *)buf; zi->ci.bstream.avail_in = len; err = BZ_RUN_OK; while ((err == BZ_RUN_OK) && (zi->ci.bstream.avail_in > 0)) { if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char *)zi->ci.buffered_data; } else { uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; err = BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo); } } if (err == BZ_RUN_OK) err = ZIP_OK; } else #endif { zi->ci.stream.next_in = (Bytef *)buf; zi->ci.stream.avail_in = len; while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0)) { if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if (err != ZIP_OK) break; if ((zi->ci.compression_method == Z_DEFLATED) && (!zi->ci.raw)) { uLong total_out_before = zi->ci.stream.total_out; err = deflate(&zi->ci.stream, Z_NO_FLUSH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); } else { uInt copy_this, i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i = 0; i < copy_this; i++) *(((char *)zi->ci.stream.next_out) + i) = *(((const char *)zi->ci.stream.next_in) + i); zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out -= copy_this; zi->ci.stream.next_in += copy_this; zi->ci.stream.next_out += copy_this; zi->ci.stream.total_in += copy_this; zi->ci.stream.total_out += copy_this; zi->ci.pos_in_buffered_data += copy_this; } } } return err; } extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64(file, uncompressed_size, crc32); } extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal *zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; uLong i = 0; short datasize = 0; int err = ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal *)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if (!zi->ci.raw) { if (zi->ci.compression_method == Z_DEFLATED) { while (err == ZIP_OK) { uLong total_out_before; if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } total_out_before = zi->ci.stream.total_out; err = deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); } } else if (zi->ci.compression_method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 err = BZ_FINISH_OK; while (err == BZ_FINISH_OK) { uLong total_out_before; if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char *)zi->ci.buffered_data; } total_out_before = zi->ci.bstream.total_out_lo32; err = BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); if (err == BZ_STREAM_END) err = Z_STREAM_END; zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - total_out_before); } if (err == BZ_FINISH_OK) err = ZIP_OK; #endif } } if (err == Z_STREAM_END) err = ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data > 0) && (err == ZIP_OK)) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; } #ifdef HAVE_AES if (zi->ci.method == AES_METHOD) { unsigned char authcode[AES_AUTHCODESIZE]; fcrypt_end(authcode, &zi->ci.aes_ctx); if (ZWRITE64(zi->z_filefunc, zi->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) err = ZIP_ERRNO; } #endif if (!zi->ci.raw) { if (zi->ci.compression_method == Z_DEFLATED) { int tmp_err = deflateEnd(&zi->ci.stream); if (err == ZIP_OK) err = tmp_err; zi->ci.stream_initialised = 0; } #ifdef HAVE_BZIP2 else if (zi->ci.compression_method == Z_BZIP2ED) { int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); if (err == ZIP_OK) err = tmperr; zi->ci.stream_initialised = 0; } #endif crc32 = (uLong)zi->ci.crc32; uncompressed_size = zi->ci.total_uncompressed; } compressed_size = zi->ci.total_compressed; #ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; #endif /* Update current item crc and sizes */ if (compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) { zip64local_putValue_inmemory(zi->ci.central_header + 4, (uLong)45, 2); /* version made by */ zip64local_putValue_inmemory(zi->ci.central_header + 6, (uLong)45, 2); /* version needed */ } zip64local_putValue_inmemory(zi->ci.central_header + 16, crc32, 4); /* crc */ if (compressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header + 20, invalidValue, 4); /* compr size */ else zip64local_putValue_inmemory(zi->ci.central_header + 20, compressed_size, 4); /* compr size */ if (zi->ci.stream.data_type == Z_ASCII) zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)Z_ASCII, 2); /* internal file attrib */ if (uncompressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header + 24, invalidValue, 4); /* uncompr size */ else zip64local_putValue_inmemory(zi->ci.central_header + 24, uncompressed_size, 4); /* uncompr size */ /* Add ZIP64 extra info field for uncompressed size */ if (uncompressed_size >= 0xffffffff) datasize += 8; /* Add ZIP64 extra info field for compressed size */ if (compressed_size >= 0xffffffff) datasize += 8; /* Add ZIP64 extra info field for relative offset to local file header of current file */ if (zi->ci.pos_local_header >= 0xffffffff) datasize += 8; /* Add Extra Information Header for 'ZIP64 information' */ if (datasize > 0) { char *p = zi->ci.central_header + zi->ci.size_centralheader; if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) return ZIP_BADZIPFILE; zip64local_putValue_inmemory(p, 0x0001, 2); p += 2; zip64local_putValue_inmemory(p, datasize, 2); p += 2; if (uncompressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, uncompressed_size, 8); p += 8; } if (compressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, compressed_size, 8); p += 8; } if (zi->ci.pos_local_header >= 0xffffffff) { zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); p += 8; } zi->ci.size_centralextrafree -= datasize + 4; zi->ci.size_centralheader += datasize + 4; zi->ci.size_centralextra += datasize + 4; zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)zi->ci.size_centralextra, 2); } #ifdef HAVE_AES /* Write the AES extended info */ if (zi->ci.method == AES_METHOD) { char *p = zi->ci.central_header + zi->ci.size_centralheader; datasize = 7; if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) return ZIP_BADZIPFILE; zip64local_putValue_inmemory(p, 0x9901, 2); p += 2; zip64local_putValue_inmemory(p, datasize, 2); p += 2; zip64local_putValue_inmemory(p, AES_VERSION, 2); p += 2; zip64local_putValue_inmemory(p, 'A', 1); p += 1; zip64local_putValue_inmemory(p, 'E', 1); p += 1; zip64local_putValue_inmemory(p, AES_ENCRYPTIONMODE, 1); p += 1; zip64local_putValue_inmemory(p, zi->ci.compression_method, 2); p += 2; zi->ci.size_centralextrafree -= datasize + 4; zi->ci.size_centralheader += datasize + 4; zi->ci.size_centralextra += datasize + 4; zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)zi->ci.size_centralextra, 2); } #endif /* Restore comment to correct position */ for (i = 0; i < zi->ci.size_comment; i++) zi->ci.central_header[zi->ci.size_centralheader + i] = zi->ci.central_header[zi->ci.size_centralheader + zi->ci.size_centralextrafree + i]; zi->ci.size_centralheader += zi->ci.size_comment; if (err == ZIP_OK) err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err == ZIP_OK) { /* Update the LocalFileHeader with the new values. */ ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); uLong cur_number_disk = zi->number_disk; /* Local file header is stored on previous disk, switch to make edits */ if (zi->ci.number_disk != cur_number_disk) err = zipGoToSpecificDisk(file, (int)zi->ci.number_disk, 1); if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_local_header + 14, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, crc32, 4); /* crc 32, unknown */ if (uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff) { if (zi->ci.pos_zip64extrainfo > 0) { /* Update the size in the ZIP64 extended field. */ if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_zip64extrainfo + 4, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; if (err == ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); if (err == ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); } else err = ZIP_BADZIPFILE; /* Caller passed zip64 = 0, so no room for zip64 info -> fatal */ } else { if (err == ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 4); if (err == ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 4); } /* Now switch back again to the disk we were on before */ if (zi->ci.number_disk != cur_number_disk) err = zipGoToSpecificDisk(file, (int)cur_number_disk, 1); if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip, ZLIB_FILEFUNC_SEEK_SET) != 0) err = ZIP_ERRNO; } zi->number_entry++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip(zipFile file) { return zipCloseFileInZipRaw(file, 0, 0); } extern int ZEXPORT zipClose(zipFile file, const char *global_comment) { zip64_internal *zi; int err = 0; uLong size_centraldir = 0; uInt size_global_comment = 0; ZPOS64_T centraldir_pos_inzip; ZPOS64_T pos = 0; uLong write = 0; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal *)file; if (zi->in_opened_file_inzip == 1) err = zipCloseFileInZip(file); #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment == NULL) global_comment = zi->globalcomment; #endif if (zi->filestream != zi->filestream_with_CD) { if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; if (zi->disk_size > 0) zi->number_disk_with_CD = zi->number_disk + 1; zi->filestream = zi->filestream_with_CD; } centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); if (err == ZIP_OK) { linkedlist_datablock_internal *ldi = zi->central_dir.first_block; while (ldi != NULL) { if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0)) { write = ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data, ldi->filled_in_this_block); if (write != ldi->filled_in_this_block) err = ZIP_ERRNO; } size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; /* Write the ZIP64 central directory header */ if (pos >= 0xffffffff || zi->number_entry > 0xffff) { ZPOS64_T zip64eocd_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); uLong zip64datasize = 44; err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDHEADERMAGIC, 4); /* size of this 'zip64 end of central directory' */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)zip64datasize, 8); /* version made by */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* version needed */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* number of this disk */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); /* number of the disk with the start of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); /* total number of entries in the central dir on this disk */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); /* total number of entries in the central dir */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); /* size of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)size_centraldir, 8); if (err == ZIP_OK) { /* offset of start of central directory with respect to the starting disk number */ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)pos, 8); } if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDLOCHEADERMAGIC, 4); /* number of the disk with the start of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); /*relative offset to the Zip64EndOfCentralDirectory */ if (err == ZIP_OK) { ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8); } /* number of the disk with the start of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD + 1, 4); } /* Write the central directory header */ /* signature */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ENDHEADERMAGIC, 4); /* number of this disk */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); /* number of the disk with the start of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); /* total number of entries in the central dir on this disk */ if (err == ZIP_OK) { if (zi->number_entry >= 0xffff) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ else err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); } /* total number of entries in the central dir */ if (err == ZIP_OK) { if (zi->number_entry >= 0xffff) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ else err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); } /* size of the central directory */ if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_centraldir, 4); /* offset of start of central directory with respect to the starting disk number */ if (err == ZIP_OK) { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; if (pos >= 0xffffffff) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffffffff, 4); else err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)pos, 4); } /* Write global comment */ if (global_comment != NULL) size_global_comment = (uInt)strlen(global_comment); if (err == ZIP_OK) err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_global_comment, 2); if (err == ZIP_OK && size_global_comment > 0) { if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment, size_global_comment) != size_global_comment) err = ZIP_ERRNO; } if ((ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) && (err == ZIP_OK)) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } ================================================ FILE: Sublime/Pods/SSZipArchive/SSZipArchive/minizip/zip.h ================================================ /* zip.h -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project Copyright (C) 1998-2010 Gilles Vollant http://www.winimage.com/zLibDll/minizip.html Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson http://result42.com This program is distributed under the terms of the same license as zlib. See the accompanying LICENSE file for the full text of the license. */ #ifndef _ZIP_H #define _ZIP_H #define HAVE_AES #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H # include "zlib.h" #endif #ifndef _ZLIBIOAPI_H # include "ioapi.h" #endif #ifdef HAVE_BZIP2 # include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) /***************************************************************************/ /* Writing a zip file */ extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); /* Create a zipfile. pathname should contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". return NULL if zipfile cannot be opened return zipFile handle if no error If the file pathname exist and append == APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) If the file pathname exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy the file you did not want delete. */ extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); extern zipFile ZEXPORT zipOpen3 OF((const char *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); /* Same as zipOpen2 but allows specification of spanned zip size */ extern zipFile ZEXPORT zipOpen3_64 OF((const void *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information extrafield_local buffer to store the local header extra field data, can be NULL size_extrafield_local size of extrafield_local buffer extrafield_global buffer to store the global header extra field data, can be NULL size_extrafield_global size of extrafield_local buffer comment buffer for comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) zip64 is set to 1 if a zip64 extended information block should be added to the local file header. this MUST be '1' if the uncompressed size is >= 0xffffffff. */ extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); /* Same as zipOpenNewFileInZip with zip64 support */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); /* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); /* Same as zipOpenNewFileInZip3 with zip64 support */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting)); /* Same as zipOpenNewFileInZip2, except windowBits, memLevel, strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCrypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64)); /* Same as zipOpenNewFileInZip3 with zip64 support */ extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase)); /* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */ extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64)); /* Same as zipOpenNewFileInZip4 with zip64 support */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ /***************************************************************************/ #ifdef __cplusplus } #endif #endif /* _ZIP_H */ ================================================ FILE: Sublime/Pods/Swifter/LICENSE ================================================ Copyright (c) 2014, Damian Kołakowski 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 {organization} nor the names of its 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 HOLDER 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. ================================================ FILE: Sublime/Pods/Swifter/README.md ================================================ ### What is Swift? >Swift is an innovative new programming language for Cocoa and Cocoa Touch. Writing code is interactive and fun, the syntax is concise yet expressive, and apps run lightning-fast. Swift is ready for your next iOS and OS X project — or for addition into your current app — because Swift code works side-by-side with Objective-C. ### What is Swifter? Tiny http server engine written in Swift ( https://developer.apple.com/swift/ ) programming language. ![Platform](https://img.shields.io/badge/Platform-Linux%20&%20OSX-4BC51D.svg?style=flat) ![Swift](https://img.shields.io/badge/Swift-2.2/3.0--dev-4BC51D.svg?style=flat) ![Protocols](https://img.shields.io/badge/Protocols-HTTP%201.1%20&%20WebSockets-4BC51D.svg?style=flat) [![CocoaPods](https://img.shields.io/cocoapods/v/Swifter.svg?style=flat)]() [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ### How to start? ```swift let server = HttpServer() server["/hello"] = { .OK(.HTML("You asked for " + $0.url)) } server.start() ``` ### How to share files? ```swift let server = HttpServer() server["/desktop/:path"] = HttpHandlers.shareFilesFromDirectory("/Users/me/Desktop") server.start() ``` ### How to redirect? ```swift let server = HttpServer() server["/redirect"] = { request in return .MovedPermanently("http://www.google.com") } server.start() ``` ### CocoaPods? Yes. ``` use_frameworks! pod 'Swifter', '~> 1.1.3' ``` ### Carthage? Also yes. ``` github "glock45/swifter" == 1.1.3 ``` ================================================ FILE: Sublime/Pods/Swifter/Sources/DemoServer.swift ================================================ // // DemoServer.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation public func demoServer(publicDir: String) -> HttpServer { print(publicDir) let server = HttpServer() server["/public/:path"] = HttpHandlers.shareFilesFromDirectory(publicDir) server["/files/:path"] = HttpHandlers.directoryBrowser("/") server["/"] = { r in var listPage = "Available services:
    " for services in server.routes { if services.isEmpty { listPage += "
  • /
  • " } else { listPage += "
  • \(services)
  • " } } listPage += "
" return .OK(.Html(listPage)) } server["/magic"] = { .OK(.Html("You asked for " + $0.path)) } server["/test/:param1/:param2"] = { r in var headersInfo = "" for (name, value) in r.headers { headersInfo += "\(name) : \(value)
" } var queryParamsInfo = "" for (name, value) in r.queryParams { queryParamsInfo += "\(name) : \(value)
" } var pathParamsInfo = "" for token in r.params { pathParamsInfo += "\(token.0) : \(token.1)
" } return .OK(.Html("

Address: \(r.address)

Url:

\(r.path)

Method:

\(r.method)

Headers:

\(headersInfo)

Query:

\(queryParamsInfo)

Path params:

\(pathParamsInfo)")) } server.GET["/upload"] = { r in if let html = NSData(contentsOfFile:"\(publicDir)/file.html") { var array = [UInt8](count: html.length, repeatedValue: 0) html.getBytes(&array, length: html.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(array) }) } return .NotFound } server.POST["/upload"] = { r in var response = "" for multipart in r.parseMultiPartFormData() { response += "Name: \(multipart.name) File name: \(multipart.fileName) Size: \(multipart.body.count)
" } return HttpResponse.OK(.Html(response)) } server.GET["/login"] = { r in if let html = NSData(contentsOfFile:"\(publicDir)/login.html") { var array = [UInt8](count: html.length, repeatedValue: 0) html.getBytes(&array, length: html.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(array) }) } return .NotFound } server.POST["/login"] = { r in let formFields = r.parseUrlencodedForm() return HttpResponse.OK(.Html(formFields.map({ "\($0.0) = \($0.1)" }).joinWithSeparator("
"))) } server["/demo"] = { r in return .OK(.Html("

Hello Swift


")) } server["/raw"] = { r in return HttpResponse.RAW(200, "OK", ["XXX-Custom-Header": "value"], { $0.write([UInt8]("test".utf8)) }) } server["/json"] = { r in let jsonObject: NSDictionary = [NSString(string: "foo"): NSNumber(int: 3), NSString(string: "bar"): NSString(string: "baz")] return .OK(.Json(jsonObject)) } server["/redirect"] = { r in return .MovedPermanently("http://www.google.com") } server["/long"] = { r in var longResponse = "" for k in 0..<1000 { longResponse += "(\(k)),->" } return .OK(.Html(longResponse)) } server["/wildcard/*/test/*/:param"] = { r in return .OK(.Html(r.path)) } server["/stream"] = { r in return HttpResponse.RAW(200, "OK", nil, { w in for i in 0...100 { w.write([UInt8]("[chunk \(i)]".utf8)); } }) } server["/websocket-echo"] = HttpHandlers.websocket({ (session, text) in session.writeText(text) }, { (session, binary) in session.writeBinary(binary) }) return server } ================================================ FILE: Sublime/Pods/Swifter/Sources/File.swift ================================================ // // File.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif public enum FileError: ErrorType { case OpenFailed(String) case WriteFailed(String) case ReadFailed(String) case SeekFailed(String) case GetCurrentWorkingDirectoryFailed(String) } public class File { public static func openNewForWriting(path: String) throws -> File { return try openFileForMode(path, "wb") } public static func openForReading(path: String) throws -> File { return try openFileForMode(path, "rb") } public static func openForWritingAndReading(path: String) throws -> File { return try openFileForMode(path, "r+b") } public static func openFileForMode(path: String, _ mode: String) throws -> File { let file = fopen(path.withCString({ $0 }), mode.withCString({ $0 })) guard file != nil else { throw FileError.OpenFailed(descriptionOfLastError()) } return File(file) } public static func currentWorkingDirectory() throws -> String { let path = getcwd(nil, 0) if path == nil { throw FileError.GetCurrentWorkingDirectoryFailed(descriptionOfLastError()) } guard let result = String.fromCString(path) else { throw FileError.GetCurrentWorkingDirectoryFailed("Could not convert getcwd(...)'s result to String.") } return result } private let pointer: UnsafeMutablePointer public init(_ pointer: UnsafeMutablePointer) { self.pointer = pointer } public func close() -> Void { fclose(pointer) } public func read(inout data: [UInt8]) throws -> Int { if data.count <= 0 { return data.count } let count = fread(&data, 1, data.count, self.pointer) if count == data.count { return count } if feof(self.pointer) != 0 { return count } if ferror(self.pointer) != 0 { throw FileError.ReadFailed(File.descriptionOfLastError()) } throw FileError.ReadFailed("Unknown file read error occured.") } public func write(data: [UInt8]) throws -> Void { if data.count <= 0 { return } try data.withUnsafeBufferPointer { if fwrite($0.baseAddress, 1, data.count, self.pointer) != data.count { throw FileError.WriteFailed(File.descriptionOfLastError()) } } } public func seek(offset: Int) throws -> Void { if fseek(self.pointer, offset, SEEK_SET) != 0 { throw FileError.SeekFailed(File.descriptionOfLastError()) } } private static func descriptionOfLastError() -> String { return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)" } } extension File { public static func withNewFileOpenedForWriting(path: String, _ f: File throws -> Result) throws -> Result { return try withFileOpenedForMode(path, mode: "wb", f) } public static func withFileOpenedForReading(path: String, _ f: File throws -> Result) throws -> Result { return try withFileOpenedForMode(path, mode: "rb", f) } public static func withFileOpenedForWritingAndReading(path: String, _ f: File throws -> Result) throws -> Result { return try withFileOpenedForMode(path, mode: "r+b", f) } public static func withFileOpenedForMode(path: String, mode: String, _ f: File throws -> Result) throws -> Result { let file = try File.openFileForMode(path, mode) defer { file.close() } return try f(file) } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpHandlers+Files.swift ================================================ // // HttpHandlers+Files.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation extension HttpHandlers { public class func shareFilesFromDirectory(directoryPath: String) -> (HttpRequest -> HttpResponse) { return { r in guard let fileRelativePath = r.params.first else { return .NotFound } let absolutePath = directoryPath + "/" + fileRelativePath.1 guard let file = try? File.openForReading(absolutePath) else { return .NotFound } return .RAW(200, "OK", [:], { writer in var buffer = [UInt8](count: 64, repeatedValue: 0) while let count = try? file.read(&buffer) where count > 0 { writer.write(buffer[0.. (HttpRequest -> HttpResponse) { return { r in guard let localPath = r.params.first else { return HttpResponse.NotFound } let filesPath = dir + "/" + localPath.1 guard let fileBody = NSData(contentsOfFile: filesPath) else { return HttpResponse.NotFound } if let rangeHeader = r.headers["range"] { guard rangeHeader.hasPrefix(HttpHandlers.rangePrefix) else { return .BadRequest(.Text("Invalid value of 'Range' header: \(r.headers["range"])")) } #if os(Linux) let rangeString = rangeHeader.substringFromIndex(HttpHandlers.rangePrefix.characters.count) #else let rangeString = rangeHeader.substringFromIndex(rangeHeader.startIndex.advancedBy(HttpHandlers.rangePrefix.characters.count)) #endif let rangeStringExploded = rangeString.split("-") guard rangeStringExploded.count == 2 else { return .BadRequest(.Text("Invalid value of 'Range' header: \(r.headers["range"])")) } let startStr = rangeStringExploded[0] let endStr = rangeStringExploded[1] guard let start = Int(startStr), end = Int(endStr) else { var array = [UInt8](count: fileBody.length, repeatedValue: 0) fileBody.getBytes(&array, length: fileBody.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(array) }) } let chunkLength = end - start let chunkRange = NSRange(location: start, length: chunkLength + 1) guard chunkRange.location + chunkRange.length <= fileBody.length else { return HttpResponse.RAW(416, "Requested range not satisfiable", nil, nil) } let chunk = fileBody.subdataWithRange(chunkRange) let headers = [ "Content-Range" : "bytes \(startStr)-\(endStr)/\(fileBody.length)" ] var content = [UInt8](count: chunk.length, repeatedValue: 0) chunk.getBytes(&content, length: chunk.length) return HttpResponse.RAW(206, "Partial Content", headers, { $0.write(content) }) } else { var content = [UInt8](count: fileBody.length, repeatedValue: 0) fileBody.getBytes(&content, length: fileBody.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(content) }) } } } public class func directoryBrowser(dir: String) -> (HttpRequest -> HttpResponse) { return { r in guard let (_, value) = r.params.first else { return HttpResponse.NotFound } let filePath = dir + "/" + value let fileManager = NSFileManager.defaultManager() var isDir: ObjCBool = false guard fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) else { return HttpResponse.NotFound } if isDir { do { let files = try fileManager.contentsOfDirectoryAtPath(filePath) var response = "

\(filePath)


" response += files.map({ ""}).joinWithSeparator("") response += "
\($0)
" return HttpResponse.OK(.Html(response)) } catch { return HttpResponse.NotFound } } else { if let content = NSData(contentsOfFile: filePath) { var array = [UInt8](count: content.length, repeatedValue: 0) content.getBytes(&array, length: content.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(array) }) } return HttpResponse.NotFound } } } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpHandlers+WebSockets.swift ================================================ // // HttpHandlers+WebSockets.swift // Swifter // // Copyright © 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation extension HttpHandlers { public class func websocket( text: ((WebSocketSession, String) -> Void)?, _ binary: ((WebSocketSession, [UInt8]) -> Void)?) -> (HttpRequest -> HttpResponse) { return { r in guard r.headers["upgrade"] == "websocket" else { return .BadRequest(.Text("Invalid value of 'Upgrade' header: \(r.headers["upgrade"])")) } guard r.headers["connection"] == "Upgrade" else { return .BadRequest(.Text("Invalid value of 'Connection' header: \(r.headers["connection"])")) } guard let secWebSocketKey = r.headers["sec-websocket-key"] else { return .BadRequest(.Text("Invalid value of 'Sec-Websocket-Key' header: \(r.headers["sec-websocket-key"])")) } let protocolSessionClosure: (Socket -> Void) = { socket in let session = WebSocketSession(socket) while let frame = try? session.readFrame() { switch frame.opcode { case .Text: if let handleText = text { handleText(session, String.fromUInt8(frame.payload)) } case .Binary: if let handleBinary = binary { handleBinary(session, frame.payload) } default: break } } } let secWebSocketAccept = String.toBase64((secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").SHA1()) let headers = [ "Upgrade": "WebSocket", "Connection": "Upgrade", "Sec-WebSocket-Accept": secWebSocketAccept] return HttpResponse.SwitchProtocols(headers, protocolSessionClosure) } } public class WebSocketSession { public enum Error: ErrorType { case UnknownOpCode(String), UnMaskedFrame } public enum OpCode { case Continue, Close, Ping, Pong, Text, Binary } public class Frame { public var opcode = OpCode.Close public var fin = false public var payload = [UInt8]() } private let socket: Socket public init(_ socket: Socket) { self.socket = socket } public func writeText(text: String) -> Void { self.writeFrame(ArraySlice(text.utf8), OpCode.Text) } public func writeBinary(binary: [UInt8]) -> Void { self.writeBinary(ArraySlice(binary)) } public func writeBinary(binary: ArraySlice) -> Void { self.writeFrame(binary, OpCode.Binary) } private func writeFrame(data: ArraySlice, _ op: OpCode, _ fin: Bool = true) { let finAndOpCode = encodeFinAndOpCode(fin, op: op) let maskAndLngth = encodeLengthAndMaskFlag(UInt64(data.count), false) do { try self.socket.writeUInt8([finAndOpCode]) try self.socket.writeUInt8(maskAndLngth) try self.socket.writeUInt8(data) } catch { print(error) } } private func encodeFinAndOpCode(fin: Bool, op: OpCode) -> UInt8 { var encodedByte = UInt8(fin ? 0x80 : 0x00); switch op { case .Continue : encodedByte |= 0x00 & 0x0F; case .Text : encodedByte |= 0x01 & 0x0F; case .Binary : encodedByte |= 0x02 & 0x0F; case .Close : encodedByte |= 0x08 & 0x0F; case .Ping : encodedByte |= 0x09 & 0x0F; case .Pong : encodedByte |= 0x0A & 0x0F; } return encodedByte } private func encodeLengthAndMaskFlag(len: UInt64, _ masked: Bool) -> [UInt8] { let encodedLngth = UInt8(masked ? 0x80 : 0x00) var encodedBytes = [UInt8]() switch len { case 0...125: encodedBytes.append(encodedLngth | UInt8(len)); case 126...UInt64(UINT16_MAX): encodedBytes.append(encodedLngth | 0x7E); encodedBytes.append(UInt8(len >> 8)); encodedBytes.append(UInt8(len & 0xFF)); default: encodedBytes.append(encodedLngth | 0x7F); encodedBytes.append(UInt8(len >> 56) & 0xFF); encodedBytes.append(UInt8(len >> 48) & 0xFF); encodedBytes.append(UInt8(len >> 40) & 0xFF); encodedBytes.append(UInt8(len >> 32) & 0xFF); encodedBytes.append(UInt8(len >> 24) & 0xFF); encodedBytes.append(UInt8(len >> 16) & 0xFF); encodedBytes.append(UInt8(len >> 08) & 0xFF); encodedBytes.append(UInt8(len >> 00) & 0xFF); } return encodedBytes } public func readFrame() throws -> Frame { let frm = Frame() let fst = try socket.read() frm.fin = fst & 0x80 != 0 let opc = fst & 0x0F switch opc { case 0x00: frm.opcode = OpCode.Continue case 0x01: frm.opcode = OpCode.Text case 0x02: frm.opcode = OpCode.Binary case 0x08: frm.opcode = OpCode.Close case 0x09: frm.opcode = OpCode.Ping case 0x0A: frm.opcode = OpCode.Pong // "If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_." // http://tools.ietf.org/html/rfc6455#section-5.2 ( Page 29 ) default : throw Error.UnknownOpCode("\(opc)") } let sec = try socket.read() let msk = sec & 0x80 != 0 guard msk else { // "...a client MUST mask all frames that it sends to the serve.." // http://tools.ietf.org/html/rfc6455#section-5.1 throw Error.UnMaskedFrame } var len = UInt64(sec & 0x7F) if len == 0x7E { let b0 = UInt64(try socket.read()) let b1 = UInt64(try socket.read()) len = UInt64(littleEndian: b0 << 8 | b1) } else if len == 0x7F { let b0 = UInt64(try socket.read()) let b1 = UInt64(try socket.read()) let b2 = UInt64(try socket.read()) let b3 = UInt64(try socket.read()) let b4 = UInt64(try socket.read()) let b5 = UInt64(try socket.read()) let b6 = UInt64(try socket.read()) let b7 = UInt64(try socket.read()) len = UInt64(littleEndian: b0 << 54 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7) } let mask = [try socket.read(), try socket.read(), try socket.read(), try socket.read()] for i in 0.. HttpRequest { let statusLine = try socket.readLine() let statusLineTokens = statusLine.split(" ") if statusLineTokens.count < 3 { throw HttpParserError.InvalidStatusLine(statusLine) } let request = HttpRequest() request.method = statusLineTokens[0] request.path = statusLineTokens[1] request.queryParams = extractQueryParams(request.path) request.headers = try readHeaders(socket) if let contentLength = request.headers["content-length"], let contentLengthValue = Int(contentLength) { request.body = try readBody(socket, size: contentLengthValue) } return request } private func extractQueryParams(url: String) -> [(String, String)] { guard let query = url.split("?").last else { return [] } return query.split("&").reduce([(String, String)]()) { (c, s) -> [(String, String)] in let tokens = s.split(1, separator: "=") if let name = tokens.first, value = tokens.last { return c + [(name.removePercentEncoding(), value.removePercentEncoding())] } return c } } private func readBody(socket: Socket, size: Int) throws -> [UInt8] { var body = [UInt8]() for _ in 0.. [String: String] { var headers = [String: String]() repeat { let headerLine = try socket.readLine() if headerLine.isEmpty { return headers } let headerTokens = headerLine.split(1, separator: ":") if let name = headerTokens.first, value = headerTokens.last { headers[name.lowercaseString] = value.trim() } } while true } func supportsKeepAlive(headers: [String: String]) -> Bool { if let value = headers["connection"] { return "keep-alive" == value.trim() } return false } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpRequest.swift ================================================ // // HttpRequest.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation public class HttpRequest { public var path: String = "" public var queryParams: [(String, String)] = [] public var method: String = "" public var headers: [String: String] = [:] public var body: [UInt8] = [] public var address: String? = "" public var params: [String: String] = [:] public func parseUrlencodedForm() -> [(String, String)] { guard let contentTypeHeader = headers["content-type"] else { return [] } let contentTypeHeaderTokens = contentTypeHeader.split(";").map { $0.trim() } guard let contentType = contentTypeHeaderTokens.first where contentType == "application/x-www-form-urlencoded" else { return [] } return String.fromUInt8(body).split("&").map { param -> (String, String) in let tokens = param.split("=") if let name = tokens.first, value = tokens.last where tokens.count == 2 { return (name.replace("+", " ").removePercentEncoding(), value.replace("+", " ").removePercentEncoding()) } return ("","") } } public struct MultiPart { public let headers: [String: String] public let body: [UInt8] public var name: String? { return valueFor("content-disposition", parameter: "name")?.unquote() } public var fileName: String? { return valueFor("content-disposition", parameter: "filename")?.unquote() } private func valueFor(headerName: String, parameter: String) -> String? { return headers.reduce([String]()) { (combined, header: (key: String, value: String)) -> [String] in guard header.key == headerName else { return combined } let headerValueParams = header.value.split(";").map { $0.trim() } return headerValueParams.reduce(combined, combine: { (results, token) -> [String] in let parameterTokens = token.split(1, separator: "=") if parameterTokens.first == parameter, let value = parameterTokens.last { return results + [value] } return results }) }.first } } public func parseMultiPartFormData() -> [MultiPart] { guard let contentTypeHeader = headers["content-type"] else { return [] } let contentTypeHeaderTokens = contentTypeHeader.split(";").map { $0.trim() } guard let contentType = contentTypeHeaderTokens.first where contentType == "multipart/form-data" else { return [] } var boundary: String? = nil contentTypeHeaderTokens.forEach({ let tokens = $0.split("=") if let key = tokens.first where key == "boundary" && tokens.count == 2 { boundary = tokens.last } }) if let boundary = boundary where boundary.utf8.count > 0 { return parseMultiPartFormData(body, boundary: "--\(boundary)") } return [] } private func parseMultiPartFormData(data: [UInt8], boundary: String) -> [MultiPart] { var generator = data.generate() var result = [MultiPart]() while let part = nextMultiPart(&generator, boundary: boundary, isFirst: result.isEmpty) { result.append(part) } return result } private func nextMultiPart(inout generator: IndexingGenerator<[UInt8]>, boundary: String, isFirst: Bool) -> MultiPart? { if isFirst { guard nextMultiPartLine(&generator) == boundary else { return nil } } else { nextMultiPartLine(&generator) } var headers = [String: String]() while let line = nextMultiPartLine(&generator) where !line.isEmpty { let tokens = line.split(":") if let name = tokens.first, value = tokens.last where tokens.count == 2 { headers[name.lowercaseString] = value.trim() } } guard let body = nextMultiPartBody(&generator, boundary: boundary) else { return nil } return MultiPart(headers: headers, body: body) } private func nextMultiPartLine(inout generator: IndexingGenerator<[UInt8]>) -> String? { var result = String() while let value = generator.next() { if value > HttpRequest.CR { result.append(Character(UnicodeScalar(value))) } if value == HttpRequest.NL { break } } return result } static let CR = UInt8(13) static let NL = UInt8(10) private func nextMultiPartBody(inout generator: IndexingGenerator<[UInt8]>, boundary: String) -> [UInt8]? { var body = [UInt8]() let boundaryArray = [UInt8](boundary.utf8) var matchOffset = 0; while let x = generator.next() { matchOffset = ( x == boundaryArray[matchOffset] ? matchOffset + 1 : 0 ) body.append(x) if matchOffset == boundaryArray.count { body.removeRange(Range(body.count-matchOffset ..< body.count)) if body.last == HttpRequest.NL { body.removeLast() if body.last == HttpRequest.CR { body.removeLast() } } return body } } return nil } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpResponse.swift ================================================ // // HttpResponse.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation public enum SerializationError: ErrorType { case InvalidObject case NotSupported } public protocol HttpResponseBodyWriter { func write(data: [UInt8]) func write(data: ArraySlice) } public enum HttpResponseBody { case Json(AnyObject) case Html(String) case Text(String) case Custom(Any, (Any) throws -> String) func content() -> (Int, (HttpResponseBodyWriter throws -> Void)?) { do { switch self { case .Json(let object): guard NSJSONSerialization.isValidJSONObject(object) else { throw SerializationError.InvalidObject } let json = try NSJSONSerialization.dataWithJSONObject(object, options: NSJSONWritingOptions.PrettyPrinted) let data = Array(UnsafeBufferPointer(start: UnsafePointer(json.bytes), count: json.length)) return (data.count, { $0.write(data) }) case .Text(let body): let data = [UInt8](body.utf8) return (data.count, { $0.write(data) }) case .Html(let body): let serialised = "\(body)" let data = [UInt8](serialised.utf8) return (data.count, { $0.write(data) }) case .Custom(let object, let closure): let serialised = try closure(object) let data = [UInt8](serialised.utf8) return (data.count, { $0.write(data) }) } } catch { let data = [UInt8]("Serialisation error: \(error)".utf8) return (data.count, { $0.write(data) }) } } } public enum HttpResponse { case SwitchProtocols([String: String], Socket -> Void) case OK(HttpResponseBody), Created, Accepted case MovedPermanently(String) case BadRequest(HttpResponseBody?), Unauthorized, Forbidden, NotFound case InternalServerError case RAW(Int, String, [String:String]?, (HttpResponseBodyWriter -> Void)? ) func statusCode() -> Int { switch self { case .SwitchProtocols(_, _) : return 101 case .OK(_) : return 200 case .Created : return 201 case .Accepted : return 202 case .MovedPermanently : return 301 case .BadRequest(_) : return 400 case .Unauthorized : return 401 case .Forbidden : return 403 case .NotFound : return 404 case .InternalServerError : return 500 case .RAW(let code, _ , _, _) : return code } } func reasonPhrase() -> String { switch self { case .SwitchProtocols(_, _) : return "Switching Protocols" case .OK(_) : return "OK" case .Created : return "Created" case .Accepted : return "Accepted" case .MovedPermanently : return "Moved Permanently" case .BadRequest(_) : return "Bad Request" case .Unauthorized : return "Unauthorized" case .Forbidden : return "Forbidden" case .NotFound : return "Not Found" case .InternalServerError : return "Internal Server Error" case .RAW(_, let phrase, _, _) : return phrase } } func headers() -> [String: String] { var headers = ["Server" : "Swifter \(HttpServer.VERSION)"] switch self { case .SwitchProtocols(let switchHeaders, _): for (key, value) in switchHeaders { headers[key] = value } case .OK(let body): switch body { case .Json(_) : headers["Content-Type"] = "application/json" case .Html(_) : headers["Content-Type"] = "text/html" default:break } case .MovedPermanently(let location): headers["Location"] = location case .RAW(_, _, let rawHeaders, _): if let rawHeaders = rawHeaders { for (k, v) in rawHeaders { headers.updateValue(v, forKey: k) } } default:break } return headers } func content() -> (length: Int, write: (HttpResponseBodyWriter throws -> Void)?) { switch self { case .OK(let body) : return body.content() case .BadRequest(let body) : return body?.content() ?? (-1, nil) case .RAW(_, _, _, let writer) : return (-1, writer) default : return (-1, nil) } } func socketSession() -> (Socket -> Void)? { switch self { case SwitchProtocols(_, let handler) : return handler default: return nil } } } /** Makes it possible to compare handler responses with '==', but ignores any associated values. This should generally be what you want. E.g.: let resp = handler(updatedRequest) if resp == .NotFound { print("Client requested not found: \(request.url)") } */ func ==(inLeft: HttpResponse, inRight: HttpResponse) -> Bool { return inLeft.statusCode() == inRight.statusCode() } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpRouter.swift ================================================ // // HttpRouter.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation public class HttpRouter { private class Node { var nodes = [String: Node]() var handler: (HttpRequest -> HttpResponse)? = nil } private var rootNode = Node() public func routes() -> [String] { var routes = [String]() for (_, child) in rootNode.nodes { routes.appendContentsOf(routesForNode(child)); } return routes } private func routesForNode(node: Node, prefix: String = "") -> [String] { var result = [String]() if let _ = node.handler { result.append(prefix) } for (key, child) in node.nodes { result.appendContentsOf(routesForNode(child, prefix: prefix + "/" + key)); } return result } public func register(method: String?, path: String, handler: (HttpRequest -> HttpResponse)?) { var pathSegments = stripQuery(path).split("/") if let method = method { pathSegments.insert(method, atIndex: 0) } else { pathSegments.insert("*", atIndex: 0) } var pathSegmentsGenerator = pathSegments.generate() inflate(&rootNode, generator: &pathSegmentsGenerator).handler = handler } public func route(method: String?, path: String) -> ([String: String], HttpRequest -> HttpResponse)? { if let method = method { let pathSegments = (method + "/" + stripQuery(path)).split("/") var pathSegmentsGenerator = pathSegments.generate() var params = [String:String]() if let handler = findHandler(&rootNode, params: ¶ms, generator: &pathSegmentsGenerator) { return (params, handler) } } let pathSegments = ("*/" + stripQuery(path)).split("/") var pathSegmentsGenerator = pathSegments.generate() var params = [String:String]() if let handler = findHandler(&rootNode, params: ¶ms, generator: &pathSegmentsGenerator) { return (params, handler) } return nil } private func inflate(inout node: Node, inout generator: IndexingGenerator<[String]>) -> Node { if let pathSegment = generator.next() { if let _ = node.nodes[pathSegment] { return inflate(&node.nodes[pathSegment]!, generator: &generator) } var nextNode = Node() node.nodes[pathSegment] = nextNode return inflate(&nextNode, generator: &generator) } return node } private func findHandler(inout node: Node, inout params: [String: String], inout generator: IndexingGenerator<[String]>) -> (HttpRequest -> HttpResponse)? { guard let pathToken = generator.next() else { return node.handler } let variableNodes = node.nodes.filter { $0.0.characters.first == ":" } if let variableNode = variableNodes.first { if variableNode.1.nodes.count == 0 { // if it's the last element of the pattern and it's a variable, stop the search and // append a tail as a value for the variable. let tail = generator.joinWithSeparator("/") if tail.utf8.count > 0 { params[variableNode.0] = pathToken + "/" + tail } else { params[variableNode.0] = pathToken } return variableNode.1.handler } params[variableNode.0] = pathToken return findHandler(&node.nodes[variableNode.0]!, params: ¶ms, generator: &generator) } if let _ = node.nodes[pathToken] { return findHandler(&node.nodes[pathToken]!, params: ¶ms, generator: &generator) } if let _ = node.nodes["*"] { return findHandler(&node.nodes["*"]!, params: ¶ms, generator: &generator) } return nil } private func stripQuery(path: String) -> String { if let path = path.split("?").first { return path } return path } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpServer.swift ================================================ // // HttpServer2.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation public class HttpServer: HttpServerIO { public static let VERSION = "1.1.3" private let router = HttpRouter() public override init() { self.DELETE = MethodRoute(method: "DELETE", router: router) self.UPDATE = MethodRoute(method: "UPDATE", router: router) self.HEAD = MethodRoute(method: "HEAD", router: router) self.POST = MethodRoute(method: "POST", router: router) self.GET = MethodRoute(method: "GET", router: router) self.PUT = MethodRoute(method: "PUT", router: router) self.delete = MethodRoute(method: "DELETE", router: router) self.update = MethodRoute(method: "UPDATE", router: router) self.head = MethodRoute(method: "HEAD", router: router) self.post = MethodRoute(method: "POST", router: router) self.get = MethodRoute(method: "GET", router: router) self.put = MethodRoute(method: "PUT", router: router) } public var DELETE, UPDATE, HEAD, POST, GET, PUT : MethodRoute public var delete, update, head, post, get, put : MethodRoute public subscript(path: String) -> (HttpRequest -> HttpResponse)? { set { router.register(nil, path: path, handler: newValue) } get { return nil } } public var routes: [String] { return router.routes(); } override public func dispatch(method: String, path: String) -> ([String:String], HttpRequest -> HttpResponse) { if let result = router.route(method, path: path) { return result } return super.dispatch(method, path: path) } public struct MethodRoute { public let method: String public let router: HttpRouter public subscript(path: String) -> (HttpRequest -> HttpResponse)? { set { router.register(method, path: path, handler: newValue) } get { return nil } } } } ================================================ FILE: Sublime/Pods/Swifter/Sources/HttpServerIO.swift ================================================ // // HttpServer.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // import Foundation #if os(Linux) import Glibc import NSLinux #endif public class HttpServerIO { private var listenSocket: Socket = Socket(socketFileDescriptor: -1) private var clientSockets: Set = [] private let clientSocketsLock = NSLock() public func start(listenPort: in_port_t = 8080) throws { stop() listenSocket = try Socket.tcpSocketForListen(listenPort) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { while let socket = try? self.listenSocket.acceptClientSocket() { self.lock(self.clientSocketsLock) { self.clientSockets.insert(socket) } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { self.handleConnection(socket) self.lock(self.clientSocketsLock) { self.clientSockets.remove(socket) } }) } self.stop() } } public func stop() { listenSocket.release() lock(self.clientSocketsLock) { for socket in self.clientSockets { socket.shutdwn() } self.clientSockets.removeAll(keepCapacity: true) } } public func dispatch(method: String, path: String) -> ([String: String], HttpRequest -> HttpResponse) { return ([:], { _ in HttpResponse.NotFound }) } private func handleConnection(socket: Socket) { let address = try? socket.peername() let parser = HttpParser() while let request = try? parser.readHttpRequest(socket) { let request = request let (params, handler) = self.dispatch(request.method, path: request.path) request.address = address request.params = params; let response = handler(request) var keepConnection = parser.supportsKeepAlive(request.headers) do { keepConnection = try self.respond(socket, response: response, keepAlive: keepConnection) } catch { print("Failed to send response: \(error)") break } if let session = response.socketSession() { session(socket) break } if !keepConnection { break } } socket.release() } private func lock(handle: NSLock, closure: () -> ()) { handle.lock() closure() handle.unlock(); } private struct InnerWriteContext: HttpResponseBodyWriter { let socket: Socket func write(data: [UInt8]) { write(ArraySlice(data)) } func write(data: ArraySlice) { do { try socket.writeUInt8(data) } catch { print("\(error)") } } } private func respond(socket: Socket, response: HttpResponse, keepAlive: Bool) throws -> Bool { try socket.writeUTF8("HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n") let content = response.content() if content.length >= 0 { try socket.writeUTF8("Content-Length: \(content.length)\r\n") } if keepAlive && content.length != -1 { try socket.writeUTF8("Connection: keep-alive\r\n") } for (name, value) in response.headers() { try socket.writeUTF8("\(name): \(value)\r\n") } try socket.writeUTF8("\r\n") if let writeClosure = content.write { let context = InnerWriteContext(socket: socket) try writeClosure(context) } return keepAlive && content.length != -1; } } ================================================ FILE: Sublime/Pods/Swifter/Sources/Socket.swift ================================================ // // Socket.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif /* Low level routines for POSIX sockets */ public enum SocketError: ErrorType { case SocketCreationFailed(String) case SocketSettingReUseAddrFailed(String) case BindFailed(String) case ListenFailed(String) case WriteFailed(String) case GetPeerNameFailed(String) case ConvertingPeerNameFailed case GetNameInfoFailed(String) case AcceptFailed(String) case RecvFailed(String) } public class Socket: Hashable, Equatable { public class func tcpSocketForListen(port: in_port_t, maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket { #if os(Linux) let socketFileDescriptor = socket(AF_INET, Int32(SOCK_STREAM.rawValue), 0) #else let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0) #endif if socketFileDescriptor == -1 { throw SocketError.SocketCreationFailed(Socket.descriptionOfLastError()) } var value: Int32 = 1 if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 { let details = Socket.descriptionOfLastError() Socket.release(socketFileDescriptor) throw SocketError.SocketSettingReUseAddrFailed(details) } Socket.setNoSigPipe(socketFileDescriptor) #if os(Linux) var addr = sockaddr_in() addr.sin_family = sa_family_t(AF_INET) addr.sin_port = Socket.htonsPort(port) addr.sin_addr = in_addr(s_addr: in_addr_t(0)) addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0) #else var addr = sockaddr_in() addr.sin_len = __uint8_t(sizeof(sockaddr_in)) addr.sin_family = sa_family_t(AF_INET) addr.sin_port = Socket.htonsPort(port) addr.sin_addr = in_addr(s_addr: inet_addr("0.0.0.0")) addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0) #endif var bind_addr = sockaddr() memcpy(&bind_addr, &addr, Int(sizeof(sockaddr_in))) if bind(socketFileDescriptor, &bind_addr, socklen_t(sizeof(sockaddr_in))) == -1 { let details = Socket.descriptionOfLastError() Socket.release(socketFileDescriptor) throw SocketError.BindFailed(details) } if listen(socketFileDescriptor, maxPendingConnection ) == -1 { let details = Socket.descriptionOfLastError() Socket.release(socketFileDescriptor) throw SocketError.ListenFailed(details) } return Socket(socketFileDescriptor: socketFileDescriptor) } private let socketFileDescriptor: Int32 public init(socketFileDescriptor: Int32) { self.socketFileDescriptor = socketFileDescriptor } public var hashValue: Int { return Int(self.socketFileDescriptor) } public func release() { Socket.release(self.socketFileDescriptor) } public func shutdwn() { Socket.shutdwn(self.socketFileDescriptor) } public func acceptClientSocket() throws -> Socket { var addr = sockaddr() var len: socklen_t = 0 let clientSocket = accept(self.socketFileDescriptor, &addr, &len) if clientSocket == -1 { throw SocketError.AcceptFailed(Socket.descriptionOfLastError()) } Socket.setNoSigPipe(clientSocket) return Socket(socketFileDescriptor: clientSocket) } public func writeUTF8(string: String) throws { try writeUInt8(ArraySlice(string.utf8)) } public func writeUInt8(data: [UInt8]) throws { try writeUInt8(ArraySlice(data)) } public func writeUInt8(data: ArraySlice) throws { try data.withUnsafeBufferPointer { var sent = 0 while sent < data.count { #if os(Linux) let s = send(self.socketFileDescriptor, $0.baseAddress + sent, Int(data.count - sent), Int32(MSG_NOSIGNAL)) #else let s = write(self.socketFileDescriptor, $0.baseAddress + sent, Int(data.count - sent)) #endif if s <= 0 { throw SocketError.WriteFailed(Socket.descriptionOfLastError()) } sent += s } } } public func read() throws -> UInt8 { var buffer = [UInt8](count: 1, repeatedValue: 0) let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0) if next <= 0 { throw SocketError.RecvFailed(Socket.descriptionOfLastError()) } return buffer[0] } private static let CR = UInt8(13) private static let NL = UInt8(10) public func readLine() throws -> String { var characters: String = "" var n: UInt8 = 0 repeat { n = try self.read() if n > Socket.CR { characters.append(Character(UnicodeScalar(n))) } } while n != Socket.NL return characters } public func peername() throws -> String { var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr)) if getpeername(self.socketFileDescriptor, &addr, &len) != 0 { throw SocketError.GetPeerNameFailed(Socket.descriptionOfLastError()) } var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0) if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 { throw SocketError.GetNameInfoFailed(Socket.descriptionOfLastError()) } guard let name = String.fromCString(hostBuffer) else { throw SocketError.ConvertingPeerNameFailed } return name } private class func descriptionOfLastError() -> String { return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)" } private class func setNoSigPipe(socket: Int32) { #if os(Linux) // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(), // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE. #else // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ). var no_sig_pipe: Int32 = 1 setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32))) #endif } private class func shutdwn(socket: Int32) { #if os(Linux) shutdown(socket, Int32(SHUT_RDWR)) #else Darwin.shutdown(socket, SHUT_RDWR) #endif } private class func release(socket: Int32) { #if os(Linux) shutdown(socket, Int32(SHUT_RDWR)) #else Darwin.shutdown(socket, SHUT_RDWR) #endif close(socket) } private class func htonsPort(port: in_port_t) -> in_port_t { #if os(Linux) return htons(port) #else let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian return isLittleEndian ? _OSSwapInt16(port) : port #endif } } public func ==(socket1: Socket, socket2: Socket) -> Bool { return socket1.socketFileDescriptor == socket2.socketFileDescriptor } ================================================ FILE: Sublime/Pods/Swifter/Sources/String+BASE64.swift ================================================ // // String+BASE64.swift // Swifter // // Copyright © 2016 Damian Kołakowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif extension String { private static let CODES = [UInt8]("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".utf8) public static func toBase64(data: [UInt8]) -> String { // Based on: https://en.wikipedia.org/wiki/Base64#Sample_Implementation_in_Java var result = [UInt8]() var tmp: UInt8 for index in 0.stride(to: data.count, by: 3) { let byte = data[index] tmp = (byte & 0xFC) >> 2; result.append(CODES[Int(tmp)]) tmp = (byte & 0x03) << 4; if index + 1 < data.count { tmp |= (data[index + 1] & 0xF0) >> 4; result.append(CODES[Int(tmp)]); tmp = (data[index + 1] & 0x0F) << 2; if (index + 2 < data.count) { tmp |= (data[index + 2] & 0xC0) >> 6; result.append(CODES[Int(tmp)]); tmp = data[index + 2] & 0x3F; result.append(CODES[Int(tmp)]); } else { result.append(CODES[Int(tmp)]); result.appendContentsOf([UInt8]("=".utf8)); } } else { result.append(CODES[Int(tmp)]); result.appendContentsOf([UInt8]("==".utf8)); } } return String.fromUInt8(result) } } ================================================ FILE: Sublime/Pods/Swifter/Sources/String+Misc.swift ================================================ // // String+Misc.swift // Swifter // // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif extension String { public func split(separator: Character) -> [String] { return self.characters.split { $0 == separator }.map(String.init) } public func split(maxSplit: Int = Int.max, separator: Character) -> [String] { return self.characters.split(maxSplit) { $0 == separator }.map(String.init) } public func replace(old: Character, _ new: Character) -> String { var buffer = [Character]() self.characters.forEach { buffer.append($0 == old ? new : $0) } return String(buffer) } public func unquote() -> String { var scalars = self.unicodeScalars; if scalars.first == "\"" && scalars.last == "\"" && scalars.count >= 2 { scalars.removeFirst(); scalars.removeLast(); return String(scalars) } return self } public func trim() -> String { var scalars = self.unicodeScalars while let _ = scalars.first?.asWhitespace() { scalars.removeFirst() } while let _ = scalars.last?.asWhitespace() { scalars.removeLast() } return String(scalars) } public static func fromUInt8(array: [UInt8]) -> String { // Apple changes the definition of String(data: .... ) every release so let's stay with 'fromUInt8(...)' wrapper. return array.reduce("", combine: { $0.0 + String(UnicodeScalar($0.1)) }) } public func removePercentEncoding() -> String { var scalars = self.unicodeScalars var output = "" var decodeBuffer = [UInt8]() while let scalar = scalars.popFirst() { if scalar == "%" { let first = scalars.popFirst() let secon = scalars.popFirst() if let first = first?.asAlpha(), secon = secon?.asAlpha() { decodeBuffer.append(first*16+secon) } else { if !decodeBuffer.isEmpty { output.appendContentsOf(String.fromUInt8(decodeBuffer)) decodeBuffer.removeAll() } if let first = first { output.append(Character(first)) } if let secon = secon { output.append(Character(secon)) } } } else { if !decodeBuffer.isEmpty { output.appendContentsOf(String.fromUInt8(decodeBuffer)) decodeBuffer.removeAll() } output.append(Character(scalar)) } } if !decodeBuffer.isEmpty { output.appendContentsOf(String.fromUInt8(decodeBuffer)) decodeBuffer.removeAll() } return output } } extension UnicodeScalar { public func asWhitespace() -> UInt8? { if self.value >= 9 && self.value <= 13 { return UInt8(self.value) } if self.value == 32 { return UInt8(self.value) } return nil } public func asAlpha() -> UInt8? { if self.value >= 48 && self.value <= 57 { return UInt8(self.value) - 48 } if self.value >= 97 && self.value <= 102 { return UInt8(self.value) - 87 } if self.value >= 65 && self.value <= 70 { return UInt8(self.value) - 55 } return nil } } ================================================ FILE: Sublime/Pods/Swifter/Sources/String+SHA1.swift ================================================ // // String+SHA1.swift // Swifter // // Copyright 2014-2016 Damian Kołakowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif extension String { public func SHA1() -> String { return SHA1().reduce("") { $0 + String(format: "%02x", $1) } } public func SHA1() -> [UInt8] { // Alghorithm from: https://en.wikipedia.org/wiki/SHA-1 var message = [UInt8](self.utf8) var h0 = UInt32(littleEndian: 0x67452301) var h1 = UInt32(littleEndian: 0xEFCDAB89) var h2 = UInt32(littleEndian: 0x98BADCFE) var h3 = UInt32(littleEndian: 0x10325476) var h4 = UInt32(littleEndian: 0xC3D2E1F0) // ml = message length in bits (always a multiple of the number of bits in a character). let ml = UInt64(message.count * 8) // append the bit '1' to the message e.g. by adding 0x80 if message length is a multiple of 8 bits. message.append(0x80) // append 0 ≤ k < 512 bits '0', such that the resulting message length in bits is congruent to −64 ≡ 448 (mod 512) let padBytesCount = ( message.count + 8 ) % 64 message.appendContentsOf([UInt8](count: 64 - padBytesCount, repeatedValue: 0)) // append ml, in a 64-bit big-endian integer. Thus, the total length is a multiple of 512 bits. var mlBigEndian = ml.bigEndian let bytePtr = withUnsafePointer(&mlBigEndian) { UnsafeBufferPointer(start: UnsafePointer($0), count: sizeofValue(mlBigEndian)) } message.appendContentsOf(Array(bytePtr)) // Process the message in successive 512-bit chunks ( 64 bytes chunks ): for chunkStart in 0..($0.baseAddress + (i*4)).memory }) words.append(value.bigEndian) } // Extend the sixteen 32-bit words into eighty 32-bit words: for i in 16...79 { let value = words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16] words.append(rotateLeft(value, 1)) } // Initialize hash value for this chunk: var a = h0 var b = h1 var c = h2 var d = h3 var e = h4 for i in 0..<80 { var f = UInt32(0) var k = UInt32(0) switch i { case 0...19: f = (b & c) | ((~b) & d) k = 0x5A827999 case 20...39: f = b ^ c ^ d k = 0x6ED9EBA1 case 40...59: f = (b & c) | (b & d) | (c & d) k = 0x8F1BBCDC case 60...79: f = b ^ c ^ d k = 0xCA62C1D6 default: break } let temp = (rotateLeft(a, 5) &+ f &+ e &+ k &+ words[i]) & 0xFFFFFFFF e = d d = c c = rotateLeft(b, 30) b = a a = temp } // Add this chunk's hash to result so far: h0 = ( h0 &+ a ) & 0xFFFFFFFF h1 = ( h1 &+ b ) & 0xFFFFFFFF h2 = ( h2 &+ c ) & 0xFFFFFFFF h3 = ( h3 &+ d ) & 0xFFFFFFFF h4 = ( h4 &+ e ) & 0xFFFFFFFF } // Produce the final hash value (big-endian) as a 160 bit number: var result = [UInt8]() let h0Big = h0.bigEndian let h1Big = h1.bigEndian let h2Big = h2.bigEndian let h3Big = h3.bigEndian let h4Big = h4.bigEndian result += ([UInt8(h0Big & 0xFF), UInt8((h0Big >> 8) & 0xFF), UInt8((h0Big >> 16) & 0xFF), UInt8((h0Big >> 24) & 0xFF)]); result += ([UInt8(h1Big & 0xFF), UInt8((h1Big >> 8) & 0xFF), UInt8((h1Big >> 16) & 0xFF), UInt8((h1Big >> 24) & 0xFF)]); result += ([UInt8(h2Big & 0xFF), UInt8((h2Big >> 8) & 0xFF), UInt8((h2Big >> 16) & 0xFF), UInt8((h2Big >> 24) & 0xFF)]); result += ([UInt8(h3Big & 0xFF), UInt8((h3Big >> 8) & 0xFF), UInt8((h3Big >> 16) & 0xFF), UInt8((h3Big >> 24) & 0xFF)]); result += ([UInt8(h4Big & 0xff), UInt8((h4Big >> 8) & 0xFF), UInt8((h4Big >> 16) & 0xFF), UInt8((h4Big >> 24) & 0xFF)]); return result; } func rotateLeft(v: UInt32, _ n: UInt32) -> UInt32 { return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n)) } } ================================================ FILE: Sublime/Pods/SwiftyJSON/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Ruoyu Fu 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/SwiftyJSON/README.md ================================================ #SwiftyJSON [中文介绍](http://tangplin.github.io/swiftyjson/) [![Travis CI](https://travis-ci.org/SwiftyJSON/SwiftyJSON.svg?branch=master)](https://travis-ci.org/SwiftyJSON/SwiftyJSON) SwiftyJSON makes it easy to deal with JSON data in Swift. 1. [Why is the typical JSON handling in Swift NOT good](#why-is-the-typical-json-handling-in-swift-not-good) 1. [Requirements](#requirements) 1. [Integration](#integration) 1. [Usage](#usage) - [Initialization](#initialization) - [Subscript](#subscript) - [Loop](#loop) - [Error](#error) - [Optional getter](#optional-getter) - [Non-optional getter](#non-optional-getter) - [Setter](#setter) - [Raw object](#raw-object) - [Literal convertibles](#literal-convertibles) 1. [Work with Alamofire](#work-with-alamofire) ##Why is the typical JSON handling in Swift NOT good? Swift is very strict about types. But although explicit typing is good for saving us from mistakes, it becomes painful when dealing with JSON and other areas that are, by nature, implicit about types. Take the Twitter API for example. Say we want to retrieve a user's "name" value of some tweet in Swift (according to Twitter's API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline). The code would look like this: ```swift if let statusesArray = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]], let user = statusesArray[0]["user"] as? [String: AnyObject], let username = user["name"] as? String { // Finally we got the username } ``` It's not good. Even if we use optional chaining, it would be messy: ```swift if let JSONObject = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]], let username = (JSONObject[0]["user"] as? [String: AnyObject])?["name"] as? String { // There's our username } ``` An unreadable mess--for something that should really be simple! With SwiftyJSON all you have to do is: ```swift let json = JSON(data: dataFromNetworking) if let userName = json[0]["user"]["name"].string { //Now you got your value } ``` And don't worry about the Optional Wrapping thing. It's done for you automatically. ```swift let json = JSON(data: dataFromNetworking) if let userName = json[999999]["wrong_key"]["wrong_name"].string { //Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety } else { //Print the error print(json[999999]["wrong_key"]["wrong_name"]) } ``` ## Requirements - iOS 7.0+ / Mac OS X 10.9+ - Xcode 7 ##Integration ####CocoaPods (iOS 8+, OS X 10.9+) You can use [Cocoapods](http://cocoapods.org/) to install `SwiftyJSON`by adding it to your `Podfile`: ```ruby platform :ios, '8.0' use_frameworks! target 'MyApp' do pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git' end ``` Note that this requires CocoaPods version 36, and your iOS deployment target to be at least 8.0: ####Carthage (iOS 8+, OS X 10.9+) You can use [Carthage](https://github.com/Carthage/Carthage) to install `SwiftyJSON` by adding it to your `Cartfile`: ``` github "SwiftyJSON/SwiftyJSON" ``` ####Manually (iOS 7+, OS X 10.9+) To use this library in your project manually you may: 1. for Projects, just drag SwiftyJSON.swift to the project tree 2. for Workspaces, include the whole SwiftyJSON.xcodeproj ## Usage ####Initialization ```swift import SwiftyJSON ``` ```swift let json = JSON(data: dataFromNetworking) ``` ```swift let json = JSON(jsonObject) ``` ```swift if let dataFromString = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { let json = JSON(data: dataFromString) } ``` ####Subscript ```swift //Getting a double from a JSON Array let name = json[0].double ``` ```swift //Getting a string from a JSON Dictionary let name = json["name"].stringValue ``` ```swift //Getting a string using a path to the element let path = [1,"list",2,"name"] let name = json[path].string //Just the same let name = json[1]["list"][2]["name"].string //Alternatively let name = json[1,"list",2,"name"].string ``` ```swift //With a hard way let name = json[].string ``` ```swift //With a custom way let keys:[SubscriptType] = [1,"list",2,"name"] let name = json[keys].string ``` ####Loop ```swift //If json is .Dictionary for (key,subJson):(String, JSON) in json { //Do something you want } ``` *The first element is always a String, even if the JSON is an Array* ```swift //If json is .Array //The `index` is 0.. = json["list"].arrayValue ``` ```swift //If not a Dictionary or nil, return [:] let user: Dictionary = json["user"].dictionaryValue ``` ####Setter ```swift json["name"] = JSON("new-name") json[0] = JSON(1) ``` ```swift json["id"].int = 1234567890 json["coordinate"].double = 8766.766 json["name"].string = "Jack" json.arrayObject = [1,2,3,4] json.dictionary = ["name":"Jack", "age":25] ``` ####Raw object ```swift let jsonObject: AnyObject = json.object ``` ```swift if let jsonObject: AnyObject = json.rawValue ``` ```swift //convert the JSON to raw NSData if let data = json.rawData() { //Do something you want } ``` ```swift //convert the JSON to a raw String if let string = json.rawString() { //Do something you want } ``` ####Existance ```swift //shows you whether value specified in JSON or not if json["name"].isExists() ``` ####Literal convertibles For more info about literal convertibles: [Swift Literal Convertibles](http://nshipster.com/swift-literal-convertible/) ```swift //StringLiteralConvertible let json: JSON = "I'm a json" ``` ```swift //IntegerLiteralConvertible let json: JSON = 12345 ``` ```swift //BooleanLiteralConvertible let json: JSON = true ``` ```swift //FloatLiteralConvertible let json: JSON = 2.8765 ``` ```swift //DictionaryLiteralConvertible let json: JSON = ["I":"am", "a":"json"] ``` ```swift //ArrayLiteralConvertible let json: JSON = ["I", "am", "a", "json"] ``` ```swift //NilLiteralConvertible let json: JSON = nil ``` ```swift //With subscript in array var json: JSON = [1,2,3] json[0] = 100 json[1] = 200 json[2] = 300 json[999] = 300 //Don't worry, nothing will happen ``` ```swift //With subscript in dictionary var json: JSON = ["name": "Jack", "age": 25] json["name"] = "Mike" json["age"] = "25" //It's OK to set String json["address"] = "L.A." // Add the "address": "L.A." in json ``` ```swift //Array & Dictionary var json: JSON = ["name": "Jack", "age": 25, "list": ["a", "b", "c", ["what": "this"]]] json["list"][3]["what"] = "that" json["list",3,"what"] = "that" let path = ["list",3,"what"] json[path] = "that" ``` ##Work with Alamofire SwiftyJSON nicely wraps the result of the Alamofire JSON response handler: ```swift Alamofire.request(.GET, url).validate().responseJSON { response in switch response.result { case .Success: if let value = response.result.value { let json = JSON(value) print("JSON: \(json)") } case .Failure(let error): print(error) } } ``` ================================================ FILE: Sublime/Pods/SwiftyJSON/Source/SwiftyJSON.swift ================================================ // SwiftyJSON.swift // // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang // // 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: - Error ///Error domain public let ErrorDomain: String = "SwiftyJSONErrorDomain" ///Error code public let ErrorUnsupportedType: Int = 999 public let ErrorIndexOutOfBounds: Int = 900 public let ErrorWrongType: Int = 901 public let ErrorNotExist: Int = 500 public let ErrorInvalidJSON: Int = 490 // MARK: - JSON Type /** JSON's type definitions. See http://www.json.org */ public enum Type :Int{ case Number case String case Bool case Array case Dictionary case Null case Unknown } // MARK: - JSON Base public struct JSON { /** Creates a JSON using the data. - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary - parameter opt: The JSON serialization reading options. `.AllowFragments` by default. - parameter error: error The NSErrorPointer used to return the error. `nil` by default. - returns: The created JSON */ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) { do { let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt) self.init(object) } catch let aError as NSError { if error != nil { error.memory = aError } self.init(NSNull()) } } /** Create a JSON from JSON string - parameter string: Normal json string like '{"a":"b"}' - returns: The created JSON */ public static func parse(string:String) -> JSON { return string.dataUsingEncoding(NSUTF8StringEncoding) .flatMap({JSON(data: $0)}) ?? JSON(NSNull()) } /** Creates a JSON using the object. - parameter object: The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity. - returns: The created JSON */ public init(_ object: AnyObject) { self.object = object } /** Creates a JSON from a [JSON] - parameter jsonArray: A Swift array of JSON objects - returns: The created JSON */ public init(_ jsonArray:[JSON]) { self.init(jsonArray.map { $0.object }) } /** Creates a JSON from a [String: JSON] - parameter jsonDictionary: A Swift dictionary of JSON objects - returns: The created JSON */ public init(_ jsonDictionary:[String: JSON]) { var dictionary = [String: AnyObject]() for (key, json) in jsonDictionary { dictionary[key] = json.object } self.init(dictionary) } /// Private object private var rawArray: [AnyObject] = [] private var rawDictionary: [String : AnyObject] = [:] private var rawString: String = "" private var rawNumber: NSNumber = 0 private var rawNull: NSNull = NSNull() /// Private type private var _type: Type = .Null /// prviate error private var _error: NSError? = nil /// Object in JSON public var object: AnyObject { get { switch self.type { case .Array: return self.rawArray case .Dictionary: return self.rawDictionary case .String: return self.rawString case .Number: return self.rawNumber case .Bool: return self.rawNumber default: return self.rawNull } } set { _error = nil switch newValue { case let number as NSNumber: if number.isBool { _type = .Bool } else { _type = .Number } self.rawNumber = number case let string as String: _type = .String self.rawString = string case _ as NSNull: _type = .Null case let array as [AnyObject]: _type = .Array self.rawArray = array case let dictionary as [String : AnyObject]: _type = .Dictionary self.rawDictionary = dictionary default: _type = .Unknown _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"]) } } } /// json type public var type: Type { get { return _type } } /// Error in JSON public var error: NSError? { get { return self._error } } /// The static null json @available(*, unavailable, renamed="null") public static var nullJSON: JSON { get { return null } } public static var null: JSON { get { return JSON(NSNull()) } } } // MARK: - CollectionType, SequenceType, Indexable extension JSON : Swift.CollectionType, Swift.SequenceType, Swift.Indexable { public typealias Generator = JSONGenerator public typealias Index = JSONIndex public var startIndex: JSON.Index { switch self.type { case .Array: return JSONIndex(arrayIndex: self.rawArray.startIndex) case .Dictionary: return JSONIndex(dictionaryIndex: self.rawDictionary.startIndex) default: return JSONIndex() } } public var endIndex: JSON.Index { switch self.type { case .Array: return JSONIndex(arrayIndex: self.rawArray.endIndex) case .Dictionary: return JSONIndex(dictionaryIndex: self.rawDictionary.endIndex) default: return JSONIndex() } } public subscript (position: JSON.Index) -> JSON.Generator.Element { switch self.type { case .Array: return (String(position.arrayIndex), JSON(self.rawArray[position.arrayIndex!])) case .Dictionary: let (key, value) = self.rawDictionary[position.dictionaryIndex!] return (key, JSON(value)) default: return ("", JSON.null) } } /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `true`. public var isEmpty: Bool { get { switch self.type { case .Array: return self.rawArray.isEmpty case .Dictionary: return self.rawDictionary.isEmpty default: return true } } } /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`. public var count: Int { switch self.type { case .Array: return self.rawArray.count case .Dictionary: return self.rawDictionary.count default: return 0 } } public func underestimateCount() -> Int { switch self.type { case .Array: return self.rawArray.underestimateCount() case .Dictionary: return self.rawDictionary.underestimateCount() default: return 0 } } /** If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary`, otherwise return a generator over empty. - returns: Return a *generator* over the elements of JSON. */ public func generate() -> JSON.Generator { return JSON.Generator(self) } } public struct JSONIndex: ForwardIndexType, _Incrementable, Equatable, Comparable { let arrayIndex: Int? let dictionaryIndex: DictionaryIndex? let type: Type init(){ self.arrayIndex = nil self.dictionaryIndex = nil self.type = .Unknown } init(arrayIndex: Int) { self.arrayIndex = arrayIndex self.dictionaryIndex = nil self.type = .Array } init(dictionaryIndex: DictionaryIndex) { self.arrayIndex = nil self.dictionaryIndex = dictionaryIndex self.type = .Dictionary } public func successor() -> JSONIndex { switch self.type { case .Array: return JSONIndex(arrayIndex: self.arrayIndex!.successor()) case .Dictionary: return JSONIndex(dictionaryIndex: self.dictionaryIndex!.successor()) default: return JSONIndex() } } } public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex == rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex == rhs.dictionaryIndex default: return false } } public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex < rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex < rhs.dictionaryIndex default: return false } } public func <=(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex <= rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex <= rhs.dictionaryIndex default: return false } } public func >=(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex >= rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex >= rhs.dictionaryIndex default: return false } } public func >(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex > rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex > rhs.dictionaryIndex default: return false } } public struct JSONGenerator : GeneratorType { public typealias Element = (String, JSON) private let type: Type private var dictionayGenerate: DictionaryGenerator? private var arrayGenerate: IndexingGenerator<[AnyObject]>? private var arrayIndex: Int = 0 init(_ json: JSON) { self.type = json.type if type == .Array { self.arrayGenerate = json.rawArray.generate() }else { self.dictionayGenerate = json.rawDictionary.generate() } } public mutating func next() -> JSONGenerator.Element? { switch self.type { case .Array: if let o = self.arrayGenerate?.next() { return (String(self.arrayIndex++), JSON(o)) } else { return nil } case .Dictionary: if let (k, v): (String, AnyObject) = self.dictionayGenerate?.next() { return (k, JSON(v)) } else { return nil } default: return nil } } } // MARK: - Subscript /** * To mark both String and Int can be used in subscript. */ public enum JSONKey { case Index(Int) case Key(String) } public protocol JSONSubscriptType { var jsonKey:JSONKey { get } } extension Int: JSONSubscriptType { public var jsonKey:JSONKey { return JSONKey.Index(self) } } extension String: JSONSubscriptType { public var jsonKey:JSONKey { return JSONKey.Key(self) } } extension JSON { /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error. private subscript(index index: Int) -> JSON { get { if self.type != .Array { var r = JSON.null r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"]) return r } else if index >= 0 && index < self.rawArray.count { return JSON(self.rawArray[index]) } else { var r = JSON.null r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"]) return r } } set { if self.type == .Array { if self.rawArray.count > index && newValue.error == nil { self.rawArray[index] = newValue.object } } } } /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error. private subscript(key key: String) -> JSON { get { var r = JSON.null if self.type == .Dictionary { if let o = self.rawDictionary[key] { r = JSON(o) } else { r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"]) } } else { r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"]) } return r } set { if self.type == .Dictionary && newValue.error == nil { self.rawDictionary[key] = newValue.object } } } /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`. private subscript(sub sub: JSONSubscriptType) -> JSON { get { switch sub.jsonKey { case .Index(let index): return self[index: index] case .Key(let key): return self[key: key] } } set { switch sub.jsonKey { case .Index(let index): self[index: index] = newValue case .Key(let key): self[key: key] = newValue } } } /** Find a json in the complex data structuresby using the Int/String's array. - parameter path: The target json's path. Example: let json = JSON[data] let path = [9,"list","person","name"] let name = json[path] The same as: let name = json[9]["list"]["person"]["name"] - returns: Return a json found by the path or a null json with error */ public subscript(path: [JSONSubscriptType]) -> JSON { get { return path.reduce(self) { $0[sub: $1] } } set { switch path.count { case 0: return case 1: self[sub:path[0]].object = newValue.object default: var aPath = path; aPath.removeAtIndex(0) var nextJSON = self[sub: path[0]] nextJSON[aPath] = newValue self[sub: path[0]] = nextJSON } } } /** Find a json in the complex data structuresby using the Int/String's array. - parameter path: The target json's path. Example: let name = json[9,"list","person","name"] The same as: let name = json[9]["list"]["person"]["name"] - returns: Return a json found by the path or a null json with error */ public subscript(path: JSONSubscriptType...) -> JSON { get { return self[path] } set { self[path] = newValue } } } // MARK: - LiteralConvertible extension JSON: Swift.StringLiteralConvertible { public init(stringLiteral value: StringLiteralType) { self.init(value) } public init(extendedGraphemeClusterLiteral value: StringLiteralType) { self.init(value) } public init(unicodeScalarLiteral value: StringLiteralType) { self.init(value) } } extension JSON: Swift.IntegerLiteralConvertible { public init(integerLiteral value: IntegerLiteralType) { self.init(value) } } extension JSON: Swift.BooleanLiteralConvertible { public init(booleanLiteral value: BooleanLiteralType) { self.init(value) } } extension JSON: Swift.FloatLiteralConvertible { public init(floatLiteral value: FloatLiteralType) { self.init(value) } } extension JSON: Swift.DictionaryLiteralConvertible { public init(dictionaryLiteral elements: (String, AnyObject)...) { self.init(elements.reduce([String : AnyObject]()){(dictionary: [String : AnyObject], element:(String, AnyObject)) -> [String : AnyObject] in var d = dictionary d[element.0] = element.1 return d }) } } extension JSON: Swift.ArrayLiteralConvertible { public init(arrayLiteral elements: AnyObject...) { self.init(elements) } } extension JSON: Swift.NilLiteralConvertible { public init(nilLiteral: ()) { self.init(NSNull()) } } // MARK: - Raw extension JSON: Swift.RawRepresentable { public init?(rawValue: AnyObject) { if JSON(rawValue).type == .Unknown { return nil } else { self.init(rawValue) } } public var rawValue: AnyObject { return self.object } public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(rawValue: 0)) throws -> NSData { guard NSJSONSerialization.isValidJSONObject(self.object) else { throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"]) } return try NSJSONSerialization.dataWithJSONObject(self.object, options: opt) } public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? { switch self.type { case .Array, .Dictionary: do { let data = try self.rawData(options: opt) return NSString(data: data, encoding: encoding) as? String } catch _ { return nil } case .String: return self.rawString case .Number: return self.rawNumber.stringValue case .Bool: return self.rawNumber.boolValue.description case .Null: return "null" default: return nil } } } // MARK: - Printable, DebugPrintable extension JSON: Swift.Printable, Swift.DebugPrintable { public var description: String { if let string = self.rawString(options:.PrettyPrinted) { return string } else { return "unknown" } } public var debugDescription: String { return description } } // MARK: - Array extension JSON { //Optional [JSON] public var array: [JSON]? { get { if self.type == .Array { return self.rawArray.map{ JSON($0) } } else { return nil } } } //Non-optional [JSON] public var arrayValue: [JSON] { get { return self.array ?? [] } } //Optional [AnyObject] public var arrayObject: [AnyObject]? { get { switch self.type { case .Array: return self.rawArray default: return nil } } set { if let array = newValue { self.object = array } else { self.object = NSNull() } } } } // MARK: - Dictionary extension JSON { //Optional [String : JSON] public var dictionary: [String : JSON]? { if self.type == .Dictionary { return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, AnyObject)) -> [String : JSON] in var d = dictionary d[element.0] = JSON(element.1) return d } } else { return nil } } //Non-optional [String : JSON] public var dictionaryValue: [String : JSON] { return self.dictionary ?? [:] } //Optional [String : AnyObject] public var dictionaryObject: [String : AnyObject]? { get { switch self.type { case .Dictionary: return self.rawDictionary default: return nil } } set { if let v = newValue { self.object = v } else { self.object = NSNull() } } } } // MARK: - Bool extension JSON: Swift.BooleanType { //Optional bool public var bool: Bool? { get { switch self.type { case .Bool: return self.rawNumber.boolValue default: return nil } } set { if let newValue = newValue { self.object = NSNumber(bool: newValue) } else { self.object = NSNull() } } } //Non-optional bool public var boolValue: Bool { get { switch self.type { case .Bool, .Number, .String: return self.object.boolValue default: return false } } set { self.object = NSNumber(bool: newValue) } } } // MARK: - String extension JSON { //Optional string public var string: String? { get { switch self.type { case .String: return self.object as? String default: return nil } } set { if let newValue = newValue { self.object = NSString(string:newValue) } else { self.object = NSNull() } } } //Non-optional string public var stringValue: String { get { switch self.type { case .String: return self.object as? String ?? "" case .Number: return self.object.stringValue case .Bool: return (self.object as? Bool).map { String($0) } ?? "" default: return "" } } set { self.object = NSString(string:newValue) } } } // MARK: - Number extension JSON { //Optional number public var number: NSNumber? { get { switch self.type { case .Number, .Bool: return self.rawNumber default: return nil } } set { self.object = newValue ?? NSNull() } } //Non-optional number public var numberValue: NSNumber { get { switch self.type { case .String: let decimal = NSDecimalNumber(string: self.object as? String) if decimal == NSDecimalNumber.notANumber() { // indicates parse error return NSDecimalNumber.zero() } return decimal case .Number, .Bool: return self.object as? NSNumber ?? NSNumber(int: 0) default: return NSNumber(double: 0.0) } } set { self.object = newValue } } } //MARK: - Null extension JSON { public var null: NSNull? { get { switch self.type { case .Null: return self.rawNull default: return nil } } set { self.object = NSNull() } } public func isExists() -> Bool{ if let errorValue = error where errorValue.code == ErrorNotExist{ return false } return true } } //MARK: - URL extension JSON { //Optional URL public var URL: NSURL? { get { switch self.type { case .String: if let encodedString_ = self.rawString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) { return NSURL(string: encodedString_) } else { return nil } default: return nil } } set { self.object = newValue?.absoluteString ?? NSNull() } } } // MARK: - Int, Double, Float, Int8, Int16, Int32, Int64 extension JSON { public var double: Double? { get { return self.number?.doubleValue } set { if let newValue = newValue { self.object = NSNumber(double: newValue) } else { self.object = NSNull() } } } public var doubleValue: Double { get { return self.numberValue.doubleValue } set { self.object = NSNumber(double: newValue) } } public var float: Float? { get { return self.number?.floatValue } set { if let newValue = newValue { self.object = NSNumber(float: newValue) } else { self.object = NSNull() } } } public var floatValue: Float { get { return self.numberValue.floatValue } set { self.object = NSNumber(float: newValue) } } public var int: Int? { get { return self.number?.longValue } set { if let newValue = newValue { self.object = NSNumber(integer: newValue) } else { self.object = NSNull() } } } public var intValue: Int { get { return self.numberValue.integerValue } set { self.object = NSNumber(integer: newValue) } } public var uInt: UInt? { get { return self.number?.unsignedLongValue } set { if let newValue = newValue { self.object = NSNumber(unsignedLong: newValue) } else { self.object = NSNull() } } } public var uIntValue: UInt { get { return self.numberValue.unsignedLongValue } set { self.object = NSNumber(unsignedLong: newValue) } } public var int8: Int8? { get { return self.number?.charValue } set { if let newValue = newValue { self.object = NSNumber(char: newValue) } else { self.object = NSNull() } } } public var int8Value: Int8 { get { return self.numberValue.charValue } set { self.object = NSNumber(char: newValue) } } public var uInt8: UInt8? { get { return self.number?.unsignedCharValue } set { if let newValue = newValue { self.object = NSNumber(unsignedChar: newValue) } else { self.object = NSNull() } } } public var uInt8Value: UInt8 { get { return self.numberValue.unsignedCharValue } set { self.object = NSNumber(unsignedChar: newValue) } } public var int16: Int16? { get { return self.number?.shortValue } set { if let newValue = newValue { self.object = NSNumber(short: newValue) } else { self.object = NSNull() } } } public var int16Value: Int16 { get { return self.numberValue.shortValue } set { self.object = NSNumber(short: newValue) } } public var uInt16: UInt16? { get { return self.number?.unsignedShortValue } set { if let newValue = newValue { self.object = NSNumber(unsignedShort: newValue) } else { self.object = NSNull() } } } public var uInt16Value: UInt16 { get { return self.numberValue.unsignedShortValue } set { self.object = NSNumber(unsignedShort: newValue) } } public var int32: Int32? { get { return self.number?.intValue } set { if let newValue = newValue { self.object = NSNumber(int: newValue) } else { self.object = NSNull() } } } public var int32Value: Int32 { get { return self.numberValue.intValue } set { self.object = NSNumber(int: newValue) } } public var uInt32: UInt32? { get { return self.number?.unsignedIntValue } set { if let newValue = newValue { self.object = NSNumber(unsignedInt: newValue) } else { self.object = NSNull() } } } public var uInt32Value: UInt32 { get { return self.numberValue.unsignedIntValue } set { self.object = NSNumber(unsignedInt: newValue) } } public var int64: Int64? { get { return self.number?.longLongValue } set { if let newValue = newValue { self.object = NSNumber(longLong: newValue) } else { self.object = NSNull() } } } public var int64Value: Int64 { get { return self.numberValue.longLongValue } set { self.object = NSNumber(longLong: newValue) } } public var uInt64: UInt64? { get { return self.number?.unsignedLongLongValue } set { if let newValue = newValue { self.object = NSNumber(unsignedLongLong: newValue) } else { self.object = NSNull() } } } public var uInt64Value: UInt64 { get { return self.numberValue.unsignedLongLongValue } set { self.object = NSNumber(unsignedLongLong: newValue) } } } //MARK: - Comparable extension JSON : Swift.Comparable {} public func ==(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber == rhs.rawNumber case (.String, .String): return lhs.rawString == rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func <=(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber <= rhs.rawNumber case (.String, .String): return lhs.rawString <= rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func >=(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber >= rhs.rawNumber case (.String, .String): return lhs.rawString >= rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func >(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber > rhs.rawNumber case (.String, .String): return lhs.rawString > rhs.rawString default: return false } } public func <(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber < rhs.rawNumber case (.String, .String): return lhs.rawString < rhs.rawString default: return false } } private let trueNumber = NSNumber(bool: true) private let falseNumber = NSNumber(bool: false) private let trueObjCType = String.fromCString(trueNumber.objCType) private let falseObjCType = String.fromCString(falseNumber.objCType) // MARK: - NSNumber: Comparable extension NSNumber { var isBool:Bool { get { let objCType = String.fromCString(self.objCType) if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){ return true } else { return false } } } } func ==(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedSame } } func !=(lhs: NSNumber, rhs: NSNumber) -> Bool { return !(lhs == rhs) } func <(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedAscending } } func >(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedDescending } } func <=(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) != NSComparisonResult.OrderedDescending } } func >=(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) != NSComparisonResult.OrderedAscending } } ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/AASquaresLoading-dummy.m ================================================ #import @interface PodsDummy_AASquaresLoading : NSObject @end @implementation PodsDummy_AASquaresLoading @end ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/AASquaresLoading-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/AASquaresLoading-umbrella.h ================================================ #import FOUNDATION_EXPORT double AASquaresLoadingVersionNumber; FOUNDATION_EXPORT const unsigned char AASquaresLoadingVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/AASquaresLoading.modulemap ================================================ framework module AASquaresLoading { umbrella header "AASquaresLoading-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/AASquaresLoading.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/AASquaresLoading" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/AASquaresLoading/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 0.3.2 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Alamofire-dummy.m ================================================ #import @interface PodsDummy_Alamofire : NSObject @end @implementation PodsDummy_Alamofire @end ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h ================================================ #import FOUNDATION_EXPORT double AlamofireVersionNumber; FOUNDATION_EXPORT const unsigned char AlamofireVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Alamofire.modulemap ================================================ framework module Alamofire { umbrella header "Alamofire-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Alamofire.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Alamofire" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/Alamofire/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 3.2.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/AlamofireRSSParser-dummy.m ================================================ #import @interface PodsDummy_AlamofireRSSParser : NSObject @end @implementation PodsDummy_AlamofireRSSParser @end ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/AlamofireRSSParser-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/AlamofireRSSParser-umbrella.h ================================================ #import #import "AlamofireRSSParser.h" FOUNDATION_EXPORT double AlamofireRSSParserVersionNumber; FOUNDATION_EXPORT const unsigned char AlamofireRSSParserVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/AlamofireRSSParser.modulemap ================================================ framework module AlamofireRSSParser { umbrella header "AlamofireRSSParser-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/AlamofireRSSParser.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/AlamofireRSSParser" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/AlamofireRSSParser/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.2 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/CYRTextView-dummy.m ================================================ #import @interface PodsDummy_CYRTextView : NSObject @end @implementation PodsDummy_CYRTextView @end ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/CYRTextView-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/CYRTextView-umbrella.h ================================================ #import #import "CYRLayoutManager.h" #import "CYRTextStorage.h" #import "CYRTextView.h" #import "CYRToken.h" FOUNDATION_EXPORT double CYRTextViewVersionNumber; FOUNDATION_EXPORT const unsigned char CYRTextViewVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/CYRTextView.modulemap ================================================ framework module CYRTextView { umbrella header "CYRTextView-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/CYRTextView.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/CYRTextView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = -framework "CoreText" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/CYRTextView/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 0.4.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Charts-dummy.m ================================================ #import @interface PodsDummy_Charts : NSObject @end @implementation PodsDummy_Charts @end ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Charts-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Charts-umbrella.h ================================================ #import FOUNDATION_EXPORT double ChartsVersionNumber; FOUNDATION_EXPORT const unsigned char ChartsVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Charts.modulemap ================================================ framework module Charts { umbrella header "Charts-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Charts.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Charts" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/Charts/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 2.2.4 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh-dummy.m ================================================ #import @interface PodsDummy_DGElasticPullToRefresh : NSObject @end @implementation PodsDummy_DGElasticPullToRefresh @end ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh-umbrella.h ================================================ #import FOUNDATION_EXPORT double DGElasticPullToRefreshVersionNumber; FOUNDATION_EXPORT const unsigned char DGElasticPullToRefreshVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh.modulemap ================================================ framework module DGElasticPullToRefresh { umbrella header "DGElasticPullToRefresh-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/DGElasticPullToRefresh.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/DGElasticPullToRefresh" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = -framework "Foundation" -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/DGElasticPullToRefresh/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.3 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/EZAudio-dummy.m ================================================ #import @interface PodsDummy_EZAudio : NSObject @end @implementation PodsDummy_EZAudio @end ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/EZAudio-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/EZAudio-umbrella.h ================================================ #import #import "AEFloatConverter.h" #import "EZAudio.h" #import "EZAudioFile.h" #import "EZAudioPlayer.h" #import "EZAudioPlot.h" #import "EZAudioPlotGL.h" #import "EZAudioPlotGLKViewController.h" #import "EZMicrophone.h" #import "EZOutput.h" #import "EZPlot.h" #import "EZRecorder.h" #import "TPCircularBuffer.h" FOUNDATION_EXPORT double EZAudioVersionNumber; FOUNDATION_EXPORT const unsigned char EZAudioVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/EZAudio.modulemap ================================================ framework module EZAudio { umbrella header "EZAudio-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/EZAudio.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/EZAudio" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = -framework "AVFoundation" -framework "AudioToolbox" -framework "GLKit" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/EZAudio/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 0.0.6 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Gifu-dummy.m ================================================ #import @interface PodsDummy_Gifu : NSObject @end @implementation PodsDummy_Gifu @end ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Gifu-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Gifu-umbrella.h ================================================ #import #import "Gifu.h" FOUNDATION_EXPORT double GifuVersionNumber; FOUNDATION_EXPORT const unsigned char GifuVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Gifu.modulemap ================================================ framework module Gifu { umbrella header "Gifu-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Gifu.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Gifu" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/Gifu/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.1 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 2.2.5 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/NMSSH-dummy.m ================================================ #import @interface PodsDummy_NMSSH : NSObject @end @implementation PodsDummy_NMSSH @end ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/NMSSH-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/NMSSH-umbrella.h ================================================ #import #import "NMSFTP.h" #import "NMSFTPFile.h" #import "NMSSH.h" #import "NMSSHChannel.h" #import "NMSSHConfig.h" #import "NMSSHHostConfig.h" #import "NMSSHSession.h" #import "NMSSHChannelDelegate.h" #import "NMSSHSessionDelegate.h" #import "NMSSHLogger.h" #import "libssh2.h" #import "libssh2_publickey.h" #import "libssh2_sftp.h" #import "NMSSH.h" FOUNDATION_EXPORT double NMSSHVersionNumber; FOUNDATION_EXPORT const unsigned char NMSSHVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/NMSSH.modulemap ================================================ framework module NMSSH { umbrella header "NMSSH-umbrella.h" export * module * { export * } private header "NMSSH+Protected.h" private header "socket_helper.h" } ================================================ FILE: Sublime/Pods/Target Support Files/NMSSH/NMSSH.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/NMSSH" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/NMSSH/NMSSH-iOS/Libraries/lib" $(inherited) "${PODS_ROOT}/NMSSH/NMSSH-iOS/Libraries/lib" $(inherited) "${PODS_ROOT}/NMSSH/NMSSH-iOS/Libraries/lib" OTHER_LDFLAGS = -ObjC -l"crypto" -l"ssh2" -l"ssl" -l"z" -framework "CFNetwork" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: ## AASquaresLoading 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. ## Alamofire 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. ## AlamofireRSSParser 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. ## 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. ## Charts 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. ## DGElasticPullToRefresh 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. ## EZAudio 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. ## Gifu 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. ## NMSSH 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. ## RongCloudIMKit Copyright 2014 Rong Cloud ## SJCSimplePDFView The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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. ## SSZipArchive Copyright (c) 2010-2015, Sam Soffes, http://soff.es 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. ## Swifter Copyright (c) 2014, Damian Kołakowski 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 {organization} nor the names of its 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 HOLDER 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. ## SwiftyJSON The MIT License (MIT) Copyright (c) 2014 Ruoyu Fu 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. ## ZLMusicFlowWaveView The MIT License (MIT) Copyright (c) 2014 Zhixuan Lai 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. ## ZLSinusWaveView Copyright (c) 2013 Raffael Hannemann Copyright (c) 2014, Zhixuan Lai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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. Generated by CocoaPods - http://cocoapods.org ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText 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. Title AASquaresLoading Type PSGroupSpecifier FooterText 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. Title Alamofire Type PSGroupSpecifier FooterText Copyright (c) 2016 Don Angelillo <dangelillo@gmail.com> 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. Title AlamofireRSSParser Type PSGroupSpecifier FooterText 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. Title CYRTextView Type PSGroupSpecifier FooterText 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. Title Charts Type PSGroupSpecifier FooterText 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. Title DGElasticPullToRefresh Type PSGroupSpecifier FooterText 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. Title EZAudio Type PSGroupSpecifier FooterText 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. Title Gifu Type PSGroupSpecifier FooterText 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. Title NMSSH Type PSGroupSpecifier FooterText Copyright 2014 Rong Cloud Title RongCloudIMKit Type PSGroupSpecifier FooterText The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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. Title SJCSimplePDFView Type PSGroupSpecifier FooterText Copyright (c) 2010-2015, Sam Soffes, http://soff.es 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. Title SSZipArchive Type PSGroupSpecifier FooterText Copyright (c) 2014, Damian Kołakowski 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 {organization} nor the names of its 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 HOLDER 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. Title Swifter Type PSGroupSpecifier FooterText The MIT License (MIT) Copyright (c) 2014 Ruoyu Fu 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. Title SwiftyJSON Type PSGroupSpecifier FooterText The MIT License (MIT) Copyright (c) 2014 Zhixuan Lai 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. Title ZLMusicFlowWaveView Type PSGroupSpecifier FooterText Copyright (c) 2013 Raffael Hannemann Copyright (c) 2014, Zhixuan Lai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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. Title ZLSinusWaveView Type PSGroupSpecifier FooterText Generated by CocoaPods - http://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-dummy.m ================================================ #import @interface PodsDummy_Pods : NSObject @end @implementation PodsDummy_Pods @end ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-frameworks.sh ================================================ #!/bin/sh set -e echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi # use filter instead of exclude so missing patterns dont' throw errors echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identitiy echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" fi } # Strip invalid architectures strip_invalid_archs() { binary="$1" # Get architectures for current file archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" stripped="" for arch in $archs; do if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" || exit 1 stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi } if [[ "$CONFIGURATION" == "Debug" ]]; then install_framework "Pods/AASquaresLoading.framework" install_framework "Pods/Alamofire.framework" install_framework "Pods/AlamofireRSSParser.framework" install_framework "Pods/CYRTextView.framework" install_framework "Pods/Charts.framework" install_framework "Pods/DGElasticPullToRefresh.framework" install_framework "Pods/EZAudio.framework" install_framework "Pods/Gifu.framework" install_framework "Pods/NMSSH.framework" install_framework "Pods/SJCSimplePDFView.framework" install_framework "Pods/SSZipArchive.framework" install_framework "Pods/Swifter.framework" install_framework "Pods/SwiftyJSON.framework" install_framework "Pods/ZLMusicFlowWaveView.framework" install_framework "Pods/ZLSinusWaveView.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_framework "Pods/AASquaresLoading.framework" install_framework "Pods/Alamofire.framework" install_framework "Pods/AlamofireRSSParser.framework" install_framework "Pods/CYRTextView.framework" install_framework "Pods/Charts.framework" install_framework "Pods/DGElasticPullToRefresh.framework" install_framework "Pods/EZAudio.framework" install_framework "Pods/Gifu.framework" install_framework "Pods/NMSSH.framework" install_framework "Pods/SJCSimplePDFView.framework" install_framework "Pods/SSZipArchive.framework" install_framework "Pods/Swifter.framework" install_framework "Pods/SwiftyJSON.framework" install_framework "Pods/ZLMusicFlowWaveView.framework" install_framework "Pods/ZLSinusWaveView.framework" fi ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-resources.sh ================================================ #!/bin/sh set -e mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt > "$RESOURCES_TO_COPY" XCASSET_FILES=() realpath() { DIRECTORY="$(cd "${1%/*}" && pwd)" FILENAME="${1##*/}" echo "$DIRECTORY/$FILENAME" } install_resource() { case $1 in *.storyboard) echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" ;; *.xib) echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" ;; *.framework) echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" ;; *.xcdatamodel) echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" ;; *.xcdatamodeld) echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" ;; *.xcmappingmodel) echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" ;; *.xcassets) ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") ;; /*) echo "$1" echo "$1" >> "$RESOURCES_TO_COPY" ;; *) echo "${PODS_ROOT}/$1" echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" ;; esac } if [[ "$CONFIGURATION" == "Debug" ]]; then install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongCloud.bundle" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/en.lproj" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/zh-Hans.lproj" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/Emoji.plist" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/RongCloud.bundle" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/en.lproj" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/zh-Hans.lproj" install_resource "RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev/Emoji.plist" fi mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi rm -f "$RESOURCES_TO_COPY" if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] then case "${TARGETED_DEVICE_FAMILY}" in 1,2) TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" ;; 1) TARGET_DEVICE_ARGS="--target-device iphone" ;; 2) TARGET_DEVICE_ARGS="--target-device ipad" ;; *) TARGET_DEVICE_ARGS="--target-device mac" ;; esac # Find all other xcassets (this unfortunately includes those of path pods and other targets). OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) while read line; do if [[ $line != "`realpath $PODS_ROOT`*" ]]; then XCASSET_FILES+=("$line") fi done <<<"$OTHER_XCASSETS" printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods-umbrella.h ================================================ #import FOUNDATION_EXPORT double PodsVersionNumber; FOUNDATION_EXPORT const unsigned char PodsVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods.debug.xcconfig ================================================ EMBEDDED_CONTENT_CONTAINS_SWIFT = YES FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/AASquaresLoading.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Alamofire.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/AlamofireRSSParser.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/CYRTextView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Charts.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/DGElasticPullToRefresh.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/EZAudio.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Gifu.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/NMSSH.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SJCSimplePDFView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SSZipArchive.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Swifter.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SwiftyJSON.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/ZLMusicFlowWaveView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/ZLSinusWaveView.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"c++abi" -l"opencore-amrnb" -l"sqlite3" -l"stdc++" -l"xml2" -l"z" -framework "AASquaresLoading" -framework "AVFoundation" -framework "Alamofire" -framework "AlamofireRSSParser" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "CFNetwork" -framework "CYRTextView" -framework "Charts" -framework "CoreAudio" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMedia" -framework "CoreTelephony" -framework "CoreVideo" -framework "DGElasticPullToRefresh" -framework "EZAudio" -framework "Gifu" -framework "ImageIO" -framework "MapKit" -framework "NMSSH" -framework "OpenGLES" -framework "QuartzCore" -framework "RongIMKit" -framework "RongIMLib" -framework "SJCSimplePDFView" -framework "SSZipArchive" -framework "Swifter" -framework "SwiftyJSON" -framework "SystemConfiguration" -framework "UIKit" -framework "ZLMusicFlowWaveView" -framework "ZLSinusWaveView" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods.modulemap ================================================ framework module Pods { umbrella header "Pods-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/Pods/Pods.release.xcconfig ================================================ EMBEDDED_CONTENT_CONTAINS_SWIFT = YES FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/RongCloudIMKit/Rong_Cloud_iOS_IMKit_SDK_v2_4_9_dev" OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/AASquaresLoading.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Alamofire.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/AlamofireRSSParser.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/CYRTextView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Charts.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/DGElasticPullToRefresh.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/EZAudio.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Gifu.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/NMSSH.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SJCSimplePDFView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SSZipArchive.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Swifter.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/SwiftyJSON.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/ZLMusicFlowWaveView.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/ZLSinusWaveView.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"c++abi" -l"opencore-amrnb" -l"sqlite3" -l"stdc++" -l"xml2" -l"z" -framework "AASquaresLoading" -framework "AVFoundation" -framework "Alamofire" -framework "AlamofireRSSParser" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "CFNetwork" -framework "CYRTextView" -framework "Charts" -framework "CoreAudio" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMedia" -framework "CoreTelephony" -framework "CoreVideo" -framework "DGElasticPullToRefresh" -framework "EZAudio" -framework "Gifu" -framework "ImageIO" -framework "MapKit" -framework "NMSSH" -framework "OpenGLES" -framework "QuartzCore" -framework "RongIMKit" -framework "RongIMLib" -framework "SJCSimplePDFView" -framework "SSZipArchive" -framework "Swifter" -framework "SwiftyJSON" -framework "SystemConfiguration" -framework "UIKit" -framework "ZLMusicFlowWaveView" -framework "ZLSinusWaveView" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/SJCSimplePDFView-dummy.m ================================================ #import @interface PodsDummy_SJCSimplePDFView : NSObject @end @implementation PodsDummy_SJCSimplePDFView @end ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/SJCSimplePDFView-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/SJCSimplePDFView-umbrella.h ================================================ #import #import "SJCSimplePDFView.h" FOUNDATION_EXPORT double SJCSimplePDFViewVersionNumber; FOUNDATION_EXPORT const unsigned char SJCSimplePDFViewVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/SJCSimplePDFView.modulemap ================================================ framework module SJCSimplePDFView { umbrella header "SJCSimplePDFView-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/SJCSimplePDFView/SJCSimplePDFView.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SJCSimplePDFView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = -framework "UIKit" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.1 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/SSZipArchive-dummy.m ================================================ #import @interface PodsDummy_SSZipArchive : NSObject @end @implementation PodsDummy_SSZipArchive @end ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/SSZipArchive-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/SSZipArchive-umbrella.h ================================================ #import #import "Common.h" #import "SSZipArchive.h" #import "ZipArchive.h" FOUNDATION_EXPORT double SSZipArchiveVersionNumber; FOUNDATION_EXPORT const unsigned char SSZipArchiveVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/SSZipArchive.modulemap ================================================ framework module SSZipArchive { umbrella header "SSZipArchive-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/SSZipArchive/SSZipArchive.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SSZipArchive" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_LDFLAGS = -l"z" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.1.3 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Swifter-dummy.m ================================================ #import @interface PodsDummy_Swifter : NSObject @end @implementation PodsDummy_Swifter @end ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Swifter-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Swifter-umbrella.h ================================================ #import FOUNDATION_EXPORT double SwifterVersionNumber; FOUNDATION_EXPORT const unsigned char SwifterVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Swifter.modulemap ================================================ framework module Swifter { umbrella header "Swifter-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/Swifter/Swifter.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Swifter" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 2.3.2 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-dummy.m ================================================ #import @interface PodsDummy_SwiftyJSON : NSObject @end @implementation PodsDummy_SwiftyJSON @end ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-umbrella.h ================================================ #import FOUNDATION_EXPORT double SwiftyJSONVersionNumber; FOUNDATION_EXPORT const unsigned char SwiftyJSONVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.modulemap ================================================ framework module SwiftyJSON { umbrella header "SwiftyJSON-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SwiftyJSON" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 0.0.1 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView-dummy.m ================================================ #import @interface PodsDummy_ZLMusicFlowWaveView : NSObject @end @implementation PodsDummy_ZLMusicFlowWaveView @end ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView-umbrella.h ================================================ #import #import "ZLMusicFlowDecorativeView.h" #import "ZLMusicFlowWaveView.h" FOUNDATION_EXPORT double ZLMusicFlowWaveViewVersionNumber; FOUNDATION_EXPORT const unsigned char ZLMusicFlowWaveViewVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView.modulemap ================================================ framework module ZLMusicFlowWaveView { umbrella header "ZLMusicFlowWaveView-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/ZLMusicFlowWaveView/ZLMusicFlowWaveView.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ZLMusicFlowWaveView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.cocoapods.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 0.0.3 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/ZLSinusWaveView-dummy.m ================================================ #import @interface PodsDummy_ZLSinusWaveView : NSObject @end @implementation PodsDummy_ZLSinusWaveView @end ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/ZLSinusWaveView-prefix.pch ================================================ #ifdef __OBJC__ #import #endif ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/ZLSinusWaveView-umbrella.h ================================================ #import #import "ZLSinusWaveView.h" FOUNDATION_EXPORT double ZLSinusWaveViewVersionNumber; FOUNDATION_EXPORT const unsigned char ZLSinusWaveViewVersionString[]; ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/ZLSinusWaveView.modulemap ================================================ framework module ZLSinusWaveView { umbrella header "ZLSinusWaveView-umbrella.h" export * module * { export * } } ================================================ FILE: Sublime/Pods/Target Support Files/ZLSinusWaveView/ZLSinusWaveView.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ZLSinusWaveView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/RongCloudIMKit" PODS_ROOT = ${SRCROOT} SKIP_INSTALL = YES ================================================ FILE: Sublime/Pods/ZLMusicFlowWaveView/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Zhixuan Lai 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/ZLMusicFlowWaveView/README.md ================================================ ZLMusicFlowWaveView =================== A [ZLSinusWaveView](https://github.com/zhxnlai/ZLSinusWaveView) subclass inspired by [乐流/MusicFlow](https://itunes.apple.com/us/app/le-liu/id848206791?mt=8) Preview --- ![preview](Previews/preview.gif) CocoaPods --- You can install `ZLMusicFlowWaveView` through CocoaPods adding the following to your Podfile: pod 'ZLMusicFlowWaveView' Usage --- Check out the [demo app](https://github.com/zhxnlai/ZLMusicFlowWaveView/tree/master/ZLMusicFlowWaveViewDemo) for an example. Dependencies --- ZLMusicFlowWaveView is a subclass of `ZLSinusWaveView`. It requires [ZLSinusWaveView](https://github.com/zhxnlai/ZLSinusWaveView) and [EZAudio](https://github.com/syedhali/EZAudio). License --- ZLMusicFlowWaveView is available under the MIT license. ================================================ FILE: Sublime/Pods/ZLMusicFlowWaveView/ZLMusicFlowWaveView/ZLMusicFlowDecorativeView.h ================================================ // // ZLMusicFlowDecorativeView.h // ZLMusicFlowWaveViewDemo // // Created by Zhixuan Lai on 11/17/14. // Copyright (c) 2014 Zhixuan Lai. All rights reserved. // #import @interface ZLMusicFlowDecorativeView : UIView @end ================================================ FILE: Sublime/Pods/ZLMusicFlowWaveView/ZLMusicFlowWaveView/ZLMusicFlowDecorativeView.m ================================================ // // ZLMusicFlowDecorativeView.m // ZLMusicFlowWaveViewDemo // // Created by Zhixuan Lai on 11/17/14. // Copyright (c) 2014 Zhixuan Lai. All rights reserved. // #import "ZLMusicFlowDecorativeView.h" @implementation ZLMusicFlowDecorativeView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; self.layer.shadowRadius = 5; self.layer.shadowOffset = CGSizeMake(5, 5); } return self; } - (void)drawRect:(CGRect)rect { [super drawRect:rect]; CGContextRef context = UIGraphicsGetCurrentContext(); UIColor* color = [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 1]; UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0, 0, CGRectGetWidth(rect), CGRectGetHeight(rect))]; CGContextSaveGState(context); [color setFill]; [ovalPath fill]; CGContextRestoreGState(context); } @end ================================================ FILE: Sublime/Pods/ZLMusicFlowWaveView/ZLMusicFlowWaveView/ZLMusicFlowWaveView.h ================================================ // // ZLMusicFlowWaveView.h // ZLMusicFlowWaveViewDemo // // Created by Zhixuan Lai on 11/17/14. // Copyright (c) 2014 Zhixuan Lai. All rights reserved. // #import @interface ZLMusicFlowWaveView : ZLSinusWaveView @end ================================================ FILE: Sublime/Pods/ZLMusicFlowWaveView/ZLMusicFlowWaveView/ZLMusicFlowWaveView.m ================================================ // // ZLMusicFlowWaveView.m // ZLMusicFlowWaveViewDemo // // Created by Zhixuan Lai on 11/17/14. // Copyright (c) 2014 Zhixuan Lai. All rights reserved. // #import "ZLMusicFlowWaveView.h" #import "ZLMusicFlowDecorativeView.h" @implementation ZLMusicFlowWaveView - (instancetype)init { self = [super init]; if (self) { [self Setup]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self Setup]; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self Setup]; } return self; } - (void)Setup { self.backgroundColor = [UIColor colorWithRed:0.937 green:0.933 blue:0.914 alpha:1.000]; // Waveform color self.color = [UIColor colorWithRed:0.165 green:0.043 blue:0.000 alpha:1.000]; // Plot type self.plotType = EZPlotTypeBuffer; // Fill self.shouldFill = YES; // Mirror self.shouldMirror = YES; self.dampingFactor = 0.97; self.phaseShift = -0.25; self.waveWidth = 3; self.waveInsets = UIEdgeInsetsMake(250, 60, 250, 60); CGFloat decorativeViewWidth = 20; self.leftDecorativeView = [[ZLMusicFlowDecorativeView alloc] initWithFrame:CGRectMake(0, 0, decorativeViewWidth, decorativeViewWidth)]; self.rightDecorativeView = [[ZLMusicFlowDecorativeView alloc] initWithFrame:CGRectMake(0, 0, decorativeViewWidth, decorativeViewWidth)]; } @end ================================================ FILE: Sublime/Pods/ZLSinusWaveView/LICENSE ================================================ Copyright (c) 2013 Raffael Hannemann Copyright (c) 2014, Zhixuan Lai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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. ================================================ FILE: Sublime/Pods/ZLSinusWaveView/README.md ================================================ ZLSinusWaveView =============== A Siri like voice visualization view using EZAudio. Modified from [SISinusWaveView](https://github.com/raffael/SISinusWaveView) for iOS. Preview --- ![preview](Previews/preview.gif) ![SISinusWaveView](Previews/waveform.gif) CocoaPods --- You can install `ZLSinusWaveView` through CocoaPods adding the following to your Podfile: pod 'ZLSinusWaveView' Usage --- Check out the [demo app](https://github.com/zhxnlai/ZLSinusWaveView/tree/master/EZAudioPlayFileExample) for an example. Dependencies --- ZLSinusWaveView is a subclass of `EZAudioPlot`. It requires [EZAudio](https://github.com/syedhali/EZAudio). License --- ZLSinusWaveView is available under the BSD license. - Copyright (c) 2014, Zhixuan Lai - Copyright (c) 2013 Raffael Hannemann - All rights reserved. ================================================ FILE: Sublime/Pods/ZLSinusWaveView/ZLSinusWaveView/ZLSinusWaveView.h ================================================ // // SIAudioPlot.h // EZAudioRecordExample // // Created by Zhixuan Lai on 8/2/14. // Copyright (c) 2014 Syed Haris Ali. All rights reserved. // #import "EZAudio/EZAudioPlot.h" @interface ZLSinusWaveView : EZAudioPlot /// The amplitude that is used when the incoming microphone amplitude is near zero. Setting a value greater 0 provides a more vivid visualization. @property (assign,nonatomic) float idleAmplitude; /// The phase of the sinus wave. Default: 0. @property (assign,nonatomic) float phase; /// The frequency of the sinus wave. The higher the value, the more sinus wave peaks you will have. Default: 1.5 @property (assign,nonatomic) float frequency; /// The damping factor that is used to calm the wave down after a sound level peak. Default: 0.86 @property (assign,nonatomic) float dampingFactor; /// The number of additional waves in the background. The more waves, to more CPU power is needed. Default: 4. @property (assign,nonatomic) float waves; /// The stroke width of the first wave. @property (assign,nonatomic) float waveWidth; /// The actual amplitude the view is visualizing. This amplitude is based on the microphone's amplitude @property (assign,nonatomic,readonly) float amplitude; /// The damped amplitude. @property (assign,nonatomic,readonly) float dampingAmplitude; /// The lines are joined stepwise, the more dense you draw, the more CPU power is used. Default: 5. @property (assign,nonatomic) float density; /// The phase shift that will be applied with each delivering of the microphone's value. A higher value will make the waves look more nervous. Default: -0.15. @property (assign,nonatomic) float phaseShift; /// The white value of the color to draw the waves with. Default: 1.0 (white). @property (assign,nonatomic) float whiteValue; /// Set to NO, if you want to stop the view to oscillate. @property (assign,nonatomic) BOOL oscillating; /// The maximum amplitude of the waveform in percent of the view height. Default: 0.5 (half). @property (assign,nonatomic) float maxAmplitude; /// The wave inset for each edge. @property (assign,nonatomic) UIEdgeInsets waveInsets; /// The decoritive views to be placed at the left end of the wave. @property (strong, nonatomic) UIView *leftDecorativeView; /// The decoritive views to be placed at the right end of the wave. @property (strong, nonatomic) UIView *rightDecorativeView; @end ================================================ FILE: Sublime/Pods/ZLSinusWaveView/ZLSinusWaveView/ZLSinusWaveView.m ================================================ // // SIAudioPlot.m // EZAudioRecordExample // // Created by Zhixuan Lai on 8/2/14. // Copyright (c) 2014 Syed Haris Ali. All rights reserved. // #import "ZLSinusWaveView.h" @interface ZLSinusWaveView() { int tick; } @end @implementation ZLSinusWaveView @synthesize backgroundColor = _backgroundColor; @synthesize color = _color; @synthesize gain = _gain; @synthesize plotType = _plotType; @synthesize shouldFill = _shouldFill; @synthesize shouldMirror = _shouldMirror; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setup]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self setup]; } return self; } -(void)setup { _frequency = 1.5; _phase = 0; _amplitude = 1.0; _whiteValue = 1.0; _idleAmplitude = 0.1; _dampingFactor = 0.86; _waves = 5; _waveWidth = 2; _phaseShift = -0.15; _density = 5.0; _maxAmplitude = 0.5; _waveInsets = UIEdgeInsetsZero; } -(void)_refreshDisplay { #if TARGET_OS_IPHONE [self setNeedsDisplay]; #elif TARGET_OS_MAC [self setNeedsDisplay:YES]; #endif } - (void)setLeftDecorativeView:(UIView *)leftDecorativeView { if (leftDecorativeView) { [self addSubview:leftDecorativeView]; } else { [leftDecorativeView removeFromSuperview]; } _leftDecorativeView = leftDecorativeView; [self setNeedsLayout]; } - (void)setRightDecorativeView:(UIView *)rightDecorativeView { if (rightDecorativeView) { [self addSubview:rightDecorativeView]; } else { [rightDecorativeView removeFromSuperview]; } _rightDecorativeView = rightDecorativeView; [self setNeedsLayout]; } -(void)setSampleData:(float *)data length:(int)length { int requiredTickes = 1; // Alter this to draw more or less often tick = (tick+1)%requiredTickes; // Let's use the buffer's first float value to determine the current sound level. float value = fabsf(data[0]); /// If we defined the current sound level as the amplitude of the wave, the wave would jitter very nervously. /// To avoid this, we use an inert amplitude that lifts slowly if the value is currently high, and damps itself /// if the value decreases. if (value > _dampingAmplitude) _dampingAmplitude += (fmin(value,1.0)-_dampingAmplitude)/4.0; else if (value<0.01) _dampingAmplitude *= _dampingFactor; _phase += _phaseShift; _amplitude = fmax( fmin(_dampingAmplitude*20, 1.0), _idleAmplitude); if (tick==0) { 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]; } } - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); CGRect frame = self.bounds; // Set the background color [(UIColor*)self.backgroundColor set]; UIRectFill(frame); // Set the waveform line color [(UIColor*)self.color set]; frame = UIEdgeInsetsInsetRect(self.bounds, self.waveInsets); // We draw multiple sinus waves, with equal phases but altered amplitudes, multiplied by a parable function. for(int i=0;i<_waves+1;i++) { // [[NSGraphicsContext currentContext] saveGraphicsState]; CGContextRef context = UIGraphicsGetCurrentContext(); // CGContextSaveGState(context); // CGContextRef context = (CGContextRef) [nsGraphicsContext graphicsPort]; // The first wave is drawn with a waveWidth stroke width, all others a with 1px stroke width. CGContextSetLineWidth(context, (i==0)? self.waveWidth:1 ); CGFloat halfHeight = CGRectGetHeight(frame)/2; CGFloat width = CGRectGetWidth(frame); CGFloat mid = width /2.0; const CGFloat maxAmplitude = halfHeight*_maxAmplitude-4; // 4 corresponds to twice the stroke width // Progress is a value between 1.0 and -0.5, determined by the current wave idx, which is used to alter the wave's amplitude. CGFloat progress = 1.0-(CGFloat)i/_waves; CGFloat normedAmplitude = (1.5*progress-0.5)*_amplitude; // Choose the color based on the progress (that is, based on the wave idx) // [[NSColor colorWithCalibratedWhite:_whiteValue alpha:progress/3.0*2+1.0/3.0] set]; // [[UIColor colorWithWhite:_whiteValue alpha:progress/3.0*2+1.0/3.0] set]; CGFloat multiplier = MIN(1.0, (progress / 3.0f * 2.0f) + (1.0f / 3.0f)); [[self.color colorWithAlphaComponent:multiplier * CGColorGetAlpha([UIColor whiteColor].CGColor)] set]; for(CGFloat x = 0; x Bool { window?.backgroundColor = Constant.CapeCod UIApplication.sharedApplication().statusBarStyle = .LightContent UINavigationBar.appearance().barStyle = UIBarStyle.Black UINavigationBar.appearance().tintColor = UIColor.whiteColor() UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()] // Remove navigationBar border UINavigationBar.appearance().translucent = false UINavigationBar.appearance().shadowImage = UIImage() UINavigationBar.appearance().setBackgroundImage(Constant.NavigationBarColor.toImage(), forBarMetrics: UIBarMetrics.Default) UITabBar.appearance().barTintColor = Constant.NavigationBarAndTabBarColor UITabBar.appearance().tintColor = UIColor.whiteColor() UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.whiteColor()], forState: UIControlState.Selected) UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.grayColor()], forState: UIControlState.Normal) // Remove tabBar border UITabBar.appearance().translucent = false UITabBar.appearance().shadowImage = UIImage() UITabBar.appearance().backgroundImage = UIImage() // 微信 WXApi.registerApp(Constant.weixinAppID) // 融云 RCIM.sharedRCIM().showUnkownMessageNotificaiton = true RCIM.sharedRCIM().enableTypingStatus = true RCIM.sharedRCIM().initWithAppKey(Constant.RongCloudAppKey) RCIM.sharedRCIM().userInfoDataSource = self RCIM.sharedRCIM().receiveMessageDelegate = self // 推送处理 application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[.Alert, .Badge, .Sound], categories: nil)) RCIM.sharedRCIM().Login() // Cycript if Config.CycriptStartListen { CYListenServer(8888) } return true } func getUserInfoWithUserId(userId: String!, completion: ((RCUserInfo!) -> Void)!) { RCIM.sharedRCIM().getInfo(userId) { (name, portrait) in var username = name if (userId == Constant.RongCloudAuthorUserID) { username = Constant.RongCloudAuthorUserName } completion(RCUserInfo(userId: userId, name: username, portrait: portrait)) } } func onRCIMReceiveMessage(message: RCMessage!, left: Int32) { Global.UnreadMessageCount += 1 if left == 0 { Global.Notifi.postNotificationName(Constant.RongCloudUnreadMessageNotifi, object: nil) } } func applicationWillResignActive(application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool { return WXApi.handleOpenURL(url, delegate: self) } func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool { // 处理 github token 跳转的链接 GitHubAPIManager.handleURL(url) // 处理接收到的文件 if url.fileURL { let app = options[UIApplicationOpenURLOptionsSourceApplicationKey] ?? "AirDrop" Log("Receive a file from \(app!), url: \(url)") } // 微信 return WXApi.handleOpenURL(url, delegate: self) } } ================================================ FILE: Sublime/Sublime/AppInfoViewController.swift ================================================ // // AppInfoViewController.swift // Sublime // // Created by Eular on 2/24/16. // Copyright © 2016 Eular. All rights reserved. // class AppInfoViewController: UIViewController { let popupMenu = PopupMenu() override func viewDidLoad() { super.viewDidLoad() title = "Sublime" view.backgroundColor = Constant.CapeCod if let logo = UIView.loadFromNibNamed("LogoView") { logo.frame = view.frame logo.height -= Constant.NavigationBarOffset view.addSubview(logo) } let version = UILabel() view.addSubview(version) version.text = "Version 1.0" version.font = version.font.fontWithSize(13) version.width = 100 version.height = 20 version.autoLayout(left: 12, bottom: -9) version.textColor = UIColor.lightGrayColor() let btn = UIButton() view.addSubview(btn) btn.setTitle("Github", forState: .Normal) btn.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) btn.titleLabel?.adjustsFontSizeToFitWidth = true btn.width = 50 btn.height = 20 btn.autoLayout(right: -10, bottom: -10) btn.addTarget(self, action: #selector(self.goToAppGithub), forControlEvents: .TouchUpInside) // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self // 摇一摇 UIApplication.sharedApplication().applicationSupportsShakeToEdit = true self.becomeFirstResponder() } override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) { if motion == .MotionShake { AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) // 震动 var mySound: SystemSoundID = 0 if let url = NSBundle.mainBundle().URLForResource("shake", withExtension: "wav") { AudioServicesCreateSystemSoundID(url, &mySound) AudioServicesPlaySystemSound(mySound) } let go = GomokuViewController() self.presentViewController(go, animated: true, completion: nil) } } func goToAppGithub() { let svc = SublimeSafari(URL: NSURL(string: Constant.AppGithubUrl)!) svc.title = "Urinx" navigationController?.pushViewController(svc, animated: true) } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "29x29", "idiom" : "iphone", "filename" : "appIcon29@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "appIcon29@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "appIcon40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "appIcon40@3x copy.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "appIcon60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "appIcon60@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Repositories.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Repositories.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_douban_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_douban_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_facebook_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_facebook_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_instagram.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_instagram@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_line_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_line_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_more_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_more_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_pinterest_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_pinterest_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_qq_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_qq_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_qzone_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_qzone_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_sina_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_sina_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_twitter_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_twitter_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_wechat_session_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_wechat_session_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Share_wechat_timeline_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Share_wechat_timeline_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/Stars.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Stars.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/add_friend_icon_addfriend.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "plugins_FriendNotify@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "plugins_FriendNotify@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/add_friend_icon_group.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "add_friend_icon_addgroup@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "add_friend_icon_addgroup@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/add_friend_icon_offical.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "add_friend_icon_offical@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "add_friend_icon_offical@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/app_small_icon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "app_small_icon@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/code_share_btn.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "code_share_btn@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/comment.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "comment@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/config_cycript.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "config_cycript@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/config_full_screen_code_reading.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "config_full_screen_code_reading@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/config_show_hidden_file.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "config_show_hidden_file@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate.jpeg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate1.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate1.jpg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate2.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate2.jpg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate3.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate3.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate4.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate4.jpg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate5.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate2.jpeg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/donate_weixin.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "donate_weixin.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/explore_codezZ.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "explore_codezZ@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_3fr.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_3fr.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_7z.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_7z.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_aac.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_aac.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_ai.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_ai.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_asc.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_asc.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_asp.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_asp.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_avi.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_avi.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_bas.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_bas.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_cls.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_cls.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_code_share.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_code_share1.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_cpp.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_cpp.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_cr2.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_cr2.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_cs.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_cs.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_css.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_css.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_csv.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_csv.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_dll.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_dll.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_dmg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_dmg.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_dng.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_dng.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_eps.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_eps.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_exe.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_exe.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_fff.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_fff.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_flv.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_flv.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_gif.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_gif.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_gis.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_gis.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_gpx.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_gpx.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_html.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_html.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_j2k.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_j2k.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_jp2.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_jp2.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_jpg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_jpg.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_js.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_js.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_jsp.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_jsp.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_kml.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_kml.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_kmz.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_kmz.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_mov.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_mov.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_mp3.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_mp3.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_mp4.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_mp4.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_mpg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_mpg.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_nef.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_nef.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_nmea.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_nmea.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_ogg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_ogg.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_osm.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_osm.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_otf.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_otf.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_pdf.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_pdf.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_png.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_png.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_ppt.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_ppt.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_pptx.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_pptx.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_ps.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_ps.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_psd.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_psd.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_py.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_py.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_rar.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_rar.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_raw.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_raw.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_svg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_svg.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_tar.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_tar.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_tif.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_tif.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_ttf.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_ttf.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_txt.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_txt.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_unknown.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_unknown.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_vb.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_vb.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_vbs.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_vbs.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_wav.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_wav.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_wma.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_wma.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_woff.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_woff.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_word.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_word.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_wsh.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_wsh.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_xaml.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_xaml.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_xls.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_xls.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_xml.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_xml.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/file_zip.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "file_zip.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/folder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "folder.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/function_rss.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "function_rss@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/function_scan.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "function_scan@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/gist_bg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "11953427,2560,1600.jpg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_avatar.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "github_avatar@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_folder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "github_folder@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_fork.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "github-fork@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_login.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "Github-Login@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_star.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "github-star@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/github_watcher.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "github_watcher@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/open_safari.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "open_safari@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/pdf_continuous.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "pdf_continuous@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/pdf_horizontal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "pdf_horizontal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/pdf_vertical.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "pdf_vertical@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/repo_download.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "repo_download@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/right_arrow.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "right_arrow.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_cache.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_cache@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_configure.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_configure@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_donate.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_donate@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_feedback.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_feedback@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_github.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_github@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_license.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_license@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_reading.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_reading@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_server.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_server@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_ssh.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_server@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_storage.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_storage@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_sublime.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_sublime@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/setting_themes.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "setting_themes@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_done.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_done@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_keyboard.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_keyboard@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_password.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_password@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_port.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_port@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_server.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_server@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/ssh_user.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "ssh_user@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/tab_icon_explore.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tab_icon_explore.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/tab_icon_files.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tab_icon_files.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/tab_icon_setting.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tab_icon_setting.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/user_author.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "head0.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/user_info.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "user_info@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Assets.xcassets/user_robot.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "IMG_1683.jpg", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sublime/Sublime/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Sublime/Sublime/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Sublime/Sublime/BoardModel.swift ================================================ // // GoBoardModel.swift // Sublime // // Created by Eular on 4/15/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Stone { enum StoneType: Int { case White = 2 case Black = 1 case Void = 0 } var type: StoneType var value: Int { get { return type.rawValue } set { switch newValue { case 2: type = .White case 1: type = .Black default: type = .Void } } } init() { self.type = .Void } init(type: StoneType) { self.type = type } } class GoBoardModel { enum GameResult { case Win case Lose case None } let dimension: Int var winStone: [(Int, Int)] = [] private var board: Array> init(dimension d: Int) { dimension = d board = Array(count: d, repeatedValue: Array(count: d, repeatedValue: Stone())) reset() } // 清空棋盘 func reset() { for i in range(dimension) { for j in range(dimension) { board[i][j] = Stone() } } } // 判断输赢 func check() -> GameResult { // 四个方向遍历: 右,右上,右下,下 let dirs = [(1, 0), (1, -1), (1, 1), (0, 1)] for i in range(dimension) { for j in range(dimension) { let t = self[i,j].type if t == .Void { continue } for d in dirs { var x = i var y = j var count = 0 for _ in range(5) { if self[x,y].type != t { winStone = [] break } winStone.append((x,y)) x += d.0 y += d.1 count += 1 } if count == 5 { if t == .Black { return .Win } if t == .White { return .Lose } } } } } return .None } // 输出棋盘 func log() { print("-" * (2 * dimension + 3)) for i in range(dimension) { let symbol = [".", "x", "o"] var row = [String]() for j in range(dimension) { row.append(symbol[board[j][i].value]) } print("| " + " ".join(row) + " |") } print("-" * (2 * dimension + 3)) } // 索引 subscript(row: Int, column: Int) -> Stone { get { if row < 0 || row >= 15 || column < 0 || column >= 15 { return Stone() } return board[row][column] } set { board[row][column] = newValue } } subscript(row: Int) -> Array { get { return board[row] } set { board[row] = newValue } } } class GomokuBoardModel: GoBoardModel { init() { super.init(dimension: 15) } } ================================================ FILE: Sublime/Sublime/BoardView.swift ================================================ // // GoBoard.swift // Sublime // // Created by Eular on 4/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class GoBoardView: UIView { let padding: CGFloat = 10 var dimension: Int var gridWidth: CGFloat var stoneWidth: CGFloat = 9 var isEnd: Bool = false let board: GoBoardModel init(board: GoBoardModel, gridWidth: CGFloat) { self.gridWidth = gridWidth self.board = board self.dimension = board.dimension let width = gridWidth * (dimension - 1) + 2 * padding super.init(frame: CGRectMake(0, 0, width, width)) self.backgroundColor = UIColor.clearColor() self.layer.borderWidth = 1 self.layer.borderColor = UIColor.grayColor().CGColor } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func drawRect(rect: CGRect) { let d = dimension for i in 0.., withEvent event: UIEvent?) { super.touchesEnded(touches, withEvent: event) if !isEnd { if let touch = touches.first { let location = touch.locationInView(self) let x = Int(round((location.x - padding) / gridWidth)) let y = Int(round((location.y - padding) / gridWidth)) onStoneDropDown(x, y) } } } func onStoneDropDown(x: Int, _ y: Int) { print("Stone: [\(x), \(y)]") } private func drawStone(x: Int, _ y: Int, _ c: CGFloat) { let g = gridWidth let r = stoneWidth let pos = (g * x + padding, g * y + padding) let context = UIGraphicsGetCurrentContext() CGContextAddArc(context, pos.0, pos.1, r - c / 2, 0, 3.1415926*2, 0) CGContextSetRGBFillColor(context, c, c, c, 1) CGContextFillPath(context) } private func drawLine(p1: (Int, Int), _ p2: (Int, Int)) { let g = gridWidth let context = UIGraphicsGetCurrentContext() CGContextMoveToPoint(context, g * p1.0 + padding, g * p1.1 + padding) CGContextAddLineToPoint(context, g * p2.0 + padding, g * p2.1 + padding) CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1) CGContextStrokePath(context) } func reset() { isEnd = false board.reset() setNeedsDisplay() } } class GomokuBoardView: GoBoardView { let depth = 1 // 目前只能用 1 层,2 的计算量太大,耗时太长,有待后续优化 let AI: GomokuAI var onWin: (() -> Void)? var onLose: (() -> Void)? init() { let gomokuBoard = GomokuBoardModel() self.AI = GomokuAI(board: gomokuBoard) super.init(board: gomokuBoard, gridWidth: 20) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func onStoneDropDown(x: Int, _ y: Int) { if board[x,y].type == .Void { // 黑棋落子 board[x,y].type = .Black setNeedsDisplay() // 检查输赢 let r = board.check() if r == .Win { isEnd = true onWin?() } else { let queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0) dispatch_async(queue) { let AIMove = self.AI.search(2, depth: self.depth) self.board[AIMove[1], AIMove[2]].type = .White dispatch_async(dispatch_get_main_queue()) { self.setNeedsDisplay() // 再次检查输赢 if self.board.check() == .Lose { self.isEnd = true self.onLose?() } } } } } } } ================================================ FILE: Sublime/Sublime/Code.swift ================================================ // // Code.swift // Sublime // // Created by Eular on 5/10/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation class Code: File { let language: String var id: String { return self.read().md5 } var lastReadPosition: Double { get { return Global.Database.doubleForKey("Code-\(id)") } set { Global.Database.setDouble(newValue, forKey: "Code-\(id)") } } init(path: String, language: String) { self.language = language super.init(path: path) } } ================================================ FILE: Sublime/Sublime/CodeEngine.swift ================================================ // // CodeTextView.swift // Sublime // // Created by Eular on 5/9/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import CYRTextView extension CYRTextView { public override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { if action == #selector(copy(_:)) { return true } return false } } class CodeEngine { let textView = CYRTextView() init() { textView.editable = false textView.lineCursorEnabled = false textView.backgroundColor = Constant.CodeBackgroudColor textView.gutterBackgroundColor = Constant.CodeLineNumberBackgroudColor textView.gutterLineColor = Constant.CodeLineNumberBackgroudColor textView.textColor = UIColor.whiteColor() textView.font = textView.font?.fontWithSize(12) textView.setLineBreakMode(.ByCharWrapping) textView.contentInset.top = -7 textView.scrollIndicatorInsets.top = -7 setupTokens() } @objc func shareCodeInPicture() { print(123) } func setupTokens() { textView.tokens = [ CYRToken(name: "Parameter", expression: "(?<=\\()[^\\)]*(?=\\))", attributes: [NSForegroundColorAttributeName : "#FD9720".color!]), CYRToken(name: "Parameter-fixbug", expression: "\\)+(?=\\))|\\)[^\\(]+(?=\\))", attributes: [NSForegroundColorAttributeName : "#FD9720".color!]), CYRToken(name: "Number", expression: "\\b(0[xX][0-9a-fA-F]+|\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|\\.\\d+(?:[eE][+-]?\\d+)?)\\b", attributes: [NSForegroundColorAttributeName : "#AE81FF".color!]), CYRToken(name: "Boolean", expression: "\\b(true|false|True|False|None|nil|null|undefined|NaN)\\b", attributes: [NSForegroundColorAttributeName : "#FF3C50".color!]), CYRToken(name: "Operator", expression: "[/\\*\\;:=<>\\+\\-\\^!·≤≥\\?|%]", attributes: [NSForegroundColorAttributeName : "#F92772".color!]), CYRToken(name: "ReservedWords-js", expression: "\\b(break|continue|do|for|in|function|if|else|return|switch|default|this|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void|Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|JSON|console|window|document|navigator|location)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-css", expression: "\\b(px|em|pt|s|ms|deg|%)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-php", expression: "\\b(print_r|exception|array|break|case|class|const|continue|declare|default|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|foreach|for|function|global|if|include|include_once|isset|list|new|print|require|require_once|return|static|switch|unset|use|var|while|final|interface|implements|extends|public|private|protected|abstract|clone|try|catch|throw|and|or|xor|as|die|do|echo|else|this)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-c", expression: "\\b(asm|do|if|return|typedef|inline|typeid|bool|dynamic_cast|signed|typename|break|else|sizeof|union|case|enum|mutable|static|unsigned|catch|explicit|namespace|static_cast|using|export|new|struct|virtual|class|extern|operator|switch|void|const|private|template|volatile|const_cast|protected|this|wchar_t|continue|for|public|throw|while|default|friend|register|delete|goto|reinterpret_cast|try)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-mysql", expression: "\\b(select|from|where|order|like|group|by|left|right|join|desc|asc|insert|into|values|and|or|sum|count|length|on|duplicate|key|update|limit|union|add|alter|delete|regexp|as|find_in_set|create|drop|table|exists|value|function|begin|declare|default|while|do|end|if|else|then|set|substr|return|repeat|returns|locate|int|float|varchar|char|bool|text|double|trigger|for|each|row|timestamp|primary|after|now)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-python", expression: "\\b(class|finally|is|return|continue|for|lambda|try|def|from|nonlocal|while|and|del|global|not|with|as|elif|if|or|yield|assert|else|import|pass|break|except|in|raise)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "ReservedWords-swift", expression: "\\b(class|deinit|enum|extension|func|import|init|let|protocol|static|struct|subscript|typealias|var|break|case|continue|default|do|else|fallthrough|if|in|for|return|switch|where|while|as|dynamicType|is|new|super|self|__COLUMN__|__FILE__|__FUNCTION__|__LINE__|didSet|get|inout|mutating|override|set|unowned|weak|willSet)\\b", attributes: [NSForegroundColorAttributeName : "#66D9EF".color!]), CYRToken(name: "String", expression: "\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"|'(?:[^'\\\\]|\\\\[\\s\\S])*'", attributes: [NSForegroundColorAttributeName : "#E6DB74".color!]), CYRToken(name: "Comment", expression: "^//.*|\\s//.*|/\\*[\\s\\S]*?\\*/|#.*|", attributes: [NSForegroundColorAttributeName : "#75715E".color!]), ] } } ================================================ FILE: Sublime/Sublime/CodeViewController.swift ================================================ // // FileViewController.swift // Sublime // // Created by Eular on 2/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import CYRTextView class CodeViewController: UIViewController, UIScrollViewDelegate, PopupMenuDelegate { var curFile: Code? var codeShareImage: UIImage? var codeCardView: UIView? var blackMaskView: UIView? var hideStatusBar = false let codeText = CodeEngine().textView let popupMenu = PopupMenu() override func viewDidLoad() { super.viewDidLoad() title = curFile!.name view.backgroundColor = Constant.CodeBackgroudColor self.automaticallyAdjustsScrollViewInsets = false let bottom = Constant.NavigationBarOffset codeText.frame = view.frame codeText.contentInset.bottom = bottom codeText.scrollIndicatorInsets.bottom = bottom codeText.text = curFile!.read()+"\n" codeText.setLineBreakMode(.ByCharWrapping) view.addSubview(codeText) // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.delegate = self popupMenu.itemsToShare = [curFile!.url] // Add a selected menu item let shareCodeItem = UIMenuItem(title: NSLocalizedString("SHARE_IN_PICTURE", comment: "Share in picture"), action: #selector(self.shareCodeInPicture)) UIMenuController.sharedMenuController().menuItems = [shareCodeItem] // 保持屏幕常亮 UIApplication.sharedApplication().idleTimerDisabled = true // 下滑显示导航栏+状态栏,上滑收起导航栏+状态栏 (codeText as UIScrollView).delegate = self // 点击屏幕显示或隐藏导航栏+状态栏 if Config.FullScreenCodeReadingMode { codeText.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.hideOrShowStatusBar))) } } // 下滑显示导航栏+状态栏,上滑收起导航栏+状态栏 func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { if Config.FullScreenCodeReadingMode { if velocity.y < 0 { hideStatusBar = false } else if velocity.y > 0 { hideStatusBar = true } let bottom = hideStatusBar ? 0 : Constant.NavigationBarOffset codeText.contentInset.bottom = bottom codeText.scrollIndicatorInsets.bottom = bottom navigationController?.setNavigationBarHidden(hideStatusBar, animated: true) self.setNeedsStatusBarAppearanceUpdate() } } func hideOrShowStatusBar() { hideStatusBar = !hideStatusBar let bottom = hideStatusBar ? 0 : Constant.NavigationBarOffset codeText.contentInset.bottom = bottom codeText.scrollIndicatorInsets.bottom = bottom navigationController?.setNavigationBarHidden(hideStatusBar, animated: true) self.setNeedsStatusBarAppearanceUpdate() } override func prefersStatusBarHidden() -> Bool { return hideStatusBar } override func viewDidDisappear(animated: Bool) { // 取消屏幕常亮 UIApplication.sharedApplication().idleTimerDisabled = false // 记录位置 curFile?.lastReadPosition = Double(codeText.contentOffset.y) } // Generate a picture to share code func shareCodeInPicture() { let rects = codeText.selectionRectsForRange(codeText.selectedTextRange!) codeText.selectable = false codeText.setLineBreakMode(.ByCharWrapping) let minR = rects.minElement { (a, b) -> Bool in return a.rect.origin.y < b.rect.origin.y } let maxR = rects.maxElement { (a, b) -> Bool in return a.rect.origin.y < b.rect.origin.y } let frame = CGRectMake(0, minR!.rect.origin.y, codeText.width, maxR!.rect.origin.y - minR!.rect.origin.y + 16) makeShareCodePicture(codeText.snapshot(frame)) codeText.selectable = true } func makeShareCodePicture(codeImg: UIImage) -> UIImage { let w = codeImg.size.width let h = codeImg.size.height let sideMargin: CGFloat = 15 let topMargin: CGFloat = 100 let buttomMargin: CGFloat = 60 let headImg = UIImageView(frame: CGRectMake(sideMargin, 20, 60, 60)) headImg.image = UIImage(named: "setting_sublime") let nameLB = UILabel() nameLB.frame = CGRectMake(sideMargin + headImg.width + 10, 25, w - headImg.width - 10, 15) nameLB.text = "Sublime" nameLB.textColor = UIColor.grayColor() nameLB.font = nameLB.font.fontWithSize(14) if GitHubAPIManager.isLogin { nameLB.text = GitHubAPIManager.sharedInstance.user["name"].string if let avatar_url = GitHubAPIManager.sharedInstance.user["avatar_url"].string { headImg.imageFromUrl(avatar_url) headImg.layer.cornerRadius = headImg.width / 2 headImg.clipsToBounds = true headImg.layer.borderWidth = 1 headImg.layer.borderColor = UIColor.whiteColor().CGColor } } let textInput = UITextView() textInput.frame = CGRectMake(sideMargin + headImg.width + 5, nameLB.y + nameLB.height, w - headImg.width - 5, 50) textInput.text = "What’s amazing, this code save me from hair pulling!" textInput.textColor = UIColor.whiteColor() textInput.textContainer.maximumNumberOfLines = 2 textInput.backgroundColor = UIColor.clearColor() textInput.font = textInput.font?.fontWithSize(16) textInput.setLineBreakMode(.ByWordWrapping) textInput.tag = 211 let doneBtn = UIButton() doneBtn.frame = CGRectMake(2 * sideMargin + w - 50, 10, 40, 30) doneBtn.setImage(UIImage(named: "code_share_btn"), forState: .Normal) doneBtn.addTarget(self, action: #selector(self._tapOnShareCodeSendButton), forControlEvents: .TouchUpInside) doneBtn.tag = 212 let codeImgView = UIImageView(frame: CGRectMake(sideMargin, topMargin, w, h)) codeImgView.image = codeImg // set shadow codeImgView.layer.shadowOffset = CGSizeMake(0, 2) codeImgView.layer.shadowRadius = 2 codeImgView.layer.shadowColor = UIColor.blackColor().CGColor codeImgView.layer.shadowOpacity = 0.5 let fileLB = UILabel() fileLB.frame = CGRectMake(sideMargin, topMargin + h + 20, w, 20) fileLB.text = "—— \(curFile!.name)" fileLB.textColor = UIColor.grayColor() fileLB.textAlignment = .Right fileLB.font = fileLB.font.fontWithSize(14) let codeCard = UIView() codeCard.backgroundColor = Constant.CodeLineNumberBackgroudColor codeCard.frame = CGRectMake(0, 0, w + 2 * sideMargin, topMargin + h + buttomMargin) // set shadow codeCard.layer.shadowOffset = CGSizeMake(0, 2) codeCard.layer.shadowRadius = 2 codeCard.layer.shadowColor = UIColor.blackColor().CGColor codeCard.layer.shadowOpacity = 0.5 codeCard.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self._tapOnShareCodeBlackMaskView))) let blackView = UIView() blackView.frame = view.window!.frame blackView.backgroundColor = RGB(0, 0, 0, alpha: 0.8) blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self._tapOnShareCodeBlackMaskView))) codeCard.addSubview(headImg) codeCard.addSubview(nameLB) codeCard.addSubview(textInput) codeCard.addSubview(doneBtn) codeCard.addSubview(codeImgView) codeCard.addSubview(fileLB) codeCard.transform = CGAffineTransformMakeScale(0, 0) view.window?.addSubview(blackView) view.window?.addSubview(codeCard) codeCard.atCenter() UIView.animateWithDuration(0.5) { codeCard.transform = CGAffineTransformMakeScale(0.85, 0.85) } blackMaskView = blackView codeCardView = codeCard return codeImg } func _tapOnShareCodeBlackMaskView() { _removeShareCode(completion: nil) } func _removeShareCode(completion completion: ((codeCard: UIView) -> Void)?) { if let blackView = blackMaskView, let codeCard = codeCardView { let input = codeCard.viewWithTag(211) as! UITextView if !input.resignFirstResponder() { UIView.animateWithDuration(0.5, animations: { codeCard.y += self.view.height }, completion: { (_) in codeCard.removeFromSuperview() blackView.removeFromSuperview() completion?(codeCard: codeCard) }) } } } func _tapOnShareCodeSendButton() { _removeShareCode { (codeCard) in codeCard.transform = CGAffineTransformMakeScale(1, 1) codeCard.viewWithTag(212)?.removeFromSuperview() self.codeShareImage = codeCard.snapshot() self.popupMenu.showUp() } } override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { if action == #selector(self.shareCodeInPicture) { return true } return super.canPerformAction(action, withSender: sender) } // 旋转屏幕 override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) { let bottom = Constant.NavigationBarOffset codeText.frame = CGRectMake(0, 0, view.width, view.height + bottom) codeText.contentInset.bottom = bottom codeText.scrollIndicatorInsets.bottom = bottom } func tapOnPopupMenuItem(itemIndex i: Int) { switch i { case 2: // 微信 if let codeImg = codeShareImage { codeShareImage = nil WXShareImage(codeImg) } else { getGhostbinUrl(curFile!.codeLang, text: curFile!.read(), target: self) { url in self.WXShareLink(self.curFile!.name, desc: "给你分享一个神奇的代码", img: "file_code_share", link: url) } } case 3: // 朋友圈 if let codeImg = codeShareImage { codeShareImage = nil WXShareImage(codeImg, isTimeline: true) } else { getGhostbinUrl(curFile!.codeLang, text: curFile!.read(), target: self) { url in self.WXShareLink("这是一份神奇的代码: \(self.curFile!.name)", desc: "", img: "file_code_share", link: url, isTimeline: true) } } default: return } } } ================================================ FILE: Sublime/Sublime/ConfigTableViewController.swift ================================================ // // ConfigTableViewController.swift // Sublime // // Created by Eular on 4/7/16. // Copyright © 2016 Eular. All rights reserved. // class ConfigTableViewController: UITableViewController { @IBOutlet weak var cycriptLabel: UILabel! @IBOutlet weak var cycriptSwitch: UISwitch! @IBOutlet weak var codeReadingSwitch: UISwitch! @IBOutlet weak var showHiddenFilesSwitch: UISwitch! let secTitle = [" Debug", " System"] override func viewDidLoad() { super.viewDidLoad() tableView.allowsSelection = false if Network.isConnectedToNetwork() { let ip = Network.getIFAddresses()[0] cycriptLabel.text = "\(ip):8888" } cycriptSwitch.on = Config.CycriptStartListen codeReadingSwitch.on = Config.FullScreenCodeReadingMode showHiddenFilesSwitch.on = Config.ShowHiddenFiles } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) } @IBAction func cycriptChangeStatus(sender: UISwitch) { Config.CycriptStartListen = sender.on if sender.on { CYListenServer(8888) } else { view.Toast(message: "Restart the app to stop Cycript") } } @IBAction func codeReadingChangeStatus(sender: UISwitch) { Config.FullScreenCodeReadingMode = sender.on } @IBAction func showHiddenChangeStatus(sender: UISwitch) { Config.ShowHiddenFiles = sender.on } } ================================================ FILE: Sublime/Sublime/Configure.swift ================================================ // // Configure.swift // Sublime // // Created by Eular on 4/26/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Config { // Cycript开启监听 static var CycriptStartListen: Bool { get { return Global.Database.boolForKey("Config-CycriptStartListen") } set { Global.Database.setBool(newValue, forKey: "Config-CycriptStartListen") } } // 下滑全屏 static var FullScreenCodeReadingMode: Bool { get { return Global.Database.boolForKey("Config-FullScreenCodeReadingMode") } set { Global.Database.setBool(newValue, forKey: "Config-FullScreenCodeReadingMode") } } // 显示隐藏文件 static var ShowHiddenFiles: Bool { get { return Global.Database.boolForKey("Config-ShowHiddenFiles") } set { Global.Database.setBool(newValue, forKey: "Config-ShowHiddenFiles") } } // 是否为本项目点赞 static var Starred: Bool { get { return Global.Database.boolForKey("Donate-Starred") } set { Global.Database.setBool(newValue, forKey: "Donate-Starred") } } // 是否关注作者 static var FollowedAuthor: Bool { get { return Global.Database.boolForKey("Donate-FollowedAuthor") } set { Global.Database.setBool(newValue, forKey: "Donate-FollowedAuthor") } } static var WeixinDonated: Bool { get { return Global.Database.boolForKey("Donate-WeixinDonated") } set { Global.Database.setBool(newValue, forKey: "Donate-WeixinDonated") } } static var AlipayDonated: Bool { get { return Global.Database.boolForKey("Donate-AlipayDonated") } set { Global.Database.setBool(newValue, forKey: "Donate-AlipayDonated") } } } ================================================ FILE: Sublime/Sublime/Constant.swift ================================================ // // Constant.swift // Sublime // // Created by Eular on 4/26/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Constant { // Color static let TableCellColor = "#515151".color static let TableCellSeparatorColor = "#515151".color static let TableCellSelectedColor = RGB(60, 60, 60) static let ActionSheetColor = UIColor.whiteColor() static let ActionSheetTextColor = UIColor.blackColor() static let ActionSheetLineColor = RGB(200, 200, 200, alpha: 0.5) static let BlackMaskViewColor = RGB(0, 0, 0, alpha: 0.5) static let CapeCod = RGB(81, 81, 81) static let CodeBackgroudColor = RGB(52, 53, 46) static let CodeLineNumberBackgroudColor = RGB(39, 40, 34) static let TableLoadingCircleColor = RGB(78, 221, 200) static let GithubTableShowMsgLabelTextColor = UIColor.grayColor() static let GithubTableShowMsgLabelTextShadowColor = RGB(40, 40, 40) static let TabBatItemBadgeColor = RGB(256, 0, 0, alpha: 0.8) static let PopupMenuColor = UIColor.whiteColor() static let NavigationBarColor = RGB(81, 81, 81) static let NavigationBarAndTabBarColor = RGB(81, 81, 81) // Identifies static let GithubTableCellIdentifier = "GithubTableCellIdentifier" static let SettingTableCellIdentifier = "SettingTableCellIdentifier" static let GithubSegue = "githubSegue" static let FolderStoryboardID = "FolderStoryboard" static let ContactTableStoryboardID = "ContactTableVC" static let ContactInfoStoryboardID = "ContactInfoVC" static let AppGithubUrl = "https://github.com/urinx" // Number static let TabBarHeight: CGFloat = 49 static let FilesTableSectionHight: CGFloat = 22 static let SSHServerListCellHeight: CGFloat = 60 static var NavigationBarOffset: CGFloat { guard let navBar = UIApplication.topViewController()?.navigationController?.navigationBar else { return 64 } return navBar.y + navBar.height } // License static let License = [ "AASquaresLoading", "Alamofire", "AlamofireRSSParser", "Charts", "CYRTextView", "DGElasticPullToRefresh", "EZAudio", "Gifu", "NMSSH", "MobileVLCKit", "RongCloudIMKit", "SJCSimplePDFView", "SSZipArchive", "Swifter", "SwiftyJSON", "ZLMusicFlowWaveView", "ZLSinusWaveView" ] // Github Application static let githubClientID = "5b2b9bdf9c689989240c" static let githubClientSecret = "538fb1ae3b29ff7a5c86dea3b2605870a3d9e146" // Weixin Application static let weixinAppID = "wxb597aecde6aadd28" // static let weixinAppID = "wxeb7ec651dd0aefa9" //微信网页版ID // 融云 static let RongCloudAppKey = "m7ua80gbu9itm" static let RongCloudAppSecret = "n36KioPk7esTtR" static let RongCloudAuthorUserID = "Urinx" static let RongCloudAuthorUserName = "Uri" static let RongCloudDefaultUserPortrait = "http://cdn.duitang.com/uploads/item/201509/27/20150927191624_2tnMS.thumb.700_0.jpeg" static let RongCloudRobotID = "KEFU145857181547734" static let RongCloudRobotName = "客服机器人" static let RongCloudUnreadMessageNotifi = "hasUnreadMessagesNotifi" // Share Items static let PopupMenuDefaultShareItems = [ ["title":"QQ", "image":"Share_qq_icon"], ["title":"新浪微博", "image":"Share_sina_icon"], ["title":"微信", "image":"Share_wechat_session_icon"], ["title":"朋友圈", "image":"Share_wechat_timeline_icon"], ["title":"Facebook", "image":"Share_facebook_icon"], ["title":"Line", "image":"Share_line_icon"], ["title":"Instagram", "image":"Share_instagram"], ["title":"Twitter", "image":"Share_twitter_icon"], ["title":"QQ空间", "image":"Share_qzone_icon"], ["title":"Pinterest", "image":"Share_pinterest_icon"], ["title":"豆瓣", "image":"Share_douban_icon"] ] static var SublimeRoot: String { return NSHomeDirectory() + "/Documents/.Sublime" } static var CachePath: String { return NSHomeDirectory() + "/Library/Caches/" } static let AppGithubLink = "https://github.com/Urinx/Sublime" } ================================================ FILE: Sublime/Sublime/ContactInfoViewController.swift ================================================ // // ContactInfoViewController.swift // Sublime // // Created by Eular on 4/1/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class ContactInfoViewController: UIViewController, PopupMenuDelegate { @IBOutlet weak var headImageView: UIImageView! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var githubLabel: UILabel! @IBOutlet weak var QRImageView: UIImageView! let popupMenu = PopupMenu() var id = "" var nameCardImage: UIImage { get { return view.snapshot(CGRectMake(0, Constant.NavigationBarOffset, view.width, view.height - 100)) } } override func viewDidLoad() { super.viewDidLoad() if id.isEmpty { githubLabel.text = "github: null" headImageView.image = UIImage(named: "user_robot") nameLabel.text = Constant.RongCloudRobotName QRImageView.image = QRCode().makeWithColor(Constant.AppGithubLink) } else { githubLabel.text = "github: \(id)" RCIM.sharedRCIM().getInfo(id) { (name, portrait) in dispatch_async(dispatch_get_main_queue()) { self.headImageView.imageFromUrl(portrait) self.nameLabel.text = name } } QRImageView.image = QRCode().makeWithColor("https://github.com/\(id)") } // set shadow QRImageView.layer.shadowOffset = CGSizeMake(0, 2) QRImageView.layer.shadowRadius = 2 QRImageView.layer.shadowColor = UIColor.blackColor().CGColor QRImageView.layer.shadowOpacity = 0.5 // recognize qrcode QRImageView.recognizeQRCodeEnabled = true // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.delegate = self } override func viewDidAppear(animated: Bool) { popupMenu.itemsToShare = [nameCardImage] } func tapOnPopupMenuItem(itemIndex i: Int) { switch i { case 2: WXShareImage(nameCardImage) case 3: WXShareImage(nameCardImage, isTimeline: true) default: return } } } ================================================ FILE: Sublime/Sublime/ContactTableViewController.swift ================================================ // // ContactTableViewController.swift // Sublime // // Created by Eular on 3/21/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class ContactTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let infoBtn = UIBarButtonItem(image: UIImage(named: "user_info"), style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.lookUserInfo)) navigationItem.rightBarButtonItem = infoBtn let lb = UILabel() lb.text = "2 位联系人" lb.font = lb.font.fontWithSize(13) lb.textAlignment = .Center lb.textColor = UIColor.grayColor() lb.frame = CGRectMake(0, 0, view.bounds.width, 60) tableView.tableFooterView = lb } func lookUserInfo() { let contactInfoVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(Constant.ContactInfoStoryboardID) as! ContactInfoViewController contactInfoVC.id = RCIM.sharedRCIM().currentUserInfo.userId navigationController?.pushViewController(contactInfoVC, animated: true) } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let chat = RCChatViewController() switch indexPath.section { case 1: chat.conversationType = .ConversationType_APPSERVICE chat.title = Constant.RongCloudRobotName chat.targetId = Constant.RongCloudRobotID case 2: chat.conversationType = .ConversationType_PRIVATE chat.title = Constant.RongCloudAuthorUserName chat.targetId = Constant.RongCloudAuthorUserID default: return } navigationController?.pushViewController(chat, animated: true) } } ================================================ FILE: Sublime/Sublime/CustomServer.swift ================================================ // // CustomServer.swift // Sublime // // Created by Eular on 3/10/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import Swifter extension HttpHandlers { public class func shareFilesFromDirectory(directoryPath: String, serverLog: WebServerLog?) -> (HttpRequest -> HttpResponse) { return { r in guard let fileRelativePath = r.params.first else { serverLog?.log(r, statusCode: 404) return Page404() } let absolutePath = directoryPath + "/" + fileRelativePath.1 guard let file = try? Swifter.File.openForReading(absolutePath) else { serverLog?.log(r, statusCode: 404) serverLog?.log("Error: Read file failed", isError: true) return Page404() } serverLog?.log(r, statusCode: 200) return .RAW(200, "OK", [:], { writer in var buffer = [UInt8](count: 64, repeatedValue: 0) while let count = try? file.read(&buffer) where count > 0 { writer.write(buffer[0.. HttpResponse { let html = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("Web/404", ofType: "html")!)! var array = [UInt8](count: html.length, repeatedValue: 0) html.getBytes(&array, length: html.length) return .RAW(200, "OK", nil, { $0.write(array) }) } } public func CustomServer(serverLog: WebServerLog?) -> HttpServer { let server = HttpServer() let publicDir = Folder(path: Constant.SublimeRoot+"/var/www") server["/:path"] = HttpHandlers.shareFilesFromDirectory(publicDir.path, serverLog: serverLog) server["/"] = { r in if let html = NSData(contentsOfFile:"\(publicDir.path)/index.html") { serverLog?.log(r) var array = [UInt8](count: html.length, repeatedValue: 0) html.getBytes(&array, length: html.length) return HttpResponse.RAW(200, "OK", nil, { $0.write(array) }) } else { serverLog?.log(r, statusCode: 404) return HttpHandlers.Page404() } } return server } ================================================ FILE: Sublime/Sublime/DonateViewController.swift ================================================ // // DonateViewController.swift // Sublime // // Created by Eular on 5/6/16. // Copyright © 2016 Eular. All rights reserved. // class DonateViewController: UITableViewController { let secTitle = [ "Never doubt a little star can make a difference", "Because of you guys, I'm not alone anymore", "Money is devil, but devil push me to make this better", "2016.5 夏日小记" ] let cellText = [ ["└─ Star Project:\(Config.Starred)"], ["└─ Follow Author:\(Config.FollowedAuthor)"], ["├─ Weixin Donate:\(Config.WeixinDonated)", "└─ AliPay Donate:\(Config.AlipayDonated)"], [ "从2012年那个秋季踏入这个校园开始,没想到,四年就这样过去了,山河仍在,心境已改。说快不快,也不是那么的让人缓慢,倒有点像暴雨前夕般让人闷热难耐。", "大学四年,尽管都是从相同的起点走到相同的终点,可是在这样一个不满足柯西公式的世界里,路径不同,风景不同,结果总会让人相视无言。", "img:donate1", "此时我处于图书馆六楼一个坐在靠窗座位上的场景下,早上的图书馆人来的较少,之前复习的学生也随着刚过去的考试周而退潮,周围只有零星几个看书的少年。这个时候再回过头来看看自己大学这段时期,讲真,也没啥可回忆的。那个你曾经憧憬的大学生活,等你真正体验过,才明白原来不过如此。大学里让你映像最深刻的一件事是什么是一个很难回答的问题,至少,我给不出答案。", "有时候我不得不承认,自己确实是一个失败的人。每天浑浑噩噩,虚度光阴,三点一线的穿梭在校园,就像一部黑白默片,悄无声息的放映着,直到最后,才发现什么都没做,才发现自己是多么的一无是处。就像太宰治所说,生而为人,我很抱歉。", "img:donate2", "当我第一次注意到《咒怨》里的佐佐木希,我就发现我喜欢上她了,她在《天使之恋》里的表现也让人激动。我还记得有一个场景里,她那45度角仰望青空,若有所思的样子让人沉迷。不过让人遗憾的是,我的佐佐木希并没有在大学四年里出现在我的身边,尽管我也曾多么希望有那么一位能一起共享这段时光。好吧,诸事难遂人意,强争无益。", "img:donate3", "为什么做这个,也许是自己闲的蛋疼,也许是给自己这四年最后的一个交代。记得是那天晚上,我又一次的失眠了,与外界的安逸不同,内心的躁动让我辗转反侧。掏出手机,微信上各种小红点以及庞大的信息流让人无所适从,夜深人静的时候,有时你会发现,莫名的,自己突然想看看代码了。", "在手机上阅读源码,就是这么简单的一件事,在App store上搜索了半天,代码阅读的应用没几个,也没有一个令人满意的:Codeanywhere的代码是存在云端要联网;CodeMate支持多种代码,但功能单一;Pythonista最强大,能够在手机上本地运行python脚本无所不能,具有多种主题,不过价格较贵,且主要是针对python代码。在现实面前,这是我唯一能做到的不妥协和不将就。所以,那就自己做了,就这样。", "img:donate4", "安迪·安德鲁斯说过,人的一生中至少有两次冲动,一次奋不顾身的爱情,一次说走就走的旅行。世界那么大,说实话,还真没怎么看过,我想去看看。", "img:donate5", "(完) —— 2016.5.31 K.K M" ] ] let headerHeight: CGFloat = 300 let headerImage = UIImageView() var player: AVAudioPlayer! override func viewDidLoad() { super.viewDidLoad() title = "Donate" view.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.TableCellSeparatorColor tableView.estimatedRowHeight = 44 tableView.rowHeight = UITableViewAutomaticDimension tableView.contentInset = UIEdgeInsets(top: headerHeight, left: 0, bottom: 0, right: 0) headerImage.frame = CGRectMake(0, -headerHeight, view.width, headerHeight) headerImage.image = UIImage(named: "donate") headerImage.contentMode = .ScaleAspectFill tableView.addSubview(headerImage) tableView.sendSubviewToBack(headerImage) do { player = try AVAudioPlayer(contentsOfURL: NSBundle.mainBundle().URLForResource("山外小楼夜听雨.m4a", withExtension: nil)!) player.numberOfLoops = -1 player.play() } catch {} } override func scrollViewDidScroll(scrollView: UIScrollView) { let point = scrollView.contentOffset headerImage.frame = CGRectMake(0, point.y, view.width, -point.y) if point.y > -headerHeight && point.y <= 0 { tableView.contentInset = UIEdgeInsets(top: abs(point.y), left: 0, bottom: 0, right: 0) } else if point.y > 0 { tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) } } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = " "+secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return secTitle.count } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return cellText[section].count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Default, reuseIdentifier: nil) cell.backgroundColor = Constant.TableCellColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.textLabel?.textColor = UIColor.whiteColor() cell.tintColor = UIColor.whiteColor() let text = cellText[indexPath.section][indexPath.row] if indexPath.section == secTitle.count - 1 { cell.selectedBackgroundView?.backgroundColor = Constant.TableCellColor cell.textLabel?.numberOfLines = 0 if text.hasPrefix("img:") { let name = text.split(":")[1] let width = view.width - 17 * 2 cell.imageView?.image = UIImage(named: name)?.rescaleImageByWidth(width) } else { cell.textLabel?.text = text cell.textLabel?.lineBreakMode = .ByCharWrapping cell.textLabel?.font = cell.textLabel?.font.fontWithSize(15) } } else { cell.textLabel?.text = text.split(":")[0] cell.accessoryType = text.split(":")[1] == "true" ? .Checkmark : .DisclosureIndicator cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor } return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) switch (indexPath.section, indexPath.row) { case (0,0): if !Config.Starred { if GitHubAPIManager.isLogin { if Network.isConnectedToNetwork() { let github = GitHubAPIManager() github.star("Urinx", repo: "WeixinBot", success: { let cell = tableView.cellForRowAtIndexPath(indexPath) cell?.accessoryType = .Checkmark Config.Starred = true }, fail: { self.view.window?.Toast(message: "The network is not well, please try again") }) } else { view.window?.Toast(message: "Error: No network") } } else { let alert = UIAlertController(title: "(*´ڡ`●)", message: "Ops! This function requires that Github account is logined.", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) presentViewController(alert, animated: true, completion: nil) } } case (1,0): if !Config.FollowedAuthor { if GitHubAPIManager.isLogin { if Network.isConnectedToNetwork() { let github = GitHubAPIManager() github.follow("Urinx", success: { let cell = tableView.cellForRowAtIndexPath(indexPath) cell?.accessoryType = .Checkmark Config.FollowedAuthor = true }, fail: { self.view.window?.Toast(message: "The network is not well, please try again") }) } else { view.window?.Toast(message: "Error: No network") } } else { let alert = UIAlertController(title: "(*´ڡ`●)", message: "Ops! This function requires that Github account is logined.", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) presentViewController(alert, animated: true, completion: nil) } } case (2,0): // https://wx.tenpay.com/f2f?t=AQAAAAKUGF%2BtHt037N4rgTLUV54%3D Config.WeixinDonated = true let cell = tableView.cellForRowAtIndexPath(indexPath) cell?.accessoryType = .Checkmark WXShareImage(UIImage(named: "donate_weixin")!) case (2,1): // #吱口令#gSstPA146v let pasteBoard = UIPasteboard.generalPasteboard() pasteBoard.string = "#吱口令#gSstPA146v" Config.AlipayDonated = true let cell = tableView.cellForRowAtIndexPath(indexPath) cell?.accessoryType = .Checkmark UIApplication.sharedApplication().openURL(NSURL(string: "alipay://")!) default: break } } } ================================================ FILE: Sublime/Sublime/ExploreTableViewController.swift ================================================ // // ExploreTableViewController.swift // Sublime // // Created by Eular on 4/6/16. // Copyright © 2016 Eular. All rights reserved. // class ExploreTableViewController: UITableViewController { @IBOutlet weak var msgCountLB: UILabel! let secTitle = [" Explore", " Function"] override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(animated: Bool) { msgCountLB.hidden = true if Global.UnreadMessageCount != 0 { msgCountLB.text = "\(Global.UnreadMessageCount)" msgCountLB.hidden = false } tabBarController?.tabBar.hideRedBadgeOnItem(1) } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) // Functions switch (indexPath.section, indexPath.row) { // case (0,0): // let gvc = GistTable() // gvc.hidesBottomBarWhenPushed = true // navigationController?.pushViewController(gvc, animated: true) case (1,1): let svc = SSHServerListTableViewController() svc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(svc, animated: true) case (1,2): if GitHubAPIManager.isLogin { let messageList = MessageListViewController() messageList.hidesBottomBarWhenPushed = true navigationController?.pushViewController(messageList, animated: true) } else { let alert = UIAlertController(title: "(*´ڡ`●)", message: "Ops! This function requires that Github account is logined.", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) presentViewController(alert, animated: true, completion: nil) } case (1,3): let rss = RSSListTableViewController() rss.hidesBottomBarWhenPushed = true navigationController?.pushViewController(rss, animated: true) case (1,4): let qrReader = QRCodeReaderViewController() qrReader.hidesBottomBarWhenPushed = true navigationController?.pushViewController(qrReader, animated: true) default: return } } } ================================================ FILE: Sublime/Sublime/FolderTableViewController.swift ================================================ // // FolderTableViewController.swift // Sublime // // Created by Eular on 2/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class FolderTableViewController: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, ActionSheetDelegate { var curFolder: Folder = Folder(path: NSHomeDirectory()+"/Documents") var mainViewFlag: Int = 1 var fileList: [File] = [] var actionSheet: ActionSheet! override func viewDidLoad() { super.viewDidLoad() title = curFolder.name tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.TableCellSeparatorColor self.clearsSelectionOnViewWillAppear = true tableView.tintColor = UIColor.whiteColor() // Dropdown Menu actionSheet = ActionSheet(rowWidth: view.width, rowHight: 50) actionSheet.items = ["File", "Folder", "Image"] actionSheet.controller = self actionSheet.delegate = self navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: actionSheet, action: #selector(actionSheet.showUp)) } override func viewWillAppear(animated: Bool) { updateFileListData() } override func viewDidAppear(animated: Bool) { updateFileListData() } func updateFileListData() { fileList = curFolder.listFiles() // 隐藏文件 if !Config.ShowHiddenFiles { fileList = fileList.filter { !$0.name.hasPrefix(".") } } // 按目录在最上面规则排序 fileList.sortInPlace { if $0.0.isDir && $0.1.isDir { return false } else { return $0.0.isDir } } tableView.reloadData() } func tapOnActionSheetItem(itemAtRow row: Int) { switch row { case 0, 1: let nvc = NewFileViewController() nvc.tag = row nvc.curFolder = curFolder navigationController?.pushViewController(nvc, animated: true) case 2: let imgPicker = UIImagePickerController() imgPicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary imgPicker.delegate = self self.presentViewController(imgPicker, animated: true, completion: nil) default: return } } // 保存图片 func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { let image = info["UIImagePickerControllerOriginalImage"] as! UIImage let url = info["UIImagePickerControllerReferenceURL"] as! NSURL curFolder.saveImage(image, name: "IMG_\(random(1000)).\(url.pathExtension!.lower)", url: url) picker.dismissViewControllerAnimated(true, completion: nil) } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return fileList.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Default, reuseIdentifier: nil) let f = fileList[indexPath.row] setFileTableCell(cell, name: f.name, imgname: f.img, isDir: f.isDir) return cell } func setFileTableCell(cell: UITableViewCell, name: String, imgname: String, isDir: Bool) { cell.backgroundColor = Constant.TableCellColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = isDir ? .DisclosureIndicator : .None cell.textLabel?.text = name cell.textLabel?.textColor = UIColor.whiteColor() let img = UIImageView() img.frame = CGRectMake(14, 8, 28, 28) img.image = UIImage(named: imgname) cell.imageView?.contentMode = .ScaleAspectFit cell.addSubview(img) // 占位用 cell.imageView?.image = UIImage(named: "tab_icon_files") cell.imageView?.hidden = true } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) switch indexPath.section + mainViewFlag { case 0: let gvc = GithubTableViewController() gvc.tag = indexPath.row gvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(gvc, animated: true) case 1: let file = fileList[indexPath.row] if file.isDir { let fvc = FolderTableViewController() fvc.hidesBottomBarWhenPushed = true fvc.curFolder = file as! Folder navigationController?.pushViewController(fvc, animated: true) } else if file.isImg { let ivc = ImagePageViewController() let imgList = fileList.filter { $0.isImg } ivc.index = (imgList as NSArray).indexOfObject(file) ivc.imgList = imgList ivc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(ivc, animated: true) } else if file.isAudio { let mvc = MusicViewController() mvc.curFile = file mvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(mvc, animated: true) } else if file.isVideo { let vvc = VideoViewController() vvc.curFile = file vvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(vvc, animated: true) } else if file.ext == "pdf" { let pvc = PDFViewController() pvc.curFile = file pvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(pvc, animated: true) } else if file.ext == "zip" { //... } else { let fvc = CodeViewController() fvc.curFile = Code(path: file.path, language: file.codeLang) fvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(fvc, animated: true) } default: return } } override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return indexPath.section + mainViewFlag == 1 } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let f = fileList.removeAtIndex(indexPath.row) f.delete() tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } } } ================================================ FILE: Sublime/Sublime/Gist.swift ================================================ // // Gist.swift // Sublime // // Created by Eular on 5/9/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import SwiftyJSON import Alamofire struct Gist { var url: String var ownerLogin: String var description: String var avatar_url: String var comments: Int var created_at: String var files: [[String: String]] = [] init(json: JSON) { self.url = json["url"].string ?? "" self.description = json["description"].string ?? "" self.ownerLogin = json["owner"]["login"].string ?? "" self.avatar_url = json["owner"]["avatar_url"].string ?? "" self.comments = json["comments"].int ?? 0 let time = json["created_at"].string?.replace("T", " ").replace("Z", "") ?? "" self.created_at = time for (key, value) in json["files"] { var t: [String: String] = [:] t["raw_url"] = value["raw_url"].string t["size"] = value["size"].string t["language"] = value["language"].string t["filename"] = key self.files << t } } func getRawData(completion: ((content: String) -> Void)? = nil) { let url = self.files[0]["raw_url"]! Alamofire.request(.GET, url).responseString { response in guard let content = response.result.value else { return } completion?(content: content) } } } ================================================ FILE: Sublime/Sublime/GistTable.swift ================================================ // // GistTable.swift // Sublime // // Created by Eular on 5/9/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation class GistTable: UITableViewController { let github = GitHubAPIManager() let refreshController = UIRefreshControl() var gistData: [Gist] = [] override func viewDidLoad() { super.viewDidLoad() title = "Gist" view.backgroundColor = Constant.CapeCod tableView.separatorColor = UIColor.clearColor() tableView.estimatedRowHeight = 216 tableView.rowHeight = UITableViewAutomaticDimension tableView.allowsSelection = false makeTableHeader() // add pull-to-refresh refreshController.addTarget(self, action: #selector(self.refreshData), forControlEvents: UIControlEvents.ValueChanged) refreshController.tintColor = UIColor.whiteColor() tableView.addSubview(refreshController) // right bar item let downloadBtn = UIBarButtonItem(barButtonSystemItem: .Camera, target: self, action: nil) navigationItem.rightBarButtonItem = downloadBtn refreshData() } func makeTableHeader() { let headerView = UIView() let bgImgView = UIImageView() let headImgView = UIImageView() let nameLabel = UILabel() let headerWidth = self.view.bounds.size.width let headerHeight = headerWidth - 30 let imgOffset = CGFloat(-60) let headImgWidth = CGFloat(70) let labelWidth = headerWidth - headImgWidth - 25 let labelHeight = CGFloat(30) headerView.frame = CGRectMake(0, 0, headerWidth, headerHeight) headerView.backgroundColor = UIColor.whiteColor() bgImgView.frame = CGRectMake(0, imgOffset, headerWidth + 5, headerWidth) bgImgView.image = UIImage(named: "gist_bg") bgImgView.contentMode = .ScaleAspectFill headerView.addSubview(bgImgView) headImgView.frame = CGRectMake(headerWidth - headImgWidth - 10, headerHeight - headImgWidth - 10, headImgWidth, headImgWidth) headImgView.layer.borderWidth = 1 headImgView.layer.borderColor = UIColor.whiteColor().CGColor if let avatar_url = github.user["avatar_url"].string { headImgView.imageFromUrl(avatar_url) } headerView.addSubview(headImgView) nameLabel.frame = CGRectMake(0, headerHeight - labelHeight - 35, labelWidth, labelHeight) nameLabel.text = github.user["name"].string nameLabel.textColor = UIColor.whiteColor() nameLabel.textAlignment = .Right nameLabel.font = UIFont(name: nameLabel.font.fontName, size: 19) headerView.addSubview(nameLabel) tableView.tableHeaderView = headerView } func refreshData() { github.listGists { gists in self.gistData = gists self.tableView.reloadData() self.refreshController.endRefreshing() } } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return gistData.count == 0 ? 1:gistData.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("gistCell", forIndexPath: indexPath) if gistData.count != 0 { let gist = gistData[indexPath.row] let header = cell.viewWithTag(6) as! UIImageView let title = cell.viewWithTag(3) as! UILabel let description = cell.viewWithTag(4) as! UILabel let comment = cell.viewWithTag(7) as! UILabel let time = cell.viewWithTag(5) as! UILabel let codeView = cell.viewWithTag(2)! let codeText = CodeEngine().textView codeView.addSubview(codeText) codeText.autoLayout(top: 0, left: 0, bottom: 0, right: 0) header.imageFromUrl(gist.avatar_url) title.text = "\(gist.ownerLogin) / \(gist.files[0]["filename"]!)" description.text = gist.description comment.text = "\(gist.comments)" let now = NSDate() let diff = now - gist.created_at.toGMTDate("yyyy-MM-dd HH:mm:ss")! time.text = "\(diff.minute) minutes ago" gist.getRawData { content in codeText.text = content } } return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) } } ================================================ FILE: Sublime/Sublime/GithubAccountTableViewController.swift ================================================ // // GithubAccountTableViewController.swift // Sublime // // Created by Eular on 2/24/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import AASquaresLoading class GithubAccountTableViewController: UITableViewController, GithubAPIManagerDelegate { @IBOutlet weak var avatarView: UIImageView! @IBOutlet weak var nameLB: UILabel! @IBOutlet weak var idLB: UILabel! @IBOutlet weak var companyLB: UILabel! @IBOutlet weak var locationLB: UILabel! @IBOutlet weak var emailLB: UILabel! @IBOutlet weak var blogLB: UILabel! @IBOutlet weak var usageLB: UILabel! @IBOutlet weak var followerLB: UILabel! @IBOutlet weak var repoLB: UILabel! @IBOutlet weak var followingLB: UILabel! let github = GitHubAPIManager() var loadingSquare: AASquaresLoading? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod title = "Github" if GitHubAPIManager.isLogin { updateUserInfo() } else { loadingSquare = AASquaresLoading(target: self.view, size: 40) loadingSquare?.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3) loadingSquare?.color = UIColor.whiteColor() showLoginView() } navigationController?.navigationBar.translucent = false } func updateUserInfo() { nameLB.text = github.user["name"].string idLB.text = github.user["login"].string companyLB.text = github.user["company"].string locationLB.text = github.user["location"].string emailLB.text = github.user["email"].string blogLB.text = github.user["blog"].string if let avatar_url = github.user["avatar_url"].string { avatarView.imageFromUrl(avatar_url) } followerLB.text = "\(github.user["followers"].int ?? 0)" repoLB.text = "\(github.user["public_repos"].int ?? 0)" followingLB.text = "\(github.user["following"].int ?? 0)" let used = (github.user["disk_usage"].double ?? 0) * 1024 let total = (github.user["plan"]["space"].double ?? 0) * 1024 usageLB.text = "\(used.GB.afterPoint(2))GB / \(total.GB.afterPoint(2))GB" } func showLoginView() { tableView.separatorColor = UIColor.blackColor().colorWithAlphaComponent(0) let loginView = UIView() loginView.tag = 1008611 loginView.frame = view.frame loginView.y = view.height loginView.backgroundColor = Constant.CapeCod let img = UIImageView() let imgH: CGFloat = 290 let imgW: CGFloat = 300 let imgOffsetH: CGFloat = (view.height - imgH - Constant.NavigationBarOffset) / 2 let imgOffsetW: CGFloat = (view.width - imgW) / 2 img.frame = CGRectMake(imgOffsetW, imgOffsetH, imgW, imgH) img.image = UIImage(named: "github_login") let btn = UIButton() btn.frame = CGRectMake(imgOffsetW + 105, imgOffsetH + 165, 100, 50) //btn.layer.borderWidth = 1 btn.addTarget(self, action: #selector(self.githubLogin), forControlEvents: .TouchUpInside) loginView.addSubview(img) loginView.addSubview(btn) view.addSubview(loginView) UIView.animateWithDuration(1) { loginView.y = 0 } } func githubLogin() { github.delegate = self github.OAuth2() } func githubOAuthCode(notification: NSNotification) { github.handleOAuthCode(notification) loadingSquare?.start() } func githubGetUserInfoCompleted() { loadingSquare?.stop() updateUserInfo() tableView.reloadData() tableView.separatorColor = Constant.CapeCod if let loginView = view.viewWithTag(1008611) { UIView.animateWithDuration(1, animations: { loginView.alpha = 0 }) { (_) -> Void in loginView.removeFromSuperview() } } } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return GitHubAPIManager.isLogin ? 3 : 0 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return section == 0 ? 6 : 1 } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) if indexPath.section == 2 { github.logout() showLoginView() } } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let headerView = UIView() headerView.backgroundColor = Constant.CapeCod return headerView } } ================================================ FILE: Sublime/Sublime/GithubTableViewController.swift ================================================ // // GithubTableViewController.swift // Sublime // // Created by Eular on 2/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import AASquaresLoading import DGElasticPullToRefresh class GithubTableViewController: UITableViewController { let github = GitHubAPIManager() var accuntBtn: UIBarButtonItem? var tag = 0 var repoData = [Repo]() var loadingSquare: AASquaresLoading! override func viewDidLoad() { super.viewDidLoad() title = ["Stars", "Repositories"][tag] view.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.CapeCod tableView.tableFooterView = UIView() accuntBtn = UIBarButtonItem(title: "0", style: .Plain, target: self, action: nil) self.navigationItem.rightBarButtonItem = accuntBtn if Network.isConnectedToNetwork() { if GitHubAPIManager.isLogin { loadingSquare = AASquaresLoading(target: self.view, size: 40) loadingSquare.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3) loadingSquare.color = UIColor.whiteColor() loadingSquare.start() tableView.scrollEnabled = false // Table push Loading Circle let loadingView = DGElasticPullToRefreshLoadingViewCircle() loadingView.tintColor = Constant.TableLoadingCircleColor tableView.dg_addPullToRefreshWithActionHandler({ [weak self] () -> Void in self?.updateDataList() self?.tableView.dg_stopLoading() }, loadingView: loadingView) tableView.dg_setPullToRefreshFillColor(Constant.CodeBackgroudColor) tableView.dg_setPullToRefreshBackgroundColor(Constant.NavigationBarAndTabBarColor) updateDataList() } else { showMsgLabel("Not Login") } } else { showMsgLabel("No Network") } } deinit { tableView.dg_removePullToRefresh() } func showMsgLabel(text: String) { let lb = UILabel() lb.frame = view.frame lb.frame.origin.y -= Constant.NavigationBarOffset lb.text = text lb.textAlignment = .Center lb.textColor = Constant.GithubTableShowMsgLabelTextColor lb.shadowColor = Constant.GithubTableShowMsgLabelTextShadowColor lb.shadowOffset = CGSizeMake(1, 1) view.addSubview(lb) tableView.scrollEnabled = false; } func updateDataList() { switch tag { case 0: github.listStarred(handleRepos) case 1: github.listRepositories(handleRepos) default: break } } func handleRepos(repos: [Repo]) { repoData = repos accuntBtn?.title = "\(repos.count)" tableView.separatorColor = Constant.CapeCod tableView.reloadData() loadingSquare.stop() tableView.scrollEnabled = true } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return repoData.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: nil) cell.backgroundColor = Constant.NavigationBarAndTabBarColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = .DisclosureIndicator cell.textLabel?.text = repoData[indexPath.row].name cell.detailTextLabel?.text = repoData[indexPath.row].description cell.textLabel?.textColor = UIColor.whiteColor() cell.detailTextLabel?.textColor = UIColor.grayColor() return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let rvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ReposTableView") as! ReposTableViewController rvc.repo = repoData[indexPath.row] rvc.repo.downloadFolder = Folder(path: github.githubFolder.path.stringByAppendingPathComponent(title!.lower)) navigationController?.pushViewController(rvc, animated: true) } } ================================================ FILE: Sublime/Sublime/Global.swift ================================================ // // Constant.swift // Sublime // // Created by Eular on 2/14/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Global { static var UnreadMessageCount = 0 static let Database = NSUserDefaults.standardUserDefaults() static let Notifi = NSNotificationCenter.defaultCenter() } ================================================ FILE: Sublime/Sublime/GomokuAI.swift ================================================ // // GoAI.swift // Sublime // // Created by Eular on 4/15/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation /* The origin gomoku AI algorithm codes is writen by Linwei in python, here is the project: https://github.com/skywind3000/gobang . And I rewrite in Swift for my game ^_^ */ // 棋盘评估类,给当前棋盘打分用 class GomokuEvaluation { let Dimension = 15 let STWO = 1 // 冲二 let STHREE = 2 // 冲三 let SFOUR = 3 // 冲四 let TWO = 4 // 活二 let THREE = 5 // 活三 let FOUR = 6 // 活四 let FIVE = 7 // 活五 let DFOUR = 8 // 双四 let FOURT = 9 // 四三 let DTHREE = 10 // 双三 let NOTYPE = 11 let ANALYSED = 255 // 已经分析过 let TODO = 0 // 没有分析过 let POS = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0], [0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0], [0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0], [0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0], [0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0], [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ] var RESULT = Array(count: 30, repeatedValue: 0) // 保存当前直线分析值 var LINE = Array(count: 30, repeatedValue: 0) // 当前直线数据 // 全盘分析结果 [row][col][方向] var RECORD = Array(count: 15, repeatedValue: Array(count: 15, repeatedValue: Array(count: 4, repeatedValue: 0))) // 每种棋局的个数:count[黑棋/白棋][模式] var COUNT = Array(count: 3, repeatedValue: Array(count: 20, repeatedValue: 0)) init() { reset() } // 复位数据 func reset() { RECORD = Array(count: Dimension, repeatedValue: Array(count: Dimension, repeatedValue: Array(count: 4, repeatedValue: TODO))) COUNT = Array(count: 3, repeatedValue: Array(count: 20, repeatedValue: 0)) } // 四个方向(水平,垂直,左斜,右斜)分析评估棋盘,然后根据分析结果打分 func evaluate(board: GomokuBoardModel, _ turn: Int) -> Int { var score = _evaluate(board, turn) if score < -9000 { for i in range(20) { let stone = turn == 1 ? 2:1 if COUNT[stone][i] > 0 { score -= i } } } else if score > 9000 { for i in range(20) { if COUNT[turn][i] > 0 { score += i } } } return score } // 四个方向(水平,垂直,左斜,右斜)分析评估棋盘,然后根据分析结果打分 private func _evaluate(board: GomokuBoardModel, _ turn: Int) -> Int { reset() // 四个方向分析 for i in range(Dimension) { for j in range(Dimension) { if board[i,j].type != .Void { if RECORD[i][j][0] == TODO { // 水平没有分析过? _analysis_horizon(board, i, j) } if RECORD[i][j][1] == TODO { // 垂直没有分析过? _analysis_vertical(board, i, j) } if RECORD[i][j][2] == TODO { // 左斜没有分析过? _analysis_left(board, i, j) } if RECORD[i][j][3] == TODO { // 右斜没有分析过? _analysis_right(board, i, j) } } } } // 分别对白棋黑棋计算:FIVE, FOUR, THREE, TWO等出现的次数 let check = [FIVE, FOUR, SFOUR, THREE, STHREE, TWO, STWO] for i in range(Dimension) { for j in range(Dimension) { let stone = board[i,j] if stone.type != .Void { for k in range(4) { let ch = RECORD[i][j][k] if check.indexOf(ch) != nil { COUNT[stone.value][ch] += 1 } } } } } // 如果有五连则马上返回分数 let BLACK = 1 let WHITE = 2 if turn == WHITE { // 当前是白棋 if COUNT[BLACK][FIVE] > 0 { return -9999 } if COUNT[WHITE][FIVE] > 0 { return 9999 } } else { // 当前是黑棋 if COUNT[WHITE][FIVE] > 0 { return -9999 } if COUNT[BLACK][FIVE] > 0 { return 9999 } } // 如果存在两个冲四,则相当于有一个活四 if COUNT[WHITE][SFOUR] >= 2 { COUNT[WHITE][FOUR] += 1 } if COUNT[BLACK][SFOUR] >= 2 { COUNT[BLACK][FOUR] += 1 } // 具体打分 var wvalue = 0 var bvalue = 0 if turn == WHITE { if COUNT[WHITE][FOUR] > 0 { return 9990 } if COUNT[WHITE][SFOUR] > 0 { return 9980 } if COUNT[BLACK][FOUR] > 0 { return -9970 } if COUNT[BLACK][SFOUR] > 0 && COUNT[BLACK][THREE] > 0 { return -9960 } if COUNT[WHITE][THREE] > 0 && COUNT[BLACK][SFOUR] == 0 { return 9950 } if COUNT[BLACK][THREE] > 1 && COUNT[WHITE][SFOUR] == 0 && COUNT[WHITE][THREE] == 0 && COUNT[WHITE][STHREE] == 0 { return -9940 } if COUNT[WHITE][THREE] > 1 { wvalue += 2000 } else if COUNT[WHITE][THREE] > 0 { wvalue += 200 } if COUNT[BLACK][THREE] > 1 { bvalue += 500 } else if COUNT[BLACK][THREE] > 0 { bvalue += 100 } if COUNT[WHITE][STHREE] > 0 { wvalue += COUNT[WHITE][STHREE] * 10 } if COUNT[BLACK][STHREE] > 0 { bvalue += COUNT[BLACK][STHREE] * 10 } if COUNT[WHITE][TWO] > 0 { wvalue += COUNT[WHITE][TWO] * 4 } if COUNT[BLACK][TWO] > 0 { bvalue += COUNT[BLACK][TWO] * 4 } if COUNT[WHITE][STWO] > 0 { wvalue += COUNT[WHITE][STWO] } if COUNT[BLACK][STWO] > 0 { bvalue += COUNT[BLACK][STWO] } } else { if COUNT[BLACK][FOUR] > 0 { return 9990 } if COUNT[BLACK][SFOUR] > 0 { return 9980 } if COUNT[WHITE][FOUR] > 0 { return -9970 } if COUNT[WHITE][SFOUR] > 0 && COUNT[WHITE][THREE] > 0 { return -9960 } if COUNT[BLACK][THREE] > 0 && COUNT[WHITE][SFOUR] == 0 { return 9950 } if COUNT[WHITE][THREE] > 1 && COUNT[BLACK][SFOUR] == 0 && COUNT[BLACK][THREE] == 0 && COUNT[BLACK][STHREE] == 0 { return -9940 } if COUNT[BLACK][THREE] > 1 { bvalue += 2000 } else if COUNT[BLACK][THREE] > 0 { bvalue += 200 } if COUNT[WHITE][THREE] > 1 { wvalue += 500 } else if COUNT[WHITE][THREE] > 0 { wvalue += 100 } if COUNT[BLACK][STHREE] > 0 { bvalue += COUNT[BLACK][STHREE] * 10 } if COUNT[WHITE][STHREE] > 0 { wvalue += COUNT[WHITE][STHREE] * 10 } if COUNT[BLACK][TWO] > 0 { bvalue += COUNT[BLACK][TWO] * 4 } if COUNT[WHITE][TWO] > 0 { wvalue += COUNT[WHITE][TWO] * 4 } if COUNT[BLACK][STWO] > 0 { bvalue += COUNT[BLACK][STWO] } if COUNT[WHITE][STWO] > 0 { wvalue += COUNT[WHITE][STWO] } } // 加上位置权值,棋盘最中心点权值是7,往外一格-1,最外圈是0 var wc = 0 var bc = 0 for i in range(Dimension) { for j in range(Dimension) { let stone = board[i,j] if stone.type != .Void { if stone.type == .White { wc += POS[i][j] } else { bc += POS[i][j] } } } } wvalue += wc bvalue += bc if turn == WHITE { return wvalue - bvalue } return bvalue - wvalue } // 分析横向 private func _analysis_horizon(board: GomokuBoardModel, _ i: Int, _ j: Int) -> Int { for x in range(Dimension) { LINE[x] = board[i,x].value } analysis_line(Dimension, j) for x in range(Dimension) { if RESULT[x] != TODO { RECORD[i][x][0] = RESULT[x] } } return RECORD[i][j][0] } // 分析纵向 private func _analysis_vertical(board: GomokuBoardModel, _ i: Int, _ j: Int) -> Int { for x in range(Dimension) { LINE[x] = board[x,j].value } analysis_line(Dimension, i) for x in range(Dimension) { if RESULT[x] != TODO { RECORD[x][j][1] = RESULT[x] } } return RECORD[i][j][1] } // 分析左斜 private func _analysis_left(board: GomokuBoardModel, _ i: Int, _ j: Int) -> Int { var x: Int var y: Int if i < j { x = j - i y = 0 } else { x = 0 y = i - j } var k = 0 while k < 15 { if x + k > 14 || y + k > 14 { break } LINE[k] = board[y+k, x+k].value k += 1 } analysis_line(k, j - x) for s in range(k) { if RESULT[s] != TODO { RECORD[y + s][x + s][2] = RESULT[s] } } return RECORD[i][j][2] } // 分析右斜 private func _analysis_right(board: GomokuBoardModel, _ i: Int, _ j: Int) -> Int { var x: Int var y: Int if 14 - i < j { x = j - 14 + i y = 14 } else { x = 0 y = i + j } var k = 0 while k < 15 { if x + k > 14 || y - k < 0 { break } LINE[k] = board[y - k, x + k].value k += 1 } analysis_line(k, j - x) for s in range(k) { if RESULT[s] != TODO { RECORD[y - s][x + s][3] = RESULT[s] } } return RECORD[i][j][3] } // 分析一条线:五四三二等棋型 private func analysis_line(num: Int, _ pos: Int) -> Int{ for i in range(num, 30) { LINE[i] = 0xf } for i in range(num) { RESULT[i] = TODO } if num < 5 { for i in range(num) { RESULT[i] = ANALYSED } return 0 } let stone = LINE[pos] <= 2 ? LINE[pos]:0 let inverse = [0, 2, 1][stone] var xl = pos var xr = pos while xl > 0 { // 探索左边界 if LINE[xl - 1] != stone { break } xl -= 1 } while xr < num - 1 { // 探索右边界 if LINE[xr + 1] != stone { break } xr += 1 } var left_range = xl var right_range = xr while left_range > 0 { // 探索左边范围(非对方棋子的格子坐标) if LINE[left_range - 1] == inverse { break } left_range -= 1 } while right_range < num - 1 { // 探索右边范围(非对方棋子的格子坐标) if LINE[right_range + 1] == inverse { break } right_range += 1 } // 如果该直线范围小于 5,则直接返回 if right_range - left_range < 4 { for k in range(left_range, right_range + 1) { RESULT[k] = ANALYSED } return 0 } // 设置已经分析过 for k in range(xl, xr + 1) { RESULT[k] = ANALYSED } let srange = xr - xl // 如果是 5连 if srange >= 4 { RESULT[pos] = FIVE return FIVE } // 如果是 4连 if srange == 3 { var leftfour = false // 是否左边是空格 if xl > 0 { if LINE[xl - 1] == 0 { // 活四 leftfour = true } } if xr < num - 1 { if LINE[xr + 1] == 0 { if leftfour { RESULT[pos] = FOUR // 活四 } else { RESULT[pos] = SFOUR // 冲四 } } else { if leftfour { RESULT[pos] = SFOUR // 冲四 } } } else { if leftfour { RESULT[pos] = SFOUR // 冲四 } } return RESULT[pos] } // 如果是 3连 if srange == 2 { // 三连 var left3 = false // 是否左边是空格 if xl > 0 { if LINE[xl - 1] == 0 { // 左边有气 if xl > 1 && LINE[xl - 2] == stone { RESULT[xl] = SFOUR RESULT[xl - 2] = ANALYSED } else { left3 = true } } else if xr == num - 1 || LINE[xr + 1] != 0 { return 0 } } if xr < num - 1 { if LINE[xr + 1] == 0 { // 右边有气 if xr < num - 2 && LINE[xr + 2] == stone { RESULT[xr] = SFOUR // XXX-X 相当于冲四 RESULT[xr + 2] = ANALYSED } else if left3 { RESULT[xr] = THREE } else { RESULT[xr] = STHREE } } } else { if RESULT[xl] == SFOUR { return RESULT[xl] } if left3 { RESULT[pos] = STHREE } } return RESULT[pos] } // 如果是 2连 if srange == 1 { var left2 = false if xl > 2 { if LINE[xl - 1] == 0 { // 左边有气 if LINE[xl - 2] == stone { if LINE[xl - 3] == stone { RESULT[xl - 3] = ANALYSED RESULT[xl - 2] = ANALYSED RESULT[xl] = SFOUR } else if LINE[xl - 3] == 0 { RESULT[xl - 2] = ANALYSED RESULT[xl] = STHREE } } else { left2 = true } } } if xr < num - 1 { if LINE[xr + 1] == 0 { // 左边有气 if xr < num - 3 && LINE[xr + 2] == stone { if LINE[xr + 3] == stone { RESULT[xr + 3] = ANALYSED RESULT[xr + 2] = ANALYSED RESULT[xr] = SFOUR } else if LINE[xr + 3] == 0 { RESULT[xr + 2] = ANALYSED RESULT[xr] = left2 ? THREE : STHREE } } else { if RESULT[xl] == SFOUR { return RESULT[xl] } if RESULT[xl] == STHREE { RESULT[xl] = THREE return RESULT[xl] } if left2 { RESULT[pos] = TWO } else { RESULT[pos] = STWO } } } else { if RESULT[xl] == SFOUR { return RESULT[xl] } if left2 { RESULT[pos] = STWO } } } return RESULT[pos] } return 0 } } // DFS: 博弈树搜索 class GomokuAI { let evaluator = GomokuEvaluation() var maxdepth = 3 var bestMove = [Int]() var dimension = 15 private var board: GomokuBoardModel init(board: GomokuBoardModel) { self.board = board self.dimension = board.dimension } // 产生当前棋局的走法 private func genmove(turn: Int) -> Array> { var moves = Array>() let POSES = evaluator.POS for i in range(dimension) { for j in range(dimension) { if board[i,j].type == .Void { let score = POSES[i][j] moves.append([score, i, j]) } } } moves = moves.sort() { $0[0] > $1[0] } return moves } // 递归搜索:返回最佳分数 private func _search (turn: Int, _ depth: Int, _ alpha: Int = -0x7fffffff, _ beta: Int = 0x7fffffff) -> Int { // 深度为零则评估棋盘并返回 if depth <= 0 { let score = evaluator.evaluate(board, turn) return score } // 如果游戏结束则立马返回 let s = evaluator.evaluate(board, turn) if abs(s) >= 9999 && depth < maxdepth { return s } // 产生新的走法 let moves = genmove(turn) var bestmove = [Int]() // 枚举当前所有走法 var a = alpha for m in moves { let row = m[1] let col = m[2] // 标记当前走法到棋盘 board[row, col].value = turn // 计算下一回合该谁走 let nturn = turn == 1 ? 2:1 // 深度优先搜索,返回评分,走的行和走的列 let score = -self._search(nturn, depth - 1, -beta, -alpha) // 棋盘上清除当前走法 board[row, col].value = 0 // 计算最好分值的走法 // alpha/beta 剪枝 if score > a { a = score bestmove = [row, col] if a >= beta { break } } } // 如果是第一层则记录最好的走法 if depth == maxdepth && bestmove.count != 0 { self.bestMove = bestmove } // 返回当前最好的分数,和该分数的对应走法 return a } // 具体搜索:传入当前是该谁走(turn=1黑/2白),以及搜索深度(depth) func search(turn: Int, depth: Int = 3) -> [Int] { maxdepth = depth bestMove = [] var score = _search(turn, depth) if abs(score) > 8000 { maxdepth = depth score = _search(turn, 1) } let row = bestMove[0] let col = bestMove[1] return [score, row, col] } } ================================================ FILE: Sublime/Sublime/GomokuViewController.swift ================================================ // // GameOfGoViewController.swift // Sublime // // Created by Eular on 4/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class GomokuViewController: UIViewController { let board = GomokuBoardView() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod board.onWin = { self.view.Toast(message: "黑棋赢") } board.onLose = { self.view.Toast(message: "白棋赢") } view.addSubview(board) board.atCenter() addCloseBtn() addNewBtn() } func close() { self.dismissViewControllerAnimated(true, completion: nil) } func addCloseBtn() { let closeBtn = UIButton() closeBtn.setTitle("<-", forState: .Normal) closeBtn.setTitleColor(UIColor.grayColor(), forState: .Normal) closeBtn.frame = CGRectMake(10, view.height - 20, 20, 10) closeBtn.addTarget(self, action: #selector(self.close), forControlEvents: .TouchUpInside) view.addSubview(closeBtn) } func addNewBtn() { let newBtn = UIButton() newBtn.setTitle("new", forState: .Normal) newBtn.setTitleColor(UIColor.grayColor(), forState: .Normal) newBtn.titleLabel?.font = newBtn.titleLabel?.font.fontWithSize(13) newBtn.frame = CGRectMake(view.width - 40, view.height - 22, 30, 15) newBtn.addTarget(self, action: #selector(board.reset), forControlEvents: .TouchUpInside) view.addSubview(newBtn) } override func preferredStatusBarStyle() -> UIStatusBarStyle { return UIStatusBarStyle.LightContent } } ================================================ FILE: Sublime/Sublime/HTTPServerTableViewController.swift ================================================ // // HTTPServerTableViewController.swift // Sublime // // Created by Eular on 2/23/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Swifter import SafariServices class HTTPServerTableViewController: UITableViewController { @IBOutlet weak var portTF: UITextField! @IBOutlet weak var ipLB: UILabel! @IBOutlet weak var serverSW: UISwitch! @IBOutlet weak var pathSW: UISwitch! @IBOutlet weak var logTV: UITextView! private var server: HttpServer? private var serverLog: WebServerLog? override func viewDidLoad() { super.viewDidLoad() title = "HTTP" let safariBtn = UIBarButtonItem(image: UIImage(named: "open_safari"), style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.openSafari)) navigationItem.rightBarButtonItem = safariBtn if Network.isConnectedToNetwork() { let ip = Network.getIFAddresses()[0] ipLB.text = ip } else { ipLB.text = "localhost" } // Here is a bug: if first start SublimeServer then CustomServer doesn't work. // Idk why, so just add the following useless code. // ----- Don't forget move it to isConnectedToNetwork satuation ------ let server = HttpServer() try! server.start() server.stop() serverLog = WebServerLog(output: logTV) } deinit { self.server?.stop() serverLog?.saveInLogFile(self.logTV.text) } @IBAction func serverStatusChanged(sender: UISwitch) { if sender.on { startServer(SublimeServer(serverLog)) } else { self.server?.stop() serverLog?.log("Server has stopped.") } portTF.enabled = !sender.on pathSW.on = false pathSW.enabled = sender.on } @IBAction func pathEnableStatusChanged(sender: UISwitch) { startServer(sender.on ? CustomServer(serverLog) : SublimeServer(serverLog)) } func startServer(server: HttpServer) { self.server?.stop() guard let port = portTF.text!.isEmpty ? 8080 : UInt16(portTF.text!) else { serverLog?.log("Error: please set valid port.", isError: true) return } do { try server.start(port) self.server = server serverLog?.log("Server has started: http://\(ipLB.text!):\(port).") } catch { serverLog?.log("Error: \(error)", isError: true) } } func openSafari() { guard let port = portTF.text!.isEmpty ? 8080 : UInt16(portTF.text!) else {return} let svc = SFSafariViewController(URL: NSURL(string: "http://localhost:\(port)")!) svc.modalPresentationStyle = .OverCurrentContext self.presentViewController(svc, animated: true, completion: nil) } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return [4, 1][section] } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let secTitle = [" HTTP", " Log"] let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { portTF.resignFirstResponder() } } ================================================ FILE: Sublime/Sublime/ImageFileViewController.swift ================================================ // // ImageFileViewController.swift // Sublime // // Created by Eular on 2/15/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Gifu class ImageFileViewController: UIViewController { var curFile: File! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod let imgView: UIImageView let imgData = NSData(contentsOfURL: curFile.url)! if curFile.ext == "gif" { imgView = AnimatableImageView() (imgView as! AnimatableImageView).animateWithImageData(imgData) (imgView as! AnimatableImageView).startAnimatingGIF() } else { imgView = UIImageView(image: UIImage(data: imgData)) imgView.recognizeQRCodeEnabled = true } imgView.frame = CGRectMake(0, 10, view.width, view.height - 140 ) imgView.contentMode = .ScaleAspectFit view.addSubview(imgView) } } ================================================ FILE: Sublime/Sublime/ImagePageViewController.swift ================================================ // // ImagePageViewController.swift // Sublime // // Created by Eular on 2/15/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class ImagePageViewController: UIPageViewController, UIPageViewControllerDataSource, PopupMenuDelegate { let popupMenu = PopupMenu() var index: Int = 0 var imgList: [File]! var curImage: UIImage? override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : AnyObject]?) { super.init(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: options) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidLoad() { super.viewDidLoad() dataSource = self view.backgroundColor = Constant.CapeCod if let startingViewController = self.viewControllerByOffset(0) { setViewControllers([startingViewController], direction: .Forward, animated: true, completion: nil) } // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.delegate = self } func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { return viewControllerByOffset(1) } func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { return viewControllerByOffset(-1) } /* Page Control*/ func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int { return imgList.count } func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int { return index } func viewControllerByOffset(offset: Int) -> ImageFileViewController? { index += offset if index < 0 || index >= imgList.count { index -= offset return nil } title = imgList[index].name self.curImage = UIImage(contentsOfFile: imgList[index].path) popupMenu.itemsToShare = [self.curImage!] let imageView = ImageFileViewController() imageView.curFile = imgList[index] return imageView } func tapOnPopupMenuItem(itemIndex i: Int) { let curFile = imgList[index] switch i { case 2: if curFile.ext == "gif" { WXShareEmoticon(curFile.path) } else { WXShareImage(self.curImage!) } case 3: WXShareImage(self.curImage!, isTimeline: true) default: return } } } ================================================ FILE: Sublime/Sublime/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDocumentTypes LSHandlerRank Owner CFBundleTypeIconFiles CFBundleTypeName public.file LSItemContentTypes public.image public.content public.data CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLName weixin CFBundleURLSchemes wxb597aecde6aadd28 CFBundleTypeRole Editor CFBundleURLName sublime CFBundleURLSchemes sublime CFBundleVersion 1 LSApplicationQueriesSchemes wechat weixin sinaweibohd sinaweibo sinaweibosso weibosdk weibosdk2.5 mqqapi mqq mqqOpensdkSSoLogin mqqconnect mqqopensdkdataline mqqopensdkgrouptribeshare mqqopensdkfriend mqqopensdkapi mqqopensdkapiV2 mqqopensdkapiV3 mqzoneopensdk wtloginmqq wtloginmqq2 mqqwpa mqzone mqzonev2 mqzoneshare wtloginqzone mqzonewx mqzoneopensdkapiV2 mqzoneopensdkapi19 mqzoneopensdkapi mqqbrowser mttbrowser renrenios renrenapi renren renreniphone laiwangsso yixin yixinopenapi instagram whatsapp line fbapi fb-messenger-api fbauth2 fbshareextension alipay LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIFileSharingEnabled UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UIStatusBarHidden UIStatusBarTintParameters UINavigationBar Style UIBarStyleDefault Translucent UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Sublime/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/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/Sublime/LICENSE/MobileVLCKit.LICENSE ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: Sublime/Sublime/LICENSE/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/Sublime/LICENSE/RongCloudIMKit.LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 融云 RongCloud 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/Sublime/LICENSE/SJCSimplePDFView.LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Stuart Crook 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/Sublime/LICENSE/SSZipArchive.LICENSE ================================================ Copyright (c) 2010-2015, Sam Soffes, http://soff.es 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/Sublime/LICENSE/Swifter.LICENSE ================================================ Copyright (c) 2014, Damian Kołakowski 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 {organization} nor the names of its 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 HOLDER 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. ================================================ FILE: Sublime/Sublime/LICENSE/SwiftyJSON.LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Ruoyu Fu 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/Sublime/LICENSE/ZLMusicFlowWaveView.LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Zhixuan Lai 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/Sublime/LICENSE/ZLSinusWaveView.LICENSE ================================================ Copyright (c) 2013 Raffael Hannemann Copyright (c) 2014, Zhixuan Lai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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. ================================================ FILE: Sublime/Sublime/LicenseTableViewController.swift ================================================ // // LicenseTableViewController.swift // Sublime // // Created by Eular on 2/24/16. // Copyright © 2016 Eular. All rights reserved. // class LicenseTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() title = "License" tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.CapeCod } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return Constant.License.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Default, reuseIdentifier: nil) cell.backgroundColor = Constant.TableCellColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = .DisclosureIndicator cell.textLabel?.text = Constant.License[indexPath.row] cell.textLabel?.textColor = UIColor.whiteColor() return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let vc = UIViewController() vc.title = Constant.License[indexPath.row] vc.view.backgroundColor = Constant.CapeCod vc.automaticallyAdjustsScrollViewInsets = false let tv = UITextView() tv.frame = CGRectMake(0, 0, vc.view.width, vc.view.height - Constant.NavigationBarOffset) vc.view.addSubview(tv) tv.backgroundColor = Constant.CapeCod tv.textColor = UIColor.whiteColor() tv.editable = false tv.text = File(path: NSBundle.mainBundle().pathForResource(Constant.License[indexPath.row], ofType: "LICENSE")!).read() navigationController?.pushViewController(vc, animated: true) } } ================================================ FILE: Sublime/Sublime/LogoView.xib ================================================ ================================================ FILE: Sublime/Sublime/MainTableViewController.swift ================================================ // // FilesTableViewController.swift // Sublime // // Created by Eular on 2/12/16. // Copyright © 2016 Eular. All rights reserved. // class MainTableViewController: FolderTableViewController { var gitList = [File(path: "Stars"), File(path: "Repositories")] override func viewDidLoad() { super.viewDidLoad() title = "Sublime" mainViewFlag = 0 Global.Notifi.addObserver(self, selector: #selector(self.hasUnreadMessages), name: Constant.RongCloudUnreadMessageNotifi, object: nil) } deinit { Global.Notifi.removeObserver(self) } func hasUnreadMessages() { dispatch_async(dispatch_get_main_queue()) { self.tabBarController?.tabBar.showRedBadgeOnItem(1, totalItemNums: 3) } } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch section { case 0: return gitList.count case 1: return fileList.count default: return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Default, reuseIdentifier: nil) if indexPath.section == 0 { let f = gitList[indexPath.row] setFileTableCell(cell, name: f.name, imgname: f.name, isDir: true) } else { let f = fileList[indexPath.row] setFileTableCell(cell, name: f.name, imgname: f.img, isDir: f.isDir) } return cell } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let secTitle = [" Github", " Local"] let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } } ================================================ FILE: Sublime/Sublime/MessageListViewController.swift ================================================ // // MessageListViewController.swift // Sublime // // Created by Eular on 3/21/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class MessageListViewController: RCConversationListViewController { override func viewDidLoad() { super.viewDidLoad() title = "Messages" showConnectingStatusOnNavigatorBar = true emptyConversationView.atCenter() navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(self.newChat)) //设置需要显示哪些类型的会话 self.setDisplayConversationTypes([ RCConversationType.ConversationType_PRIVATE.rawValue, RCConversationType.ConversationType_DISCUSSION.rawValue, RCConversationType.ConversationType_CHATROOM.rawValue, RCConversationType.ConversationType_GROUP.rawValue, RCConversationType.ConversationType_APPSERVICE.rawValue, RCConversationType.ConversationType_SYSTEM.rawValue]) //设置需要将哪些类型的会话在会话列表中聚合显示 self.setCollectionConversationType([ RCConversationType.ConversationType_DISCUSSION.rawValue, RCConversationType.ConversationType_GROUP.rawValue]) if RCIM.sharedRCIM().getConnectionStatus() == .ConnectionStatus_Unconnected { RCIM.sharedRCIM().getTokenAndLogin() } } override func viewWillDisappear(animated: Bool) { Global.UnreadMessageCount = 0 tabBarController?.tabBar.hideRedBadgeOnItem(2) } override func onSelectedTableRow(conversationModelType: RCConversationModelType, conversationModel model: RCConversationModel!, atIndexPath indexPath: NSIndexPath!) { let chat = RCChatViewController(conversationType: model.conversationType, targetId: model.targetId) chat.title = model.conversationTitle navigationController?.pushViewController(chat, animated: true) } override func didTapCellPortrait(model: RCConversationModel!) { let contactInfoVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(Constant.ContactInfoStoryboardID) as! ContactInfoViewController contactInfoVC.id = model.targetId == Constant.RongCloudRobotID ? "" : model.targetId navigationController?.pushViewController(contactInfoVC, animated: true) } func newChat() { let contactVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(Constant.ContactTableStoryboardID) as! ContactTableViewController navigationController?.pushViewController(contactVC, animated: true) } } ================================================ FILE: Sublime/Sublime/MusicViewController.swift ================================================ // // MusicViewController.swift // Sublime // // Created by Eular on 2/21/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import AVFoundation class MusicViewController: MusicWave { let popupMenu = PopupMenu() var curFile: File! override func viewDidLoad() { super.viewDidLoad() title = curFile.name // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.itemsToShare = [curFile.url] self.audioUrl = curFile.url self.start() } override func viewWillDisappear(animated: Bool) { self.audioPlayer.stop() } override func touchesEnded(touches: Set, withEvent event: UIEvent?) { if self.audioPlayer.isPlaying() { self.audioPlayer.pause() } else { self.audioPlayer.play() } } } ================================================ FILE: Sublime/Sublime/NewFileViewController.swift ================================================ // // NewFileViewController.swift // Sublime // // Created by Eular on 2/14/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class NewFileViewController: UIViewController { var fileImg: UIImageView! var filenameText: UITextField! var warningLabel: UILabel! let keywords = [ ["file_unknown", "New File", "File Name"], ["folder", "New Folder", "Folder Name"] ] var tag = 0 var curFolder: Folder! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod title = keywords[tag][1] let inputView = UIView() inputView.frame = CGRectMake(0, Constant.NavigationBarOffset + 43, view.width, 44) inputView.backgroundColor = RGB(140, 140, 140, alpha: 0.4) view.addSubview(inputView) fileImg = UIImageView() fileImg.frame = CGRectMake(10, 8, 28, 28) fileImg.image = UIImage(named: keywords[tag][0]) inputView.addSubview(fileImg) filenameText = UITextField() filenameText.frame = CGRectMake(48, 0, view.width - 52, 44) filenameText.textColor = UIColor.whiteColor() filenameText.placeholder = keywords[tag][2] filenameText.autocorrectionType = .No filenameText.autocapitalizationType = .None filenameText.keyboardType = .ASCIICapable filenameText.spellCheckingType = .No filenameText.becomeFirstResponder() inputView.addSubview(filenameText) warningLabel = UILabel() warningLabel.frame = CGRectMake(0, inputView.y + inputView.height + 12, view.width, 18) warningLabel.font = warningLabel.font.fontWithSize(12) warningLabel.textAlignment = .Center warningLabel.textColor = UIColor.whiteColor() warningLabel.alpha = 0 view.insertSubview(warningLabel, belowSubview: inputView) navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: #selector(self.createNew)) } func createNew() { let text = filenameText.text!.strip() if text.isEmpty { showWarningMsg("Name can't be empty") } else if curFolder.checkFileExist(text) { showWarningMsg("The file already existed") } else { switch tag { case 0: if curFolder.newFile(text) { navigationController?.popViewControllerAnimated(true) } else { showWarningMsg("New file failed") } case 1: if curFolder.newFolder(text) { navigationController?.popViewControllerAnimated(true) } else { showWarningMsg("New folder failed") } default: return } } } func showWarningMsg(word: String) { warningLabel.text = word UIView.animateWithDuration(0.5, animations: { () -> Void in self.warningLabel.alpha = 1 }, completion: { (_) -> Void in UIView.animateWithDuration(3) { self.warningLabel.alpha = 0 } }) } } ================================================ FILE: Sublime/Sublime/PDFViewController.swift ================================================ // // PDFViewController.swift // Sublime // // Created by Eular on 2/22/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import SJCSimplePDFView class PDFViewController: UIViewController, PopupMenuDelegate { var curFile: File! var pdfView: SJCSimplePDFView! let pagenumLabel = UILabel() let popupMenu = PopupMenu() override func viewDidLoad() { super.viewDidLoad() self.automaticallyAdjustsScrollViewInsets = false tabBarController?.tabBar.hidden = true view.backgroundColor = Constant.CapeCod title = curFile.name pdfView = SJCSimplePDFView() pdfView.frame = CGRectMake(0, 0, view.width, view.height - Constant.NavigationBarOffset) pdfView.pageBackgroundColour = UIColor.whiteColor() pdfView.PDFFileURL = curFile.url pdfView.pageInsets = UIEdgeInsets(top: 2.5, left: 5, bottom: 2.5, right: 5) let viewMode = Global.Database.integerForKey("pdf-viewmode-\(curFile.path.md5)") pdfView.viewMode = [.Continuous, .PageVertical, .PageHorizontal][viewMode] let curPage = Global.Database.integerForKey("pdf-curPage-\(curFile.path.md5)") pdfView.currentPage = UInt(curPage) // bug: currentPage为'0,1'都显示第一页,'2'显示第三页 view.addSubview(pdfView) // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.delegate = self popupMenu.itemsToShare = [curFile.url] popupMenu.items = [ ["title":"QQ", "image":"Share_qq_icon"], ["title":"新浪微博", "image":"Share_sina_icon"], ["title":"微信", "image":"Share_wechat_session_icon"], ["title":"Facebook", "image":"Share_facebook_icon"], ["title":"Line", "image":"Share_line_icon"], ["title":"Instagram", "image":"Share_instagram"], ["title":"Twitter", "image":"Share_twitter_icon"], ["title":"Pinterest", "image":"Share_pinterest_icon"], ["title":"PDF Continuous", "image":"pdf_continuous"], ["title":"PDF Vertical", "image":"pdf_vertical"], ["title":"PDF Horizontal", "image":"pdf_horizontal"], ] pdfView.addObserver(self, forKeyPath: "currentPage", options: NSKeyValueObservingOptions.New, context: nil) pagenumLabel.frame = CGRectMake(0, view.height - 30, 0, 0) pagenumLabel.layer.masksToBounds = true pagenumLabel.layer.cornerRadius = 3 pagenumLabel.backgroundColor = RGB(0, 0, 0, alpha: 0.5) pagenumLabel.textColor = UIColor.whiteColor() pagenumLabel.textAlignment = .Center pagenumLabel.alpha = 0 view.addSubview(pagenumLabel) } func setPagenumLabelText(str: String) { pagenumLabel.text = str pagenumLabel.sizeToFit() pagenumLabel.width += 10 pagenumLabel.x = (view.width - pagenumLabel.width) / 2 UIView.animateWithDuration(0.5, animations: { () -> Void in self.pagenumLabel.alpha = 1 }) { (_) -> Void in UIView.animateWithDuration(2) { self.pagenumLabel.alpha = 0 } } } override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { if keyPath == "currentPage" { let n = change?[NSKeyValueChangeNewKey]?.integerValue setPagenumLabelText("\(n!) / \(pdfView.documentPageCount)") } } deinit { pdfView.removeObserver(self, forKeyPath: "currentPage") } override func viewWillDisappear(animated: Bool) { Global.Database.setInteger(Int(pdfView.currentPage)-1, forKey: "pdf-curPage-\(curFile.path.md5)") } func tapOnPopupMenuItem(itemIndex i: Int) { switch i { case 2: WXShareFile(curFile.name, desc: curFile.name, file: curFile) case 8: pdfView.viewMode = .Continuous Global.Database.setInteger(0, forKey: "pdf-viewmode-\(curFile.path.md5)") case 9: pdfView.viewMode = .PageVertical Global.Database.setInteger(1, forKey: "pdf-viewmode-\(curFile.path.md5)") case 10: pdfView.viewMode = .PageHorizontal Global.Database.setInteger(2, forKey: "pdf-viewmode-\(curFile.path.md5)") default: return } } } ================================================ FILE: Sublime/Sublime/RCChatViewController.swift ================================================ // // ChatViewController.swift // Sublime // // Created by Eular on 4/1/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class RCChatViewController: RCConversationViewController { override func didTapCellPortrait(userId: String!) { let contactInfoVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(Constant.ContactInfoStoryboardID) as! ContactInfoViewController contactInfoVC.id = userId == Constant.RongCloudRobotID ? "" : userId navigationController?.pushViewController(contactInfoVC, animated: true) } } ================================================ FILE: Sublime/Sublime/RSSItemListTableViewController.swift ================================================ // // RSSItemListTableViewController.swift // Sublime // // Created by Eular on 4/7/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Alamofire import AlamofireRSSParser import AASquaresLoading class RSSItemListTableViewController: UITableViewController { var rssUrl = "" var itemList: [RSSItem] = [] override func viewDidLoad() { super.viewDidLoad() tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.TableCellSeparatorColor tableView.tableFooterView = UIView() tableView.estimatedRowHeight = 70 tableView.rowHeight = UITableViewAutomaticDimension navigationItem.rightBarButtonItem = UIBarButtonItem(title: "0", style: .Plain, target: self, action: nil) if Network.isConnectedToNetwork() { let loadingSquare = AASquaresLoading(target: self.view, size: 40) loadingSquare.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5) loadingSquare.color = UIColor.whiteColor() loadingSquare.start() tableView.scrollEnabled = false Alamofire.request(.GET, rssUrl).responseRSS() { (response) -> Void in if let feed: RSSFeed = response.result.value { self.itemList = feed.items self.navigationItem.rightBarButtonItem?.title = "\(feed.items.count)" loadingSquare.stop() self.tableView.scrollEnabled = true self.tableView.reloadData() } } } else { view.Toast(message: "No network", hasNavigationBar: true) } } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return itemList.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: nil) cell.backgroundColor = Constant.NavigationBarAndTabBarColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = .DisclosureIndicator cell.textLabel?.text = itemList[indexPath.row].title cell.textLabel?.numberOfLines = 0 cell.textLabel?.lineBreakMode = .ByWordWrapping cell.detailTextLabel?.text = itemList[indexPath.row].itemDescription?.trim(charSet: .whitespaceAndNewlineCharacterSet()) cell.textLabel?.textColor = UIColor.whiteColor() cell.detailTextLabel?.textColor = UIColor.grayColor() return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let backItem = UIBarButtonItem() backItem.title = "back" navigationItem.backBarButtonItem = backItem let svc = SublimeSafari(URL: NSURL(string: itemList[indexPath.row].link!)!) svc.title = title navigationController?.pushViewController(svc, animated: true) } } ================================================ FILE: Sublime/Sublime/RSSListTableViewController.swift ================================================ // // RSSListTableViewController.swift // Sublime // // Created by Eular on 4/7/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class RSSListTableViewController: UITableViewController { let RSSPlist = Plist(path: Constant.SublimeRoot+"/etc/rss_list.plist") var RSSList: [[String: String]] = [] { didSet { do { try RSSPlist.saveToPlistFile(RSSList) } catch { view.Toast(message: "Save failed!", hasNavigationBar: true) } if RSSList.count > oldValue.count { tableView.reloadData() } } } override func viewDidLoad() { super.viewDidLoad() title = "RSS" tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.TableCellSeparatorColor tableView.tableFooterView = UIView() navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(self.addNewRSS)) } override func viewWillAppear(animated: Bool) { if let arr = RSSPlist.getArrayInPlistFile() { RSSList = arr as! [[String : String]] tableView.reloadData() } } func addNewRSS() { let alertController = UIAlertController(title: "New RSS", message: "Enter RSS info below", preferredStyle: .Alert) alertController.addTextFieldWithConfigurationHandler({(textField: UITextField!) in textField.placeholder = "RSS Title" textField.borderStyle = .None textField.textAlignment = .Center }) alertController.addTextFieldWithConfigurationHandler({(textField: UITextField!) in textField.placeholder = "RSS URL" textField.borderStyle = .None textField.textAlignment = .Center }) let addAction = UIAlertAction(title: "Add", style: UIAlertActionStyle.Default, handler: { (paramAction: UIAlertAction!) in if let textFields = alertController.textFields { let theTextFields = textFields as [UITextField] if let title = theTextFields[0].text, let url = theTextFields[1].text { if !title.isEmpty && !url.isEmpty { self.RSSList.append(["title": title, "rss": url]) } else { self.view.Toast(message: "RSS title or url can't be empty!", hasNavigationBar: true) } } } }) alertController.addAction(addAction) alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) self.presentViewController(alertController, animated: true, completion: nil) } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return RSSList.count } override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { RSSList.removeAtIndex(indexPath.row) tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: nil) cell.backgroundColor = Constant.NavigationBarAndTabBarColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = .DisclosureIndicator cell.textLabel?.text = RSSList[indexPath.row]["title"] cell.detailTextLabel?.text = RSSList[indexPath.row]["rss"] cell.textLabel?.textColor = UIColor.whiteColor() cell.detailTextLabel?.textColor = UIColor.grayColor() return cell } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return 50 } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let rssItemList = RSSItemListTableViewController() rssItemList.title = RSSList[indexPath.row]["title"] rssItemList.rssUrl = RSSList[indexPath.row]["rss"]! navigationController?.pushViewController(rssItemList, animated: true) } } ================================================ FILE: Sublime/Sublime/ReadingViewController.swift ================================================ // // ReadingViewController.swift // Sublime // // Created by Eular on 5/10/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class ReadingViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() title = "Reading" view.backgroundColor = Constant.CapeCod } } ================================================ FILE: Sublime/Sublime/Repo.swift ================================================ // // Repo.swift // Sublime // // Created by Eular on 5/9/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import Alamofire import SwiftyJSON class Repo { var id: String! var name: String! var description: String! var ownerLogin: String! var url: String! var stargazers: Int! var forks: Int! var watchers: Int! var language: String! var issues: Int! var size: Double! var created_at: String! var downloadFolder: Folder? var downloadZipPath: String = "" required init(json: JSON) { self.description = json["description"].string self.id = json["id"].string self.name = json["name"].string self.ownerLogin = json["owner"]["login"].string self.url = json["url"].string self.stargazers = json["stargazers_count"].int self.forks = json["forks_count"].int self.watchers = json["watchers_count"].int self.language = json["language"].string self.issues = json["open_issues_count"].int self.size = json["size"].double self.created_at = json["created_at"].string } func fatchReadmeFile(format: String = "raw", completion: (String) -> Void) { let url = "https://api.github.com/repos/\(ownerLogin)/\(name)/readme" let header = ["Accept": "application/vnd.github.VERSION.\(format)"] Alamofire.request(.GET, url, headers: header).responseString { response in if let str = response.result.value { let metafix = "" let cssfix = "" switch format { case "raw": completion(str) case "html": completion(metafix+str+cssfix) default: completion(str) } } } } func download(duration: ((Int64, Int64, Int64) -> Void)? = nil, completion: (() -> Void)? = nil, failed: (() -> Void)? = nil) { let url = "https://api.github.com/repos/\(ownerLogin)/\(name)/zipball/master" Alamofire.download(.GET, url) { temporaryURL, response in let pathComponent = response.suggestedFilename let downloadUrl: NSURL! if let url = self.downloadFolder?.url { downloadUrl = url.URLByAppendingPathComponent(pathComponent!) } else { let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] downloadUrl = directoryURL.URLByAppendingPathComponent(pathComponent!) } self.downloadZipPath = downloadUrl.path! return downloadUrl }.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in Log("Total bytes read: \(totalBytesRead)") if let d = duration { d(bytesRead, totalBytesRead, totalBytesExpectedToRead) } // 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 { Log("Download failed with error: \(error)") if let f = failed { f() } } else { Log("Downloaded file successfully") let zipFile = File(path: self.downloadZipPath) zipFile.unzip(keepFile: false) Log("Unzip file successfully") if let c = completion { c() } } } } } ================================================ FILE: Sublime/Sublime/ReposTableViewController.swift ================================================ // // ReposTableViewController.swift // Sublime // // Created by Eular on 2/29/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import AASquaresLoading class ReposTableViewController: UITableViewController { @IBOutlet weak var starLB: UILabel! @IBOutlet weak var forkLB: UILabel! @IBOutlet weak var watcherLB: UILabel! @IBOutlet weak var commitTimeLB: UILabel! @IBOutlet weak var descriptionLB: UILabel! @IBOutlet weak var sizeLB: UILabel! @IBOutlet weak var webView: UIWebView! var repo: Repo! var loadingSquare: AASquaresLoading! override func viewDidLoad() { super.viewDidLoad() title = repo.name let downloadBtn = UIBarButtonItem(image: UIImage(named: "repo_download"), style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.downloadRepo)) navigationItem.rightBarButtonItem = downloadBtn watcherLB.text = "\(repo.watchers)" starLB.text = "\(repo.stargazers)" forkLB.text = "\(repo.forks)" commitTimeLB.text = "Created at: \(repo.created_at)" descriptionLB.text = repo.description sizeLB.text = "[\((repo.size * 1024).MB.afterPoint(2))M]" webView.backgroundColor = UIColor.clearColor() webView.opaque = false webView.scalesPageToFit = true webView.scrollView.showsHorizontalScrollIndicator = false repo.fatchReadmeFile("html") { (str) -> Void in self.webView.loadHTMLString(str, baseURL: nil) } //webView.loadRequest(NSURLRequest(URL: NSURL(string: "https://github.com/\(repo.ownerLogin)/\(repo.name)/blob/master/README.md")!)) loadingSquare = AASquaresLoading(target: self.view, size: 40) loadingSquare.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5) loadingSquare.color = UIColor.whiteColor() } func downloadRepo() { tableView.scrollEnabled = false let barItem = UIBarButtonItem(title: "0 %", style: .Plain, target: nil, action: nil) navigationItem.rightBarButtonItem = barItem loadingSquare.start() repo.download({ (bytesRead, totalBytesRead, totalBytesExpectedToRead) -> Void in let read = CGFloat(totalBytesRead) let total = CGFloat(totalBytesExpectedToRead) let r = Int(read * 100.0 / total) dispatch_async(dispatch_get_main_queue()) { // 导航栏右边按钮显示下载进度 let barItem = UIBarButtonItem(title: "\(r) %", style: .Plain, target: nil, action: nil) self.navigationItem.rightBarButtonItem = barItem } }, completion: { self.loadingSquare.stop() self.tableView.scrollEnabled = true self.navigationItem.rightBarButtonItem = nil }) { self.loadingSquare.stop() self.tableView.scrollEnabled = true let downloadBtn = UIBarButtonItem(image: UIImage(named: "repo_download"), style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.downloadRepo)) self.navigationItem.rightBarButtonItem = downloadBtn self.view.Toast(message: "Download Fail", hasNavigationBar: true) } } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 3 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return [3,1,1][section] } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let secTitle = [" \(repo.ownerLogin) / \(repo.name)", " master", " README.md"] let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return indexPath.section == 2 ? view.height - Constant.NavigationBarOffset : 44 } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) } } ================================================ FILE: Sublime/Sublime/SDK/Weixin/WXApi.h ================================================ // // WXApi.h // 所有Api接口 // // Created by Wechat on 12-2-28. // Copyright (c) 2012年 Tencent. All rights reserved. // #import #import "WXApiObject.h" #pragma mark - WXApiDelegate /*! @brief 接收并处理来自微信终端程序的事件消息 * * 接收并处理来自微信终端程序的事件消息,期间微信界面会切换到第三方应用程序。 * WXApiDelegate 会在handleOpenURL:delegate:中使用并触发。 */ @protocol WXApiDelegate @optional /*! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果 * * 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。 * 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。 * @param req 具体请求内容,是自动释放的 */ -(void) onReq:(BaseReq*)req; /*! @brief 发送一个sendReq后,收到微信的回应 * * 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。 * 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。 * @param resp具体的回应内容,是自动释放的 */ -(void) onResp:(BaseResp*)resp; @end #pragma mark - WXApi /*! @brief 微信Api接口函数类 * * 该类封装了微信终端SDK的所有接口 */ @interface WXApi : NSObject /*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。 * * 需要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现。 * iOS7及以上系统需要调起一次微信才会出现在微信的可用应用列表中。 * @attention 请保证在主线程中调用此函数 * @param appid 微信开发者ID * @param typeFlag 应用支持打开的文件类型 * @return 成功返回YES,失败返回NO。 */ +(BOOL) registerApp:(NSString *)appid; /*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。 * * 需要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现。 * @see registerApp * @param appid 微信开发者ID * @param appdesc 应用附加信息,长度不超过1024字节 * @return 成功返回YES,失败返回NO。 */ +(BOOL) registerApp:(NSString *)appid withDescription:(NSString *)appdesc; /*! @brief WXApi的成员函数,向微信终端程序注册应用支持打开的文件类型。 * * 需要在每次启动第三方应用程序时调用。调用后并第一次成功分享数据到微信后,会在微信的可用应用列表中出现。 * @see registerApp * @param typeFlag 应用支持打开的数据类型, enAppSupportContentFlag枚举类型 “|” 操作后结果 */ +(void) registerAppSupportContentFlag:(UInt64)typeFlag; /*! @brief 处理微信通过URL启动App时传递的数据 * * 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。 * @param url 微信启动第三方应用时传递过来的URL * @param delegate WXApiDelegate对象,用来接收微信触发的消息。 * @return 成功返回YES,失败返回NO。 */ +(BOOL) handleOpenURL:(NSURL *) url delegate:(id) delegate; /*! @brief 检查微信是否已被用户安装 * * @return 微信已安装返回YES,未安装返回NO。 */ +(BOOL) isWXAppInstalled; /*! @brief 判断当前微信的版本是否支持OpenApi * * @return 支持返回YES,不支持返回NO。 */ +(BOOL) isWXAppSupportApi; /*! @brief 获取微信的itunes安装地址 * * @return 微信的安装地址字符串。 */ +(NSString *) getWXAppInstallUrl; /*! @brief 获取当前微信SDK的版本号 * * @return 返回当前微信SDK的版本号 */ +(NSString *) getApiVersion; /*! @brief 打开微信 * * @return 成功返回YES,失败返回NO。 */ +(BOOL) openWXApp; /*! @brief 发送请求到微信,等待微信返回onResp * * 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型 * SendAuthReq、SendMessageToWXReq、PayReq等。 * @param req 具体的发送请求,在调用函数后,请自己释放。 * @return 成功返回YES,失败返回NO。 */ +(BOOL) sendReq:(BaseReq*)req; /*! @brief 发送Auth请求到微信,支持用户没安装微信,等待微信返回onResp * * 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持SendAuthReq类型。 * @param req 具体的发送请求,在调用函数后,请自己释放。 * @param viewController 当前界面对象。 * @param delegate WXApiDelegate对象,用来接收微信触发的消息。 * @return 成功返回YES,失败返回NO。 */ +(BOOL) sendAuthReq:(SendAuthReq*)req viewController:(UIViewController*)viewController delegate:(id)delegate; /*! @brief 收到微信onReq的请求,发送对应的应答给微信,并切换到微信界面 * * 函数调用后,会切换到微信的界面。第三方应用程序收到微信onReq的请求,异步处理该请求,完成后必须调用该函数。可能发送的相应有 * GetMessageFromWXResp、ShowMessageFromWXResp等。 * @param resp 具体的应答内容,调用函数后,请自己释放 * @return 成功返回YES,失败返回NO。 */ +(BOOL) sendResp:(BaseResp*)resp; @end ================================================ FILE: Sublime/Sublime/SDK/Weixin/WXApiObject.h ================================================ // // MMApiObject.h // Api对象,包含所有接口和对象数据定义 // // Created by Wechat on 12-2-28. // Copyright (c) 2012年 Tencent. All rights reserved. // #import /*! @brief 错误码 * */ enum WXErrCode { WXSuccess = 0, /**< 成功 */ WXErrCodeCommon = -1, /**< 普通错误类型 */ WXErrCodeUserCancel = -2, /**< 用户点击取消并返回 */ WXErrCodeSentFail = -3, /**< 发送失败 */ WXErrCodeAuthDeny = -4, /**< 授权失败 */ WXErrCodeUnsupport = -5, /**< 微信不支持 */ }; /*! @brief 请求发送场景 * */ enum WXScene { WXSceneSession = 0, /**< 聊天界面 */ WXSceneTimeline = 1, /**< 朋友圈 */ WXSceneFavorite = 2, /**< 收藏 */ }; enum WXAPISupport { WXAPISupportSession = 0, }; /*! @brief 跳转profile类型 * */ enum WXBizProfileType{ WXBizProfileType_Normal = 0, //**< 普通公众号 */ WXBizProfileType_Device = 1, //**< 硬件公众号 */ }; /*! @brief 跳转mp网页类型 * */ enum WXMPWebviewType { WXMPWebviewType_Ad = 0, /**< 广告网页 **/ }; /*! @brief 应用支持接收微信的文件类型 * */ typedef NS_ENUM(UInt64, enAppSupportContentFlag) { MMAPP_SUPPORT_NOCONTENT = 0x0, MMAPP_SUPPORT_TEXT = 0x1, MMAPP_SUPPORT_PICTURE = 0x2, MMAPP_SUPPORT_LOCATION = 0x4, MMAPP_SUPPORT_VIDEO = 0x8, MMAPP_SUPPORT_AUDIO = 0x10, MMAPP_SUPPORT_WEBPAGE = 0x20, // Suport File Type MMAPP_SUPPORT_DOC = 0x40, // doc MMAPP_SUPPORT_DOCX = 0x80, // docx MMAPP_SUPPORT_PPT = 0x100, // ppt MMAPP_SUPPORT_PPTX = 0x200, // pptx MMAPP_SUPPORT_XLS = 0x400, // xls MMAPP_SUPPORT_XLSX = 0x800, // xlsx MMAPP_SUPPORT_PDF = 0x1000, // pdf }; #pragma mark - BaseReq /*! @brief 该类为微信终端SDK所有请求类的基类 * */ @interface BaseReq : NSObject /** 请求类型 */ @property (nonatomic, assign) int type; /** 由用户微信号和AppID组成的唯一标识,发送请求时第三方程序必须填写,用于校验微信用户是否换号登录*/ @property (nonatomic, retain) NSString* openID; @end #pragma mark - BaseResp /*! @brief 该类为微信终端SDK所有响应类的基类 * */ @interface BaseResp : NSObject /** 错误码 */ @property (nonatomic, assign) int errCode; /** 错误提示字符串 */ @property (nonatomic, retain) NSString *errStr; /** 响应类型 */ @property (nonatomic, assign) int type; @end #pragma mark - WXMediaMessage @class WXMediaMessage; /*! @brief 第三方向微信终端发起支付的消息结构体 * * 第三方向微信终端发起支付的消息结构体,微信终端处理后会向第三方返回处理结果 * @see PayResp */ @interface PayReq : BaseReq /** 商家向财付通申请的商家id */ @property (nonatomic, retain) NSString *partnerId; /** 预支付订单 */ @property (nonatomic, retain) NSString *prepayId; /** 随机串,防重发 */ @property (nonatomic, retain) NSString *nonceStr; /** 时间戳,防重发 */ @property (nonatomic, assign) UInt32 timeStamp; /** 商家根据财付通文档填写的数据和签名 */ @property (nonatomic, retain) NSString *package; /** 商家根据微信开放平台文档对数据做的签名 */ @property (nonatomic, retain) NSString *sign; @end #pragma mark - PayResp /*! @brief 微信终端返回给第三方的关于支付结果的结构体 * * 微信终端返回给第三方的关于支付结果的结构体 */ @interface PayResp : BaseResp /** 财付通返回给商家的信息 */ @property (nonatomic, retain) NSString *returnKey; @end /*! @brief 第三方向微信终端发起拆企业红包的消息结构体 * * 第三方向微信终端发起拆企业红包的消息结构体,微信终端处理后会向第三方返回处理结果 * @see HBReq */ @interface HBReq : BaseReq /** 随机串,防重发 */ @property (nonatomic, retain) NSString *nonceStr; /** 时间戳,防重发 */ @property (nonatomic, assign) UInt32 timeStamp; /** 商家根据微信企业红包开发文档填写的数据和签名 */ @property (nonatomic, retain) NSString *package; /** 商家根据微信企业红包开发文档对数据做的签名 */ @property (nonatomic, retain) NSString *sign; @end #pragma mark - HBResp /*! @brief 微信终端返回给第三方的关于拆企业红包结果的结构体 * * 微信终端返回给第三方的关于拆企业红包结果的结构体 */ @interface HBResp : BaseResp @end #pragma mark - SendAuthReq /*! @brief 第三方程序向微信终端请求认证的消息结构 * * 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数, * 向微信终端发送一个SendAuthReq消息结构。微信终端处理完后会向第三方程序发送一个处理结果。 * @see SendAuthResp */ @interface SendAuthReq : BaseReq /** 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数,向微信终端发送一个SendAuthReq消息结构。微信终端处理完后会向第三方程序发送一个处理结果。 * @see SendAuthResp * @note scope字符串长度不能超过1K */ @property (nonatomic, retain) NSString* scope; /** 第三方程序本身用来标识其请求的唯一性,最后跳转回第三方程序时,由微信终端回传。 * @note state字符串长度不能超过1K */ @property (nonatomic, retain) NSString* state; @end #pragma mark - SendAuthResp /*! @brief 微信处理完第三方程序的认证和权限申请后向第三方程序回送的处理结果。 * * 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数,向微信终端发送一个SendAuthReq消息结构。 * 微信终端处理完后会向第三方程序发送一个SendAuthResp。 * @see onResp */ @interface SendAuthResp : BaseResp @property (nonatomic, retain) NSString* code; /** 第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用sendReq时传入,由微信终端回传 * @note state字符串长度不能超过1K */ @property (nonatomic, retain) NSString* state; @property (nonatomic, retain) NSString* lang; @property (nonatomic, retain) NSString* country; @end #pragma mark - SendMessageToWXReq /*! @brief 第三方程序发送消息至微信终端程序的消息结构体 * * 第三方程序向微信发送信息需要传入SendMessageToWXReq结构体,信息类型包括文本消息和多媒体消息, * 分别对应于text和message成员。调用该方法后,微信处理完信息会向第三方程序发送一个处理结果。 * @see SendMessageToWXResp */ @interface SendMessageToWXReq : BaseReq /** 发送消息的文本内容 * @note 文本长度必须大于0且小于10K */ @property (nonatomic, retain) NSString* text; /** 发送消息的多媒体内容 * @see WXMediaMessage */ @property (nonatomic, retain) WXMediaMessage* message; /** 发送消息的类型,包括文本消息和多媒体消息两种,两者只能选择其一,不能同时发送文本和多媒体消息 */ @property (nonatomic, assign) BOOL bText; /** 发送的目标场景,可以选择发送到会话(WXSceneSession)或者朋友圈(WXSceneTimeline)。 默认发送到会话。 * @see WXScene */ @property (nonatomic, assign) int scene; @end #pragma mark - SendMessageToWXResp /*! @brief 微信终端向第三方程序返回的SendMessageToWXReq处理结果。 * * 第三方程序向微信终端发送SendMessageToWXReq后,微信发送回来的处理结果,该结果用SendMessageToWXResp表示。 */ @interface SendMessageToWXResp : BaseResp @property(nonatomic, retain) NSString* lang; @property(nonatomic, retain) NSString* country; @end #pragma mark - GetMessageFromWXReq /*! @brief 微信终端向第三方程序请求提供内容的消息结构体。 * * 微信终端向第三方程序请求提供内容,微信终端会向第三方程序发送GetMessageFromWXReq消息结构体, * 需要第三方程序调用sendResp返回一个GetMessageFromWXResp消息结构体。 */ @interface GetMessageFromWXReq : BaseReq @property (nonatomic, retain) NSString* lang; @property (nonatomic, retain) NSString* country; @end #pragma mark - GetMessageFromWXResp /*! @brief 微信终端向第三方程序请求提供内容,第三方程序向微信终端返回的消息结构体。 * * 微信终端向第三方程序请求提供内容,第三方程序调用sendResp向微信终端返回一个GetMessageFromWXResp消息结构体。 */ @interface GetMessageFromWXResp : BaseResp /** 向微信终端提供的文本内容 @note 文本长度必须大于0且小于10K */ @property (nonatomic, retain) NSString* text; /** 向微信终端提供的多媒体内容。 * @see WXMediaMessage */ @property (nonatomic, retain) WXMediaMessage* message; /** 向微信终端提供内容的消息类型,包括文本消息和多媒体消息两种,两者只能选择其一,不能同时发送文本和多媒体消息 */ @property (nonatomic, assign) BOOL bText; @end #pragma mark - ShowMessageFromWXReq /*! @brief 微信通知第三方程序,要求第三方程序显示的消息结构体。 * * 微信需要通知第三方程序显示或处理某些内容时,会向第三方程序发送ShowMessageFromWXReq消息结构体。 * 第三方程序处理完内容后调用sendResp向微信终端发送ShowMessageFromWXResp。 */ @interface ShowMessageFromWXReq : BaseReq /** 微信终端向第三方程序发送的要求第三方程序处理的多媒体内容 * @see WXMediaMessage */ @property (nonatomic, retain) WXMediaMessage* message; @property (nonatomic, retain) NSString* lang; @property (nonatomic, retain) NSString* country; @end #pragma mark - ShowMessageFromWXResp /*! @brief 微信通知第三方程序,要求第三方程序显示或处理某些消息,第三方程序处理完后向微信终端发送的处理结果。 * * 微信需要通知第三方程序显示或处理某些内容时,会向第三方程序发送ShowMessageFromWXReq消息结构体。 * 第三方程序处理完内容后调用sendResp向微信终端发送ShowMessageFromWXResp。 */ @interface ShowMessageFromWXResp : BaseResp @end #pragma mark - LaunchFromWXReq /*! @brief 微信终端打开第三方程序携带的消息结构体 * * 微信向第三方发送的结构体,第三方不需要返回 */ @interface LaunchFromWXReq : BaseReq @property (nonatomic, retain) WXMediaMessage* message; @property (nonatomic, retain) NSString* lang; @property (nonatomic, retain) NSString* country; @end #pragma mark - OpenTempSessionReq /* ! @brief 第三方通知微信,打开临时会话 * * 第三方通知微信,打开临时会话 */ @interface OpenTempSessionReq : BaseReq /** 需要打开的用户名 * @attention 长度不能超过512字节 */ @property (nonatomic, retain) NSString* username; /** 开发者自定义参数,拉起临时会话后会发给开发者后台,可以用于识别场景 * @attention 长度不能超过32位 */ @property (nonatomic, retain) NSString* sessionFrom; @end #pragma mark - OpenWebviewReq /* ! @brief 第三方通知微信启动内部浏览器,打开指定网页 * * 第三方通知微信启动内部浏览器,打开指定Url对应的网页 */ @interface OpenWebviewReq : BaseReq /** 需要打开的网页对应的Url * @attention 长度不能超过1024 */ @property(nonatomic,retain)NSString* url; @end #pragma mark - OpenWebviewResp /*! @brief 微信终端向第三方程序返回的OpenWebviewReq处理结果 * * 第三方程序向微信终端发送OpenWebviewReq后,微信发送回来的处理结果,该结果用OpenWebviewResp表示 */ @interface OpenWebviewResp : BaseResp @end #pragma mark - OpenTempSessionResp /*! @brief 微信终端向第三方程序返回的OpenTempSessionReq处理结果。 * * 第三方程序向微信终端发送OpenTempSessionReq后,微信发送回来的处理结果,该结果用OpenTempSessionResp表示。 */ @interface OpenTempSessionResp : BaseResp @end #pragma mark - OpenRankListReq /* ! @brief 第三方通知微信,打开硬件排行榜 * * 第三方通知微信,打开硬件排行榜 */ @interface OpenRankListReq : BaseReq @end #pragma mark - OpenRanklistResp /*! @brief 微信终端向第三方程序返回的OpenRankListReq处理结果。 * * 第三方程序向微信终端发送OpenRankListReq后,微信发送回来的处理结果,该结果用OpenRankListResp表示。 */ @interface OpenRankListResp : BaseResp @end #pragma mark - JumpToBizProfileReq /* ! @brief 第三方通知微信,打开指定微信号profile页面 * * 第三方通知微信,打开指定微信号profile页面 */ @interface JumpToBizProfileReq : BaseReq /** 跳转到该公众号的profile * @attention 长度不能超过512字节 */ @property (nonatomic, retain) NSString* username; /** 如果用户加了该公众号为好友,extMsg会上传到服务器 * @attention 长度不能超过1024字节 */ @property (nonatomic, retain) NSString* extMsg; /** * 跳转的公众号类型 * @see WXBizProfileType */ @property (nonatomic, assign) int profileType; @end #pragma mark - JumpToBizWebviewReq /* ! @brief 第三方通知微信,打开指定usrname的profile网页版 * */ @interface JumpToBizWebviewReq : BaseReq /** 跳转的网页类型,目前只支持广告页 * @see WXMPWebviewType */ @property(nonatomic, assign) int webType; /** 跳转到该公众号的profile网页版 * @attention 长度不能超过512字节 */ @property(nonatomic, retain) NSString* tousrname; /** 如果用户加了该公众号为好友,extMsg会上传到服务器 * @attention 长度不能超过1024字节 */ @property(nonatomic, retain) NSString* extMsg; @end #pragma mark - WXCardItem @interface WXCardItem : NSObject /** 卡id * @attention 长度不能超过1024字节 */ @property (nonatomic,retain) NSString* cardId; /** ext信息 * @attention 长度不能超过2024字节 */ @property (nonatomic,retain) NSString* extMsg; /** * @attention 卡的状态,req不需要填。resp:0为未添加,1为已添加。 */ @property (nonatomic,assign) UInt32 cardState; /** * @attention req不需要填,chooseCard返回的。 */ @property (nonatomic,retain) NSString* encryptCode; /** * @attention req不需要填,chooseCard返回的。 */ @property (nonatomic,retain) NSString* appID; @end; #pragma mark - AddCardToWXCardPackageReq /* ! @brief 请求添加卡券至微信卡包 * */ @interface AddCardToWXCardPackageReq : BaseReq /** 卡列表 * @attention 个数不能超过40个 类型WXCardItem */ @property (nonatomic,retain) NSArray* cardAry; @end #pragma mark - AddCardToWXCardPackageResp /** ! @brief 微信返回第三方添加卡券结果 * */ @interface AddCardToWXCardPackageResp : BaseResp /** 卡列表 * @attention 个数不能超过40个 类型WXCardItem */ @property (nonatomic,retain) NSArray* cardAry; @end #pragma mark - WXChooseCardReq /* ! @brief 请求从微信选取卡券 * */ @interface WXChooseCardReq : BaseReq @property(nonatomic, strong) NSString *appID; @property(nonatomic, assign) UInt32 shopID; @property(nonatomic, assign) UInt32 canMultiSelect; @property(nonatomic, strong) NSString *cardType; @property(nonatomic, strong) NSString *cardTpID; @property(nonatomic, strong) NSString *signType; @property(nonatomic, strong) NSString *cardSign; @property(nonatomic, assign) UInt32 timeStamp; @property(nonatomic, strong) NSString *nonceStr; @end #pragma mark - WXChooseCardResp /** ! @brief 微信返回第三方请求选择卡券结果 * */ @interface WXChooseCardResp : BaseResp @property (nonatomic,retain) NSArray* cardAry; @end #pragma mark - WXMediaMessage /*! @brief 多媒体消息结构体 * * 用于微信终端和第三方程序之间传递消息的多媒体消息内容 */ @interface WXMediaMessage : NSObject +(WXMediaMessage *) message; /** 标题 * @note 长度不能超过512字节 */ @property (nonatomic, retain) NSString *title; /** 描述内容 * @note 长度不能超过1K */ @property (nonatomic, retain) NSString *description; /** 缩略图数据 * @note 大小不能超过32K */ @property (nonatomic, retain) NSData *thumbData; /** * @note 长度不能超过64字节 */ @property (nonatomic, retain) NSString *mediaTagName; /** * */ @property (nonatomic, retain) NSString *messageExt; @property (nonatomic, retain) NSString *messageAction; /** * 多媒体数据对象,可以为WXImageObject,WXMusicObject,WXVideoObject,WXWebpageObject等。 */ @property (nonatomic, retain) id mediaObject; /*! @brief 设置消息缩略图的方法 * * @param image 缩略图 * @note 大小不能超过32K */ - (void) setThumbImage:(UIImage *)image; @end #pragma mark - WXImageObject /*! @brief 多媒体消息中包含的图片数据对象 * * 微信终端和第三方程序之间传递消息中包含的图片数据对象。 * @note imageData成员不能为空 * @see WXMediaMessage */ @interface WXImageObject : NSObject /*! @brief 返回一个WXImageObject对象 * * @note 返回的WXImageObject对象是自动释放的 */ +(WXImageObject *) object; /** 图片真实数据内容 * @note 大小不能超过10M */ @property (nonatomic, retain) NSData *imageData; @end #pragma mark - WXMusicObject /*! @brief 多媒体消息中包含的音乐数据对象 * * 微信终端和第三方程序之间传递消息中包含的音乐数据对象。 * @note musicUrl和musicLowBandUrl成员不能同时为空。 * @see WXMediaMessage */ @interface WXMusicObject : NSObject /*! @brief 返回一个WXMusicObject对象 * * @note 返回的WXMusicObject对象是自动释放的 */ +(WXMusicObject *) object; /** 音乐网页的url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *musicUrl; /** 音乐lowband网页的url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *musicLowBandUrl; /** 音乐数据url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *musicDataUrl; /**音乐lowband数据url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *musicLowBandDataUrl; @end #pragma mark - WXVideoObject /*! @brief 多媒体消息中包含的视频数据对象 * * 微信终端和第三方程序之间传递消息中包含的视频数据对象。 * @note videoUrl和videoLowBandUrl不能同时为空。 * @see WXMediaMessage */ @interface WXVideoObject : NSObject /*! @brief 返回一个WXVideoObject对象 * * @note 返回的WXVideoObject对象是自动释放的 */ +(WXVideoObject *) object; /** 视频网页的url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *videoUrl; /** 视频lowband网页的url地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *videoLowBandUrl; @end #pragma mark - WXWebpageObject /*! @brief 多媒体消息中包含的网页数据对象 * * 微信终端和第三方程序之间传递消息中包含的网页数据对象。 * @see WXMediaMessage */ @interface WXWebpageObject : NSObject /*! @brief 返回一个WXWebpageObject对象 * * @note 返回的WXWebpageObject对象是自动释放的 */ +(WXWebpageObject *) object; /** 网页的url地址 * @note 不能为空且长度不能超过10K */ @property (nonatomic, retain) NSString *webpageUrl; @end #pragma mark - WXAppExtendObject /*! @brief 多媒体消息中包含的App扩展数据对象 * * 第三方程序向微信终端发送包含WXAppExtendObject的多媒体消息, * 微信需要处理该消息时,会调用该第三方程序来处理多媒体消息内容。 * @note url,extInfo和fileData不能同时为空 * @see WXMediaMessage */ @interface WXAppExtendObject : NSObject /*! @brief 返回一个WXAppExtendObject对象 * * @note 返回的WXAppExtendObject对象是自动释放的 */ +(WXAppExtendObject *) object; /** 若第三方程序不存在,微信终端会打开该url所指的App下载地址 * @note 长度不能超过10K */ @property (nonatomic, retain) NSString *url; /** 第三方程序自定义简单数据,微信终端会回传给第三方程序处理 * @note 长度不能超过2K */ @property (nonatomic, retain) NSString *extInfo; /** App文件数据,该数据发送给微信好友,微信好友需要点击后下载数据,微信终端会回传给第三方程序处理 * @note 大小不能超过10M */ @property (nonatomic, retain) NSData *fileData; @end #pragma mark - WXEmoticonObject /*! @brief 多媒体消息中包含的表情数据对象 * * 微信终端和第三方程序之间传递消息中包含的表情数据对象。 * @see WXMediaMessage */ @interface WXEmoticonObject : NSObject /*! @brief 返回一个WXEmoticonObject对象 * * @note 返回的WXEmoticonObject对象是自动释放的 */ +(WXEmoticonObject *) object; /** 表情真实数据内容 * @note 大小不能超过10M */ @property (nonatomic, retain) NSData *emoticonData; @end #pragma mark - WXFileObject /*! @brief 多媒体消息中包含的文件数据对象 * * @see WXMediaMessage */ @interface WXFileObject : NSObject /*! @brief 返回一个WXFileObject对象 * * @note 返回的WXFileObject对象是自动释放的 */ +(WXFileObject *) object; /** 文件后缀名 * @note 长度不超过64字节 */ @property (nonatomic, retain) NSString *fileExtension; /** 文件真实数据内容 * @note 大小不能超过10M */ @property (nonatomic, retain) NSData *fileData; @end #pragma mark - WXLocationObject /*! @brief 多媒体消息中包含的地理位置数据对象 * * 微信终端和第三方程序之间传递消息中包含的地理位置数据对象。 * @see WXMediaMessage */ @interface WXLocationObject : NSObject /*! @brief 返回一个WXLocationObject对象 * * @note 返回的WXLocationObject对象是自动释放的 */ +(WXLocationObject *) object; /** 地理位置信息 * @note 经纬度 */ @property (nonatomic, assign) double lng; //经度 @property (nonatomic, assign) double lat; //纬度 @end #pragma mark - WXTextObject /*! @brief 多媒体消息中包含的文本数据对象 * * 微信终端和第三方程序之间传递消息中包含的文本数据对象。 * @see WXMediaMessage */ @interface WXTextObject : NSObject /*! @brief 返回一个WXTextObject对象 * * @note 返回的WXTextObject对象是自动释放的 */ +(WXTextObject *) object; /** 地理位置信息 * @note 文本内容 */ @property (nonatomic, retain) NSString *contentText; @end ================================================ FILE: Sublime/Sublime/SDK/Weixin/WechatAuthSDK.h ================================================ // // WechatAuthSDK.h // WechatAuthSDK // // Created by 李凯 on 13-11-29. // Copyright (c) 2013年 Tencent. All rights reserved. // #import #import enum AuthErrCode { WechatAuth_Err_Ok = 0, //Auth成功 WechatAuth_Err_NormalErr = -1, //普通错误 WechatAuth_Err_NetworkErr = -2, //网络错误 WechatAuth_Err_GetQrcodeFailed = -3, //获取二维码失败 WechatAuth_Err_Cancel = -4, //用户取消授权 WechatAuth_Err_Timeout = -5, //超时 }; @protocol WechatAuthAPIDelegate @optional - (void)onAuthGotQrcode:(UIImage *)image; //得到二维码 - (void)onQrcodeScanned; //二维码被扫描 - (void)onAuthFinish:(int)errCode AuthCode:(NSString *)authCode; //成功登录 @end @interface WechatAuthSDK : NSObject{ NSString *_sdkVersion; __weak id _delegate; } @property(nonatomic, weak) id delegate; @property(nonatomic, readonly) NSString *sdkVersion; //authSDK版本号 /*! @brief 发送登录请求,等待WechatAuthAPIDelegate回调 * * @param appId 微信开发者ID * @param nonceStr 一个随机的尽量不重复的字符串,用来使得每次的signature不同 * @param timeStamp 时间戳 * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔 * @param signature 签名 * @param schemeData 会在扫码后拼在scheme后 * @return 成功返回YES,失败返回NO 注:该实现只保证同时只有一个Auth在运行,Auth未完成或未Stop再次调用Auth接口时会返回NO。 */ - (BOOL)Auth:(NSString *)appId nonceStr:(NSString *)nonceStr timeStamp:(NSString*)timeStamp scope:(NSString *)scope signature:(NSString *)signature schemeData:(NSString *)schemeData; /*! @brief 暂停登录请求 * * @return 成功返回YES,失败返回NO。 */ - (BOOL)StopAuth; @end ================================================ FILE: Sublime/Sublime/SDK/Weixin/libWeChatSDK.a ================================================ [File too large to display: 13.7 MB] ================================================ FILE: Sublime/Sublime/SSHAddNewServerViewController.swift ================================================ // // SSHAddNewServerViewController.swift // Sublime // // Created by Eular on 3/28/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Gifu class SSHAddNewServerViewController: UITableViewController, UITextFieldDelegate { let settingList = [ ["ssh_server", "host"], ["ssh_port", "port"], ["ssh_user", "username"], ["ssh_password", "password"] ] var textFieldList = [UITextField]() override func viewDidLoad() { super.viewDidLoad() title = "New Server" tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.TableCellSeparatorColor tableView.tableFooterView = UIView() Global.Notifi.addObserver(self, selector: #selector(self.keyboardDidShow), name: UIKeyboardDidShowNotification, object: nil) Global.Notifi.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIKeyboardDidHideNotification, object: nil) let header = UIView(frame: CGRectMake(0, 0, view.width, 80)) let gif = AnimatableImageView() gif.frame = CGRectMake(0, 20, view.width, 60) gif.contentMode = .ScaleAspectFit gif.animateWithImageData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("animation", ofType: "gif")!)!) gif.startAnimatingGIF() header.addSubview(gif) tableView.tableHeaderView = header } func keyboardDidShow() { navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "ssh_keyboard"), style: .Plain, target: self, action: #selector(self.dismissKeyboard)) } func keyboardWillHide() { navigationItem.rightBarButtonItem = nil } func dismissKeyboard() { self.view.endEditing(true) } func textFieldShouldReturn(textField: UITextField) -> Bool { textField.resignFirstResponder() return true } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return [settingList.count, 1][section] } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return 50 } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { if section == 0 { return 0 } return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { if section == 0 { return nil } let headerView = UIView() headerView.frame = CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight) headerView.backgroundColor = Constant.CapeCod return headerView } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Default, reuseIdentifier: nil) cell.backgroundColor = Constant.NavigationBarAndTabBarColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.NavigationBarAndTabBarColor if indexPath.section == 0 { let tf = UITextField() tf.frame = CGRectMake(70, 3, cell.frame.width - 80, cell.frame.height) tf.attributedPlaceholder = NSAttributedString(string: settingList[indexPath.row][1], attributes: [NSForegroundColorAttributeName: UIColor.grayColor()]) tf.textColor = UIColor.whiteColor() tf.delegate = self if tf.placeholder == "port" { tf.keyboardType = .NumberPad } else if tf.placeholder == "host" { tf.keyboardType = .URL } tf.autocorrectionType = .No tf.autocapitalizationType = .None cell.addSubview(tf) cell.imageView?.image = UIImage(named: settingList[indexPath.row][0]) textFieldList.append(tf) } else { let doneImg = UIImageView() doneImg.frame = CGRectMake(0, 0, 40, 40) doneImg.image = UIImage(named: "ssh_done") cell.addSubview(doneImg) doneImg.atCenter() } return cell } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) if indexPath.section == 1 { var serverInfo = [String:String]() for tf in textFieldList { if tf.text!.isEmpty { view.Toast(message: "\(tf.placeholder!) can't be empty", hasNavigationBar: true) return } else { serverInfo[tf.placeholder!] = tf.text } } let serverPlist = Plist(path: Constant.SublimeRoot+"/etc/ssh_list.plist") do { try serverPlist.appendToPlistFile(serverInfo) navigationController?.popViewControllerAnimated(true) } catch { view.Toast(message: "Save failed!", hasNavigationBar: true) } } } } ================================================ FILE: Sublime/Sublime/SSHServerListTableViewController.swift ================================================ // // SSHServerListTableViewController.swift // Sublime // // Created by Eular on 3/28/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class SSHServerListTableViewController: UITableViewController { let serverPlist = Plist(path: Constant.SublimeRoot+"/etc/ssh_list.plist") var serverList: [[String: String]] = [] override func viewDidLoad() { super.viewDidLoad() title = "Servers" tableView.backgroundColor = Constant.CapeCod tableView.separatorColor = Constant.NavigationBarAndTabBarColor tableView.tableFooterView = UIView() navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(self.addNewServer)) } override func viewWillAppear(animated: Bool) { if let arr = serverPlist.getArrayInPlistFile() { serverList = arr as! [[String : String]] tableView.reloadData() } } func addNewServer() { let addnew = SSHAddNewServerViewController() navigationController?.pushViewController(addnew, animated: true) } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return serverList.count } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return Constant.SSHServerListCellHeight } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: nil) cell.backgroundColor = Constant.NavigationBarAndTabBarColor cell.selectedBackgroundView = UIView(frame: cell.frame) cell.selectedBackgroundView?.backgroundColor = Constant.TableCellSelectedColor cell.accessoryType = .DisclosureIndicator cell.textLabel?.text = serverList[indexPath.row]["host"] cell.textLabel?.textColor = UIColor.whiteColor() cell.detailTextLabel?.text = serverList[indexPath.row]["username"] cell.detailTextLabel?.textColor = RGB(190, 190, 190) cell.imageView?.image = UIImage(named: "ssh_server") return cell } override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { serverList.removeAtIndex(indexPath.row) do { try serverPlist.saveToPlistFile(serverList) } catch {} tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) let terminal = SSHTerminalViewController() terminal.server = serverList[indexPath.row] navigationController?.pushViewController(terminal, animated: true) } } ================================================ FILE: Sublime/Sublime/SSHTerminalViewController.swift ================================================ // // SSHTerminalViewController.swift // Sublime // // Created by Eular on 3/28/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import NMSSH class SSHTerminalViewController: UIViewController, UITextViewDelegate { var server = ["host": "localhost", "port": "22", "username": "sublime", "password": "sublime"] let terminalTextView = UITextView() var sshSession: NMSSHSession! var shellPrompt: String! let promptView = UIView() var promptViewBottom: NSLayoutConstraint! var promptViewHeight: NSLayoutConstraint! let promptLines = 3 let promptLineHeight: CGFloat = 14 let promptViewTopMargin: CGFloat = 5 let promptViewBottomOffset: CGFloat = 5 override func viewDidLoad() { super.viewDidLoad() title = server["host"] view.backgroundColor = Constant.CapeCod shellPrompt = "[\(server["username"]!)@\(server["host"]!) ~] >" Global.Notifi.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil) Global.Notifi.addObserver(self, selector: #selector(self.keyboardDidShow), name: UIKeyboardDidShowNotification, object: nil) Global.Notifi.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil) view.addSubview(terminalTextView) view.addSubview(promptView) setTerminalTextView() setPromptView(">", lineHeight: promptLineHeight, maxLines: promptLines) SSHLog("[sublime@localhost ~] > ssh \(server["username"]!)@\(server["host"]!):\(server["port"]!)") } deinit { sshSession.disconnect() } func keyboardWillShow(noti: NSNotification) { let info = noti.userInfo! let value = info[UIKeyboardFrameBeginUserInfoKey] as! NSValue let value2 = info[UIKeyboardAnimationDurationUserInfoKey] as! NSValue let keyboardSize = value.CGRectValue() let height = keyboardSize.height var time: NSTimeInterval = 0 value2.getValue(&time) promptViewBottom.constant = -height - promptViewBottomOffset UIView.animateWithDuration(time, animations: { self.view.layoutIfNeeded() }) { (_) in self.updateTerminalTextView() } } func keyboardDidShow() { navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "ssh_keyboard"), style: .Plain, target: self, action: #selector(self.dismissKeyboard)) } func keyboardWillHide(noti: NSNotification) { navigationItem.rightBarButtonItem = nil let info = noti.userInfo! let value2 = info[UIKeyboardAnimationDurationUserInfoKey] as! NSValue var time: NSTimeInterval = 0 value2.getValue(&time) promptViewBottom.constant = -promptViewBottomOffset UIView.animateWithDuration(time) { () -> Void in self.view.layoutIfNeeded() } } func dismissKeyboard() { self.view.endEditing(true) } func setTerminalTextView() { // terminalTextView.frame = view.frame terminalTextView.backgroundColor = Constant.CapeCod terminalTextView.textColor = UIColor.whiteColor() terminalTextView.textContainerInset.top = 0 terminalTextView.textContainerInset.bottom = 0 terminalTextView.editable = false terminalTextView.translatesAutoresizingMaskIntoConstraints = false view.addConstraint(NSLayoutConstraint(item: terminalTextView, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1, constant: 0)) view.addConstraint(NSLayoutConstraint(item: terminalTextView, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 1, constant: 0)) view.addConstraint(NSLayoutConstraint(item: terminalTextView, attribute: .Bottom, relatedBy: .Equal, toItem: promptView, attribute: .Top, multiplier: 1, constant: 0)) view.addConstraint(NSLayoutConstraint(item: terminalTextView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: view.width)) } func setPromptView(promptText: String, lineHeight: CGFloat, maxLines: Int){ promptView.translatesAutoresizingMaskIntoConstraints = false // Add constraints promptViewBottom = NSLayoutConstraint(item: promptView, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .Bottom, multiplier: 1, constant: -promptViewBottomOffset) promptViewHeight = NSLayoutConstraint(item: promptView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: lineHeight) view.addConstraint(promptViewBottom) view.addConstraint(NSLayoutConstraint(item: promptView, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 1, constant: 0)) view.addConstraint(NSLayoutConstraint(item: promptView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: view.width)) view.addConstraint(promptViewHeight) let prompt = UILabel() prompt.text = promptText prompt.textColor = UIColor.whiteColor() prompt.font = terminalTextView.font prompt.frame = CGRectMake(5, 0, prompt.intrinsicContentSize().width, lineHeight) promptView.addSubview(prompt) let input = UITextView() input.frame = CGRectMake(0, 0, view.width, lineHeight * maxLines) input.backgroundColor = UIColor.clearColor() input.font = terminalTextView.font input.textContainer.maximumNumberOfLines = maxLines input.textContainerInset.top = 0 input.textContainerInset.bottom = 0 input.autocorrectionType = .No input.autocapitalizationType = .None input.keyboardType = .ASCIICapable input.keyboardAppearance = .Dark input.spellCheckingType = .No input.delegate = self input.tintColor = UIColor.whiteColor() let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .ByCharWrapping paragraphStyle.firstLineHeadIndent = prompt.frame.width + prompt.frame.origin.x let attrs = [ NSParagraphStyleAttributeName: paragraphStyle, NSForegroundColorAttributeName: UIColor.whiteColor() ] input.attributedText = NSAttributedString(string: " ", attributes: attrs) input.text = nil promptView.addSubview(input) } func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { if text == "\n" { let cmd = textView.text.trim() if cmd.isEmpty { SSHLog(shellPrompt) } else { SSHLog("\(shellPrompt) \(cmd)") textView.text = nil if promptViewHeight.constant != promptLineHeight { promptViewHeight.constant = promptLineHeight UIView.animateWithDuration(0.3, animations: { () -> Void in self.view.layoutIfNeeded() }) } if sshSession.authorized { do { let response = try sshSession.channel.execute(cmd) if !response.isEmpty { SSHLog(response[nil,-1]) } } catch {} } } return false } return true } func textViewDidChange(textView: UITextView) { promptViewHeight.constant = textView.contentSize.height UIView.animateWithDuration(0.3, animations: { () -> Void in self.view.layoutIfNeeded() }) } override func viewDidAppear(animated: Bool) { let user = server["username"]! let host = server["host"]! let port = server["port"]! let passwd = server["password"]! sshSession = NMSSHSession(host: "\(host):\(port)", andUsername: user) if Network.isConnectedToNetwork() { if sshSession.connect() { SSHLog("Password: ******") if sshSession.authenticateByPassword(passwd) { SSHLog("Connect: Successful!") SSHLog("=============================") } else { SSHLog("Error: Password is wrong!") } } else { SSHLog("Error: Connect fialed!") } } else { SSHLog("Error: No network!") } } func SSHLog(msg: String) { terminalTextView.text = terminalTextView.text + "\(msg)\n" terminalTextView.setLineBreakMode(.ByCharWrapping) terminalTextView.scrollToBottom() } func updateTerminalTextView() { terminalTextView.attributedText = terminalTextView.attributedText.copy() as! NSAttributedString terminalTextView.scrollToBottom() } } ================================================ FILE: Sublime/Sublime/SettingTableViewController.swift ================================================ // // SettingTableViewController.swift // Sublime // // Created by Eular on 2/23/16. // Copyright © 2016 Eular. All rights reserved. // class SettingTableViewController: UITableViewController { let secTitle = [" General", " Other", " About"] override func viewDidLoad() { super.viewDidLoad() } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let title = UILabel(frame: CGRectMake(0, 0, view.width, Constant.FilesTableSectionHight)) title.backgroundColor = Constant.CapeCod title.text = secTitle[section] title.textColor = UIColor.whiteColor() title.font = title.font.fontWithSize(12) title.textAlignment = .Natural let headerView = UIView() headerView.addSubview(title) return headerView } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return Constant.FilesTableSectionHight } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) switch (indexPath.section, indexPath.row) { case (1,0): let rvc = ReadingViewController() rvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(rvc, animated: true) case (1,1): let svc = StorageViewController() svc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(svc, animated: true) case (2,0): let avc = AppInfoViewController() avc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(avc, animated: true) case (2,1): let dvc = DonateViewController() dvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(dvc, animated: true) case (2,2): let lvc = LicenseTableViewController() lvc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(lvc, animated: true) default: return } } } ================================================ FILE: Sublime/Sublime/StorageViewController.swift ================================================ // // StorageViewController.swift // Sublime // // Created by Eular on 5/5/16. // Copyright © 2016 Eular. All rights reserved. // import Charts class StorageViewController: UIViewController { let pieChart = PieChartView() let cacheCell = UITableViewCell(style: .Value1, reuseIdentifier: nil) let processing = UILabel() override func viewDidLoad() { super.viewDidLoad() title = "Storage" view.backgroundColor = Constant.CapeCod view.addSubview(processing) processing.text = "0 %" processing.textAlignment = .Center processing.textColor = UIColor.whiteColor() processing.frame = CGRectMake(0, 0, view.width, 40) processing.atCenter(true) } override func viewDidAppear(animated: Bool) { let total = Device.systemSize var tmp = 0 Device.appSize({ percent in let per = Int(percent * 100) if per != tmp { tmp = per dispatch_async(dispatch_get_main_queue()) { self.processing.text = "\(per) %" } } }, completion: { app, cache in let sublime = app / total * 100 let available = Device.systemFreeSize / total * 100 let other = 100 - available - sublime let xValues = ["Sublime", "Available", "Other"] let yValues = [sublime, available, other] dispatch_async(dispatch_get_main_queue()) { self.processing.removeFromSuperview() self.setupPieChart(xValues, values: yValues) self.setupCacheCell(cache.size) } }) } func setupCacheCell(cache: String) { cacheCell.frame = CGRectMake(0, view.height - 80, view.width, 50) cacheCell.backgroundColor = RGB(100, 100, 100, alpha: 0.5) cacheCell.selectedBackgroundView = UIView(frame: cacheCell.frame) cacheCell.selectedBackgroundView?.backgroundColor = Constant.CapeCod cacheCell.accessoryType = .DisclosureIndicator cacheCell.textLabel?.text = "Cache" cacheCell.textLabel?.textColor = UIColor.whiteColor() cacheCell.imageView?.image = UIImage(named: "setting_cache") cacheCell.detailTextLabel?.text = cache view.addSubview(cacheCell) cacheCell.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.cleanCache))) } func cleanCache() { cacheCell.selected = true Device.cache = 0 cacheCell.detailTextLabel?.text = "0 KB" } func setupPieChart(dataPoints: [String], values: [Double]) { pieChart.frame = CGRectMake(0, 0, view.width, view.height - 100) pieChart.descriptionText = "Sublime 仅占有少量储存空间,建议清理手机中其他应用和数据" pieChart.descriptionTextAlign = .Center pieChart.descriptionTextPosition = CGPoint(x: pieChart.center.x, y: pieChart.height - 40) pieChart.descriptionTextColor = UIColor.whiteColor() pieChart.descriptionFont = pieChart.descriptionFont?.fontWithSize(10) pieChart.holeColor = UIColor.clearColor() pieChart.legend.position = .BelowChartCenter pieChart.legend.textColor = UIColor.whiteColor() pieChart.infoTextColor = UIColor.whiteColor() view.addSubview(pieChart) var dataEntries: [ChartDataEntry] = [] for i in 0.. #import #import #import "WXApi.h" #import "MusicWave.h" #import "ObjC.h" #include #import #import ================================================ FILE: Sublime/Sublime/SublimeSafari.swift ================================================ // // SublimeSafari.swift // Sublime // // Created by Eular on 4/19/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import WebKit class SublimeSafari: UIViewController, WKNavigationDelegate { let popupMenu = PopupMenu() let url: NSURL var webView: WKWebView! var progressBar: UIProgressView! init(URL: NSURL) { url = URL super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod self.automaticallyAdjustsScrollViewInsets = false // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.itemsToShare = [url] webView = WKWebView() webView.frame = CGRectMake(0, 0, view.width, view.height - Constant.NavigationBarOffset) webView.backgroundColor = UIColor.clearColor() webView.scrollView.backgroundColor = UIColor.clearColor() webView.navigationDelegate = self view.addSubview(webView) if let host = url.host { let hostLB = UILabel() hostLB.frame = CGRectMake(0, 10, view.width, 20) hostLB.text = "网页由 \(host) 提供" hostLB.font = hostLB.font.fontWithSize(12) hostLB.textAlignment = .Center hostLB.textColor = UIColor.grayColor() webView.addSubview(hostLB) webView.sendSubviewToBack(hostLB) } progressBar = UIProgressView() progressBar.frame = CGRectMake(0, 0, view.width, 0) progressBar.progress = 0 progressBar.progressTintColor = UIColor.greenColor() progressBar.trackTintColor = UIColor.clearColor() webView.addSubview(progressBar) webView.loadRequest(NSURLRequest(URL: url)) webView.allowsBackForwardNavigationGestures = true } // 准备加载页面 func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { progressBar.setProgress(0.5, animated: true) } // 已开始加载页面 func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation!) { progressBar.setProgress(0.9, animated: true) } // 页面已全部加载 func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { if title == nil { title = webView.title } progressBar.removeFromSuperview() } } ================================================ FILE: Sublime/Sublime/SublimeServer.swift ================================================ // // SublimeServer.swift // Sublime // // Created by Eular on 3/10/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import Swifter import SwiftyJSON public func SublimeServer(serverLog: WebServerLog?) -> HttpServer { let server = HttpServer() let webDir = NSBundle.mainBundle().resourcePath!.stringByAppendingPathComponent("Web") server["/file_manager/:path"] = HttpHandlers.shareFilesFromDirectory(webDir, serverLog: serverLog) server["/file_manager"] = { r in serverLog?.log(r, statusCode: 301) return .MovedPermanently("/file_manager/index.html") } server["/"] = { r in serverLog?.log(r, statusCode: 301) return .MovedPermanently("/file_manager/index.html") } server["/json/:param"] = { r in serverLog?.log(r) var json = ["code": 200, "filelist": []] var filelist = [NSObject]() if r.params[":param"] == "filelist" { for (key, value) in r.queryParams { if key == "path" { let folder = Folder(path: NSHomeDirectory()+"/Documents"+value) for f in folder.listFiles() { var type = "unknown" if f.isImg { type = "image" } else { switch f.img { case "folder": type = "folder" case "file_unknown": type = "unknown" default: type = "file" } } filelist.append(["name": f.name, "type": type]) } } } } json["filelist"] = filelist return .OK(.Json(json)) } return server } ================================================ FILE: Sublime/Sublime/Utils/ActionSheet.swift ================================================ // // DropdownMenu.swift // Sublime // // Created by Eular on 5/3/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation protocol ActionSheetDelegate { func tapOnActionSheetItem(itemAtRow row: Int) } class ActionSheet { var delegate: ActionSheetDelegate? var controller: UIViewController? var items: [String] = [] private var sheet: UIView? private var mask: UIView? private let rowWidth: CGFloat private let rowHight: CGFloat private let cancelGap: CGFloat = 5 private let textColor = Constant.ActionSheetTextColor private let splitLineColor = Constant.ActionSheetLineColor private let actionSheetColor = Constant.ActionSheetColor private let maskColor = Constant.BlackMaskViewColor init(rowWidth: CGFloat, rowHight: CGFloat) { self.rowWidth = rowWidth self.rowHight = rowHight } @objc func showUp() { let window = controller?.view.window var sheetItems = items sheetItems << "Cancel" let numberOfRow = sheetItems.count let actionSheetHight = rowHight * numberOfRow + cancelGap let actionSheet = UIView(frame: CGRectMake(0, window?.height ?? 0, rowWidth, actionSheetHight)) actionSheet.backgroundColor = actionSheetColor // Insert item label into menu for i in 0.. Void in actionSheet.y -= actionSheet.height } self.sheet = actionSheet self.mask = blackMaskView } @objc private func tapOnBlackMaskView() { dismissActionSheet() } @objc private func tapOnActionSheetItem(btn: UIButton) { dismissActionSheet { if btn.tag != self.items.count { self.delegate?.tapOnActionSheetItem(itemAtRow: btn.tag) } } } private func dismissActionSheet(completion: (() -> Void)? = nil) { if let actionSheet = self.sheet, blackMaskView = self.mask { UIView.animateWithDuration(0.3, animations: { () -> Void in actionSheet.y += actionSheet.height }, completion: { (_) -> Void in actionSheet.removeFromSuperview() blackMaskView.removeFromSuperview() completion?() }) } } } ================================================ FILE: Sublime/Sublime/Utils/Device.swift ================================================ // // Device.swift // Sublime // // Created by Eular on 5/6/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Device { static func appSize(process: ((Double) -> Void)? = nil, completion: ((Double, Double) -> Void)? = nil) { // 后台执行 let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT dispatch_async(dispatch_get_global_queue(priority, 0)) { let fileMgr = NSFileManager.defaultManager() let homePath = NSHomeDirectory() let appPath = NSBundle.mainBundle().bundlePath let fileArray:[AnyObject] = fileMgr.subpathsAtPath(homePath)! let fileArray2:[AnyObject] = fileMgr.subpathsAtPath(appPath)! let total = fileArray.count + fileArray2.count var count = 0 var allSize = 0.0 var cacheSize = 0.0 for fn in fileArray { count += 1 let attr = try! fileMgr.attributesOfItemAtPath(homePath + "/\(fn)") let size = attr["NSFileSize"] as! Double allSize += size if fn.hasPrefix("Library/Caches") { cacheSize += size } process?(Double(count) / Double(total)) } for fn in fileArray2 { count += 1 let attr = try! fileMgr.attributesOfItemAtPath(appPath + "/\(fn)") let size = attr["NSFileSize"] as! Double allSize += size process?(Double(count) / Double(total)) } completion?(allSize, cacheSize) } } static var cache: Double { get { let fileMgr = NSFileManager.defaultManager() let path = NSHomeDirectory() + "/Library/Caches/" let fileArray:[AnyObject] = fileMgr.subpathsAtPath(path)! var allSize = 0.0 for fn in fileArray { let attr = try! fileMgr.attributesOfItemAtPath(path + "/\(fn)") let size = attr["NSFileSize"] as! Double allSize += size } return allSize } set { let fileMgr = NSFileManager.defaultManager() let path = NSHomeDirectory() + "/Library/Caches/" do { try fileMgr.removeItemAtPath(path) try fileMgr.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil) } catch { Log("Error: clean cache failed.") } } } static var systemFreeSize: Double { let fm = NSFileManager.defaultManager() let fattributes = try! fm.attributesOfFileSystemForPath(NSHomeDirectory()) return fattributes["NSFileSystemFreeSize"] as! Double } static var systemSize: Double { let fm = NSFileManager.defaultManager() let fattributes = try! fm.attributesOfFileSystemForPath(NSHomeDirectory()) return fattributes["NSFileSystemSize"] as! Double } static var batteryLevel: Float { return UIDevice.currentDevice().batteryLevel } static var batteryState: UIDeviceBatteryState { return UIDevice.currentDevice().batteryState } static var UUID: String { return UIDevice.currentDevice().identifierForVendor!.UUIDString } static var name: String { return UIDevice.currentDevice().name } static var systemVersion: String { return UIDevice.currentDevice().systemVersion } static var app: Array { var appList = [String]() for app in ObjC.getAppList() { let BundleID = String(app).split(" ")[2] if !BundleID.hasPrefix("com.apple") { appList.append(BundleID) } } return appList } static var appNum: Int { return app.count } static var SSID: String { return ObjC.SSID() } static var BSSID: String { return ObjC.BSSID() } } ================================================ FILE: Sublime/Sublime/Utils/Extension/Array.swift ================================================ // // Array.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - Array extension Array { mutating func shift() -> Element? { return self.removeFirst() } mutating func pop() -> Element? { return self.popLast() } } class Array2D { let rows: Int let columns: Int var array: Array init(_ rows: Int, _ columns: Int) { self.rows = rows self.columns = columns array = Array(count:rows * columns, repeatedValue: nil) } subscript(row: Int, column: Int) -> T? { get { return array[(row * columns) + column] } set { array[(row * columns) + column] = newValue } } } ================================================ FILE: Sublime/Sublime/Utils/Extension/Date.swift ================================================ // // Date.swift // Sublime // // Created by Eular on 4/25/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation enum TimeIntervalUnit { case Seconds, Minutes, Hours, Days, Months, Years func dateComponents(interval: Int) -> NSDateComponents { let components = NSDateComponents() switch (self) { case .Seconds: components.second = interval case .Minutes: components.minute = interval case .Hours: components.hour = interval case .Days: components.day = interval case .Months: components.month = interval case .Years: components.year = interval } return components } } struct TimeInterval { var interval: Int var unit: TimeIntervalUnit var ago: NSDate { let calendar = NSCalendar.currentCalendar() let today = NSDate() let components = unit.dateComponents(-self.interval) return calendar.dateByAddingComponents(components, toDate: today, options: .WrapComponents)! } init(interval: Int, unit: TimeIntervalUnit) { self.interval = interval self.unit = unit } } extension Int { var seconds: TimeInterval { return TimeInterval(interval: self, unit: .Seconds) } var minutes: TimeInterval { return TimeInterval(interval: self, unit: .Minutes) } var hours: TimeInterval { return TimeInterval(interval: self, unit: .Hours) } var days: TimeInterval { return TimeInterval(interval: self, unit: .Days) } var months: TimeInterval { return TimeInterval(interval: self, unit: .Months) } var years: TimeInterval { return TimeInterval(interval: self, unit: .Years) } } extension NSDate { class func yesterday() -> NSDate { return NSDate() - 1.days } func toS(format: String) -> String? { let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.timeZone = NSTimeZone() formatter.dateFormat = format return formatter.stringFromDate(self) } } extension String { func toDate(format: String = "dd/MM/yyyy") -> NSDate? { let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.timeZone = NSTimeZone() formatter.dateFormat = format return formatter.dateFromString(self) } func toGMTDate(format: String = "dd/MM/yyyy") -> NSDate? { let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) formatter.dateFormat = format return formatter.dateFromString(self) } } func + (left: NSDate, right: TimeInterval) -> NSDate { let calendar = NSCalendar.currentCalendar() let components = right.unit.dateComponents(right.interval) return calendar.dateByAddingComponents(components, toDate: left, options: .WrapComponents)! } func - (left: NSDate, right: TimeInterval) -> NSDate { let calendar = NSCalendar.currentCalendar() let components = right.unit.dateComponents(-right.interval) return calendar.dateByAddingComponents(components, toDate: left, options: .WrapComponents)! } func < (left: NSDate, right: NSDate) -> Bool { let result: NSComparisonResult = left.compare(right) var isEarlier = false if (result == NSComparisonResult.OrderedAscending) { isEarlier = true } return isEarlier } func - (left: NSDate, right: NSDate) -> NSDateComponents { let diffDateComponents = NSCalendar.currentCalendar().components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: right, toDate: left, options: NSCalendarOptions.init(rawValue: 0)) return diffDateComponents } ================================================ FILE: Sublime/Sublime/Utils/Extension/Number.swift ================================================ // // Number.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - Int extension Int { var KB: Int { return self / 1024 } var MB: Int { return self.KB / 1024 } var GB: Int { return self.MB / 1024 } func times(block: () -> ()) { for _ in 0.. Double { let s = String(format: "%.\(n)f", self) return Double(s)! } func formatedTime(format: String) -> String { let d = NSDate(timeIntervalSince1970: self) let GTMzone = NSTimeZone(forSecondsFromGMT: 0) let formatter = NSDateFormatter() formatter.dateFormat = format formatter.timeZone = GTMzone return formatter.stringFromDate(d) } } ================================================ FILE: Sublime/Sublime/Utils/Extension/Operation.swift ================================================ // // Operation.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - Operation func + (left: Int, right: String) -> String { return "\(left)"+right } func + (left: String, right: Int) -> String { return left+"\(right)" } func * (left: String, right: Int) -> String { var s = "" for _ in 0.. Int { var tmp = left tmp %= right return tmp >= 0 ? tmp : tmp + right } func / (left: CGFloat, right: Int) -> CGFloat { return left / CGFloat(right) } func * (left: CGFloat, right: Int) -> CGFloat { return left * CGFloat(right) } func << (inout left: [T], right: T) { left.append(right) } ================================================ FILE: Sublime/Sublime/Utils/Extension/Other.swift ================================================ // // Other.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UIImage extension UIImage { func saveToCameraRoll() { UIImageWriteToSavedPhotosAlbum(self, nil, nil, nil) } } // MARK: - UITabBar extension UITabBar { func showRedBadgeOnItem(index: Int, totalItemNums: Int) { hideRedBadgeOnItem(index) let badgeSize: CGFloat = 8 let badgeView = UIView() badgeView.tag = 888 + index badgeView.layer.cornerRadius = badgeSize / 2 badgeView.backgroundColor = Constant.TabBatItemBadgeColor let percentX = (CGFloat(index) + 0.6) / totalItemNums let x = CGFloat(ceilf(Float(percentX * self.width))) let y = CGFloat(ceilf(Float(0.1 * self.height))) badgeView.frame = CGRectMake(x, y, badgeSize, badgeSize) addSubview(badgeView) } func hideRedBadgeOnItem(index: Int) { for subView in self.subviews { if (subView.tag == 888 + index) { subView.removeFromSuperview() } } } } // MARK: - Range extension Range { func each(iterator: (Element) -> ()) { for i in self { iterator(i) } } } ================================================ FILE: Sublime/Sublime/Utils/Extension/String.swift ================================================ // // String.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - String extension String { // MARK: - property // md5 need import in bridging header file var md5: String! { let str = self.cStringUsingEncoding(NSUTF8StringEncoding) let strLen = CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = Int(CC_MD5_DIGEST_LENGTH) let result = UnsafeMutablePointer.alloc(digestLen) CC_MD5(str!, strLen, result) let hash = NSMutableString() for i in 0.. in bridging header file var sha1: String { let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)! var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH),repeatedValue:0) CC_SHA1(data.bytes, CC_LONG(data.length), &digest) let output = NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH)) for byte in digest{ output.appendFormat("%02x", byte) } return output as String } // length of the string var count: Int { return self.characters.count } var lower: String { return self.lowercaseString } var upper: String { return self.uppercaseString } var islower: Bool { return self == self.lower } var isupper: Bool { return self == self.upper } var lastPathComponent: String { return (self as NSString).lastPathComponent } var pathExtension: String { return (self as NSString).pathExtension } var stringByDeletingLastPathComponent: String { return (self as NSString).stringByDeletingLastPathComponent } var stringByDeletingPathExtension: String { return (self as NSString).stringByDeletingPathExtension } var pathComponents: [String] { return (self as NSString).pathComponents } // format: "#ffffff" var color: UIColor? { if self[0] == "#" { if let r = Int(self[1,3], radix: 16), let g = Int(self[3,5], radix: 16), let b = Int(self[5,nil], radix: 16) { return RGB(r, g, b) } } return nil } // MARK: - method func stringByAppendingPathComponent(path: String) -> String { let nsSt = self as NSString return nsSt.stringByAppendingPathComponent(path) } func stringByAppendingPathExtension(ext: String) -> String? { let nsSt = self as NSString return nsSt.stringByAppendingPathExtension(ext) } // Return the number of non-overlapping occurrences of substring sub in string S[start:end] func count(subString: String) -> Int { var n = 0 if let r = self.rangeOfString(subString) { n += 1 + self.substringFromIndex(r.endIndex).count(subString) } return n } func has(subString: String) -> Bool { if self.rangeOfString(subString) != nil { return true } return false } func hasAny(strArr: Array) -> Bool { let r = strArr.filter() { self.has($0) } return !r.isEmpty } // Remove the last character and return it mutating func pop() -> Character { return self.removeAtIndex(self.endIndex.predecessor()) } // Return the lowest index in S where substring sub is found func find(subString: String) -> Int { if let r = self.rangeOfString(subString) { return Int(String(r.startIndex))! } else { return -1 } } // Return a string which is the concatenation of the strings in the iterable. func join(arr: Array) -> String { var str = "" for i in arr { str += String(i) + self } str.pop() return str } func split(separator: String = " ") -> [String] { return self.componentsSeparatedByString(separator) } func replace(before: String, _ after: String) -> String { return self.stringByReplacingOccurrencesOfString(before, withString: after) } // Return a copy of the string S with leading and trailing whitespace removed func strip(char: Character = " ") -> String { return String(self.characters.filter() { $0 != char } ) } func trim() -> String { return self.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()) } func trim(charSet charSet: NSCharacterSet) -> String { return self.stringByTrimmingCharactersInSet(charSet) } func urlencode() -> String { return self.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())! } // String indices subscript(index: Int) -> Character { if index >= 0 { return self[self.startIndex.advancedBy(index)] } else { return self[self.endIndex.advancedBy(index)] } } subscript(m: Int?, n: Int?) -> String { var i1: Index, i2: Index if m != nil { i1 = self.startIndex.advancedBy(m!) } else { i1 = self.startIndex } if n != nil { if n >= 0 { i2 = self.startIndex.advancedBy(n!) } else { i2 = self.endIndex.advancedBy(n!) } } else { i2 = self.endIndex } let indexRange = Range(i1..) -> String { return self[range.startIndex, range.endIndex] } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIApplication.swift ================================================ // // UIApplication.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UIApplication extension UIApplication { class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return topViewController(selected) } } if let presented = base?.presentedViewController { return topViewController(presented) } return base } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIColor.swift ================================================ // // UIColor.swift // Sublime // // Created by Eular on 5/4/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation extension UIColor{ func toImage() -> UIImage { let rect = CGRectMake(0, 0, 1, 1) UIGraphicsBeginImageContextWithOptions(rect.size, true, 0) self.setFill() UIRectFill(rect) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIImage.swift ================================================ // // UIImage.swift // Sublime // // Created by Eular on 5/8/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation extension UIImage { func rescaleImageToSize(width: CGFloat, _ height: CGFloat) -> UIImage { let rect = CGRectMake(0, 0, width, height) UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale) self.drawInRect(rect) let resImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return resImage } func rescaleImageByWidth(width: CGFloat) -> UIImage { let height = width / self.size.width * self.size.height return self.rescaleImageToSize(width, height) } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIImageView.swift ================================================ // // UIImageView.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UIImageView extension UIImageView { // --------------------------------- // MARK: - 长按识别二维码 var recognizeQRCodeEnabled: Bool { get { return self.userInteractionEnabled } set { self.userInteractionEnabled = newValue let longPress = UILongPressGestureRecognizer(target: self, action: #selector(self._handleLongPress(_:))) if newValue { self.addGestureRecognizer(longPress) } else { self.removeGestureRecognizer(longPress) } } } override public func canBecomeFirstResponder() -> Bool { return true } override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { if action == #selector(self.recognizeQrcode) { return true } return super.canPerformAction(action, withSender: sender) } @objc private func _handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { guard let img = self.image else { return } if QRCode().hasQRCode(img) { self.becomeFirstResponder() let qrcodeItem = UIMenuItem(title: NSLocalizedString("RECOGNIZE_QRCODE", comment: "Recognize QRCode"), action: #selector(self.recognizeQrcode)) let menu = UIMenuController.sharedMenuController() menu.menuItems = [qrcodeItem] menu.setTargetRect(self.bounds, inView: self) menu.setMenuVisible(true, animated: true) } } } func recognizeQrcode() { guard let img = self.image else { return } guard let topController = UIApplication.topViewController() else { return } let str = QRCode().read(img)! if let url = NSURL(string: str) { let backItem = UIBarButtonItem() backItem.title = "back" topController.navigationItem.backBarButtonItem = backItem let svc = SublimeSafari(URL: url) topController.navigationController?.pushViewController(svc, animated: true) } else { topController.view.Toast(message: str) } } // --------------------------------- // 请求网络图片并简单缓存 public func imageFromUrl(urlString: String) { if !urlString.isEmpty { let fileMgr = NSFileManager.defaultManager() let filePath = Constant.CachePath + urlString.md5 + ".png" if fileMgr.fileExistsAtPath(filePath) { let imgData = fileMgr.contentsAtPath(filePath) self.image = UIImage(data: imgData!) } else { if Network.isConnectedToNetwork() { if let url = NSURL(string: urlString) { let request = NSURLRequest(URL: url) let session = NSURLSession.sharedSession() let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in guard let d = data else { return } let img = UIImage(data: d) let imgData = UIImagePNGRepresentation(img!) imgData?.writeToFile(filePath, atomically: true) dispatch_async(dispatch_get_main_queue()) { self.image = img } }) task.resume() } } } } } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UITableView.swift ================================================ // // UITableView.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UITableView extension UITableView { func scrollToBottomAnimated(animated: Bool) { let row = numberOfRowsInSection(0) - 1 if row >= 0 { let indexPath = NSIndexPath(forRow: row, inSection: 0) scrollToIndexPath(indexPath, animated: animated) } } func scrollToIndexPath(indexPath: NSIndexPath, animated: Bool) { scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated) } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UITextView.swift ================================================ // // UITextView.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UITextView extension UITextView { func scrollToBottom() { let range:NSRange = NSMakeRange(self.text.characters.count - 1, 1) self.scrollRangeToVisible(range) self.scrollEnabled = false self.scrollEnabled = true } func setLineBreakMode(mode: NSLineBreakMode) { let attrStr = self.attributedText.mutableCopy() let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = mode attrStr.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attrStr.mutableString.length)) self.attributedText = attrStr as! NSAttributedString } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIView.swift ================================================ // // UIView.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - UIView extension UIView { var x: CGFloat { get { return self.frame.origin.x } set { self.frame.origin.x = newValue } } var y: CGFloat { get { return self.frame.origin.y } set { self.frame.origin.y = newValue } } var width: CGFloat { get { return self.frame.width } set { self.frame.size.width = newValue } } var height: CGFloat { get { return self.frame.height } set { self.frame.size.height = newValue } } func atCenter(hasNavigationBar: Bool = false) { if let s = self.superview { self.center = s.center if hasNavigationBar { self.y -= 64 } } } func snapshot() -> UIImage { UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.mainScreen().scale) self.layer.renderInContext(UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } func snapshot(frame: CGRect) -> UIImage { let pt = frame.origin UIGraphicsBeginImageContextWithOptions(frame.size, false, UIScreen.mainScreen().scale) let context = UIGraphicsGetCurrentContext() CGContextConcatCTM(context, CGAffineTransformMakeTranslation(-pt.x, -pt.y)) // Dirty fix: force update layer self.snapshotViewAfterScreenUpdates(true) // Is there someone who help me to can fix this problem, T_T... self.layer.renderInContext(context!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } func Toast(message msg: String, hasNavigationBar: Bool = false) { let toast = UILabel() let h: CGFloat = 30 toast.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.8) toast.text = msg toast.textColor = UIColor.whiteColor() toast.textAlignment = .Center toast.font = toast.font.fontWithSize(12) toast.alpha = 0 toast.frame = CGRectMake(0, 0, toast.intrinsicContentSize().width + 10, h) addSubview(toast) bringSubviewToFront(toast) toast.atCenter(hasNavigationBar) UIView.animateWithDuration(0.5, animations: { toast.alpha = 1 }) { (_) -> Void in UIView.animateWithDuration(4, animations: { toast.alpha = 0 }, completion: { (_) -> Void in toast.removeFromSuperview() }) } } class func loadFromNibNamed(nibNamed: String, bundle : NSBundle? = nil) -> UIView? { return UINib( nibName: nibNamed, bundle: bundle ).instantiateWithOwner(nil, options: nil)[0] as? UIView } func autoLayout(top top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) { self.translatesAutoresizingMaskIntoConstraints = false superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: superview, attribute: .Top, multiplier: 1, constant: top)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Left, relatedBy: .Equal, toItem: superview, attribute: .Left, multiplier: 1, constant: left)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: superview, attribute: .Bottom, multiplier: 1, constant: bottom)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Right, relatedBy: .Equal, toItem: superview, attribute: .Right, multiplier: 1, constant: right)) } func autoLayout(top top: CGFloat, left: CGFloat) { self.translatesAutoresizingMaskIntoConstraints = false superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: superview, attribute: .Top, multiplier: 1, constant: top)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Left, relatedBy: .Equal, toItem: superview, attribute: .Left, multiplier: 1, constant: left)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.width)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.height)) } func autoLayout(left left: CGFloat, bottom: CGFloat) { self.translatesAutoresizingMaskIntoConstraints = false superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Left, relatedBy: .Equal, toItem: superview, attribute: .Left, multiplier: 1, constant: left)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: superview, attribute: .Bottom, multiplier: 1, constant: bottom)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.width)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.height)) } func autoLayout(right right: CGFloat, bottom: CGFloat) { self.translatesAutoresizingMaskIntoConstraints = false superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Right, relatedBy: .Equal, toItem: superview, attribute: .Right, multiplier: 1, constant: right)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: superview, attribute: .Bottom, multiplier: 1, constant: bottom)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.width)) superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.height)) } } ================================================ FILE: Sublime/Sublime/Utils/Extension/UIViewController.swift ================================================ // // UIViewController.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - Loading extension UIViewController { func startLoading(text: String) { let backView = UIView() backView.frame = CGRectMake((view.width - 100) / 2, (view.height - 100) / 2, 100, 100) backView.backgroundColor = RGB(0, 0, 0) backView.alpha = 0.8 backView.layer.cornerRadius = 10 backView.tag = 10086 let activityIndicator = UIActivityIndicatorView() activityIndicator.frame = CGRectMake(25, 15, 50, 50) activityIndicator.activityIndicatorViewStyle = .WhiteLarge activityIndicator.hidesWhenStopped = true let lb = UILabel() lb.frame = CGRectMake(0, 72, 100, 20) lb.font = lb.font.fontWithSize(12) lb.text = text lb.textAlignment = .Center lb.textColor = UIColor.whiteColor() backView.addSubview(lb) backView.addSubview(activityIndicator) view.addSubview(backView) activityIndicator.startAnimating() } func stopLoading() { if let v = view.viewWithTag(10086) { v.removeFromSuperview() } } } ================================================ FILE: Sublime/Sublime/Utils/File.swift ================================================ // // File.swift // Sublime // // Created by Eular on 2/18/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Foundation import Photos import SSZipArchive enum FileType { case Regular, Directory, SymbolicLink, Socket, CharacterSpecial, BlockSpecial, Unknown } // MARK: - File Class class File { var name = "" var ext = "" var path = "" var url: NSURL var isDir: Bool = false var type: FileType = .Unknown var size: Int = 0 var img: String { get { if isDir { return "folder" } else if isExistImageResource("file_\(ext)") { return "file_\(ext)" } else { return "file_unknown" } } } var isImg: Bool { return (["jpg", "png", "gif"] as NSArray).containsObject(ext) } var isAudio: Bool { return (["mp3"] as NSArray).containsObject(ext) } var isVideo: Bool { return (["mp4", "rmvb", "avi", "flv", "mov"] as NSArray).containsObject(ext) } var data: NSData? { get { return NSData(contentsOfFile: path) } } var codeLang: String { let codeLangs = [ "swift": "swift", "m": "objective-c", "h": "objective-c", "c": "c", "py": "python", "cpp": "cpp", "css": "css", "js": "javascript", "html": "html", "htm": "html", "xml": "xml", "jsp": "jsp", // "m": "matlab", "sh": "shell", "f90": "fortran", "java": "java", "md": "markdown", "asm": "asm", "bat": "bat", "scala": "scala", "tex": "latex", "pl": "perl", "cs": "c-sharp", "php": "php", "json": "json", "yml": "yml", ] return codeLangs[ext] ?? "txt" } let readable: Bool let writeable: Bool let executable: Bool let deleteable: Bool private let filemgr = NSFileManager.defaultManager() init(path: String) { self.path = path self.name = path.lastPathComponent self.ext = name.pathExtension self.url = NSURL(fileURLWithPath: path) self.readable = filemgr.isReadableFileAtPath(path) self.writeable = filemgr.isWritableFileAtPath(path) self.executable = filemgr.isExecutableFileAtPath(path) self.deleteable = filemgr.isDeletableFileAtPath(path) do { let attribs = try filemgr.attributesOfItemAtPath(path) let filetype = attribs["NSFileType"] as! String switch filetype { case "NSFileTypeDirectory": self.type = .Directory self.isDir = true case "NSFileTypeRegular": self.type = .Regular case "NSFileTypeSymbolicLink": self.type = .SymbolicLink case "NSFileTypeSocket": self.type = .Socket case "NSFileTypeCharacterSpecial": self.type = .CharacterSpecial case "NSFileTypeBlockSpecial": self.type = .BlockSpecial default: self.type = .Unknown } self.size = attribs["NSFileSize"] as! Int } catch {} } func delete() -> Bool { do { try filemgr.removeItemAtPath(path) return true } catch { return false } } func read() -> String { if let data = filemgr.contentsAtPath(path) { return String(data: data, encoding: NSUTF8StringEncoding) ?? "" } return "" } func readlines() -> [String] { return (self.read() ?? "").split("\n") } func write(str: String) -> Bool { do { try str.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding) return true } catch { return false } } func write(data: NSData) -> Bool { return data.writeToFile(path, atomically: true) } func append(str: String) -> Bool { if let handler = NSFileHandle(forUpdatingAtPath: path), let data = str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) { handler.seekToEndOfFile() handler.writeData(data) return true } return false } func insert(str: String, offset: UInt64) -> Bool { if let handler = NSFileHandle(forUpdatingAtPath: path), let data = str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) { handler.seekToFileOffset(offset) let data2 = handler.readDataToEndOfFile() handler.seekToFileOffset(offset) handler.writeData(data) handler.writeData(data2) return true } return false } func copy(dest: String) -> Bool { do { try filemgr.copyItemAtPath(path, toPath: dest) return true } catch { return false } } func move(dest: String) -> Bool { do { try filemgr.moveItemAtPath(path, toPath: dest) return true } catch { return false } } func unzip(destPath: String = "", keepFile: Bool = true) { if ext == "zip" { if destPath.isEmpty { SSZipArchive.unzipFileAtPath(path, toDestination: path.stringByDeletingLastPathComponent) } else { SSZipArchive.unzipFileAtPath(path, toDestination: destPath) } if !keepFile { self.delete() } } else { Log("Not zip file") } } static func exist(path: String) -> Bool { return NSFileManager.defaultManager().fileExistsAtPath(path) } } // MARK: - Folder Class class Folder: File { override init(path: String) { if !File.exist(path) { let upper = Folder(path: path.stringByDeletingLastPathComponent) upper.newFolder(path.lastPathComponent) } super.init(path: path) } func checkFileExist(name: String) -> Bool { return filemgr.fileExistsAtPath(path.stringByAppendingPathComponent(name)) } func newFile(name: String) -> Bool { return filemgr.createFileAtPath(path.stringByAppendingPathComponent(name), contents: nil, attributes: nil) } func newFolder(name: String) -> Bool { do { try filemgr.createDirectoryAtPath(path.stringByAppendingPathComponent(name), withIntermediateDirectories: true, attributes: nil) return true } catch { return false } } func listFiles() -> [File] { var fileList = [File]() do { let files = try filemgr.contentsOfDirectoryAtPath(path) for file in files { let p = path.stringByAppendingPathComponent(file) var f = File(path: p) if f.isDir {f = Folder(path: p)} fileList.append(f) } } catch {} return fileList } func saveImage(image: UIImage, name: String, url: NSURL?) { let imgext = name.pathExtension switch imgext { case "png": if let data = UIImagePNGRepresentation(image) { data.writeToFile(path.stringByAppendingPathComponent(name), atomically: true) } case "jpg": if let data = UIImageJPEGRepresentation(image, 1) { data.writeToFile(path.stringByAppendingPathComponent(name), atomically: true) } case "gif": let imgMgr = PHImageManager() let asset = PHAsset.fetchAssetsWithALAssetURLs([url!], options: nil)[0] as! PHAsset imgMgr.requestImageDataForAsset(asset, options: nil) { (data, _, _, _) -> Void in data?.writeToFile(self.path.stringByAppendingPathComponent(name), atomically: true) } default: return } } func zip(destPath: String = "") -> File { var zipPath: String if destPath.isEmpty { zipPath = path.stringByDeletingPathExtension.stringByAppendingPathExtension("zip")! } else { zipPath = destPath } SSZipArchive.createZipFileAtPath(zipPath, withContentsOfDirectory: path) return File(path: zipPath) } } ================================================ FILE: Sublime/Sublime/Utils/Function.swift ================================================ // // Function.swift // Sublime // // Created by Eular on 2/18/16. // Copyright © 2016 Eular. All rights reserved. // import Alamofire import Foundation import AASquaresLoading // MARK: - Functions func len(any: AnyObject) -> Int { if any.isKindOfClass(NSString) { let str = any as! String return str.count } return any.count } func range(n: Int) -> Array { return Array(0.. Array { if d == 1 { return Array(m.. UInt32? { guard a < b else { return nil } return arc4random_uniform(b - a) + a } func random(n: UInt32) -> UInt32 { return arc4random_uniform(n) } func random(a: UInt32, _ b: UInt32, arrLen: Int) -> Array { guard a < b else { return [] } var arr = [UInt32]() for _ in range(arrLen) { arr.append(random(a, b)!) } return arr } func isExistImageResource(name: String) -> Bool { if UIImage(named: name) != nil { return true } //if NSBundle.mainBundle().pathForResource(name, ofType: "png") != nil { // return true //} return false } func RGB(r: Int, _ g: Int, _ b: Int) -> UIColor { return UIColor(red: CGFloat(r) / 256, green: CGFloat(g) / 256, blue: CGFloat(b) / 256, alpha: 1) } func RGB(r: Int, _ g: Int, _ b: Int, alpha: CGFloat) -> UIColor { return UIColor(red: CGFloat(r) / 256, green: CGFloat(g) / 256, blue: CGFloat(b) / 256, alpha: alpha) } // MARK: - Ghostbin func getGhostbinUrl(lang: String, text: String, target: UIViewController, complete: (url: String) -> Void ){ let key = "ghostbin-\(text.md5)" if let ghostbinUrl = Global.Database.stringForKey(key) { complete(url: ghostbinUrl) } else { if Network.isConnectedToNetwork() { let loadingSquare = AASquaresLoading(target: target.view, size: 40) loadingSquare.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5) loadingSquare.color = UIColor.whiteColor() loadingSquare.start() let url = "https://ghostbin.com/paste/new" let paras = [ "lang": lang, "text": text ] Alamofire.request(.POST, url, parameters: paras).response { request, response, data, error in if let url = response?.URL{ loadingSquare.stop() Global.Database.setValue(url, forKey: key) complete(url: url.URLString) } } } else { target.view.Toast(message: "No Network") } } } func timestamp() -> Int { return Int(NSDate().timeIntervalSince1970) } ================================================ FILE: Sublime/Sublime/Utils/Github.swift ================================================ // // Github.swift // Sublime // // Created by Eular on 2/24/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Foundation import SafariServices import Alamofire import SwiftyJSON class GitHubAPIManager { private let clientID = Constant.githubClientID private let clientSecret = Constant.githubClientSecret private var OAuthToken: String! private var safariVC: SFSafariViewController? static let sharedInstance = GitHubAPIManager() static let GetOAuthCodeNotifi = "GetOAuthCodeNotifi" static let GetUserInfoDoneNotifi = "GetUserInfoDoneNotifi" static var isLogin: Bool { set { Global.Database.setBool(newValue, forKey: "github-islogin") } get { return Global.Database.boolForKey("github-islogin") } } let githubFolder: Folder! var user: JSON! var delegate: UIViewController? { didSet { self.addObserver(delegate!) } } init() { githubFolder = Folder(path: Constant.SublimeRoot+"/home/sublime/github") if !githubFolder.checkFileExist("stars") { githubFolder.newFolder("stars") } if !githubFolder.checkFileExist("repositories") { githubFolder.newFolder("repositories") } if GitHubAPIManager.isLogin { OAuthToken = Global.Database.stringForKey("github-oauthtoken") if let data = Global.Database.objectForKey("github-user") as? NSData { user = JSON(data: data) } } else { OAuthToken = "" user = JSON("") } } func OAuth2() { let OAuthURL = "https://github.com/login/oauth/authorize?scope=user,repo,gist&client_id=\(clientID)" safariVC = SFSafariViewController(URL: NSURL(string: OAuthURL)!) safariVC!.modalPresentationStyle = .OverCurrentContext delegate!.presentViewController(safariVC!, animated: true, completion: nil) } func handleOAuthCode(notification: NSNotification) { safariVC!.dismissViewControllerAnimated(true, completion: nil) let info = notification.userInfo as! Dictionary let code = info["code"] as! String getOAuthToken(code) } private func getOAuthToken(code: String) { let TokenURL = "https://github.com/login/oauth/access_token" let params = ["client_id": clientID, "client_secret": clientSecret, "code": code] Alamofire.request(.POST, TokenURL, parameters: params).responseString { response in if let str = response.result.value { self.OAuthToken = str.split("&")[0].split("=")[1] Global.Database.setValue(self.OAuthToken, forKey: "github-oauthtoken") self.getUserInfo() } } } func getUserInfo() { let url = "https://api.github.com/user" let params = ["access_token": OAuthToken] Alamofire.request(.GET, url, parameters: params).responseJSON { response in if let data = response.result.value { self.user = JSON(data) Global.Database.setObject(try! self.user.rawData(), forKey: "github-user") GitHubAPIManager.isLogin = true Global.Notifi.postNotificationName(GitHubAPIManager.GetUserInfoDoneNotifi, object: nil) } } } func listRepositories(completion: (repos: [Repo]) -> Void) { let url = "https://api.github.com/user/repos" let params = ["access_token": OAuthToken, "sort": "pushed"] Alamofire.request(.GET, url, parameters: params).responseJSON { response in if let data = response.result.value { var repos = [Repo]() for (_, r) in JSON(data) { repos.append(Repo(json: r)) } completion(repos: repos) } } } func listStarred(completion: (repos: [Repo]) -> Void) { let url = "https://api.github.com/user/starred" let params = ["access_token": OAuthToken] Alamofire.request(.GET, url, parameters: params).responseJSON { response in if let data = response.result.value { var repos = [Repo]() for (_, r) in JSON(data) { repos.append(Repo(json: r)) } completion(repos: repos) } } } func logout() { GitHubAPIManager.isLogin = false Global.Database.setValue("", forKey: "github-oauthtoken") Global.Database.setValue("", forKey: "github-user") } private func addObserver(observer: UIViewController) { // ----------------- Rewrite Code Later ----------------- Global.Notifi.addObserver(observer, selector: #selector(GithubAccountTableViewController.githubOAuthCode(_:)), name: GitHubAPIManager.GetOAuthCodeNotifi, object: nil) Global.Notifi.addObserver(observer, selector: #selector(GithubAccountTableViewController.githubGetUserInfoCompleted), name: GitHubAPIManager.GetUserInfoDoneNotifi, object: nil) } static func handleURL(url: NSURL) { if url.host == "githubLogin" { Global.Notifi.postNotificationName(GitHubAPIManager.GetOAuthCodeNotifi, object: nil, userInfo: ["code": url.query!.split("=")[1]]) } } func star(owner: String, repo: String, success: (() -> Void)? = nil, fail: (() -> Void)? = nil) { let url = "https://api.github.com/user/starred/\(owner)/\(repo)" let headers = ["Authorization": "token " + OAuthToken] Alamofire.request(.PUT, url, headers: headers).response { result in let response = result.1 if let code = response?.statusCode { if code == 204 { success?() } else { fail?() } } } } func follow(user: String, success: (() -> Void)? = nil, fail: (() -> Void)? = nil) { let url = "https://api.github.com/user/following/\(user)" let headers = ["Authorization": "token " + OAuthToken] Alamofire.request(.PUT, url, headers: headers).response { result in let response = result.1 if let code = response?.statusCode { if code == 204 { success?() } else { fail?() } } } } func listGists(completion: ((gists: [Gist]) -> Void)? = nil) { let url = "https://api.github.com/gists/public" Alamofire.request(.GET, url).responseJSON { response in if let data = response.result.value { var gists = [Gist]() for (_, r) in JSON(data) { if r["owner"] != nil && r["files"] != nil { gists.append(Gist(json: r)) } } completion?(gists: gists) } } } } protocol GithubAPIManagerDelegate { // return OAuth code func githubOAuthCode(notification: NSNotification) // get user info complete func githubGetUserInfoCompleted() } ================================================ FILE: Sublime/Sublime/Utils/Log.swift ================================================ // // Log.swift // Sublime // // Created by Eular on 4/20/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation // MARK: - Log func Log(message: T, file: String = #file, function: String = #function, line: Int = #line) { // Executed only on simulator #if arch(i386) || arch(x86_64) print("\(file.lastPathComponent)[\(line)], \(function): \(message)") #endif } ================================================ FILE: Sublime/Sublime/Utils/Network.swift ================================================ // // Network.swift // Sublime // // Created by Eular on 2/29/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import SystemConfiguration struct Network { // MARK: - Get IP Address // Need: #include static func getIFAddresses() -> [String] { var addresses = [String]() // Get list of all interfaces on the local machine: var ifaddr : UnsafeMutablePointer = nil if getifaddrs(&ifaddr) == 0 { // For each interface ... var ptr = ifaddr while ptr != nil { let flags = Int32(ptr.memory.ifa_flags) var addr = ptr.memory.ifa_addr.memory // Check for running IPv4, IPv6 interfaces. Skip the loopback interface. if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) { // addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) if addr.sa_family == UInt8(AF_INET) { // Convert interface address to a human readable string: var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0) if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0) { if let address = String.fromCString(hostname) { addresses.append(address) } } } } ptr = ptr.memory.ifa_next } freeifaddrs(ifaddr) } return addresses } // MARK: - Checking the network availability static func isConnectedToNetwork() -> Bool { var zeroAddress = sockaddr_in() zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress)) zeroAddress.sin_family = sa_family_t(AF_INET) guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, { SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)) }) else { return false } var flags : SCNetworkReachabilityFlags = [] if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { return false } let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired) return (isReachable && !needsConnection) } } ================================================ FILE: Sublime/Sublime/Utils/NumberedTextView.swift ================================================ // // NumberedTextView.swift // Sublime // // Created by Eular on 5/3/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation class NumberedTextView: UITextView { init(frame: CGRect) { super.init(frame: frame, textContainer: nil) self.frame.origin.y = -7 self.frame.size.height += 7 self.backgroundColor = RGB(52, 53, 46) self.editable = false } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } let lineAttr = [NSForegroundColorAttributeName: UIColor.whiteColor()] let lineNumAttr = [ NSForegroundColorAttributeName: UIColor.grayColor(), NSBackgroundColorAttributeName: RGB(39, 40, 34) ] override var text: String! { didSet { let tmp = NSMutableAttributedString() for (i, line) in text.split("\n").enumerate() { let attrLineNum = NSMutableAttributedString(string: "\(i)\t", attributes: lineNumAttr) let attrLine = NSMutableAttributedString(string: "\(line)\n", attributes: lineAttr) tmp.appendAttributedString(attrLineNum) tmp.appendAttributedString(attrLine) } self.attributedText = tmp self.contentOffset = CGPoint(x: 0, y: 0) } } } ================================================ FILE: Sublime/Sublime/Utils/Obj-C/MusicWave.h ================================================ // // MusicWave.h // Sublime // // Created by Eular on 2/21/16. // Copyright © 2016 Eular. All rights reserved. // #import #import #import #import @interface MusicWave : UIViewController @property (nonatomic,strong) EZAudioPlayer *audioPlayer; @property (nonatomic,strong) NSURL *audioUrl; -(void) start; @end ================================================ FILE: Sublime/Sublime/Utils/Obj-C/MusicWave.m ================================================ // // MusicWave.m // Sublime // // Created by Eular on 2/21/16. // Copyright © 2016 Eular. All rights reserved. // #import "MusicWave.h" #define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f] @interface MusicWave () @property (nonatomic,strong) ZLMusicFlowWaveView *audioPlot; @end @implementation MusicWave #pragma mark - Initialization -(id)init { self = [super init]; if(self){ [self initializeViewController]; } return self; } -(id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if(self){ [self initializeViewController]; } return self; } #pragma mark - Initialize View Controller Here -(void)initializeViewController { // Create an instance of the microphone and tell it to use this view controller instance as the delegate } #pragma mark - Customize the Audio Plot -(void)viewDidLoad { [super viewDidLoad]; // 1. 设置并激活音频会话类别 AVAudioSession *session = [AVAudioSession sharedInstance]; NSError *error; [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; if (error) { NSLog(@"Error setting up audio session category: %@", error.localizedDescription); } [session setActive:YES error:&error]; if (error) { NSLog(@"Error setting up audio session active: %@", error.localizedDescription); } // 2. 允许应用程序接收远程控制 [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; // 3. 设置后台任务ID UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid; newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL]; if (![self isHeadsetPluggedIn]) { [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:NULL]; if(error){ NSLog(@"There was an error sending the audio to the speakers"); } } // set plot self.audioPlot = [[ZLMusicFlowWaveView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 64)]; self.audioPlot.backgroundColor = RGB(81, 81, 81); self.audioPlot.color = RGB(255, 255, 255); [self.view addSubview:self.audioPlot]; } - (BOOL)isHeadsetPluggedIn { AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute]; for (AVAudioSessionPortDescription* desc in [route outputs]) { if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones]) return YES; } return NO; } -(void)start { self.audioPlayer = [[EZAudioPlayer alloc] initWithURL:self.audioUrl withDelegate:self]; self.audioPlayer.shouldLoop = YES; [self.audioPlayer play]; } -(void)audioPlayer:(EZAudioPlayer *)audioPlayer readAudio:(float **)buffer withBufferSize:(UInt32)bufferSize withNumberOfChannels:(UInt32)numberOfChannels inAudioFile:(EZAudioFile *)audioFile { dispatch_async(dispatch_get_main_queue(),^{ // All the audio plot needs is the buffer data (float*) and the size. Internally the audio plot will handle all the drawing related code, history management, and freeing its own resources. Hence, one badass line of code gets you a pretty plot :) [self.audioPlot updateBuffer:buffer[0] withBufferSize:bufferSize]; }); } @end ================================================ FILE: Sublime/Sublime/Utils/Obj-C/ObjC.h ================================================ // // ObjC.h // Sublime // // Created by Eular on 5/6/16. // Copyright © 2016 Eular. All rights reserved. // #import #include #include #import #include #import #import #import @interface ObjC : NSObject +(NSString*) SSID; +(NSString*) BSSID; +(NSArray*) getAppList; +(NSDictionary*) getDataFlowBytes; @end ================================================ FILE: Sublime/Sublime/Utils/Obj-C/ObjC.m ================================================ // // ObjC.m // Sublime // // Created by Eular on 5/6/16. // Copyright © 2016 Eular. All rights reserved. // #import "ObjC.h" @implementation ObjC +(NSString*) iOS9_SSID { for(NEHotspotNetwork *hotspotNetwork in [NEHotspotHelper supportedNetworkInterfaces]) { NSString *ssid = hotspotNetwork.SSID; //NSString *bssid = hotspotNetwork.BSSID; //BOOL secure = hotspotNetwork.secure; //BOOL autoJoined = hotspotNetwork.autoJoined; //double signalStrength = hotspotNetwork.signalStrength; return ssid; } return @"No WIFI Connection"; } // http://bencoding.com/2015/08/04/captivenetwork-depreciated-in-ios9/ +(NSString*) SSID { #if TARGET_IPHONE_SIMULATOR return @"Simulator"; #else NSString * informationUnknown = @"No WIFI Connection"; CFArrayRef interfaces = CNCopySupportedInterfaces();//supportedNetworkInterfaces if(interfaces == nil){ return informationUnknown; } CFIndex count = CFArrayGetCount(interfaces); if(count == 0){ return informationUnknown; } CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0)); NSDictionary *dict = ( __bridge NSDictionary*) captiveNtwrkDict; CFRelease(interfaces); return (([dict objectForKey:@"SSID"]==nil)? informationUnknown : [dict objectForKey:@"SSID"]); #endif } +(NSString*) BSSID { #if TARGET_IPHONE_SIMULATOR return @"Simulator"; #else NSString * informationUnknown = @"unknown"; CFArrayRef interfaces = CNCopySupportedInterfaces(); if(interfaces == nil){ return informationUnknown; } CFIndex count = CFArrayGetCount(interfaces); if(count == 0){ return informationUnknown; } CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0)); NSDictionary *dict = ( __bridge NSDictionary*) captiveNtwrkDict; CFRelease(interfaces); return (([dict objectForKey:@"BSSID"]==nil)? informationUnknown : [dict objectForKey:@"BSSID"]); #endif } +(NSDictionary*) getDataFlowBytes { NSString *const DataCounterKeyWWANSent = @"WWANSent"; NSString *const DataCounterKeyWWANReceived = @"WWANReceived"; NSString *const DataCounterKeyWiFiSent = @"WiFiSent"; NSString *const DataCounterKeyWiFiReceived = @"WiFiReceived"; struct ifaddrs *addrs; const struct ifaddrs *cursor; u_int32_t WiFiSent = 0; u_int32_t WiFiReceived = 0; u_int32_t WWANSent = 0; u_int32_t WWANReceived = 0; if (getifaddrs(&addrs) == 0) { cursor = addrs; while (cursor != NULL) { if (cursor->ifa_addr->sa_family == AF_LINK) { /* const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if(ifa_data != NULL) { NSLog(@"Interface name %s: sent %tu received %tu",cursor->ifa_name,ifa_data->ifi_obytes,ifa_data->ifi_ibytes); } */ // name of interfaces: // en0 is WiFi (provides network bytes exchanges and not just internet) // lo0 is WiFi // pdp_ip0 is WWAN NSString *name = [NSString stringWithFormat:@"%s",cursor->ifa_name]; if ([name hasPrefix:@"en"]) { const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if(ifa_data != NULL) { WiFiSent += ifa_data->ifi_obytes; WiFiReceived += ifa_data->ifi_ibytes; } } if ([name hasPrefix:@"pdp_ip"]) { const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if(ifa_data != NULL) { WWANSent += ifa_data->ifi_obytes; WWANReceived += ifa_data->ifi_ibytes; } } } cursor = cursor->ifa_next; } freeifaddrs(addrs); } return @{DataCounterKeyWiFiSent:[NSNumber numberWithUnsignedInt:WiFiSent], DataCounterKeyWiFiReceived:[NSNumber numberWithUnsignedInt:WiFiReceived], DataCounterKeyWWANSent:[NSNumber numberWithUnsignedInt:WWANSent], DataCounterKeyWWANReceived:[NSNumber numberWithUnsignedInt:WWANReceived]}; } + (NSArray*) getAppList { Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace"); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" NSObject* workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)]; NSArray* app = [workspace performSelector:@selector(allApplications)]; #pragma clang diagnostic pop // NSLog(@"apps: %@", app); return app; } @end ================================================ FILE: Sublime/Sublime/Utils/Plist.swift ================================================ // // Plist.swift // Sublime // // Created by Eular on 3/31/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation struct Plist { enum PlistError: ErrorType { case FileNotWritten case FileDoesNotExist } let name: String let path: String init(path: String) { self.path = path self.name = path.lastPathComponent if !NSFileManager.defaultManager().fileExistsAtPath(path) { let f = Folder(path: path.stringByDeletingLastPathComponent) f.newFile(name) } } func getDictInPlistFile() -> NSDictionary? { guard let dict = NSDictionary(contentsOfFile: path) else { return .None } return dict } func getMutableDictInPlistFile() -> NSMutableDictionary? { guard let dict = NSMutableDictionary(contentsOfFile: path) else { return .None } return dict } func getArrayInPlistFile() -> NSArray? { guard let arr = NSArray(contentsOfFile: path) else { return .None } return arr } func getMutableArrayInPlistFile() -> NSMutableArray? { guard let arr = NSMutableArray(contentsOfFile: path) else { return .None } return arr } func saveToPlistFile(any: AnyObject) throws { if !any.writeToFile(path, atomically: false) { throw PlistError.FileNotWritten } } func appendToPlistFile(any: AnyObject) throws { if let arr = getMutableArrayInPlistFile() { arr.addObject(any) if !arr.writeToFile(path, atomically: false) { throw PlistError.FileNotWritten } } else { if !NSArray(array: [any]).writeToFile(path, atomically: false) { throw PlistError.FileNotWritten } } } } ================================================ FILE: Sublime/Sublime/Utils/PopupMenu.swift ================================================ // // PopupMenu.swift // Sublime // // Created by Eular on 5/3/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation protocol PopupMenuDelegate { func tapOnPopupMenuItem(itemIndex i: Int) } class PopupMenu { var delegate: PopupMenuDelegate? var controller: UIViewController? var itemsToShare: [AnyObject] = [] var items: [[String:String]] = [] private var menu: UIView? private var mask: UIView? private let defaultItem = ["title":"更多", "image":"Share_more_icon"] private let itemNumInRow: Int private let menuColor = Constant.PopupMenuColor private let maskColor = Constant.BlackMaskViewColor init(itemNumInRow: Int = 4) { self.itemNumInRow = itemNumInRow self.items = [ ["title":"QQ", "image":"Share_qq_icon"], ["title":"新浪微博", "image":"Share_sina_icon"], ["title":"微信", "image":"Share_wechat_session_icon"], ["title":"朋友圈", "image":"Share_wechat_timeline_icon"], ["title":"Facebook", "image":"Share_facebook_icon"], ["title":"Line", "image":"Share_line_icon"], ["title":"Instagram", "image":"Share_instagram"], ["title":"Twitter", "image":"Share_twitter_icon"], ["title":"QQ空间", "image":"Share_qzone_icon"], ["title":"Pinterest", "image":"Share_pinterest_icon"], ["title":"豆瓣", "image":"Share_douban_icon"] ] } @objc func showUp() { let window = controller?.view.window let width = window?.width ?? 0 let hight = window?.height ?? 0 var menuItems = items menuItems << defaultItem let rowNum = (menuItems.count - 1) / itemNumInRow + 1 let itemWidth = width / itemNumInRow let rowHight = itemWidth let menuHight = rowHight * rowNum let popupMenu = UIView() popupMenu.backgroundColor = menuColor popupMenu.frame = CGRectMake(0, hight, width, menuHight) // Insert item label into menu for (i, item) in menuItems.enumerate() { let btn = UIButton() btn.frame = CGRectMake(itemWidth * (i % itemNumInRow), rowHight * (i / itemNumInRow), itemWidth, rowHight) btn.setImage(UIImage(named: item["image"] ?? defaultItem["image"]!), forState: .Normal) btn.tag = i btn.addTarget(self, action: #selector(tapOnPopupMenuItem(_:)), forControlEvents: .TouchUpInside) popupMenu.addSubview(btn) } // Black the below view let blackMaskView = UIView(frame: window?.frame ?? CGRectZero) blackMaskView.backgroundColor = maskColor blackMaskView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapOnBlackMaskView))) window?.addSubview(blackMaskView) window?.addSubview(popupMenu) self.menu = popupMenu self.mask = blackMaskView UIView.animateWithDuration(0.3) { () -> Void in popupMenu.y -= menuHight } } @objc private func tapOnBlackMaskView() { dismissPopupMenu() } @objc private func tapOnPopupMenuItem(btn: UIButton) { dismissPopupMenu { if btn.tag == self.items.count { let activityVC = UIActivityViewController(activityItems: self.itemsToShare, applicationActivities: nil) self.controller?.presentViewController(activityVC, animated: true, completion: nil) } else { self.delegate?.tapOnPopupMenuItem(itemIndex: btn.tag) } } } private func dismissPopupMenu(completion: (() -> Void)? = nil) { if let popupMenu = self.menu, blackMaskView = self.mask { UIView.animateWithDuration(0.3, animations: { () -> Void in popupMenu.y += popupMenu.height }, completion: { (_) -> Void in popupMenu.removeFromSuperview() blackMaskView.removeFromSuperview() completion?() }) } } } ================================================ FILE: Sublime/Sublime/Utils/QRCode.swift ================================================ // // QRCode.swift // Sublime // // Created by Eular on 4/1/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import CoreGraphics class QRCode { func make(str: String, size: CGFloat = 250) -> UIImage { let qrcode = createNonInterpolatedUIImageFormCIImage(createQRForString(str), withSize: size) return qrcode } func makeWithColor(str: String, size: CGFloat = 250, R: CGFloat = 60, G: CGFloat = 74, B: CGFloat = 89) -> UIImage { let qrcode = createNonInterpolatedUIImageFormCIImage(createQRForString(str), withSize: size) let customQrcode = imageBlackToTransparent(qrcode, red: R, green: G, blue: B) return customQrcode } func hasQRCode(img: UIImage) -> Bool { let ciImg = CIImage(image: img) let context = CIContext(options: nil) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) let features = detector.featuresInImage(ciImg!) return features.count != 0 } func read(img: UIImage) -> String? { let ciImg = CIImage(image: img) let context = CIContext(options: nil) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) let features = detector.featuresInImage(ciImg!) if features.count != 0 { return (features[0] as! CIQRCodeFeature).messageString } else { return nil } } private func createQRForString(QRStr: String) -> CIImage { // Need to convert the string to a UTF-8 encoded NSData object let strData = QRStr.dataUsingEncoding(NSUTF8StringEncoding) // Create the filter let qrFilter = CIFilter(name: "CIQRCodeGenerator")! // Set the message content and error-correction level qrFilter.setValue(strData, forKey: "inputMessage") qrFilter.setValue("M", forKey: "inputCorrectionLevel") // Send the image back return qrFilter.outputImage! } private func createNonInterpolatedUIImageFormCIImage(image: CIImage, withSize size: CGFloat) -> UIImage { let extent = CGRectIntegral(image.extent) let scale = min(size / extent.width, size / extent.height) // create a bitmap image that we'll draw into a bitmap context at the desired size; let width = extent.width * scale let height = extent.height * scale let cs = CGColorSpaceCreateDeviceGray() let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, cs, CGImageAlphaInfo.None.rawValue) let context = CIContext(options: nil) let bitmapImage = context.createCGImage(image, fromRect: extent) CGContextSetInterpolationQuality(bitmapRef, .None) CGContextScaleCTM(bitmapRef, scale, scale) CGContextDrawImage(bitmapRef, extent, bitmapImage) // Create an image with the contents of our bitmap let scaledImage = CGBitmapContextCreateImage(bitmapRef) // Cleanup // CGContext instances are automatically memory managed in Swift return UIImage(CGImage: scaledImage!) } private func imageBlackToTransparent(image: UIImage, red: CGFloat, green: CGFloat, blue: CGFloat) -> UIImage { let imageWidth = Int(image.size.width) let imageHeight = Int(image.size.height) let bytesPerRow = imageWidth * 4 let rgbImageBuf = UnsafeMutablePointer.alloc(imageWidth * imageHeight) // create context let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.NoneSkipLast.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue) let context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace, bitmapInfo.rawValue) CGContextDrawImage(context, CGRect(origin: CGPointZero, size: image.size), image.CGImage) // traverse pixe let pixelNum = imageWidth * imageHeight; var pCurPtr = UnsafeMutablePointer(rgbImageBuf) var i = 0 while i < pixelNum { if ((pCurPtr.memory & 0xFFFFFF00) < 0x99999900){ // change color let ptr = (UnsafeMutablePointer)(pCurPtr) ptr[3] = UInt8(red) ptr[2] = UInt8(green) ptr[1] = UInt8(blue) }else{ let ptr = UnsafeMutablePointer(pCurPtr) ptr[0] = 0; } i += 1 pCurPtr += 1 } let dataProvider = CGDataProviderCreateWithData(nil, rgbImageBuf, bytesPerRow * imageHeight, nil) let imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace, bitmapInfo, dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault) let resultImage = UIImage(CGImage: imageRef!) return resultImage } } ================================================ FILE: Sublime/Sublime/Utils/QRCodeReader.swift ================================================ // // QRCodeReader.swift // Sublime // // Created by Eular on 5/4/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import AVFoundation import AudioToolbox class QRCodeReaderViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { var captureSession: AVCaptureSession? var videoPreviewLayer: AVCaptureVideoPreviewLayer? var qrCodeFrameView: UIView? let messageLabel = UILabel() var isQRCodeRecognized: Bool = false override func viewDidLoad() { super.viewDidLoad() title = "QRCode" let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) let input: AVCaptureInput do { input = try AVCaptureDeviceInput(device: captureDevice) } catch { return } captureSession = AVCaptureSession() captureSession?.addInput(input) // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session let captureMetadataOutput = AVCaptureMetadataOutput() captureSession?.addOutput(captureMetadataOutput) // Set delegate and use the default dispatch queue to execute the call back captureMetadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill videoPreviewLayer?.frame = view.layer.bounds view.layer.addSublayer(videoPreviewLayer!) // Initialize QR Code Frame to highlight the QR code qrCodeFrameView = UIView() qrCodeFrameView?.frame = CGRectMake(0, 0, 230, 230) qrCodeFrameView?.center = view.center qrCodeFrameView?.y -= Constant.NavigationBarOffset qrCodeFrameView?.layer.borderColor = UIColor.whiteColor().CGColor qrCodeFrameView?.layer.borderWidth = 1 view.addSubview(qrCodeFrameView!) view.bringSubviewToFront(qrCodeFrameView!) // Initialize qrcode result label messageLabel.frame = CGRectMake(0, view.height - Constant.NavigationBarOffset - 40, view.width, 40) messageLabel.backgroundColor = Constant.BlackMaskViewColor messageLabel.textColor = UIColor.whiteColor() messageLabel.textAlignment = .Center messageLabel.font = UIFont.systemFontOfSize(15) messageLabel.numberOfLines = 2 messageLabel.text = "No QR code is detected" view.addSubview(messageLabel) // Start video capture. captureSession?.startRunning() } override func viewWillAppear(animated: Bool) { isQRCodeRecognized = false } func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { if !isQRCodeRecognized { // Check if the metadataObjects array is not nil and it contains at least one object. if metadataObjects == nil || metadataObjects.count == 0 { messageLabel.text = "No QR code is detected" return } // Get the metadata object. let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if metadataObj.type == AVMetadataObjectTypeQRCode { // If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds /* let barCodeObject = videoPreviewLayer?.transformedMetadataObjectForMetadataObject(metadataObj) as! AVMetadataMachineReadableCodeObject qrCodeFrameView?.frame = barCodeObject.bounds */ if let qrStr = metadataObj.stringValue { isQRCodeRecognized = true messageLabel.text = qrStr var mySound: SystemSoundID = 0 if let url = NSBundle.mainBundle().URLForResource("qrcode_scan", withExtension: "wav") { AudioServicesCreateSystemSoundID(url, &mySound) AudioServicesPlaySystemSound(mySound) } if let url = NSURL(string: qrStr) { let svc = SublimeSafari(URL: url) navigationController?.pushViewController(svc, animated: true) } } } } } } ================================================ FILE: Sublime/Sublime/Utils/RCIM.swift ================================================ // // RCIM.swift // Sublime // // Created by Eular on 3/23/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation import Alamofire // RongCloud extension RCIM { func Login() { if let token = Global.Database.stringForKey("RongCloud-UserToken") { let user = GitHubAPIManager.sharedInstance.user let name = user["name"].string let portrait = user["avatar_url"].string RCIM.sharedRCIM().connectWithToken(token, success: { (userId) -> Void in Log("登陆成功。当前登录的用户ID:\(userId)") RCIM.sharedRCIM().currentUserInfo = RCUserInfo.init(userId: userId, name: name ?? userId, portrait: portrait ?? Constant.RongCloudDefaultUserPortrait) }, error: { (status) -> Void in Log("登陆的错误码为: \(status.rawValue)") }, tokenIncorrect: { Log("token错误") self.getTokenAndLogin() }) } else { Log("用户token不存在") } } private func makeHeaders() -> [String: String] { let appkey = Constant.RongCloudAppKey let appSecret = Constant.RongCloudAppSecret let nonce = String(random()) let ts = String(timestamp()) let signature = (appSecret + nonce + ts).sha1 let headers = ["App-Key": appkey, "Nonce": nonce, "Timestamp": ts, "Signature": signature] return headers } func getToken(id: String, name: String, portrait: String, complete: () -> ()) { let url = "https://api.cn.rong.io/user/getToken.json" let params = ["userId": id, "name": name, "portraitUri": portrait] let headers = makeHeaders() Alamofire.request(.POST, url, parameters: params, headers: headers).responseJSON { response in if let data = response.result.value { if let token = data.stringForKey("token") { Log("获取Token成功: \(token)") Global.Database.setValue(token, forKey: "RongCloud-UserToken") complete() } } } } func getInfo(id: String, complete: (String, String) -> ()) { if let info = Global.Database.objectForKey("RongCloud-User-\(id)") { let name = info.stringForKey("name")! let portrait = info.stringForKey("portrait")! complete(name, portrait) return } let url = "https://api.cn.rong.io/user/info.json" let params = ["userId": id] let headers = makeHeaders() Alamofire.request(.POST, url, parameters: params, headers: headers).responseJSON { response in if let data = response.result.value { Log("获取用户信息成功: \(data)") let name = data.stringForKey("userName") ?? id let portrait = data.stringForKey("userPortrait") ?? Constant.RongCloudDefaultUserPortrait Global.Database.setObject(["name": name, "portrait": portrait], forKey: "RongCloud-User-\(id)") complete(name, portrait) } } } func getTokenAndLogin() { let user = GitHubAPIManager.sharedInstance.user let id = user["login"].string! let name = user["name"].string ?? id let portrait = user["avatar_url"].string ?? Constant.RongCloudDefaultUserPortrait getToken(id, name: name, portrait: portrait, complete: Login) } } ================================================ FILE: Sublime/Sublime/Utils/RearrangeTable.swift ================================================ // // RearrangeTable.swift // Sublime // // Created by Eular on 5/3/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation protocol RearrangeTableViewDelegate { func rearrangeTableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) // override func rearrangeTableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { // let temp = fileList[toIndexPath.row] // fileList[toIndexPath.row] = fileList[fromIndexPath.row] // fileList[fromIndexPath.row] = temp // tableView.moveRowAtIndexPath(fromIndexPath, toIndexPath: toIndexPath) // } } class RearrangeTableViewController: UITableViewController { private var sourceIndexPath: NSIndexPath? private var snapView: UIView? var delegate: RearrangeTableViewDelegate? override func viewDidLoad() { super.viewDidLoad() tableView.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongPress(_:)))) } private func snapView(view: UIView) -> UIImageView { UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0) view.layer.renderInContext(UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() let snapShot = UIImageView(image: image) snapShot.layer.masksToBounds = false; snapShot.layer.cornerRadius = 0; snapShot.layer.shadowOffset = CGSizeMake(-5.0, 0.0); snapShot.layer.shadowOpacity = 0.4; snapShot.layer.shadowRadius = 5; snapShot.frame = view.frame return snapShot } func handleLongPress(longPress: UILongPressGestureRecognizer) { let point = longPress.locationInView(tableView) if let indexPath = tableView.indexPathForRowAtPoint(point) { switch longPress.state { case .Began: if let cell = tableView.cellForRowAtIndexPath(indexPath) { sourceIndexPath = indexPath let snapView = self.snapView(cell) snapView.alpha = 0 self.snapView = snapView tableView.addSubview(snapView) UIView.animateWithDuration(0.25, animations: { // 选中Cell跳出放大效果 snapView.alpha = 0.95 snapView.center = CGPointMake(cell.center.x, point.y) snapView.transform = CGAffineTransformMakeScale(1.05, 1.05) cell.alpha = 0 }, completion: { (_) -> Void in cell.hidden = true cell.alpha = 1 }) } else { sourceIndexPath = nil snapView = nil } case .Changed: if let snapView = snapView { // 截图随手指上下移动 snapView.center = CGPointMake(snapView.center.x, point.y) } // 如果手指移动到一个新的Cell上面,隐藏Cell跟此Cell交换位置 if let fromIndexPath = sourceIndexPath { if fromIndexPath != indexPath { tableView.beginUpdates() delegate?.rearrangeTableView(tableView, moveRowAtIndexPath: fromIndexPath, toIndexPath: indexPath) tableView.endUpdates() sourceIndexPath = indexPath } } // 手指移动到屏幕顶端或底部,UITableView自动滚动 let step: CGFloat = 64 if let parentView = tableView.superview { let parentPos = tableView.convertPoint(point, toView: parentView) if parentPos.y > parentView.bounds.height - step { var offset = tableView.contentOffset offset.y += (parentPos.y - parentView.bounds.height + step) if offset.y > tableView.contentSize.height - tableView.bounds.height { offset.y = tableView.contentSize.height - tableView.bounds.height } tableView.setContentOffset(offset, animated: false) } else if parentPos.y <= step { var offset = tableView.contentOffset offset.y -= (step - parentPos.y) if offset.y < 0 { offset.y = 0 } tableView.setContentOffset(offset, animated: false) } } default: if let snapView = snapView, let fromIndexPath = sourceIndexPath, let cell = tableView.cellForRowAtIndexPath(fromIndexPath) { cell.alpha = 0 cell.hidden = false // 长按移动结束,隐藏的Cell恢复显示,删除截图 UIView.animateWithDuration(0.25, animations: { () -> Void in snapView.center = cell.center snapView.alpha = 0 cell.alpha = 1 }, completion: { [unowned self] (_) -> Void in snapView.removeFromSuperview() self.snapView = nil self.sourceIndexPath = nil self.tableView.performSelector(#selector(UITableView.reloadData), withObject: nil, afterDelay: 0.5) }) } } } } } ================================================ FILE: Sublime/Sublime/Utils/ShareToWeixin.swift ================================================ // // ShareToWeixin.swift // Sublime // // Created by Eular on 2/18/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Foundation // MARK: - 微信分享 extension UIViewController { // MARK: - 分享链接 func WXShareLink(title: String, desc: String, img: String, link: String, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() message.title = title message.description = desc message.setThumbImage(UIImage(named: img)) let ext = WXWebpageObject() ext.webpageUrl = link message.mediaObject = ext let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享图片 func WXShareImage(image: UIImage, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() let imageObject = WXImageObject() imageObject.imageData = UIImagePNGRepresentation(image) message.mediaObject = imageObject //图片缩略图 let width: CGFloat = 240 let height = width * image.size.height / image.size.width UIGraphicsBeginImageContext(CGSizeMake(width, height)) image.drawInRect(CGRectMake(0, 0, width, height)) message.setThumbImage(UIGraphicsGetImageFromCurrentImageContext()) UIGraphicsEndImageContext() let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享文字 func WXShareText(text: String, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let req = SendMessageToWXReq() req.bText = true req.text = text req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享音乐 func WXShareMusic(name: String, singer: String, img: String, url: String, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() message.title = name message.description = singer message.setThumbImage(UIImage(named: img)) let music = WXMusicObject() music.musicUrl = url music.musicDataUrl = url message.mediaObject = music let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享视频 func WXShareVideo(title: String, desc: String, img: String, url: String, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() message.title = title message.description = desc message.setThumbImage(UIImage(named: img)) let video = WXVideoObject() video.videoUrl = url message.mediaObject = video let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享表情,包括gif func WXShareEmoticon(emotPath: String, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() message.setThumbImage(UIImage(contentsOfFile: emotPath)) let emot = WXEmoticonObject() emot.emoticonData = NSData(contentsOfFile: emotPath) message.mediaObject = emot let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } // MARK: - 分享文件 func WXShareFile(title: String, desc: String, file: File, isTimeline: Bool = false) { if WXApi.isWXAppInstalled() { let message = WXMediaMessage() message.title = title message.description = desc message.setThumbImage(UIImage(named: file.img)) let fobj = WXFileObject() fobj.fileExtension = file.ext fobj.fileData = file.data message.mediaObject = fobj let req = SendMessageToWXReq() req.bText = false req.message = message req.scene = isTimeline ? Int32(WXSceneTimeline.rawValue) : Int32(WXSceneSession.rawValue) WXApi.sendReq(req) } else { _WXIsNotInstallAlert() } } func WXLogin() { let req: SendAuthReq = SendAuthReq() req.scope = "snsapi_userinfo,snsapi_base" WXApi.sendReq(req) } // MARK: - 私有方法 private func _WXIsNotInstallAlert() { let alert = UIAlertController(title: "Share Fail", message: "Wechat app is not installed!", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) presentViewController(alert, animated: true, completion: nil) } } ================================================ FILE: Sublime/Sublime/Utils/SublimeTable.swift ================================================ // // SublimeTable.swift // Sublime // // Created by Eular on 5/5/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit class SublimeTable: UITableViewController { override func viewDidLoad() { super.viewDidLoad() } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 0 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } } ================================================ FILE: Sublime/Sublime/Utils/UnitTest.swift ================================================ // // UnitTest.swift // Sublime // // Created by Eular on 2/18/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import Foundation // MARK: - Unit Test /* let test_str = "hello Urinx 521" let test_arr = [1, 2, 3, 4] let test_dict = ["a":1, "b":2] // String.count -> Int assert(test_str.count == 15) // lower & upper assert(test_str.islower == false) assert(test_str.upper == "HELLO URINX 521") // String[n] -> Character assert(test_str[1] == "e") assert(test_str[-1] == "1") // String[m,n] -> String assert(test_str[6,-1] == "Urinx 52") assert(test_str[nil,2] == "he") assert(test_str[7,nil] == "rinx 521") // String[range] -> String assert(test_str[0...2] == "hel") // String.count() -> Int assert(test_str.count("lo") == 1) // String.has() -> Bool assert(test_str.has("he") == true) // String.hasAny() -> Bool assert(test_str.hasAny(["aa","bb","cc"]) == false) // String.pop() -> Character var tmp = "abc" assert(tmp.pop() == "c") assert(tmp == "ab") // String.find() -> Int assert(test_str.find("U") == 6) // String.join() -> String assert("#".join([1,2,3]) == "1#2#3") assert("#".join(["a","b","c"]) == "a#b#c") // String.split() -> [String] assert(test_str.split(" ") == ["hello", "Urinx", "521"]) // String.replace() -> String var tmp2 = "abc" assert(tmp2.replace("a", "1") == "1bc") // String.strip() -> String assert(" abcd ".strip() == "abcd") // String.trim() -> String assert(" a b ".trim() == "a b") // len() -> Int assert(len(test_str) == 15) assert(len(test_arr) == 4) assert(len(test_dict) == 2) // range() -> Array assert(range(4) == [0, 1, 2, 3]) assert(range(1,5) == [1, 2, 3, 4]) assert(range(10,1,-2) == [10, 8, 6, 4, 2]) // Int + String assert(1+"a" == "1a") // String * Int assert("a" * 3 == "aaa") // Array.shift() or .pop() var arr = [1,2,3] assert(arr.shift() == 1) assert(arr.pop() == 3) // random() -> UInt32 random() random(11) random(5, 10) random(0, 10, arrLen: 5) */ ================================================ FILE: Sublime/Sublime/Utils/VideoPlayerTimeView.swift ================================================ // // VideoPlayerTimeView.swift // Sublime // // Created by Eular on 5/3/16. // Copyright © 2016 Eular. All rights reserved. // import Foundation class VideoPlayerTimeView: UIView { private let curTimeLabel = UILabel() private let totalTimeLabel = UILabel() private let curTimeLine = UILabel() private let totalTimeLine = UILabel() private var originY: CGFloat! var show: Bool = false { didSet { hidden = !show if show { UIView.animateWithDuration(0.5, animations: { self.frame.origin.y -= self.frame.height }, completion: { (_) -> Void in UIView.animateWithDuration(5) { self.alpha = 0 } }) } else { self.frame.origin.y = originY self.alpha = 0.5 } } } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.blackColor() alpha = 0.5 hidden = true originY = frame.origin.y curTimeLabel.text = "00:00:00" totalTimeLabel.text = "00:00:00" curTimeLabel.frame = CGRectMake(0, 0, 100, frame.height) totalTimeLabel.frame = CGRectMake(frame.width - 100, 0, 100, frame.height) curTimeLine.frame = CGRectMake(100, 14, 0, 2) totalTimeLine.frame = CGRectMake(100, 14, frame.width - 200, 2) curTimeLabel.textAlignment = .Center totalTimeLabel.textAlignment = .Center curTimeLabel.textColor = UIColor.whiteColor() totalTimeLabel.textColor = UIColor.whiteColor() curTimeLine.backgroundColor = RGB(0, 175, 244) totalTimeLine.backgroundColor = UIColor.whiteColor() addSubview(curTimeLabel) addSubview(totalTimeLabel) addSubview(totalTimeLine) addSubview(curTimeLine) } func setTime(curTime: Double, totalTime: Double) { curTimeLabel.text = curTime.formatedTime("HH:mm:ss") totalTimeLabel.text = totalTime.formatedTime("HH:mm:ss") curTimeLine.frame.size.width = totalTimeLine.frame.width * CGFloat( curTime / totalTime ) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } ================================================ FILE: Sublime/Sublime/VideoViewController.swift ================================================ // // VideoViewController.swift // Sublime // // Created by Eular on 2/19/16. // Copyright © 2016 Eular. All rights reserved. // import UIKit import AVKit import AVFoundation class VideoViewController: UIViewController { let popupMenu = PopupMenu() var curFile: File! var player: AVPlayer! var playerLayer: AVPlayerLayer! var isPlay: Bool { return player?.rate == 1.0 } var isFullScreen: Bool = false { didSet { navigationController?.setNavigationBarHidden(isFullScreen, animated: true) tabBarController?.tabBar.hidden = isFullScreen playerTimeView.show = isFullScreen && !isPlay } } let pauseView = UIView() var pauseViewFrame: CGRect { if isFullScreen { return CGRectMake((view.width - 200) / 2, (view.height - 200) / 2, 200, 200) } else { return CGRectMake(0, (view.height - 200) / 2, view.width, 200) } } var playerTimeView: VideoPlayerTimeView! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = Constant.CapeCod title = curFile.name // 设置分享菜单 navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Action, target: popupMenu, action: #selector(popupMenu.showUp)) popupMenu.controller = self popupMenu.itemsToShare = [curFile.url] player = AVPlayer(URL: curFile.url) playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.frame playerLayer.frame.size.height -= Constant.NavigationBarOffset self.view.layer.addSublayer(playerLayer) let oneTap = UITapGestureRecognizer(target: self, action: #selector(self.handleOneTapGesture(_:))) pauseView.frame = pauseViewFrame pauseView.frame.size.height -= Constant.NavigationBarOffset pauseView.addGestureRecognizer(oneTap) view.addSubview(pauseView) let doubleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleDoubleTapGesture(_:))) doubleTap.numberOfTapsRequired = 2 view.addGestureRecognizer(doubleTap) playerTimeView = VideoPlayerTimeView(frame: CGRectMake( 0, view.width, view.height, 30)) view.addSubview(playerTimeView) let lastPlayTime = Global.Database.doubleForKey("video-\(curFile.name.md5)") player.seekToTime(CMTimeMakeWithSeconds(lastPlayTime, 600)) player.play() } func handleOneTapGesture(sender: UITapGestureRecognizer) { if isPlay { player.pause() } else { player.play() } let playerItem = player.currentItem! playerTimeView.setTime(playerItem.currentTime().seconds, totalTime: playerItem.duration.seconds) playerTimeView.show = isFullScreen && !isPlay } func handleDoubleTapGesture(sender: UITapGestureRecognizer) { isFullScreen = !isFullScreen if isFullScreen { UIDevice.currentDevice().setValue(UIInterfaceOrientation.LandscapeLeft.rawValue, forKey: "orientation") } else { UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation") tabBarController?.tabBar.hidden = true } playerLayer.frame = self.view.bounds pauseView.frame = pauseViewFrame } override func viewWillDisappear(animated: Bool) { player.pause() let key = "video-\(curFile.name.md5)" let playerItem = player.currentItem! if CMTimeGetSeconds(playerItem.duration - playerItem.currentTime()) < 0.1 { Global.Database.setDouble(0, forKey: key) } else { Global.Database.setDouble(playerItem.currentTime().seconds, forKey: key) } } override func shouldAutorotate() -> Bool { return true } } // let player = AVPlayer(URL: curFile.url) // let playerController = AVPlayerViewController() // playerController.player = player // self.addChildViewController(playerController) // self.view.addSubview(playerController.view) // playerController.view.frame = CGRectMake(0, 200, 320, 200) // player.play() ================================================ FILE: Sublime/Sublime/Web/404.html ================================================ Sublime Text

Sublime Text

  • This is default 404 page and it will shows up when there is no page in the current path.
  • The server root folder is located at /var/www/, you can put all your HTML, js, css files into there.
  • Remind, PHP file is not support now.
================================================ FILE: Sublime/Sublime/Web/README.txt ================================================ A Pen created at CodePen.io. You can find this one at http://codepen.io/frxnz/pen/kqGaI. ================================================ FILE: Sublime/Sublime/Web/index.html ================================================ Sublime Text

Sublime Text


File Browser

    ================================================ FILE: Sublime/Sublime/Web/js/index.js ================================================ /*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) },removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("